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-05-13 19:24:46 -04:00
|
|
|
io.ports sequences strings structs sbufs threads unix
|
2008-05-05 03:19:25 -04:00
|
|
|
vectors io.buffers io.backend io.encodings math.parser
|
|
|
|
continuations system libc qualified namespaces io.timeouts
|
2008-05-15 00:23:12 -04:00
|
|
|
io.encodings.utf8 destructors accessors inspector combinators ;
|
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
|
2008-05-12 19:53:22 -04:00
|
|
|
GENERIC: handle-fd ( handle -- fd )
|
|
|
|
|
2008-05-15 00:23:12 -04:00
|
|
|
TUPLE: fd fd disposed ;
|
2008-05-14 04:55:33 -04:00
|
|
|
|
2008-05-15 19:14:46 -04:00
|
|
|
: <fd> ( n -- 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 ]
|
|
|
|
[ F_SETFD FD_CLOEXEC fcntl drop ]
|
|
|
|
[ f fd boa ]
|
|
|
|
tri ;
|
2008-05-14 04:55:33 -04:00
|
|
|
|
2008-05-15 00:23:12 -04:00
|
|
|
M: fd dispose* fd>> close-file ;
|
2008-05-14 04:55:33 -04:00
|
|
|
|
|
|
|
M: fd handle-fd fd>> ;
|
2008-05-12 19:53:22 -04:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
! I/O multiplexers
|
|
|
|
TUPLE: mx fd reads writes ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
: new-mx ( class -- obj )
|
2008-04-13 16:06:27 -04:00
|
|
|
new
|
2008-05-13 19:24:46 -04:00
|
|
|
H{ } clone >>reads
|
|
|
|
H{ } clone >>writes ; inline
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
GENERIC: add-input-callback ( thread fd mx -- )
|
2008-01-21 15:33:43 -05:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
: add-callback ( thread fd assoc -- )
|
|
|
|
[ ?push ] change-at ;
|
2008-01-21 15:33:43 -05:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
M: mx add-input-callback reads>> add-callback ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
GENERIC: add-output-callback ( thread fd mx -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
M: mx add-output-callback writes>> add-callback ;
|
2008-01-21 15:33:43 -05:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
GENERIC: remove-input-callbacks ( fd mx -- callbacks )
|
2008-01-21 15:33:43 -05:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
M: mx remove-input-callbacks reads>> delete-at* drop ;
|
|
|
|
|
|
|
|
GENERIC: remove-output-callbacks ( fd mx -- callbacks )
|
|
|
|
|
|
|
|
M: mx remove-output-callbacks writes>> delete-at* drop ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-01-21 15:33:43 -05:00
|
|
|
GENERIC: wait-for-events ( ms mx -- )
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
: input-available ( fd mx -- )
|
|
|
|
remove-input-callbacks [ resume ] each ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
: output-available ( fd mx -- )
|
|
|
|
remove-output-callbacks [ resume ] each ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
M: unix cancel-io ( port -- )
|
|
|
|
handle>> handle-fd mx get-global
|
2008-05-18 00:50:11 -04:00
|
|
|
[ remove-input-callbacks [ t swap resume-with ] each ]
|
|
|
|
[ remove-output-callbacks [ t swap resume-with ] each ]
|
|
|
|
2bi ;
|
2008-05-13 19:24:46 -04:00
|
|
|
|
|
|
|
SYMBOL: +retry+ ! just try the operation again without blocking
|
|
|
|
SYMBOL: +input+
|
|
|
|
SYMBOL: +output+
|
|
|
|
|
2008-05-18 00:50:11 -04:00
|
|
|
: wait-for-fd ( handle event -- timeout? )
|
|
|
|
dup +retry+ eq? [ 2drop f ] [
|
2008-05-13 19:24:46 -04:00
|
|
|
[
|
2008-05-14 04:55:33 -04:00
|
|
|
>r
|
|
|
|
swap handle-fd
|
|
|
|
mx get-global
|
|
|
|
r> {
|
|
|
|
{ +input+ [ add-input-callback ] }
|
|
|
|
{ +output+ [ add-output-callback ] }
|
|
|
|
} case
|
2008-05-18 00:50:11 -04:00
|
|
|
] curry "I/O" suspend nip
|
2008-05-13 19:24:46 -04:00
|
|
|
] if ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-05-18 00:50:11 -04:00
|
|
|
ERROR: io-timeout ;
|
|
|
|
|
|
|
|
M: io-timeout summary drop "I/O operation timed out" ;
|
|
|
|
|
2008-05-14 04:55:33 -04:00
|
|
|
: wait-for-port ( port event -- )
|
2008-05-18 00:50:11 -04:00
|
|
|
[
|
|
|
|
>r handle>> r> wait-for-fd
|
|
|
|
[ io-timeout ] when
|
2008-05-18 18:04:21 -04:00
|
|
|
] curry with-timeout ;
|
2008-05-14 04:55:33 -04:00
|
|
|
|
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 ;
|
|
|
|
|
|
|
|
! Readers
|
|
|
|
: (refill) ( port -- n )
|
2008-04-11 15:09:09 -04:00
|
|
|
[ handle>> ]
|
|
|
|
[ buffer>> buffer-end ]
|
|
|
|
[ buffer>> buffer-capacity ] tri read ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-05-13 19:24:46 -04:00
|
|
|
! Returns an event to wait for which will ensure completion of
|
|
|
|
! this request
|
|
|
|
GENERIC: refill ( port handle -- event/f )
|
2008-05-12 19:53:22 -04:00
|
|
|
|
2008-05-14 04:55:33 -04:00
|
|
|
M: fd refill
|
|
|
|
fd>> over buffer>> [ buffer-end ] [ buffer-capacity ] bi read
|
2008-05-13 19:24:46 -04:00
|
|
|
{
|
2008-05-18 20:02:50 -04:00
|
|
|
{ [ dup 0 >= ] [ swap buffer>> n>buffer f ] }
|
2008-05-13 19:24:46 -04:00
|
|
|
{ [ err_no EINTR = ] [ 2drop +retry+ ] }
|
|
|
|
{ [ err_no EAGAIN = ] [ 2drop +input+ ] }
|
|
|
|
[ (io-error) ]
|
|
|
|
} cond ;
|
|
|
|
|
|
|
|
M: unix (wait-to-read) ( port -- )
|
|
|
|
dup dup handle>> refill dup
|
|
|
|
[ dupd wait-for-port (wait-to-read) ] [ 2drop ] if ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
! Writers
|
2008-05-13 19:24:46 -04:00
|
|
|
GENERIC: drain ( port handle -- event/f )
|
2008-05-12 19:53:22 -04:00
|
|
|
|
2008-05-14 04:55:33 -04:00
|
|
|
M: fd drain
|
|
|
|
fd>> over buffer>> [ buffer@ ] [ buffer-length ] bi write
|
2008-05-13 19:24:46 -04:00
|
|
|
{
|
|
|
|
{ [ dup 0 >= ] [
|
|
|
|
over buffer>> buffer-consume
|
|
|
|
buffer>> buffer-empty? f +output+ ?
|
|
|
|
] }
|
|
|
|
{ [ err_no EINTR = ] [ 2drop +retry+ ] }
|
|
|
|
{ [ err_no EAGAIN = ] [ 2drop +output+ ] }
|
|
|
|
[ (io-error) ]
|
|
|
|
} cond ;
|
|
|
|
|
|
|
|
M: unix (wait-to-write) ( port -- )
|
2008-05-18 00:50:11 -04:00
|
|
|
dup dup handle>> drain dup [ wait-for-port ] [ 2drop ] if ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
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-05-14 04:55:33 -04:00
|
|
|
0 <fd> <input-port>
|
|
|
|
1 <fd> <output-port>
|
|
|
|
2 <fd> <output-port> ;
|
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
|
2008-04-11 17:08:40 -04:00
|
|
|
TUPLE: mx-port < port mx ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
|
|
|
: <mx-port> ( mx -- port )
|
2008-04-11 17:08:40 -04:00
|
|
|
dup fd>> mx-port <port> swap >>mx ;
|
2008-01-20 17:07:18 -05:00
|
|
|
|
2008-01-18 19:43:14 -05:00
|
|
|
: multiplexer-error ( n -- )
|
2008-05-13 19:24:46 -04:00
|
|
|
0 < [
|
2008-05-18 00:50:11 -04:00
|
|
|
err_no [ EAGAIN = ] [ EINTR = ] bi or
|
|
|
|
[ (io-error) ] unless
|
2008-05-13 19:24:46 -04:00
|
|
|
] when ;
|
2008-04-11 10:54:50 -04:00
|
|
|
|
|
|
|
: ?flag ( n mask symbol -- n )
|
|
|
|
pick rot bitand 0 > [ , ] [ drop ] if ;
|