Re: Odd behavior for manually-constructed file-stream

Gary Byers <[email protected]> Tue, 26 Sep 2006 01:20:28 -0600 (MDT)
Newsgroups gmane.lisp.openmcl.bugs
Message-ID <[email protected]>
I'm changing a lot of the stream code for 1.1, so some of this may be a little
inaccurate.

Both CCL::MAKE-FD-STREAM and a function called CCL::MAKE-FILE-STREAM mostly
just:

   a) parse their arguments and do some sanity-checking/normalization of them
   b) call CCL::MAKE-IOBLOCK-STREAM - with lots of keyword arguments - to
      do most of the work of actually creating the stream and initializing it.

I think that the (in some ways) less sleazy approach would be to have something
that parsed a bunch of arguments (one of which was an open fd) and called
CCL::MAKE-IOBLOCK-STREAM.  Much of the hair in OPEN and CCL::MAKE-FILE-STREAM
has to do with handling the :IF-EXISTS and :IF-DOES-NOT-EXIST cases  -which
can be ignored - so there's probably (knock wood) not -too- much hair remaining.

I'm a little leery about trying to provide an example implementation,
but you'd basically want to parse reasonable OPEN-like arguments and
call CCL::MAKE-IOBLOCK-STREAM with arguments like those passed in
CCL::MAKE-FILE-STREAM; note that some of these are very different from
the arguments that CCL::MAKE-FD-STREAM passes to
CCL::MAKE-IOBLOCK-STREAM.   Some of these have to do with the fact that
file streams are seekable and this make's things more complicated, especialy
when the stream has :direction :io.

 	:share-buffers-p should be true for I/O FILE-STREAMS
         :advance-function (used to read when there's no pending input)
            has to handle the case where the (shared) buffer is has been
            written to.
         :force-output-function has some similar issues, especially when
            the stream has :direction :io
         :device is the file descriptor we want to wrap a stream around.

I -think- that that's most of what you'd need to be aware of.  You might
also want to do (SETF (FILE-IOBLOCK-FILEEOF ....) as CCL::MAKE-FILE-STREAM
does; I don't remember if things still use that.






On Mon, 25 Sep 2006, Richard M Kreuter wrote:

>
> First, thanks for the speedy reply.
>
> Gary Byers writes:
>> On Sun, 24 Sep 2006, Richard M Kreuter wrote:
>>>
>>> What am I doing wrong?
>>
>> Why are you using CCL::MAKE-FD-STREAM ?
>
> It was a routine in an asdf-installable library that called
> CCL::MAKE-FD-STREAM on file descriptor from a C FILE returned by
> tmpfile.  At the moment I'm trying to figure out how to fix the
> implementation of that library on OpenMCL.
>
>> (If the answer is "because you already had a file descriptor and
>> wanted to use stream functions to access it, as in your example"
>> ... it'd be handy to have something like that - something like OPEN
>> that took an open FD rather than a pathname - but it doesn't really
>> exist.)
>
> Yeah, that's basically it.
>
>> One very, very sleazy way of doing that - that might almost work -
>> would be to use OPEN to create a file stream to some (other) temporary
>> file, then use the #_dup2 functon to make the file descriptor of that
>> stream match the file descriptor in question.
> <snip>
>> That's untested (and admittedly very, very sleazy.)
>
> Hrm.  Would you consider the following to be less sleazy?
>
> (defun get-file-stream-for-fd (fd &rest open-args)
>  (let ((dev-fd (make-pathname :directory '(:absolute "dev" "fd")
>                               :name (format nil "~D" fd))))
>    (apply #'open dev-fd open-args)))
>
> The only downside to it is that it doesn't actually work on Linux
> (haven't tried on OS X yet):
>
> TMPFILE> (let ((file (tmpfile)))
> 	   (unwind-protect
> 		(fileno file)
> 	     (foreign-free file)))
> 15
> TMPFILE> (get-file-stream-for-fd 15)
> No such file or directory : #P"/dev/fd/15"
>   [Condition of type CCL::SIMPLE-FILE-ERROR]
> ; Evaluation aborted
> TMPFILE> (probe-file "/dev/fd/15")
> NIL
> TMPFILE> (directory "/dev/fd/15")
> (#P"/dev/fd/15")
>
> The problem here is that Linux presents /dev/fd/NNN as symlinks, and in
> the case of file descriptors for unlinked files (as tmpfile returns),
> symlinks that don't resolve to existing pathnames (the same holds for
> file descriptors associated with child processes).  But since
> /dev/fd/NNN nodes are special magic, open(2)ing one still works even
> though the symlink target doesn't stat.  Perhaps %PROBE-FILE-X in
> linux-files.lisp should try open(2)ing the file O_RDONLY if the
> realpath(3) call fails?
>
> (Being able to open /dev/fd/NNN nodes in general would also solve one
> other problem I've run into: to give you a way to make a binary stream
> associated with the input or output of external-processes returned by
> run-program.)
>
> Thanks,
> RmK
>
>