2008-01-18 18:18:54 -05:00
|
|
|
! Copyright (C) 2004, 2008 Slava Pestov.
|
2007-09-20 18:09:08 -04:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2008-01-18 18:18:54 -05:00
|
|
|
USING: alien generic assocs kernel kernel.private math
|
2008-02-18 08:30:16 -05:00
|
|
|
io.nonblocking sequences strings structs sbufs
|
2008-02-21 19:05:04 -05:00
|
|
|
threads unix vectors io.buffers io.backend io.encodings
|
2008-02-18 08:30:16 -05:00
|
|
|
io.streams.duplex math.parser continuations system libc
|
2008-03-29 01:59:05 -04:00
|
|
|
qualified namespaces io.timeouts io.encodings.utf8 accessors ;
|
2008-01-18 18:18:54 -05:00
|
|
|
QUALIFIED: io
|
2007-09-20 18:09:08 -04:00
|
|
|
IN: io.unix.backend
|
|
|
|
|
2008-01-20 17:07:18 -05:00
|
|
|
! I/O tasks
|
|
|
|
TUPLE: io-task port callbacks ;
|
|
|
|
|
2008-03-29 01:59:05 -04:00
|
|
|
: io-task-fd port>> handle>> ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-02-02 17:23:04 -05:00
|
|
|
: <io-task> ( port continuation/f class -- task )
|
2008-04-11 13:47:49 -04:00
|
|
|
construct-empty
|
|
|
|
swap [ 1vector ] [ V{ } clone ] if* >>callbacks
|
|
|
|
swap >>port ; inline
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-04-11 13:47:49 -04:00
|
|
|
TUPLE: input-task < io-task ;
|
2008-01-21 15:33:43 -05:00
|
|
|
|
2008-04-11 13:47:49 -04:00
|
|
|
TUPLE: output-task < io-task ;
|
2008-01-21 15:33:43 -05:00
|
|
|
|
2008-01-20 17:07:18 -05:00
|
|
|
GENERIC: do-io-task ( task -- ? )
|
|
|
|
GENERIC: io-task-container ( mx task -- hashtable )
|
|
|
|
|
|
|
|
! I/O multiplexers
|
|
|
|
TUPLE: mx fd reads writes ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-03-29 01:59:05 -04:00
|
|
|
M: input-task io-task-container drop reads>> ;
|
2008-01-21 15:33:43 -05:00
|
|
|
|
2008-03-29 01:59:05 -04:00
|
|
|
M: output-task io-task-container drop writes>> ;
|
2008-01-21 15:33:43 -05:00
|
|
|
|
2008-04-11 13:47:49 -04:00
|
|
|
: construct-mx ( class -- obj )
|
|
|
|
construct-empty
|
|
|
|
H{ } clone >>reads
|
|
|
|
H{ } clone >>writes ; inline
|
2008-01-20 17:07:18 -05:00
|
|
|
|
|
|
|
GENERIC: register-io-task ( task mx -- )
|
|
|
|
GENERIC: unregister-io-task ( task mx -- )
|
2008-01-21 15:33:43 -05:00
|
|
|
GENERIC: wait-for-events ( ms mx -- )
|
2008-01-20 17:07:18 -05:00
|
|
|
|
|
|
|
: fd/container ( task mx -- task fd container )
|
|
|
|
over io-task-container >r dup io-task-fd r> ; inline
|
|
|
|
|
|
|
|
: check-io-task ( task mx -- )
|
|
|
|
fd/container key? nip [
|
|
|
|
"Cannot perform multiple reads from the same port" throw
|
|
|
|
] when ;
|
|
|
|
|
|
|
|
M: mx register-io-task ( task mx -- )
|
|
|
|
2dup check-io-task fd/container set-at ;
|
|
|
|
|
2008-01-31 13:27:37 -05:00
|
|
|
: add-io-task ( task -- )
|
2008-02-18 06:07:40 -05:00
|
|
|
mx get-global register-io-task ;
|
2008-01-31 13:27:37 -05:00
|
|
|
|
|
|
|
: with-port-continuation ( port quot -- port )
|
2008-02-19 15:38:02 -05:00
|
|
|
[ "I/O" suspend drop ] curry with-timeout ; inline
|
2008-01-20 17:07:18 -05:00
|
|
|
|
|
|
|
M: mx unregister-io-task ( task mx -- )
|
|
|
|
fd/container delete-at drop ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
! Some general stuff
|
|
|
|
: file-mode OCT: 0666 ;
|
|
|
|
|
|
|
|
: (io-error) ( -- * ) err_no strerror throw ;
|
|
|
|
|
2008-03-21 15:53:11 -04:00
|
|
|
: check-errno ( -- )
|
|
|
|
err_no dup zero? [ drop ] [ strerror throw ] if ;
|
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
: check-null ( n -- ) zero? [ (io-error) ] when ;
|
|
|
|
|
|
|
|
: io-error ( n -- ) 0 < [ (io-error) ] when ;
|
|
|
|
|
|
|
|
M: integer init-handle ( fd -- )
|
|
|
|
#! We drop the error code rather than calling io-error,
|
|
|
|
#! since on OS X 10.3, this operation fails from init-io
|
|
|
|
#! when running the Factor.app (presumably because fd 0 and
|
|
|
|
#! 1 are closed).
|
|
|
|
F_SETFL O_NONBLOCK fcntl drop ;
|
|
|
|
|
2007-11-07 14:01:45 -05:00
|
|
|
M: integer close-handle ( fd -- )
|
|
|
|
close ;
|
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
: report-error ( error port -- )
|
2008-03-29 01:59:05 -04:00
|
|
|
[ "Error on fd " % dup handle>> # ": " % swap % ] "" make
|
|
|
|
>>error drop ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: ignorable-error? ( n -- ? )
|
2008-03-29 01:59:05 -04:00
|
|
|
[ EAGAIN number= ] [ EINTR number= ] bi or ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: defer-error ( port -- ? )
|
|
|
|
#! Return t if it is an unrecoverable error.
|
|
|
|
err_no dup ignorable-error?
|
|
|
|
[ 2drop f ] [ strerror swap report-error t ] if ;
|
|
|
|
|
2008-01-20 17:07:18 -05:00
|
|
|
: pop-callbacks ( mx task -- )
|
|
|
|
dup rot unregister-io-task
|
2008-02-18 06:07:40 -05:00
|
|
|
io-task-callbacks [ resume ] each ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-01-20 17:07:18 -05:00
|
|
|
: handle-io-task ( mx task -- )
|
|
|
|
dup do-io-task [ pop-callbacks ] [ 2drop ] if ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-02-02 01:30:47 -05:00
|
|
|
: handle-timeout ( port mx assoc -- )
|
|
|
|
>r swap port-handle r> delete-at* [
|
2008-03-29 01:59:05 -04:00
|
|
|
"I/O operation cancelled" over port>> report-error
|
2008-02-02 01:30:47 -05:00
|
|
|
pop-callbacks
|
|
|
|
] [
|
|
|
|
2drop
|
|
|
|
] if ;
|
|
|
|
|
|
|
|
: cancel-io-tasks ( port mx -- )
|
2008-03-29 01:59:05 -04:00
|
|
|
[ dup reads>> handle-timeout ]
|
|
|
|
[ dup writes>> handle-timeout ] 2bi ;
|
2008-02-02 01:30:47 -05:00
|
|
|
|
2008-04-02 21:09:56 -04:00
|
|
|
M: unix cancel-io ( port -- )
|
2008-02-02 01:30:47 -05:00
|
|
|
mx get-global cancel-io-tasks ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
! Readers
|
|
|
|
: reader-eof ( reader -- )
|
2008-03-29 01:59:05 -04:00
|
|
|
dup buffer-empty? [ t >>eof? ] when drop ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: (refill) ( port -- n )
|
2008-03-29 01:59:05 -04:00
|
|
|
[ handle>> ] [ buffer-end ] [ buffer-capacity ] tri read ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: refill ( port -- ? )
|
|
|
|
#! Return f if there is a recoverable error
|
|
|
|
dup buffer-empty? [
|
|
|
|
dup (refill) dup 0 >= [
|
|
|
|
swap n>buffer t
|
|
|
|
] [
|
|
|
|
drop defer-error
|
|
|
|
] if
|
|
|
|
] [
|
|
|
|
drop t
|
|
|
|
] if ;
|
|
|
|
|
2008-04-11 13:47:49 -04:00
|
|
|
TUPLE: read-task < input-task ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
: <read-task> ( port continuation -- task )
|
2008-04-11 13:47:49 -04:00
|
|
|
read-task <io-task> ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: read-task do-io-task
|
|
|
|
io-task-port dup refill
|
|
|
|
[ [ reader-eof ] [ drop ] if ] keep ;
|
|
|
|
|
|
|
|
M: input-port (wait-to-read)
|
2008-01-31 13:27:37 -05:00
|
|
|
[ <read-task> add-io-task ] with-port-continuation
|
|
|
|
pending-error ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
! Writers
|
|
|
|
: write-step ( port -- ? )
|
2008-03-29 01:59:05 -04:00
|
|
|
dup [ handle>> ] [ buffer@ ] [ buffer-length ] tri write
|
2007-09-20 18:09:08 -04:00
|
|
|
dup 0 >= [ swap buffer-consume f ] [ drop defer-error ] if ;
|
|
|
|
|
2008-04-11 13:47:49 -04:00
|
|
|
TUPLE: write-task < output-task ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
: <write-task> ( port continuation -- task )
|
2008-04-11 13:47:49 -04:00
|
|
|
write-task <io-task> ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: write-task do-io-task
|
2008-03-29 01:59:05 -04:00
|
|
|
io-task-port dup [ buffer-empty? ] [ port-error ] bi or
|
2007-09-20 18:09:08 -04:00
|
|
|
[ 0 swap buffer-reset t ] [ write-step ] if ;
|
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
: add-write-io-task ( port continuation -- )
|
2008-01-20 17:07:18 -05:00
|
|
|
over port-handle mx get-global mx-writes at*
|
2008-02-21 03:31:37 -05:00
|
|
|
[ io-task-callbacks push drop ]
|
2008-01-20 17:07:18 -05:00
|
|
|
[ drop <write-task> add-io-task ] if ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: (wait-to-write) ( port -- )
|
2008-01-31 13:27:37 -05:00
|
|
|
[ add-write-io-task ] with-port-continuation drop ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2007-11-07 14:01:45 -05:00
|
|
|
M: port port-flush ( port -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
dup buffer-empty? [ drop ] [ (wait-to-write) ] if ;
|
|
|
|
|
2008-04-02 21:09:56 -04:00
|
|
|
M: unix io-multiplex ( ms/f -- )
|
2008-02-09 22:34:42 -05:00
|
|
|
mx get-global wait-for-events ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 21:09:56 -04:00
|
|
|
M: unix (init-stdio) ( -- )
|
2008-02-24 02:37:05 -05:00
|
|
|
0 <reader>
|
|
|
|
1 <writer>
|
|
|
|
2 <writer> ;
|
2008-01-18 19:43:14 -05:00
|
|
|
|
2008-01-20 17:07:18 -05:00
|
|
|
! mx io-task for embedding an fd-based mx inside another mx
|
|
|
|
TUPLE: mx-port mx ;
|
|
|
|
|
|
|
|
: <mx-port> ( mx -- port )
|
2008-03-29 01:59:05 -04:00
|
|
|
dup fd>> f mx-port <port>
|
2008-01-20 17:07:18 -05:00
|
|
|
{ set-mx-port-mx set-delegate } mx-port construct ;
|
|
|
|
|
2008-04-11 13:47:49 -04:00
|
|
|
TUPLE: mx-task < io-task ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
|
|
|
: <mx-task> ( port -- task )
|
2008-02-02 17:23:04 -05:00
|
|
|
f mx-task <io-task> ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
|
|
|
M: mx-task do-io-task
|
2008-03-29 01:59:05 -04:00
|
|
|
port>> mx>> 0 swap wait-for-events f ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-01-18 19:43:14 -05:00
|
|
|
: multiplexer-error ( n -- )
|
|
|
|
0 < [ err_no ignorable-error? [ (io-error) ] unless ] when ;
|
2008-04-11 10:54:50 -04:00
|
|
|
|
|
|
|
: ?flag ( n mask symbol -- n )
|
|
|
|
pick rot bitand 0 > [ , ] [ drop ] if ;
|