chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Chicken-users] Questions/nitpicks about Posix I/O


From: Matt Gushee
Subject: [Chicken-users] Questions/nitpicks about Posix I/O
Date: Thu, 5 Sep 2013 22:48:48 -0600

Hello, Chicken folk--

This is a long and multipurpose message: first and most importantly, I
want to check my understanding of how to use the posix I/O interface.
But also, since this is a recurring issue that always bothers me, I
did some experiments, some of which revealed behavior that seems a bit
questionable--so I will present my results; and finally, I have a
small suggestion for the Posix API.

A. Is this the right way to do it?

I need to open an output file in append mode. Since none of the
high-level I/O functions appear to allow this, it seems I need to use
the posix library. Based on the example given for file-mkstemp, it
appears I should do something like this:

  (let* ((f (file-open "somefile.txt" (+ open/wronly open/creat open/append)))
            (p (open-output-file* f)))
      (display <some-text> p)
      (close-output-port p))

Of course, there are several possible variations of this code, but the
main point is that I'd like to make sure that the general approach of

  1. open file descriptor
  2. open port based on file descriptor
  3. write to port
  4. close port

is correct.

Thanks in advance!

However, assuming the above is correct, there are a couple of things
that bother me. First there is the apparent redundancy of (file-open
... open/append) vs. (open-output-file ... #:append). Then there is
the asymmetry of the open and close procedures. It is
(uncharacteristically for Scheme) rather inelegant, and that worries
me. So I decided to run a few tests ...

B. Experimental results

In an effort to get a better understanding of the relationship between
file descriptors and ports, I wrote a series of small test procedures.
Unfortunately I saved the file in /tmp ... intended to move it
somewhere, but of course I forgot to do that, so the file was lost.
But I'll summarize my observations, and if any of this is surprising I
will try to reconstruct the relevant code.

[Note: in the following list, 'fd' stands for file descriptor, and "it
is possible" implies "does not cause an error". My tests were
conducted w/ Chicken 4.8.0.3 on 32-bit Linux]

1. If you create an fd with file-open, then create an
   output port by applying open-output-file* to the
   resulting fd, you can pass an append argument to
   either function, or both; either way, both the fd
   and the port are then set to append mode.

2. An fd remains usable after an output port has been opened
   on it. I.e., both the fd and the port can receive output.
   However, strings written to the fd may appear in the output
   first, even if the program writes to the port first (I presume
   this is because the port is buffered and the fd is not, which
   seems reasonable)

3. After one output port has been opened and closed, it is an
   error to open another output port on the same fd.

4. It is an error to write to an fd after the corresponding
   port has been closed.

5. It is possible to write to a port after the corresponding
   fd has been closed, but this does not produce any output.

6. It is possible to open more than one output port on a
   single fd, but only the first port produces any output.

7. Given an fd F, it is possible to create a second fd G
   using duplicate-fileno, then open output ports P and Q,
   based on F and G respectively; both ports produce output.

8. If you pass #:append to one of the output ports opened in
   #7, that affects both fds and both ports.

9. It is possible to open more than one fd for output on a
   single file.

Now, I have a few comments on the above:

#1 is perhaps not really a problem. But given that (file-open ...
open/append) and (open-output-file* ... #:append) *appear* to do
exactly the same thing, it might be good for the documentation either
to explain the difference, or to explicitly state that there is no
difference.

#2, 3, and 4 seem unsurprising and reasonable.

#5 and 6 are a bit worrisome. Shouldn't these be errors?

#7-9: It seems like generally a bad idea to open more than one fd on a
single file. However, I took a look at the POSIX open() man page, and
as far as I can tell this behavior is permitted.

C. A Suggestion

Given all the above ... it seems to me that the name
'open-output-file*' is misleading. To me the term 'open' strongly
implies that (a) the state of some resource is changed, and (b) there
needs to be a matching 'close'. But given that open-output-file*
requires an open fd, and that you can write to the fd whether or not
you create the port, it appears that open-output-file* really doesn't
open anything ... or, in other words, it does nothing to change the
state of the file object, it simply makes it available for high-level
output procedures. So, assuming the behavior I've observed is true on
all or most platforms, and likely to remain true in the future, I
would suggest that a better name for the procedure would be:
'fileno->output-port' (and though I haven't really been looking at
'open-input-file*', perhaps that should also be renamed
'fileno->input-port'). This name would, I think, better reflect what
is really going on, and would eliminate the apparent wrongness of
writing code with two 'opens' and one 'close'.

Best regards,
Matt Gushee



reply via email to

[Prev in Thread] Current Thread [Next in Thread]