[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Chicken-users] Pipe and thread problem
From: |
Moritz Heidkamp |
Subject: |
Re: [Chicken-users] Pipe and thread problem |
Date: |
Wed, 24 Oct 2012 23:10:20 +0200 |
Hey Chickeneers,
out of curiosity I implemented (probably horribly inefficitent)
thread-aware replacements for open-input-file* and open-output-file*
(see below). While implementing them I came across something that I
didn't quite understand: file-read and file-write raise errors whenever
the underlying syscall returns -1. However, in this case I want to
handle some error situations (i.e. EINTR, EAGAIN and EWOULDBLOCK). The
only way I could find to do this is by dispatching on (errno) in the
excpetion handler. However it looks like (errno) is not thread-safe so
it might actually return a different value when my handler is run. Is
this observation correct? Perhaps we should mention this in errno's
documentation? Also, to make it possible to handle these errors I
suggest to add the respective errno to the condition object. This would
be thread-safe as the posix unit declares disable-interrupts. Thoughts?
OK, here we go. It seems to work with your program, Aaron:
(define (open-input-fd fd)
(make-input-port
(lambda ()
(let loop ()
(thread-wait-for-i/o! fd #:input)
(or (condition-case
(string-ref (car (file-read fd 1)) 0)
(exn (exn i/o file)
(select (errno)
((errno/intr errno/again errno/wouldblock)
#f)
(else (signal exn)))))
(loop))))
(lambda ()
(nth-value 0 (file-select fd #f 0)))
(lambda ()
(file-close fd))))
(define (open-output-fd fd)
(let ((port (open-output-file* fd)))
(make-output-port
(lambda (buffer)
(let loop ((buffer buffer) (len (string-length buffer)))
(thread-wait-for-i/o! fd #:output)
(let ((written (condition-case
(file-write fd buffer)
(exn (exn i/o file)
(select (errno)
((errno/intr errno/again errno/wouldblock)
#f)
(else (signal exn)))))))
(if written
(unless (= written len)
(loop (substring buffer written len) (- len written)))
(loop buffer len)))))
(lambda ()
(close-output-port port))
(lambda ()
(flush-output port)))))
Oh yeah, and note the lame solution of opening the output FD with
open-output-file* -- this is only because there is no flush-file in
posix. Perhaps worth adding?
Moritz
Aaron Patterson <address@hidden> writes:
> On Wed, Oct 24, 2012 at 08:04:37AM -0400, Felix wrote:
>> From: Aaron Patterson <address@hidden>
>> Subject: [Chicken-users] Pipe and thread problem
>> Date: Tue, 23 Oct 2012 14:30:57 -0700
>>
>> > Hi, I'm trying to simulate reading from a TTY that writes every two
>> > seconds. I want to do this with a pipe and two threads, one thread
>> > writes every N seconds, while the other reads any data available on the
>> > pipe.
>> >
>> > Unfortunately, my code just hangs. After speaking with the fine people
>> > in #chicken, it seems that this may be a bug. We played with different
>> > calls to put the threads to sleep, and different functions to read data,
>> > but they all ended up freezing at some point.
>>
>> The ports obtained from calls to "open-[input|output]-file*" use
>> internally the "stream-port" class (ports on FILE* streams, in this
>> case created via fdopen(3)). These are not thread-aware, AFAICT. Ports
>> created for socket-fd's (tcp.scm) and processes (posixunix.scm, see
>> specifically ##sys#custom-[input|output]-port") apparently do.
>
> Is there a different way I should be opening the pipe so that it is
> thread aware?