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
|
|
|
|
io.nonblocking sequences strings structs sbufs threads unix
|
|
|
|
vectors io.buffers io.backend io.streams.duplex math.parser
|
|
|
|
continuations system libc qualified namespaces ;
|
|
|
|
QUALIFIED: io
|
2007-09-20 18:09:08 -04:00
|
|
|
IN: io.unix.backend
|
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
! Multiplexer protocol
|
|
|
|
SYMBOL: unix-io-backend
|
|
|
|
|
|
|
|
HOOK: init-unix-io unix-io-backend ( -- )
|
|
|
|
HOOK: register-io-task unix-io-backend ( task -- )
|
|
|
|
HOOK: unregister-io-task unix-io-backend ( task -- )
|
|
|
|
HOOK: unix-io-multiplex unix-io-backend ( timeval -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
TUPLE: unix-io ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
! Global variables
|
|
|
|
SYMBOL: read-tasks
|
|
|
|
SYMBOL: write-tasks
|
|
|
|
|
|
|
|
! Some general stuff
|
|
|
|
: file-mode OCT: 0666 ;
|
|
|
|
|
|
|
|
: (io-error) ( -- * ) err_no strerror throw ;
|
|
|
|
|
|
|
|
: 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 -- )
|
|
|
|
[ "Error on fd " % dup port-handle # ": " % swap % ] "" make
|
|
|
|
swap set-port-error ;
|
|
|
|
|
|
|
|
: ignorable-error? ( n -- ? )
|
|
|
|
dup EAGAIN number= swap EINTR number= or ;
|
|
|
|
|
|
|
|
: defer-error ( port -- ? )
|
|
|
|
#! Return t if it is an unrecoverable error.
|
|
|
|
err_no dup ignorable-error?
|
|
|
|
[ 2drop f ] [ strerror swap report-error t ] if ;
|
|
|
|
|
|
|
|
! Associates a port with a list of continuations waiting on the
|
|
|
|
! port to finish I/O
|
|
|
|
TUPLE: io-task port callbacks ;
|
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
: <io-task> ( port continuation class -- task )
|
|
|
|
>r 1vector io-task construct-boa r> construct-delegate ;
|
|
|
|
inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
! Multiplexer
|
|
|
|
GENERIC: do-io-task ( task -- ? )
|
|
|
|
GENERIC: task-container ( task -- vector )
|
|
|
|
|
|
|
|
: io-task-fd io-task-port port-handle ;
|
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
: check-io-task ( task -- )
|
|
|
|
dup io-task-fd swap task-container at [
|
2007-09-20 18:09:08 -04:00
|
|
|
"Cannot perform multiple reads from the same port" throw
|
2008-01-18 18:18:54 -05:00
|
|
|
] when ;
|
|
|
|
|
|
|
|
: add-io-task ( task -- )
|
|
|
|
dup check-io-task
|
|
|
|
dup register-io-task
|
|
|
|
dup io-task-fd over task-container set-at ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: remove-io-task ( task -- )
|
2008-01-18 18:18:54 -05:00
|
|
|
dup io-task-fd over task-container delete-at
|
|
|
|
unregister-io-task ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: pop-callbacks ( task -- )
|
2008-01-18 18:18:54 -05:00
|
|
|
dup remove-io-task
|
|
|
|
io-task-callbacks [ schedule-thread ] each ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: handle-fd ( task -- )
|
|
|
|
dup io-task-port touch-port
|
|
|
|
dup do-io-task [ pop-callbacks ] [ drop ] if ;
|
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
: handle-timeout ( task -- )
|
|
|
|
"Timeout" over io-task-port report-error pop-callbacks ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
! Readers
|
|
|
|
: reader-eof ( reader -- )
|
|
|
|
dup buffer-empty? [ t over set-port-eof? ] when drop ;
|
|
|
|
|
|
|
|
: (refill) ( port -- n )
|
|
|
|
dup port-handle over buffer-end rot buffer-capacity read ;
|
|
|
|
|
|
|
|
: 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 ;
|
|
|
|
|
|
|
|
TUPLE: read-task ;
|
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
: <read-task> ( port continuation -- task )
|
|
|
|
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 ;
|
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
M: read-task task-container
|
|
|
|
drop read-tasks get-global ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: input-port (wait-to-read)
|
2008-01-18 18:18:54 -05:00
|
|
|
[ <read-task> add-io-task stop ] callcc0 pending-error ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
! Writers
|
|
|
|
: write-step ( port -- ? )
|
|
|
|
dup port-handle over buffer@ pick buffer-length write
|
|
|
|
dup 0 >= [ swap buffer-consume f ] [ drop defer-error ] if ;
|
|
|
|
|
|
|
|
TUPLE: write-task ;
|
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
: <write-task> ( port continuation -- task )
|
|
|
|
write-task <io-task> ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: write-task do-io-task
|
2007-11-09 03:01:45 -05:00
|
|
|
io-task-port dup buffer-empty? over port-error 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
|
|
|
M: write-task task-container
|
|
|
|
drop write-tasks get-global ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-01-18 18:18:54 -05:00
|
|
|
: add-write-io-task ( port continuation -- )
|
|
|
|
over port-handle write-tasks get-global at
|
|
|
|
[ io-task-callbacks push drop ]
|
|
|
|
[ <write-task> add-io-task ] if* ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: (wait-to-write) ( port -- )
|
2008-01-18 18:18:54 -05:00
|
|
|
[ add-write-io-task stop ] callcc0 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-01-18 18:18:54 -05:00
|
|
|
M: unix-io io-multiplex ( ms -- )
|
|
|
|
make-timeval unix-io-multiplex ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: unix-io init-io ( -- )
|
2008-01-18 18:18:54 -05:00
|
|
|
H{ } clone read-tasks set-global
|
|
|
|
H{ } clone write-tasks set-global
|
|
|
|
init-unix-io ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: unix-io init-stdio ( -- )
|
2008-01-18 18:18:54 -05:00
|
|
|
0 1 handle>duplex-stream io:stdio set-global ;
|