First question is "how comes reading a fifo isn't blocking?"
% cd /tmp % mkfifo fifo % cat > test.scm (let ((fifo-port (open-input-file "/tmp/fifo"))) (pretty-print (read fifo-port)) (close-port fifo-port))
% gsi test.scm #!eof % echo "hello" > fifo& [1] 70455 % gsi test.scm [1] + done echo "hello" > fifo hello
Second question is "Why do I often have a 'device not configured' error with code like the one above?" (Bug not reproduced here, but often happens when I try to read or open where nothing is currently being written yet.)
Finally, I would like to know whether we could have a procedure WITH-ERROR-TO-FILE to redirect the error port too.
Regards,
Adrien
Afficher les réponses par date
On 1-Feb-08, at 6:33 AM, Adrien Pierard wrote:
First question is "how comes reading a fifo isn't blocking?"
% cd /tmp % mkfifo fifo % cat > test.scm (let ((fifo-port (open-input-file "/tmp/fifo"))) (pretty-print (read fifo-port)) (close-port fifo-port))
% gsi test.scm #!eof % echo "hello" > fifo& [1] 70455 % gsi test.scm [1] + done echo "hello" > fifo hello
This is a problem with the named pipe interface on Unix. When you open a named pipe in blocking mode, the open will wait for some process to open the writing end of the pipe. But when you open a named pipe in non-blocking mode and no process has yet opened the writing end of the pipe, the open will return immediately (which is fine) and with *no error condition* (which is not fine... returning EAGAIN would have made more sense).
So the only way for Gambit to get the blocking behavior, would be to call open without the O_NONBLOCK flag. But then this would stop the thread scheduler because the whole Gambit process would be blocked.
One way around this problem is to get some other process to block on the open. On Unix this can be done with this code:
(let ((fifo-port (open-process (list path: "cat" arguments: (list "/ tmp/fifo"))))) ...)
open-process will start the "cat" subprocess and return a port to read the output of "cat". The "cat" process will block, but this will not block Gambit's scheduler.
I guess Gambit's runtime system could take care of this (i.e. detecting the file is a named pipe, forking a process, and then behaving like cat), but I wonder if it is appropriate because it is rather expensive and complex. All of this to fix a stupid bug in Unix's open.
Second question is "Why do I often have a 'device not configured' error with code like the one above?" (Bug not reproduced here, but often happens when I try to read or open where nothing is currently being written yet.)
I have never seen this. So please give more detail on the situation, version of Gambit, version of the OS, etc.
Finally, I would like to know whether we could have a procedure WITH-ERROR-TO-FILE to redirect the error port too.
Can you give me a specific situation where you need this? The standard error is seldom used by Gambit's runtime. So all you will be redirecting is your own output which is sent to (current-error-port).
Marc
All of this to fix a stupid bug in Unix's open.
Sometime, years of evolution aren't enough ^^
Finally, I would like to know whether we could have a procedure WITH-ERROR-TO-FILE to redirect the error port too.
Can you give me a specific situation where you need this? The standard error is seldom used by Gambit's runtime. So all you will be redirecting is your own output which is sent to (current-error-port).
Must be my fault, but I use PP a lot, and as you told me once, it doesn't print on STDOUT (rather on the TTY if I remember correctly, but when I wrote this earlier today, I thought it was STDERR).
The point of this question, as well as the previous ones, is that I hack vim a bit to let it run interpreters through a proxy, which then remotely prints its results in windows. When I feed it with (begin (display 42) (newline) 'hello)
I have 42 in the STDOUT window, and the symbol hello in the RESULT window. Helps developping/debugging interpreted languages in vim. I then hope that implementors of other interpreted languages (perl, caml) or users will patch their implementations to allow for some with-output-to-file wrapper around the eval function, so that this method to interact with an editor can become generic. It could also help run interpreters as daemons...
Adrien
Adrien Pierard wrote:
Can you give me a specific situation where you need this? The standard error is seldom used by Gambit's runtime. So all you will be redirecting is your own output which is sent to (current-error-port).
Must be my fault, but I use PP a lot, and as you told me once, it doesn't print on STDOUT (rather on the TTY if I remember correctly, but when I wrote this earlier today, I thought it was STDERR).
Yes pp does print to the "interaction channel" by default (as written in the docs and verified by the following piece of code):
;; file "stderr-and-tty.scm"
(for-each pp (list ##console-port (current-output-port) (current-error-port)))
(display "start..\n" ##console-port)
(parameterize () ;;((current-error-port (current-output-port))) (set! ##console-port (current-error-port)) (display "Hallo") (newline) ;;(pretty-print "pretty-print") (pp "pp-with-explicit-port" (current-error-port)) (pp "pp") 'foo)
; $ gsi stderr-and-tty.scm > out 2>err ; #<input-output-port #2 (console)> ; #<output-port #3 (stdout)> ; #<output-port #4 (stderr)> ; start.. ; "pp" ; $ cat out ; Hallo ; $ cat err ; "pp-with-explicit-port"
As you can see, (set! ##console-port (current-error-port)) didn't have the effect I intended. I can't see a way to change the current console-port (*).
The point of this question, as well as the previous ones, is that I hack vim a bit to let it run interpreters through a proxy, which then remotely prints its results in windows. When I feed it with (begin (display 42) (newline) 'hello)
I have 42 in the STDOUT window, and the symbol hello in the RESULT window. Helps developping/debugging interpreted languages in vim. I then hope that implementors of other interpreted languages (perl, caml) or users will patch their implementations to allow for some with-output-to-file wrapper around the eval function, so that this method to interact with an editor can become generic.
In perl there's no builtin concept of a console port; only through modules which reopen the tty explicitely it gets to the console. The core uses STDERR for warnings. So this is the same as (parameterize ((current-error-port (current-output-port)) ...):
$ perl -we '{ local *STDERR= *STDOUT{IO}; print "Hello\n"; warn "World" } warn "after all"' >out 2>err $ cat out Hello World at -e line 1. $ cat err after all at -e line 1.
(That doesn't take care of C libraries etc. printing to filehandle 2 instead of going through the perl layer to use the STDERR 'variable'. You'd have to close fd 2 and dup 1 to 2 for this, but the same is true (and basically unportable since tied to posix systems) for any other system of course.)
It could also help run interpreters as daemons...
I did write some daemon code some time ago, could dig out code if needed, basically I could get what I wanted; having forgotten how I did it may be a sign that it's not very clear. BTW there's gsi -:d- ; this does what you want, while interestingly ##console-port is still being created and goes to the console, so Gambit *does* have some layer between ##console-port and pp actually, it's just not documented.
Christian.
(*) Well, if you don't mind getting dirty, you could try:
(define (@port-copy! target source) (let ((len (##vector-length target))) (if (= len (##vector-length source)) (begin (force-output target) (force-output source) (let lp ((i 0)) (cond ((< i len) (##vector-set! target i (##vector-ref source i)) (lp (+ i 1)))))) (error "you're wrong"))))
(parameterize () ;;((current-error-port (current-output-port))) (@port-copy! ##console-port (current-error-port)) (display "Hallo") (newline) ;;(pretty-print "pretty-print") (pp "pp-with-explicit-port" (current-error-port)) (pp "pp") 'foo)
; $ gsi stderr-and-tty.scm > out 2>err ; $ cat out ; Hallo ; $ cat err ; "pp" ; ith-explicit-port" ; "pp"
Fine, nothing on the console anymore. Uhm, well, somehow I happened to void the warranty after all ;) (the '"pp-w' part is missing).