| 
									
										
										
										
											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-20 17:07:18 -05:00
										 |  |  | MIXIN: unix-io | 
					
						
							| 
									
										
										
										
											2008-01-18 18:18:54 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-20 17:07:18 -05:00
										 |  |  | ! I/O tasks | 
					
						
							|  |  |  | TUPLE: io-task port callbacks ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : io-task-fd io-task-port port-handle ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-02 17:23:04 -05:00
										 |  |  | : <io-task> ( port continuation/f class -- task )
 | 
					
						
							|  |  |  |     >r [ 1vector ] [ V{ } clone ] if* io-task construct-boa | 
					
						
							|  |  |  |     r> construct-delegate ; inline
 | 
					
						
							| 
									
										
										
										
											2008-01-20 17:07:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-21 15:33:43 -05:00
										 |  |  | TUPLE: input-task ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : <input-task> ( port continuation class -- task )
 | 
					
						
							|  |  |  |     >r input-task <io-task> r> construct-delegate ; inline
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TUPLE: output-task ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : <output-task> ( port continuation class -- task )
 | 
					
						
							|  |  |  |     >r output-task <io-task> r> construct-delegate ; inline
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-01-21 15:33:43 -05:00
										 |  |  | M: input-task io-task-container drop mx-reads ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: output-task io-task-container drop mx-writes ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-20 17:07:18 -05:00
										 |  |  | : <mx> ( -- mx ) f H{ } clone H{ } clone mx construct-boa ;
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-20 17:07:18 -05:00
										 |  |  | : construct-mx ( class -- obj ) <mx> swap construct-delegate ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 -- )
 | 
					
						
							|  |  |  |     mx get-global register-io-task stop ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : with-port-continuation ( port quot -- port )
 | 
					
						
							|  |  |  |     [ callcc0 ] curry with-port-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 ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : 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 ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-20 17:07:18 -05:00
										 |  |  | : pop-callbacks ( mx task -- )
 | 
					
						
							|  |  |  |     dup rot unregister-io-task | 
					
						
							| 
									
										
										
										
											2008-01-18 18:18:54 -05:00
										 |  |  |     io-task-callbacks [ schedule-thread ] 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* [ | 
					
						
							|  |  |  |         "I/O operation cancelled" over io-task-port report-error | 
					
						
							|  |  |  |         pop-callbacks | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         2drop
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : cancel-io-tasks ( port mx -- )
 | 
					
						
							|  |  |  |     2dup
 | 
					
						
							|  |  |  |     dup mx-reads handle-timeout | 
					
						
							|  |  |  |     dup mx-writes handle-timeout ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: unix-io cancel-io ( port -- )
 | 
					
						
							|  |  |  |     mx get-global cancel-io-tasks ;
 | 
					
						
							| 
									
										
										
										
											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 )
 | 
					
						
							| 
									
										
										
										
											2008-01-21 15:33:43 -05:00
										 |  |  |     read-task <input-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 -- ? )
 | 
					
						
							|  |  |  |     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 )
 | 
					
						
							| 
									
										
										
										
											2008-01-21 15:33:43 -05:00
										 |  |  |     write-task <output-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
										 |  |  | : add-write-io-task ( port continuation -- )
 | 
					
						
							| 
									
										
										
										
											2008-01-20 17:07:18 -05:00
										 |  |  |     over port-handle mx get-global mx-writes at*
 | 
					
						
							| 
									
										
										
										
											2008-01-31 13:27:37 -05:00
										 |  |  |     [ io-task-callbacks push stop ] | 
					
						
							| 
									
										
										
										
											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-01-18 18:18:54 -05:00
										 |  |  | M: unix-io io-multiplex ( ms -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-02 01:30:47 -05:00
										 |  |  |     expire-timeouts mx get-global wait-for-events ;
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | M: unix-io init-stdio ( -- )
 | 
					
						
							| 
									
										
										
										
											2008-01-18 19:43:14 -05:00
										 |  |  |     0 1 handle>duplex-stream io:stdio set-global
 | 
					
						
							|  |  |  |     2 <writer> io:stderr set-global ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-01-21 15:33:43 -05:00
										 |  |  |     dup mx-fd f mx-port <port> | 
					
						
							| 
									
										
										
										
											2008-01-20 17:07:18 -05:00
										 |  |  |     { set-mx-port-mx set-delegate } mx-port construct ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TUPLE: mx-task ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : <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-01-21 15:33:43 -05:00
										 |  |  |     io-task-port mx-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 ;
 |