factor/basis/io/backend/unix/unix.factor

227 lines
6.1 KiB
Factor
Raw Normal View History

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.
USING: accessors alien.c-types alien.data alien.syntax
classes.struct combinators destructors destructors.private fry
2014-11-16 21:54:24 -05:00
io.backend io.backend.unix.multiplexers io.buffers io.files
io.ports io.timeouts kernel kernel.private libc locals make math
namespaces sequences summary system threads unix unix.ffi
unix.stat unix.types ;
2008-01-18 18:18:54 -05:00
QUALIFIED: io
IN: io.backend.unix
2007-09-20 18:09:08 -04:00
CONSTANT: file-mode 0o0666
GENERIC: handle-fd ( handle -- fd )
TUPLE: fd < disposable fd ;
2008-05-14 04:55:33 -04:00
2008-07-03 18:44:44 -04:00
: init-fd ( fd -- fd )
[
|dispose
dup fd>> F_SETFL O_NONBLOCK [ fcntl ] unix-system-call drop
dup fd>> F_SETFD FD_CLOEXEC [ fcntl ] unix-system-call drop
2008-07-03 18:44:44 -04:00
] with-destructors ;
2008-05-15 19:14:46 -04:00
: <fd> ( n -- fd )
fd new-disposable swap >>fd ;
2008-05-14 04:55:33 -04:00
2008-05-22 01:41:18 -04:00
M: fd dispose
[
{
[ cancel-operation ]
[ t >>disposed drop ]
[ unregister-disposable ]
[ fd>> close-file ]
} cleave
] unless-disposed ;
2008-05-14 04:55:33 -04:00
M: fd handle-fd check-disposed fd>> ;
M: fd cancel-operation ( fd -- )
[
2008-05-20 19:52:11 -04:00
fd>>
mx get-global
[ remove-input-callbacks [ t swap resume-with ] each ]
[ remove-output-callbacks [ t swap resume-with ] each ]
2bi
] unless-disposed ;
2008-05-13 19:24:46 -04:00
M: unix tell-handle ( handle -- n )
fd>> 0 SEEK_CUR [ lseek ] unix-system-call [ io-error ] [ ] bi ;
M: unix seek-handle ( n seek-type handle -- )
swap {
{ io:seek-absolute [ SEEK_SET ] }
{ io:seek-relative [ SEEK_CUR ] }
{ io:seek-end [ SEEK_END ] }
2009-02-07 12:24:12 -05:00
[ io:bad-seek-type ]
} case
[ fd>> swap ] dip [ lseek ] unix-system-call drop ;
2009-02-07 02:03:12 -05:00
M: unix can-seek-handle? ( handle -- ? )
fd>> SEEK_CUR 0 lseek -1 = not ;
2011-10-18 00:12:48 -04:00
M: unix handle-length ( handle -- n/f )
fd>> \ stat <struct> [ fstat -1 = not ] keep
swap [ st_size>> ] [ drop f ] if ;
ERROR: io-timeout ;
M: io-timeout summary drop "I/O operation timed out" ;
M: unix wait-for-fd ( handle event -- )
dup +retry+ eq? [ 2drop ] [
2010-03-27 12:03:06 -04:00
[ [ self ] dip handle-fd mx get-global ] dip {
{ +input+ [ add-input-callback ] }
{ +output+ [ add-output-callback ] }
} case
2015-08-13 06:20:39 -04:00
"I/O" suspend [ throw-io-timeout ] when
2008-05-13 19:24:46 -04:00
] if ;
2007-09-20 18:09:08 -04:00
2008-05-14 04:55:33 -04:00
: wait-for-port ( port event -- )
'[ handle>> _ wait-for-fd ] with-timeout ;
2008-05-14 04:55:33 -04:00
2007-09-20 18:09:08 -04:00
! Some general stuff
2014-11-16 21:54:24 -05:00
ERROR: not-a-buffered-port port ;
: check-buffered-port ( port -- port )
2015-08-13 06:20:39 -04:00
dup buffered-port? [ throw-not-a-buffered-port ] unless ; inline
2014-11-16 21:54:24 -05:00
2008-05-14 04:55:33 -04:00
M: fd refill
2014-11-16 21:54:24 -05:00
[ check-buffered-port buffer>> ] [ fd>> ] bi*
over [ buffer-end ] [ buffer-capacity ] bi read
2014-11-20 22:46:14 -05:00
{ fixnum } declare dup 0 >= [
swap buffer+ f
] [
errno {
{ EINTR [ 2drop +retry+ ] }
{ EAGAIN [ 2drop +input+ ] }
2014-11-21 13:19:12 -05:00
[ (throw-errno) ]
2014-11-20 22:46:14 -05:00
} case
] if ;
2008-05-13 19:24:46 -04:00
M: unix (wait-to-read) ( port -- )
dup
dup handle>> check-disposed refill dup
2008-05-13 19:24:46 -04:00
[ dupd wait-for-port (wait-to-read) ] [ 2drop ] if ;
2007-09-20 18:09:08 -04:00
! Writers
2008-05-14 04:55:33 -04:00
M: fd drain
2014-11-16 21:54:24 -05:00
[ check-buffered-port buffer>> ] [ fd>> ] bi*
over [ buffer@ ] [ buffer-length ] bi write
2014-11-20 22:46:14 -05:00
{ fixnum } declare dup 0 >= [
over buffer-consume
buffer-empty? f +output+ ?
] [
errno {
{ EINTR [ 2drop +retry+ ] }
{ EAGAIN [ 2drop +output+ ] }
2014-11-21 13:19:12 -05:00
[ (throw-errno) ]
2014-11-20 22:46:14 -05:00
} case
] if ;
2008-05-13 19:24:46 -04:00
M: unix (wait-to-write) ( port -- )
dup
dup handle>> check-disposed drain
[ wait-for-port ] [ drop ] if* ;
2007-09-20 18:09:08 -04:00
M: unix io-multiplex ( nanos -- )
2008-02-09 22:34:42 -05:00
mx get-global wait-for-events ;
2007-09-20 18:09:08 -04:00
2008-07-03 18:44:44 -04:00
! On Unix, you're not supposed to set stdin to non-blocking
! because the fd might be shared with another process (either
! parent or child). So what we do is have the VM start a thread
! which pumps data from the real stdin to a pipe. We set the
! pipe to non-blocking, and read from it instead of the real
! stdin. Very crufty, but it will suffice until we get native
! threading support at the language level.
TUPLE: stdin < disposable control size data ;
2008-07-03 18:44:44 -04:00
2008-07-09 20:23:35 -04:00
M: stdin dispose*
2008-07-03 18:44:44 -04:00
[
[ control>> &dispose drop ]
[ size>> &dispose drop ]
[ data>> &dispose drop ]
tri
] with-destructors ;
: wait-for-stdin ( stdin -- size )
2008-07-03 18:44:44 -04:00
[ control>> CHAR: X over io:stream-write1 io:stream-flush ]
2011-05-19 18:45:39 -04:00
[ size>> ssize_t heap-size swap io:stream-read ssize_t deref ]
2008-07-03 18:44:44 -04:00
bi ;
:: refill-stdin ( buffer stdin size -- )
stdin data>> handle-fd buffer buffer-end size read
dup 0 < [
drop
errno EINTR = [
buffer stdin size refill-stdin
] [
throw-errno
] if
2008-07-03 18:44:44 -04:00
] [
size = [ "Error reading stdin pipe" throw ] unless
2014-11-16 21:54:24 -05:00
size buffer buffer+
2008-07-03 18:44:44 -04:00
] if ;
M: stdin refill
'[
buffer>> _ dup wait-for-stdin refill-stdin f
] with-timeout ;
M: stdin cancel-operation
[ size>> ] [ control>> ] bi [ cancel-operation ] bi@ ;
2008-07-03 18:44:44 -04:00
2010-10-20 18:42:53 -04:00
: control-write-fd ( -- fd ) &: control_write uint deref ;
2008-07-03 18:44:44 -04:00
2010-10-20 18:42:53 -04:00
: size-read-fd ( -- fd ) &: size_read uint deref ;
2008-07-03 18:44:44 -04:00
2010-10-20 18:42:53 -04:00
: data-read-fd ( -- fd ) &: stdin_read uint deref ;
2008-07-03 18:44:44 -04:00
: <stdin> ( -- stdin )
stdin new-disposable
2008-07-09 20:23:35 -04:00
control-write-fd <fd> <output-port> >>control
size-read-fd <fd> init-fd <input-port> >>size
data-read-fd <fd> >>data ;
2008-07-03 18:44:44 -04:00
SYMBOL: dispatch-signal-hook
dispatch-signal-hook [ [ drop ] ] initialize
: signal-pipe-fd ( -- n )
OBJ-SIGNAL-PIPE special-object ; inline
: signal-pipe-loop ( port -- )
'[
int heap-size _ io:stream-read
dup [ int deref dispatch-signal-hook get call( x -- ) ] when*
] loop ;
: start-signal-pipe-thread ( -- )
signal-pipe-fd [
<fd> init-fd <input-port>
'[ _ signal-pipe-loop ] "Signals" spawn drop
] when* ;
M: unix init-stdio
2008-07-03 18:44:44 -04:00
<stdin> <input-port>
2008-05-14 04:55:33 -04:00
1 <fd> <output-port>
2 <fd> <output-port>
set-stdio ;
2008-01-18 19:43:14 -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 ;
: <mx-port> ( mx -- port )
2008-04-11 17:08:40 -04:00
dup fd>> mx-port <port> swap >>mx ;
: multiplexer-error ( n -- n )
dup 0 < [
errno [ EAGAIN = ] [ EINTR = ] bi or
[ drop 0 ] [ throw-errno ] if
2008-05-13 19:24:46 -04:00
] when ;
2008-04-11 10:54:50 -04:00
2010-02-15 10:04:09 -05:00
:: ?flag ( n mask symbol -- n )
n mask bitand 0 > [ symbol , ] when n ;