]> gitweb.factorcode.org Git - factor.git/commitdiff
More Win32 IO work; FFI updates
authorMackenzie Straight <eizneckam@gmail.com>
Sat, 25 Dec 2004 10:49:30 +0000 (10:49 +0000)
committerMackenzie Straight <eizneckam@gmail.com>
Sat, 25 Dec 2004 10:49:30 +0000 (10:49 +0000)
library/io/buffer.factor
library/io/win32-console.factor
library/io/win32-io-internals.factor
library/io/win32-stream.factor
library/win32/win32-errors.factor
library/win32/win32-io.factor
native/ffi.c
native/ffi.h
native/relocate.c
native/unix/ffi.c
native/win32/ffi.c

index 20092ea5a3a5b2a6a9e96244b78318b3c1722e8f..0a44ef07168b19d6586eca99e9731419ce677808 100644 (file)
@@ -25,7 +25,7 @@
 ! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-IN: buffer
+IN: kernel-internals
 
 USE: alien
 USE: errors
@@ -36,49 +36,76 @@ USE: namespaces
 USE: strings
 USE: win32-api
 
+SYMBOL: buf-size
+SYMBOL: buf-ptr
+SYMBOL: buf-fill
+SYMBOL: buf-pos
+
 : imalloc ( size -- address )
     "int" "libc" "malloc" [ "int" ] alien-invoke ;
 
 : ifree ( address -- )
     "void" "libc" "free" [ "int" ] alien-invoke ;
 
+: irealloc ( address size -- address )
+    "int" "libc" "realloc" [ "int" "int" ] alien-invoke ;
+
 : <buffer> ( size -- buffer )
     #! Allocates and returns a new buffer.
     <namespace> [
-        dup "size" set
-        imalloc "buffer" set
-        0 "fill" set
-        0 "pos" set
+        dup buf-size set
+        imalloc buf-ptr set
+        0 buf-fill set
+        0 buf-pos set
     ] extend ;
 
 : buffer-free ( buffer -- )
     #! Frees the C memory associated with the buffer.
-    [ "buffer" get ifree ] bind ;
+    [ buf-ptr get ifree ] bind ;
 
 : buffer-contents ( buffer -- string )
     #! Returns the current contents of the buffer.
     [
-        "buffer" get "pos" get + 
-        "fill" get "pos" get - 
+        buf-ptr get buf-pos get + 
+        buf-fill get buf-pos get - 
         memory>string 
     ] bind ;
 
+: buffer-first-n ( count buffer -- string )
+    [
+        buf-fill get buf-pos get - min
+        buf-ptr get buf-pos get +
+        swap memory>string
+    ] bind ;
+
 : buffer-reset ( count buffer -- )
     #! Reset the position to 0 and the fill pointer to count.
-    [ 0 "pos" set "fill" set ] bind ;
+    [ 0 buf-pos set buf-fill set ] bind ;
 
 : buffer-consume ( count buffer -- )
     #! Consume count characters from the beginning of the buffer.
-    [ "pos" [ + "fill" get min ] change ] bind ;
+    [
+        buf-pos [ + buf-fill get min ] change 
+        buf-pos get buf-fill get = [ 
+            0 buf-pos set 0 buf-fill set 
+        ] when
+    ] bind ;
 
 : buffer-length ( buffer -- length )
     #! Returns the amount of unconsumed input in the buffer.
-    [ "fill" get "pos" get - max ] bind ;
+    [ buf-fill get buf-pos get - 0 max ] bind ;
+
+: buffer-size ( buffer -- size )
+    [ buf-size get ] bind ;
+
+: buffer-capacity ( buffer -- int )
+    #! Returns the amount of data that may be added to the buffer.
+    [ buf-size get buf-fill get - ] bind ;
 
 : buffer-set ( string buffer -- )
     #! Set the contents of a buffer to string.
     [ 
-        dup "buffer" get string>memory
+        dup buf-ptr get string>memory
         str-length namespace buffer-reset
     ] bind ;
 
@@ -86,19 +113,27 @@ USE: win32-api
     #! Appends a string to the end of the buffer. If it doesn't fit,
     #! an error is thrown.
     [ 
-        dup "size" get "fill" get - swap str-length < [
+        dup buf-size get buf-fill get - swap str-length < [
             "Buffer overflow" throw
         ] when
-        dup "buffer" get "fill" get + string>memory
-        "fill" [ swap str-length + ] change
+        dup buf-ptr get buf-fill get + string>memory
+        buf-fill [ swap str-length + ] change
+    ] bind ;
+
+: buffer-extend ( length buffer -- )
+    #! Increases the size of the buffer by length.
+    [
+        buf-size get + dup buf-ptr get swap irealloc 
+        buf-ptr set buf-size set
     ] bind ;
 
-: buffer-fill ( buffer quot -- )
-    #! Execute quot with buffer as its argument, passing its result to
-    #! buffer-reset.
-    swap dup >r swap call r> buffer-reset ; inline
+: buffer-fill ( count buffer -- )
+    #! Increases the fill pointer by count.
+    [ buf-fill [ + ] change ] bind ;
 
 : buffer-ptr ( buffer -- pointer )
     #! Returns the memory address of the buffer area.
-    [ "buffer" get ] bind ;
+    [ buf-ptr get ] bind ;
 
+: buffer-pos ( buffer -- int )
+    [ buf-ptr get buf-pos get + ] bind ;
index 9d55898db85b2c1c59d69daacc169250d5726792..ffaef4524f78c2af085e7604908bb10e881a65a1 100644 (file)
@@ -84,3 +84,5 @@ M: win32-console-stream fwrite-attr ( string style stream -- )
 C: win32-console-stream ( stream -- stream )
     [ delegate set -11 GetStdHandle handle set ] extend ;
 
+global [ [ <win32-console-stream> ] smart-term-hook set ] bind
+
index 1d75e98cfb4a60ef6ad380840435c65ba6f1487d..4d668c35aeb08d4fc046cc2d4d5da6edba61e4d0 100644 (file)
 
 IN: win32-io-internals
 USE: alien
+USE: errors
 USE: kernel
+USE: kernel-internals
 USE: lists
 USE: math
 USE: namespaces
+USE: prettyprint
+USE: vectors
 USE: win32-api
 
+SYMBOL: completion-port
+SYMBOL: io-queue
+SYMBOL: free-list
+SYMBOL: callbacks
+
+: handle-io-error ( -- )
+    #! If a write or read call fails unexpectedly, throw an error.
+    GetLastError [ 
+        ERROR_IO_PENDING ERROR_HANDLE_EOF ERROR_SUCCESS 
+    ] contains? [ 
+        win32-throw-error 
+    ] unless ;
+
 : win32-init-stdio ( -- )
     INVALID_HANDLE_VALUE NULL NULL 1 CreateIoCompletionPort
-    "completion-port" set ;
+    completion-port set 
+    
+    <namespace> [
+        32 <vector> callbacks set
+        f free-list set
+    ] extend io-queue set ;
 
 : get-access ( -- file-mode )
-    0 "file-mode" get uncons >r 
-    [ GENERIC_WRITE ] [ 0 ] ifte bitor r>
-    [ GENERIC_READ ] [ 0 ] ifte bitor ;
+    "file-mode" get uncons 
+    [ GENERIC_WRITE ] [ 0 ] ifte >r
+    [ GENERIC_READ ] [ 0 ] ifte r> bitor ;
 
 : get-sharemode ( -- share-mode )
     FILE_SHARE_READ FILE_SHARE_WRITE bitor FILE_SHARE_DELETE bitor ;
@@ -57,6 +79,53 @@ USE: win32-api
         cons "file-mode" set
         get-access get-sharemode NULL get-create FILE_FLAG_OVERLAPPED NULL 
         CreateFile dup INVALID_HANDLE_VALUE = [ win32-throw-error ] when
-        dup "completion-port" get NULL 1 CreateIoCompletionPort drop
+        dup completion-port get NULL 1 CreateIoCompletionPort drop
     ] with-scope ;
 
+BEGIN-STRUCT: indirect-pointer
+    FIELD: int value
+END-STRUCT
+
+: num-callbacks ( -- len )
+    #! Returns the length of the callback vector.
+    io-queue get [ callbacks get vector-length ] bind ;
+
+: set-callback-quot ( quot index -- )
+    io-queue get [
+        dup >r callbacks get vector-nth car swap cons
+        r> callbacks get set-vector-nth
+    ] bind ;
+
+: new-overlapped ( -- index )
+    #! Allocates and returns a new entry for the io queue.
+    #! The new index in the callback vector is returned.
+    io-queue get [
+        "overlapped-ext" c-type [ "width" get ] bind imalloc <alien>
+        dup num-callbacks swap
+        set-overlapped-ext-user-data
+        unit num-callbacks dup >r callbacks get set-vector-nth r>
+    ] bind ;
+
+: alloc-io-task ( quot -- overlapped )
+    io-queue get [
+        free-list get [
+            uncons free-list set
+        ] [ new-overlapped ] ifte*
+        [ set-callback-quot ] keep 
+        callbacks get vector-nth car
+    ] bind ;
+
+: get-io-callback ( index -- callback )
+    #! Returns and frees the io queue entry at index.
+    io-queue get [
+        dup free-list [ cons ] change
+        callbacks get vector-nth cdr
+    ] bind ;
+
+: win32-next-io-task ( -- quot )
+    completion-port get <indirect-pointer> dup >r <indirect-pointer> 
+    <indirect-pointer> dup >r INFINITE GetQueuedCompletionStatus
+    [ handle-io-error ] unless
+    r> r> indirect-pointer-value swap indirect-pointer-value <alien> 
+    overlapped-ext-user-data get-io-callback call ;
+
index 230b75f435fe7c9ec6ab82b2265c61fc0b9c62a4..c50219bc2dbc96a6f32c28a216bc57a7daea12f4 100644 (file)
 
 IN: win32-stream
 USE: alien
-USE: buffer
+USE: continuations
 USE: generic
 USE: kernel
+USE: kernel-internals
 USE: lists
 USE: math
 USE: namespaces
+USE: prettyprint
 USE: stdio
 USE: streams
+USE: strings
+USE: threads
 USE: win32-api
 USE: win32-io-internals
 
 TRAITS: win32-stream
-GENERIC: update-file-pointer
+
+SYMBOL: handle
+SYMBOL: in-buffer
+SYMBOL: out-buffer
+SYMBOL: fileptr
+SYMBOL: file-size
+
+: init-overlapped ( overlapped -- overlapped )
+    0 over set-overlapped-ext-internal
+    0 over set-overlapped-ext-internal-high
+    fileptr get over set-overlapped-ext-offset
+    0 over set-overlapped-ext-offset-high
+    0 over set-overlapped-ext-event ;
+
+: update-file-pointer ( whence -- )
+    file-size get [ fileptr [ + ] change ] when ;
+
+: flush-output ( -- ) 
+    [
+        alloc-io-task init-overlapped >r
+        handle get out-buffer get [ buffer-pos ] keep buffer-length
+        NULL r> WriteFile [ handle-io-error ] unless win32-next-io-task
+    ] callcc1
+
+    dup out-buffer get [ buffer-consume ] keep 
+    swap namespace update-file-pointer
+    buffer-length 0 > [ flush-output ] when ;
+
+: do-write ( str -- )
+    dup str-length out-buffer get buffer-capacity <= [
+        out-buffer get buffer-append
+    ] [
+        dup str-length out-buffer get buffer-size > [
+            dup str-length out-buffer get buffer-extend do-write
+        ] [ flush-output do-write ] ifte
+    ] ifte ;
+
+: fill-input ( -- ) 
+    [
+        alloc-io-task init-overlapped >r
+        handle get in-buffer get [ buffer-pos ] keep 
+        buffer-capacity file-size get [ fileptr get - min ] when*
+        NULL r>
+        ReadFile [ handle-io-error ] unless win32-next-io-task
+    ] callcc1
+
+    dup in-buffer get buffer-fill
+    namespace update-file-pointer ;
+
+: consume-input ( count -- str ) 
+    in-buffer get buffer-length 0 = [ fill-input ] when
+    in-buffer get buffer-size min
+    dup in-buffer get buffer-first-n
+    swap in-buffer get buffer-consume ;
+
+: do-read-count ( sbuf count -- str )
+    dup 0 = [ 
+        drop sbuf>str 
+    ] [
+        dup consume-input
+        dup str-length dup 0 = [
+            3drop dup sbuf-length 0 > [ sbuf>str ] [ drop f ] ifte
+        ] [
+            >r swap r> - >r swap [ sbuf-append ] keep r> do-read-count
+        ] ifte
+    ] ifte ;
 
 M: win32-stream fwrite-attr ( str style stream -- )
-    nip fwrite ;
+    nip [ do-write ] bind ;
 
 M: win32-stream freadln ( stream -- str )
     drop f ;
 
 M: win32-stream fread# ( count stream -- str )
-    drop f ;
+    [ dup <sbuf> swap do-read-count ] bind ;
 
 M: win32-stream fflush ( stream -- )
-    drop ;
+    [ flush-output ] bind ;
 
 M: win32-stream fclose ( stream -- )
-    [ "handle" get CloseHandle drop "buffer" get buffer-free ] bind ;
+    [
+        flush-output
+        handle get CloseHandle drop 
+        in-buffer get buffer-free 
+        out-buffer get buffer-free
+    ] bind ;
 
 C: win32-stream ( handle -- stream )
-    [ "handle" set 4096 <buffer> "buffer" set 0 "fp" set ] extend ;
+    [
+        dup NULL GetFileSize dup INVALID_FILE_SIZE = not [
+            file-size set
+        ] [ drop f file-size set ] ifte
+        handle set 
+        4096 <buffer> in-buffer set 
+        4096 <buffer> out-buffer set
+        0 fileptr set 
+    ] extend ;
 
 : <win32-filecr> ( path -- stream )
     t f win32-open-file <win32-stream> ;
 
+: <win32-filecw> ( path -- stream )
+    f t win32-open-file <win32-stream> ;
index e1c957a2053fc325a955943dd15587d7617fb7c6..541b6876ab64061764801a83c3ef307ed792af2d 100644 (file)
@@ -29,8 +29,20 @@ IN: win32-api
 USE: buffer
 USE: errors
 USE: kernel
+USE: kernel-internals
+USE: lists
 USE: math
+USE: parser
 USE: alien
+USE: words
+
+: CONSTANT: CREATE 
+    [ [ [ parsed ] each ] cons define-compound POSTPONE: parsing ] 
+    [ ] ; parsing
+
+CONSTANT: ERROR_SUCCESS 0 ;
+CONSTANT: ERROR_HANDLE_EOF 38 ;
+CONSTANT: ERROR_IO_PENDING 997 ;
 
 : FORMAT_MESSAGE_ALLOCATE_BUFFER HEX: 00000100 ;
 : FORMAT_MESSAGE_IGNORE_INSERTS  HEX: 00000200 ;
index b9957af9b82894454ee5bf9654b0c86f018b01cc..e4b906d538c045b66bb9d410c0afc45715dd9796 100644 (file)
@@ -70,10 +70,16 @@ END-STRUCT
 : STD_ERROR_HANDLE  -12 ;
 
 : INVALID_HANDLE_VALUE -1 <alien> ;
+: INVALID_FILE_SIZE HEX: FFFFFFFF ;
+
+: INFINITE HEX: FFFFFFFF ;
 
 : GetStdHandle ( id -- handle )
     "void*" "kernel32" "GetStdHandle" [ "int" ] alien-invoke ; 
 
+: GetFileSize ( handle out -- int )
+    "int" "kernel32" "GetFileSize" [ "void*" "void*" ] alien-invoke ; 
+
 : SetConsoleTextAttribute ( handle attrs -- ? )
     "bool" "kernel32" "SetConsoleTextAttribute" [ "void*" "int" ] 
     alien-invoke ;
@@ -99,6 +105,12 @@ END-STRUCT
     [ "void*" "void*" "void*" "int" ]
     alien-invoke ;
 
+: GetQueuedCompletionStatus 
+    ( port out-len out-key out-overlapped timeout -- ? )
+    "bool" "kernel32" "GetQueuedCompletionStatus"
+    [ "void*" "void*" "void*" "void*" "int" ]
+    alien-invoke ;
+
 : CreateFile ( name access sharemode security create flags template -- handle )
     "void*" "kernel32" "CreateFileA"
     [ "char*" "int" "int" "void*" "int" "int" "void*" ]
index b2b6f16e3f2346b681cdcb8415fea124823f1c87..732a3749565705e7436aec8f89201187e4fe9215 100644 (file)
@@ -1,5 +1,35 @@
 #include "factor.h"
 
+void primitive_dlopen(void)
+{
+       maybe_garbage_collection();
+       dpush(tag_object(ffi_dlopen(untag_string(dpop()))));
+}
+
+void primitive_dlsym(void)
+{
+       DLL *dll;       
+       F_STRING *sym;
+
+       maybe_garbage_collection();
+
+       dll = untag_dll(dpop());
+       sym = untag_string(dpop());
+       dpush(tag_cell(ffi_dlsym(dll, sym)));
+}
+
+void primitive_dlclose(void)
+{
+       maybe_garbage_collection();
+       ffi_dlclose(untag_dll(dpop()));
+}
+
+void primitive_dlsym_self(void)
+{
+       maybe_garbage_collection();
+       dpush(tag_cell(ffi_dlsym(NULL, untag_string(dpop()))));
+}
+
 DLL* untag_dll(CELL tagged)
 {
        DLL* dll = (DLL*)UNTAG(tagged);
index ad3df14a626872b90070f5f16a3b6bdbea178bad..15838ce2bca96d10309185827e53de9850973719 100644 (file)
@@ -18,6 +18,10 @@ INLINE ALIEN* untag_alien(CELL tagged)
        return (ALIEN*)UNTAG(tagged);
 }
 
+DLL *ffi_dlopen(F_STRING *path);
+void *ffi_dlsym(DLL *dll, F_STRING *symbol);
+void ffi_dlclose(DLL *dll);
+
 void primitive_dlopen(void);
 void primitive_dlsym(void);
 void primitive_dlsym_self(void);
index 7bb290a70fde41cbca37b2f02ba56484241483c4..fd5d43fcde8e75ef73c7251250f0725dca6b38f5 100644 (file)
@@ -106,8 +106,7 @@ void relocate_primitive(F_REL* rel, bool relative)
 void relocate_dlsym(F_REL* rel, bool relative)
 {
        F_STRING* str = untag_string(get(rel->argument));
-       char* c_str = to_c_string(str);
-       put(rel->offset,(CELL)dlsym(NULL,c_str)
+       put(rel->offset,(CELL)ffi_dlsym(NULL,str)
                - (relative ? rel->offset + CELLS : 0));
 }
 
index 9915b8e30bf004d931eb6baed4b07a4838784d72..e5c30a8868c983c16c47084b24e2e8a03437f2d2 100644 (file)
@@ -1,16 +1,12 @@
 #include "../factor.h"
 
-void primitive_dlopen(void)
+DLL *ffi_dlopen(F_STRING *path)
 {
 #ifdef FFI
-       char* path;
        void* dllptr;
        DLL* dll;
        
-       maybe_garbage_collection();
-       
-       path = unbox_c_string();
-       dllptr = dlopen(path,RTLD_LAZY);
+       dllptr = dlopen(to_c_string(path), RTLD_LAZY);
 
        if(dllptr == NULL)
        {
@@ -20,47 +16,31 @@ void primitive_dlopen(void)
 
        dll = allot_object(DLL_TYPE,sizeof(DLL));
        dll->dll = dllptr;
-       dpush(tag_object(dll));
+       return dll;
 #else
        general_error(ERROR_FFI_DISABLED,F);
 #endif
 }
 
-void primitive_dlsym(void)
+void *ffi_dlsym(DLL *dll, F_STRING *symbol)
 {
 #ifdef FFI
-       DLL* dll = untag_dll(dpop());
-       void* sym = dlsym(dll->dll,unbox_c_string());
+       void* sym = dlsym(dll ? dll->dll : NULL, to_c_string(symbol));
        if(sym == NULL)
        {
                general_error(ERROR_FFI,tag_object(
                        from_c_string(dlerror())));
        }
-       dpush(tag_cell((CELL)sym));
+       return sym;
 #else
        general_error(ERROR_FFI_DISABLED,F);
 #endif
 }
 
-void primitive_dlsym_self(void)
-{
-#if defined(FFI)
-       void* sym = dlsym(NULL,unbox_c_string());
-       if(sym == NULL)
-       {
-               general_error(ERROR_FFI,tag_object(
-                       from_c_string(dlerror())));
-       }
-       dpush(tag_cell((CELL)sym));
-#else
-       general_error(ERROR_FFI_DISABLED,F);
-#endif
-}
 
-void primitive_dlclose(void)
+void ffi_dlclose(DLL *dll)
 {
 #ifdef FFI
-       DLL* dll = untag_dll(dpop());
        if(dlclose(dll->dll) == -1)
        {
                general_error(ERROR_FFI,tag_object(
index 3adf1546323579357ec7108a09512f8352f37d67..c03679707a65a941882ae31c337b249edb11f73a 100644 (file)
@@ -1,66 +1,46 @@
 #include "../factor.h"
 
-void primitive_dlopen (void)
+DLL *ffi_dlopen (F_STRING *path)
 {
 #ifdef FFI
-       char *path;
        HMODULE module;
        DLL *dll;
 
-       maybe_garbage_collection();
-
-       path = unbox_c_string();
-       module = LoadLibrary(path);
+       module = LoadLibrary(to_c_string(path));
 
        if (!module)
                general_error(ERROR_FFI, tag_object(last_error()));
 
        dll = allot_object(DLL_TYPE, sizeof(DLL));
        dll->dll = module;
-       dpush(tag_object(dll));
+
+       return dll;
 #else
        general_error(ERROR_FFI_DISABLED, F);
 #endif
 }
 
-void primitive_dlsym (void)
+void *ffi_dlsym (DLL *dll, F_STRING *symbol)
 {
 #ifdef FFI
-       DLL *dll = untag_dll(dpop());
-       void *sym = GetProcAddress((HMODULE)dll->dll, unbox_c_string());
-
+       void *sym = GetProcAddress(dll ? (HMODULE)dll->dll : GetModuleHandle(NULL),
+               to_c_string(symbol));
 
        if (!sym)
                general_error(ERROR_FFI, tag_object(last_error()));
 
-       dpush(tag_cell((CELL)sym));
+       return sym;
 #else
        general_error(ERROR_FFI_DISABLED, F);
 #endif
 }
 
-void primitive_dlclose (void)
+void ffi_dlclose (DLL *dll)
 {
 #ifdef FFI
-       DLL *dll = untag_dll(dpop());
        FreeLibrary((HMODULE)dll->dll);
        dll->dll = NULL;
 #else
        general_error(ERROR_FFI_DISABLED, F);
 #endif
-}
-
-void primitive_dlsym_self (void)
-{
-#ifdef FFI
-       void *sym = GetProcAddress(GetModuleHandle(NULL), unbox_c_string());
-
-       if(sym == NULL)
-       {
-               general_error(ERROR_FFI, tag_object(last_error()));
-       }
-       dpush(tag_cell((CELL)sym));
-#else
-       general_error(ERROR_FFI_DISABLED, F);
-#endif
-}
+}
\ No newline at end of file