From 309a1c179c6fb745210eb7f92dce8c0a872abcf3 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 18 Jan 2008 19:43:14 -0500 Subject: [PATCH] Add stderr stream; more Unix I/O work --- core/io/io.factor | 3 + core/io/streams/c/c.factor | 5 +- extra/io/unix/backend/backend.factor | 8 ++- extra/io/unix/backend/kqueue/kqueue.factor | 83 ++++++++++++++++++++++ extra/io/unix/backend/select/select.factor | 5 +- extra/io/unix/unix.factor | 16 +++-- extra/structs/structs.factor | 1 - extra/unix/unix.factor | 6 ++ vm/io.c | 5 +- vm/run.h | 7 +- 10 files changed, 120 insertions(+), 19 deletions(-) create mode 100644 extra/io/unix/backend/kqueue/kqueue.factor diff --git a/core/io/io.factor b/core/io/io.factor index 0336ffda78..56b284eaaf 100755 --- a/core/io/io.factor +++ b/core/io/io.factor @@ -35,6 +35,9 @@ GENERIC: stream-write-table ( table-cells style stream -- ) ! Default stream SYMBOL: stdio +! Default error stream +SYMBOL: stderr + : close ( -- ) stdio get stream-close ; : readln ( -- str/f ) stdio get stream-readln ; diff --git a/core/io/streams/c/c.factor b/core/io/streams/c/c.factor index 61eea4ba7b..1dfb89f9c9 100755 --- a/core/io/streams/c/c.factor +++ b/core/io/streams/c/c.factor @@ -57,11 +57,12 @@ M: c-reader stream-close M: object init-io ; : stdin 11 getenv ; - : stdout 12 getenv ; +: stderr 38 getenv ; M: object init-stdio - stdin stdout stdio set-global ; + stdin stdout stdio set-global + stderr stderr set-global ; M: object io-multiplex (sleep) ; diff --git a/extra/io/unix/backend/backend.factor b/extra/io/unix/backend/backend.factor index ec73a5395e..f29d71dd86 100755 --- a/extra/io/unix/backend/backend.factor +++ b/extra/io/unix/backend/backend.factor @@ -154,7 +154,7 @@ M: port port-flush ( port -- ) dup buffer-empty? [ drop ] [ (wait-to-write) ] if ; M: unix-io io-multiplex ( ms -- ) - make-timeval unix-io-multiplex ; + unix-io-multiplex ; M: unix-io init-io ( -- ) H{ } clone read-tasks set-global @@ -162,4 +162,8 @@ M: unix-io init-io ( -- ) init-unix-io ; M: unix-io init-stdio ( -- ) - 0 1 handle>duplex-stream io:stdio set-global ; + 0 1 handle>duplex-stream io:stdio set-global + 2 io:stderr set-global ; + +: multiplexer-error ( n -- ) + 0 < [ err_no ignorable-error? [ (io-error) ] unless ] when ; diff --git a/extra/io/unix/backend/kqueue/kqueue.factor b/extra/io/unix/backend/kqueue/kqueue.factor new file mode 100644 index 0000000000..35f2641e00 --- /dev/null +++ b/extra/io/unix/backend/kqueue/kqueue.factor @@ -0,0 +1,83 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: alien.syntax kernel io.nonblocking io.unix.backend +sequences assocs unix unix.kqueue math namespaces ; +IN: io.unix.backend.kqueue + +TUPLE: unix-kqueue-io ; + +! Global variables +SYMBOL: kqueue-fd +SYMBOL: kqueue-changes +SYMBOL: kqueue-events + +: max-events ( -- n ) + #! We read up to 256 events at a time. This is an arbitrary + #! constant... + 256 ; inline + +M: unix-kqueue-io init-unix-io ( -- ) + V{ } clone kqueue-changes set-global + max-events "kevent" kqueue-events set-global + kqueue kqueue-fd dup io-error set-global ; + +: add-change ( event -- ) kqueue-changes get-global push ; + +: io-task-filter ( task -- n ) + class { + { read-task EVFILT_READ } + { accept-task EVFILT_READ } + { receive-task EVFILT_READ } + { write-task EVFILT_WRITE } + { connect-task EVFILT_WRITE } + { send-task EVFILT_WRITE } + } case ; + +: make-kevent ( task -- event ) + "kevent" + over io-task-fd over set-kevent-ident + over io-task-filter over set-kevent-filter ; + +: make-add-kevent ( task -- event ) + make-kevent + EV_ADD over set-kevent-flags ; + +: make-delete-kevent ( task -- event ) + make-kevent + EV_DELETE over set-kevent-flags ; + +M: unix-select-io register-io-task ( task -- ) + make-add-kevent add-change ; + +M: unix-select-io unregister-io-task ( task -- ) + make-delete-kevent add-change ; + +: kqueue-changelist ( -- byte-array n ) + kqueue-changes get-global + dup concat f like over length rot delete-all ; + +: kqueue-eventlist ( -- byte-array n ) + kqueue-events get-global max-events ; + +: do-kevent ( timespec -- n ) + >r + kqueue-fd get-global + kqueue-changelist + kqueue-eventlist + r> kevent dup multiplexer-error ; + +: kevent-task ( kevent -- task ) + dup kevent-filter { + { [ dup EVFILT_READ = ] [ read-tasks ] } + { [ dup EVFILT_WRITE = ] [ write-tasks ] } + } cond get at ; + +: handle-kevents ( n eventlist -- ) + [ kevent-nth kevent-task handle-fd ] curry each ; + +M: unix-select-io unix-io-multiplex ( ms -- ) + make-timespec + do-kevent + kqueue-events get-global handle-kevents ; + +T{ unix-kqueue-io } unix-io-backend set-global diff --git a/extra/io/unix/backend/select/select.factor b/extra/io/unix/backend/select/select.factor index 255010bff6..b132c8b9e8 100644 --- a/extra/io/unix/backend/select/select.factor +++ b/extra/io/unix/backend/select/select.factor @@ -44,9 +44,8 @@ M: unix-select-io register-io-task ( task -- ) drop ; M: unix-select-io unregister-io-task ( task -- ) drop ; M: unix-select-io unix-io-multiplex ( timeval -- ) - >r FD_SETSIZE init-fdsets r> select 0 < [ - err_no ignorable-error? [ (io-error) ] unless - ] when + make-timeval >r FD_SETSIZE init-fdsets r> + select multiplexer-error read-fdset/tasks handle-fdset write-fdset/tasks handle-fdset ; diff --git a/extra/io/unix/unix.factor b/extra/io/unix/unix.factor index 7114f388e0..1c86224433 100755 --- a/extra/io/unix/unix.factor +++ b/extra/io/unix/unix.factor @@ -1,9 +1,11 @@ -USE: io.unix.backend -USE: io.unix.files -USE: io.unix.sockets -USE: io.unix.launcher -USE: io.unix.mmap -USE: io.backend -USE: namespaces +USING: io.unix.backend io.unix.files io.unix.sockets +io.unix.launcher io.unix.mmap io.backend combinators namespaces +system vocabs.loader ; + +{ + { [ macosx? ] [ "io.unix.backend.kqueue" ] } + { [ bsd? ] [ "io.unix.backend.kqueue" ] } + { [ unix? ] [ "io.unix.backend.select" ] } +} cond require T{ unix-io } io-backend set-global diff --git a/extra/structs/structs.factor b/extra/structs/structs.factor index c0792ed317..f54917dc47 100644 --- a/extra/structs/structs.factor +++ b/extra/structs/structs.factor @@ -10,4 +10,3 @@ C-STRUCT: timeval "timeval" [ set-timeval-usec ] keep [ set-timeval-sec ] keep ; - diff --git a/extra/unix/unix.factor b/extra/unix/unix.factor index 94bb598c25..d87e7f885d 100755 --- a/extra/unix/unix.factor +++ b/extra/unix/unix.factor @@ -41,6 +41,12 @@ C-STRUCT: timespec { "time_t" "sec" } { "long" "nsec" } ; +: make-timespec ( ms -- timespec ) + 1000 /mod 1000000 * + "timespec" + [ set-timespec-nsec ] keep + [ set-timespec-usec ] keep ; + ! ! ! Unix constants ! File type diff --git a/vm/io.c b/vm/io.c index bc7d057abf..d3a29abe72 100755 --- a/vm/io.c +++ b/vm/io.c @@ -13,8 +13,9 @@ normal operation. */ void init_c_io(void) { - userenv[IN_ENV] = allot_alien(F,(CELL)stdin); - userenv[OUT_ENV] = allot_alien(F,(CELL)stdout); + userenv[STDIN_ENV] = allot_alien(F,(CELL)stdin); + userenv[STDOUT_ENV] = allot_alien(F,(CELL)stdout); + userenv[STDERR_ENV] = allot_alien(F,(CELL)stderr); } void io_error(void) diff --git a/vm/run.h b/vm/run.h index 6f2caa0c14..976fa36337 100755 --- a/vm/run.h +++ b/vm/run.h @@ -16,8 +16,8 @@ typedef enum { OS_ENV, /* operating system name */ ARGS_ENV = 10, /* command line arguments */ - IN_ENV, /* stdin FILE* handle */ - OUT_ENV, /* stdout FILE* handle */ + STDIN_ENV, /* stdin FILE* handle */ + STDOUT_ENV, /* stdout FILE* handle */ IMAGE_ENV = 13, /* image path name */ EXECUTABLE_ENV, /* runtime executable path name */ @@ -51,6 +51,9 @@ typedef enum { STACK_TRACES_ENV = 36, UNDEFINED_ENV = 37, /* default quotation for undefined words */ + + STDERR_ENV = 38, /* stderr FILE* handle */ + STAGE2_ENV = 39 /* have we bootstrapped? */ } F_ENVTYPE;