diff --git a/racket/src/foreign/Makefile.in b/racket/src/foreign/Makefile.in index fd06a1d247..cfa09b82bf 100644 --- a/racket/src/foreign/Makefile.in +++ b/racket/src/foreign/Makefile.in @@ -11,6 +11,7 @@ CPPFLAGS = @PREFLAGS@ ALL_CFLAGS = $(CFLAGS) $(CPPFLAGS) @OPTIONS@ @MZOPTIONS@ \ -I$(builddir)/../racket \ -I$(srcdir)/../racket/include -I$(srcdir)/../racket/src \ + -I$(srcdir)/../rktio -I$(builddir)/../rktio \ $(LIBFFI_LOCAL_INCLUDE_@OWN_LIBFFI@) ARFLAGS = @ARFLAGS@ NOOP = : diff --git a/racket/src/foreign/foreign.c b/racket/src/foreign/foreign.c index 8eda8f365b..3c596c2405 100644 --- a/racket/src/foreign/foreign.c +++ b/racket/src/foreign/foreign.c @@ -8,6 +8,7 @@ #include "schpriv.h" #include "schmach.h" +#include "schrktio.h" #ifndef DONT_USE_FOREIGN @@ -127,76 +128,6 @@ static intptr_t add_check_overflow(const char *who, intptr_t a, intptr_t b) return SCHEME_INT_VAL(c); } -/*****************************************************************************/ -/* Defining EnumProcessModules for openning `self' as an ffi-lib */ - -/* We'd like to use EnumProcessModules to find all loaded DLLs, but it's - only available in NT 4.0 and later. The alternative, Module32{First,Next}, - is available *except* for NT 4.0! So we try EnumProcessModules first. */ - -#ifdef WINDOWS_DYNAMIC_LOAD -#ifdef MZ_PRECISE_GC -START_XFORM_SKIP; -#endif - -int epm_tried = 0; -typedef BOOL (WINAPI *EnumProcessModules_t)(HANDLE hProcess, - HMODULE* lphModule, - DWORD cb, - LPDWORD lpcbNeeded); -EnumProcessModules_t _EnumProcessModules; -#include - -static BOOL mzEnumProcessModules(HANDLE hProcess, HMODULE* lphModule, - DWORD cb, LPDWORD lpcbNeeded) -{ - if (!epm_tried) { - HMODULE hm; - hm = LoadLibrary("psapi.dll"); - if (hm) { - _EnumProcessModules = - (EnumProcessModules_t)GetProcAddress(hm, "EnumProcessModules"); - } - epm_tried = 1; - } - - if (_EnumProcessModules) - return _EnumProcessModules(hProcess, lphModule, cb, lpcbNeeded); - else { - HANDLE snapshot; - MODULEENTRY32 mod; - int i, ok; - - snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, - GetCurrentProcessId()); - if (snapshot == INVALID_HANDLE_VALUE) - return FALSE; - - for (i = 0; 1; i++) { - mod.dwSize = sizeof(mod); - if (!i) - ok = Module32First(snapshot, &mod); - else - ok = Module32Next(snapshot, &mod); - if (!ok) - break; - if (cb >= sizeof(HMODULE)) { - lphModule[i] = mod.hModule; - cb -= sizeof(HMODULE); - } - } - - CloseHandle(snapshot); - *lpcbNeeded = i * sizeof(HMODULE); - return GetLastError() == ERROR_NO_MORE_FILES; - } -} - -#ifdef MZ_PRECISE_GC -END_XFORM_SKIP; -#endif -#endif /* WINDOWS_DYNAMIC_LOAD */ - /*****************************************************************************/ /* Library objects */ @@ -204,9 +135,8 @@ END_XFORM_SKIP; static Scheme_Type ffi_lib_tag; typedef struct ffi_lib_struct { Scheme_Object so; - NON_GCBALE_PTR(void) handle; + NON_GCBALE_PTR(rktio_dll_t) handle; Scheme_Object* name; - Scheme_Hash_Table* objects; int is_global; } ffi_lib_struct; #define SCHEME_FFILIBP(x) (SCHEME_TYPE(x)==ffi_lib_tag) @@ -225,13 +155,11 @@ int ffi_lib_SIZE(void *p) { int ffi_lib_MARK(void *p) { ffi_lib_struct *s = (ffi_lib_struct *)p; gcMARK(s->name); - gcMARK(s->objects); return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct)); } int ffi_lib_FIXUP(void *p) { ffi_lib_struct *s = (ffi_lib_struct *)p; gcFIXUP(s->name); - gcFIXUP(s->objects); return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct)); } END_XFORM_SKIP; @@ -245,8 +173,8 @@ static Scheme_Object *foreign_ffi_lib(int argc, Scheme_Object *argv[]) { char *name; Scheme_Object *path, *hashname; - void *handle; - int null_ok = 0, as_global = 0; + rktio_dll_t *handle; + int as_global = 0; ffi_lib_struct *lib; if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0]))) scheme_wrong_contract(MYNAME, "(or/c string? #f)", 0, argc, argv); @@ -258,46 +186,27 @@ static Scheme_Object *foreign_ffi_lib(int argc, Scheme_Object *argv[]) hashname = (Scheme_Object*)((name==NULL) ? "" : name); lib = (ffi_lib_struct*)scheme_hash_get(opened_libs, hashname); if (!lib) { - Scheme_Hash_Table *ht; -# ifdef WINDOWS_DYNAMIC_LOAD - if (name==NULL) { - /* openning the executable is marked by a NULL handle */ - handle = NULL; - null_ok = 1; - } else { - wchar_t *wp; - wp = scheme_path_to_wide_path(MYNAME, name); - handle = LoadLibraryW(wp); - } -# else /* WINDOWS_DYNAMIC_LOAD undefined */ -# ifdef __ANDROID__ - if (!name) handle = RTLD_DEFAULT; else -# endif /* __ANDROID__ */ -# ifdef __CYGWIN32__ - if (!name) { handle = RTLD_DEFAULT; null_ok = 1; } else -# endif /* __CYGWIN32__ */ - handle = dlopen(name, RTLD_NOW | (as_global ? RTLD_GLOBAL : RTLD_LOCAL)); -# endif /* WINDOWS_DYNAMIC_LOAD */ - if (handle == NULL && !null_ok) { - if (argc > 1 && SCHEME_TRUEP(argv[1])) return scheme_false; - else { -# ifdef WINDOWS_DYNAMIC_LOAD - long err; - err = GetLastError(); - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - MYNAME": couldn't open %V (%E)", argv[0], err); -# else /* WINDOWS_DYNAMIC_LOAD undefined */ - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - MYNAME": couldn't open %V (%s)", argv[0], dlerror()); -# endif /* WINDOWS_DYNAMIC_LOAD */ + handle = rktio_dll_open(scheme_rktio, name, as_global); + if (!handle) { + char *msg; + msg = rktio_dll_get_error(scheme_rktio); + if (argc > 1 && SCHEME_TRUEP(argv[1])) { + if (msg) free(msg); + return scheme_false; + } else { + if (msg) { + msg = scheme_strdup_and_free(msg); + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, + MYNAME": couldn't open %V (%s)", argv[0], msg); + } else + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, + MYNAME": couldn't open %V (%R)", argv[0]); } } - ht = scheme_make_hash_table(SCHEME_hash_string); lib = (ffi_lib_struct*)scheme_malloc_tagged(sizeof(ffi_lib_struct)); lib->so.type = ffi_lib_tag; lib->handle = (handle); lib->name = (argv[0]); - lib->objects = (ht); lib->is_global = (!name); scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib); /* no dlclose finalizer - since the hash table always keeps a reference */ @@ -354,18 +263,13 @@ int ffi_obj_FIXUP(void *p) { END_XFORM_SKIP; #endif -#ifdef __ANDROID__ -static int adjustment_set; -static uintptr_t adjustment; -#endif /* __ANDROID__ */ - /* (ffi-obj objname ffi-lib-or-libname) -> ffi-obj */ #define MYNAME "ffi-obj" static Scheme_Object *foreign_ffi_obj(int argc, Scheme_Object *argv[]) { ffi_obj_struct *obj; void *dlobj; - ffi_lib_struct *lib = NULL, *lib2; + ffi_lib_struct *lib = NULL; char *dlname; if (SCHEME_FFILIBP(argv[1])) lib = (ffi_lib_struct*)argv[1]; @@ -376,87 +280,31 @@ static Scheme_Object *foreign_ffi_obj(int argc, Scheme_Object *argv[]) if (!SCHEME_BYTE_STRINGP(argv[0])) scheme_wrong_contract(MYNAME, "bytes?", 0, argc, argv); dlname = SCHEME_BYTE_STR_VAL(argv[0]); - obj = (ffi_obj_struct*)scheme_hash_get(lib->objects, (Scheme_Object*)dlname); - if (!obj) { -# ifdef WINDOWS_DYNAMIC_LOAD - if (lib->handle) { - dlobj = GetProcAddress(lib->handle, dlname); - } else { - /* this is for the executable-open case, which was marked by a NULL - * handle, deal with it by searching all current modules */ -# define NUM_QUICK_MODS 16 - HMODULE *mods, me, quick_mods[NUM_QUICK_MODS]; - DWORD cnt = NUM_QUICK_MODS * sizeof(HMODULE), actual_cnt, i; - me = GetCurrentProcess(); - mods = quick_mods; - if (mzEnumProcessModules(me, mods, cnt, &actual_cnt)) { - if (actual_cnt > cnt) { - cnt = actual_cnt; - mods = (HMODULE *)scheme_malloc_atomic(cnt); - if (!mzEnumProcessModules(me, mods, cnt, &actual_cnt)) - mods = NULL; - } else - cnt = actual_cnt; - } else - mods = NULL; - if (mods) { - cnt /= sizeof(HMODULE); - for (i = 0; i < cnt; i++) { - dlobj = GetProcAddress(mods[i], dlname); - if (dlobj) break; - } - } else - dlobj = NULL; - } - if (!dlobj) { - long err; - err = GetLastError(); + + dlobj = rktio_dll_find_object(scheme_rktio, lib->handle, dlname); + if (!dlobj) { + char *msg; + msg = rktio_dll_get_error(scheme_rktio); + if (msg) { + msg = scheme_strdup_and_free(msg); scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - MYNAME": couldn't get \"%s\" from %V (%E)", - dlname, lib->name, err); - } -# else /* WINDOWS_DYNAMIC_LOAD undefined */ - dlobj = dlsym(lib->handle, dlname); -# ifdef __ANDROID__ - if (dlobj && (lib->handle == RTLD_DEFAULT)) { - /* Compensate for a bug in dlsym() that gets the address wrong by - an offset (incorrect use of `link_bias'?): */ - if (!adjustment_set) { - adjustment = ((uintptr_t)scheme_start_atomic_no_break - - (uintptr_t)dlsym(RTLD_DEFAULT, "scheme_start_atomic_no_break")); - adjustment_set = 1; - } - dlobj = (char *)dlobj XFORM_OK_PLUS adjustment; - } -# endif /* __ANDROID__ */ - if (!dlobj && lib->is_global) { - /* Try every handle in the table of opened libraries. */ - int i; - for (i = opened_libs->size; i--; ) { - if (opened_libs->vals[i]) { - lib2 = (ffi_lib_struct *)opened_libs->vals[i]; - dlobj = dlsym(lib2->handle, dlname); - if (dlobj) break; - } - } - } - if (!dlobj) { - const char *err; - err = dlerror(); - if (err != NULL) - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - MYNAME": couldn't get \"%s\" from %V (%s)", - dlname, lib->name, err); - } -# endif /* WINDOWS_DYNAMIC_LOAD */ + MYNAME": couldn't get \"%s\" from %V (%s)", + dlname, lib->name, msg); + } else + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, + MYNAME": couldn't get \"%s\" from %V (%R)", + dlname, lib->name); + } + + if (dlobj) { obj = (ffi_obj_struct*)scheme_malloc_tagged(sizeof(ffi_obj_struct)); obj->so.type = ffi_obj_tag; obj->obj = (dlobj); obj->name = (dlname); obj->lib = (lib); - scheme_hash_set(lib->objects, (Scheme_Object*)dlname, (Scheme_Object*)obj); - } - return (obj == NULL) ? scheme_false : (Scheme_Object*)obj; + return (Scheme_Object *)obj; + } else + return scheme_false; } #undef MYNAME diff --git a/racket/src/foreign/foreign.rktc b/racket/src/foreign/foreign.rktc index 6816ab3c85..e0a92f9912 100755 --- a/racket/src/foreign/foreign.rktc +++ b/racket/src/foreign/foreign.rktc @@ -11,6 +11,7 @@ exec racket "$0" > `echo "$0" | sed 's/rktc$/c/'` "$0" #include "schpriv.h" #include "schmach.h" +#include "schrktio.h" #ifndef DONT_USE_FOREIGN @@ -130,83 +131,12 @@ static intptr_t add_check_overflow(const char *who, intptr_t a, intptr_t b) return SCHEME_INT_VAL(c); } -/*****************************************************************************/ -/* Defining EnumProcessModules for openning `self' as an ffi-lib */ - -/* We'd like to use EnumProcessModules to find all loaded DLLs, but it's - only available in NT 4.0 and later. The alternative, Module32{First,Next}, - is available *except* for NT 4.0! So we try EnumProcessModules first. */ - -@@IFDEF{WINDOWS_DYNAMIC_LOAD}{ -#ifdef MZ_PRECISE_GC -START_XFORM_SKIP; -#endif - -int epm_tried = 0; -typedef BOOL (WINAPI *EnumProcessModules_t)(HANDLE hProcess, - HMODULE* lphModule, - DWORD cb, - LPDWORD lpcbNeeded); -EnumProcessModules_t _EnumProcessModules; -#include - -static BOOL mzEnumProcessModules(HANDLE hProcess, HMODULE* lphModule, - DWORD cb, LPDWORD lpcbNeeded) -{ - if (!epm_tried) { - HMODULE hm; - hm = LoadLibrary("psapi.dll"); - if (hm) { - _EnumProcessModules = - (EnumProcessModules_t)GetProcAddress(hm, "EnumProcessModules"); - } - epm_tried = 1; - } - - if (_EnumProcessModules) - return _EnumProcessModules(hProcess, lphModule, cb, lpcbNeeded); - else { - HANDLE snapshot; - MODULEENTRY32 mod; - int i, ok; - - snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, - GetCurrentProcessId()); - if (snapshot == INVALID_HANDLE_VALUE) - return FALSE; - - for (i = 0; 1; i++) { - mod.dwSize = sizeof(mod); - if (!i) - ok = Module32First(snapshot, &mod); - else - ok = Module32Next(snapshot, &mod); - if (!ok) - break; - if (cb >= sizeof(HMODULE)) { - lphModule[i] = mod.hModule; - cb -= sizeof(HMODULE); - } - } - - CloseHandle(snapshot); - *lpcbNeeded = i * sizeof(HMODULE); - return GetLastError() == ERROR_NO_MORE_FILES; - } -} - -#ifdef MZ_PRECISE_GC -END_XFORM_SKIP; -#endif -} - /*****************************************************************************/ /* Library objects */ @cdefstruct[ffi-lib [] - [handle "NON_GCBALE_PTR(void)"] + [handle "NON_GCBALE_PTR(rktio_dll_t)"] [name "Scheme_Object*"] - [objects "Scheme_Hash_Table*"] [is_global "int"]] THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); @@ -215,8 +145,8 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); @cdefine[ffi-lib 1 3]{ char *name; Scheme_Object *path, *hashname; - void *handle; - int null_ok = 0, as_global = 0; + rktio_dll_t *handle; + int as_global = 0; ffi_lib_struct *lib; if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0]))) scheme_wrong_contract(MYNAME, "(or/c string? #f)", 0, argc, argv); @@ -228,38 +158,24 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); hashname = (Scheme_Object*)((name==NULL) ? "" : name); lib = (ffi_lib_struct*)scheme_hash_get(opened_libs, hashname); if (!lib) { - Scheme_Hash_Table *ht; - @@@IFDEF{WINDOWS_DYNAMIC_LOAD}{ - if (name==NULL) { - /* openning the executable is marked by a NULL handle */ - handle = NULL; - null_ok = 1; + handle = rktio_dll_open(scheme_rktio, name, as_global); + if (!handle) { + char *msg; + msg = rktio_dll_get_error(scheme_rktio); + if (argc > 1 && SCHEME_TRUEP(argv[1])) { + if (msg) free(msg); + return scheme_false; } else { - wchar_t *wp; - wp = scheme_path_to_wide_path(MYNAME, name); - handle = LoadLibraryW(wp); - } - }{ - @@IFDEF{__ANDROID__}{if (!name) handle = RTLD_DEFAULT; else} - @@IFDEF{__CYGWIN32__}{if (!name) { handle = RTLD_DEFAULT; null_ok = 1; } else} - handle = dlopen(name, RTLD_NOW | (as_global ? RTLD_GLOBAL : RTLD_LOCAL)); - } - if (handle == NULL && !null_ok) { - if (argc > 1 && SCHEME_TRUEP(argv[1])) return scheme_false; - else { - @@@IFDEF{WINDOWS_DYNAMIC_LOAD}{ - long err; - err = GetLastError(); + if (msg) { + msg = scheme_strdup_and_free(msg); scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - MYNAME": couldn't open %V (%E)", argv[0], err); - }{ + MYNAME": couldn't open %V (%s)", argv[0], msg); + } else scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - MYNAME": couldn't open %V (%s)", argv[0], dlerror()); - } + MYNAME": couldn't open %V (%R)", argv[0]); } } - ht = scheme_make_hash_table(SCHEME_hash_string); - @cmake["lib" ffi-lib "handle" "argv[0]" "ht" "!name"] + @cmake["lib" ffi-lib "handle" "argv[0]" "!name"] scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib); /* no dlclose finalizer - since the hash table always keeps a reference */ /* maybe add some explicit unload at some point */ @@ -282,16 +198,11 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); [name "char*"] [lib "NON_GCBALE_PTR(ffi_lib_struct)"]] -@@IFDEF{__ANDROID__}{ -static int adjustment_set; -static uintptr_t adjustment; -} - /* (ffi-obj objname ffi-lib-or-libname) -> ffi-obj */ @cdefine[ffi-obj 2]{ ffi_obj_struct *obj; void *dlobj; - ffi_lib_struct *lib = NULL, *lib2; + ffi_lib_struct *lib = NULL; char *dlname; if (SCHEME_FFILIBP(argv[1])) lib = (ffi_lib_struct*)argv[1]; @@ -302,83 +213,27 @@ static uintptr_t adjustment; if (!SCHEME_BYTE_STRINGP(argv[0])) scheme_wrong_contract(MYNAME, "bytes?", 0, argc, argv); dlname = SCHEME_BYTE_STR_VAL(argv[0]); - obj = (ffi_obj_struct*)scheme_hash_get(lib->objects, (Scheme_Object*)dlname); - if (!obj) { - @@@IFDEF{WINDOWS_DYNAMIC_LOAD}{ - if (lib->handle) { - dlobj = GetProcAddress(lib->handle, dlname); - } else { - /* this is for the executable-open case, which was marked by a NULL - * handle, deal with it by searching all current modules */ - @DEFINE{NUM_QUICK_MODS 16} - HMODULE *mods, me, quick_mods[NUM_QUICK_MODS]; - DWORD cnt = NUM_QUICK_MODS * sizeof(HMODULE), actual_cnt, i; - me = GetCurrentProcess(); - mods = quick_mods; - if (mzEnumProcessModules(me, mods, cnt, &actual_cnt)) { - if (actual_cnt > cnt) { - cnt = actual_cnt; - mods = (HMODULE *)scheme_malloc_atomic(cnt); - if (!mzEnumProcessModules(me, mods, cnt, &actual_cnt)) - mods = NULL; - } else - cnt = actual_cnt; - } else - mods = NULL; - if (mods) { - cnt /= sizeof(HMODULE); - for (i = 0; i < cnt; i++) { - dlobj = GetProcAddress(mods[i], dlname); - if (dlobj) break; - } - } else - dlobj = NULL; - } - if (!dlobj) { - long err; - err = GetLastError(); + + dlobj = rktio_dll_find_object(scheme_rktio, lib->handle, dlname); + if (!dlobj) { + char *msg; + msg = rktio_dll_get_error(scheme_rktio); + if (msg) { + msg = scheme_strdup_and_free(msg); scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - MYNAME": couldn't get \"%s\" from %V (%E)", - dlname, lib->name, err); - } - }{ - dlobj = dlsym(lib->handle, dlname); - @@IFDEF{__ANDROID__}{ - if (dlobj && (lib->handle == RTLD_DEFAULT)) { - /* Compensate for a bug in dlsym() that gets the address wrong by - an offset (incorrect use of `link_bias'?): */ - if (!adjustment_set) { - adjustment = ((uintptr_t)scheme_start_atomic_no_break - - (uintptr_t)dlsym(RTLD_DEFAULT, "scheme_start_atomic_no_break")); - adjustment_set = 1; - } - dlobj = (char *)dlobj XFORM_OK_PLUS adjustment; - } - } - if (!dlobj && lib->is_global) { - /* Try every handle in the table of opened libraries. */ - int i; - for (i = opened_libs->size; i--; ) { - if (opened_libs->vals[i]) { - lib2 = (ffi_lib_struct *)opened_libs->vals[i]; - dlobj = dlsym(lib2->handle, dlname); - if (dlobj) break; - } - } - } - if (!dlobj) { - const char *err; - err = dlerror(); - if (err != NULL) - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - MYNAME": couldn't get \"%s\" from %V (%s)", - dlname, lib->name, err); - } - } - @cmake["obj" ffi-obj "dlobj" "dlname" "lib"] - scheme_hash_set(lib->objects, (Scheme_Object*)dlname, (Scheme_Object*)obj); + MYNAME": couldn't get \"%s\" from %V (%s)", + dlname, lib->name, msg); + } else + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, + MYNAME": couldn't get \"%s\" from %V (%R)", + dlname, lib->name); } - return (obj == NULL) ? scheme_false : (Scheme_Object*)obj; + + if (dlobj) { + @cmake["obj" ffi-obj "dlobj" "dlname" "lib"] + return (Scheme_Object *)obj; + } else + return scheme_false; } /* (ffi-obj-lib ffi-obj) -> ffi-lib */ diff --git a/racket/src/racket/src/port.c b/racket/src/racket/src/port.c index eaeeacc5da..ca3cea7b77 100644 --- a/racket/src/racket/src/port.c +++ b/racket/src/racket/src/port.c @@ -6120,7 +6120,7 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) block_timer_signals(1); result = rktio_process(scheme_rktio, - command, argc, argv, + command, argc, (rktio_const_string_t *)argv, stdout_fd, stdin_fd, stderr_fd, SCHEME_PATH_VAL(current_dir), envvars, flags); diff --git a/racket/src/rktio/Makefile.in b/racket/src/rktio/Makefile.in index 563fffbed4..ded7a7bd1d 100644 --- a/racket/src/rktio/Makefile.in +++ b/racket/src/rktio/Makefile.in @@ -31,6 +31,7 @@ OBJS = rktio_fs.@LTO@ \ rktio_network.@LTO@ \ rktio_pipe.@LTO@ \ rktio_process.@LTO@ \ + rktio_signal.@LTO@ \ rktio_envvars.@LTO@ \ rktio_fs_change.@LTO@ \ rktio_flock.@LTO@ \ @@ -38,6 +39,7 @@ OBJS = rktio_fs.@LTO@ \ rktio_time.@LTO@ \ rktio_syslog.@LTO@ \ rktio_convert.@LTO@ \ + rktio_dll.@LTO@ \ rktio_error.@LTO@ \ rktio_hash.@LTO@ \ rktio_wide.@LTO@ \ @@ -83,6 +85,9 @@ rktio_pipe.@LTO@: $(srcdir)/rktio_pipe.c $(RKTIO_HEADERS) rktio_process.@LTO@: $(srcdir)/rktio_process.c $(RKTIO_HEADERS) $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_process.@LTO@ -c $(srcdir)/rktio_process.c +rktio_signal.@LTO@: $(srcdir)/rktio_signal.c $(RKTIO_HEADERS) + $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_signal.@LTO@ -c $(srcdir)/rktio_signal.c + rktio_envvars.@LTO@: $(srcdir)/rktio_envvars.c $(RKTIO_HEADERS) $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_envvars.@LTO@ -c $(srcdir)/rktio_envvars.c @@ -104,6 +109,9 @@ rktio_syslog.@LTO@: $(srcdir)/rktio_syslog.c $(RKTIO_HEADERS) rktio_convert.@LTO@: $(srcdir)/rktio_convert.c $(RKTIO_HEADERS) $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_convert.@LTO@ -c $(srcdir)/rktio_convert.c +rktio_dll.@LTO@: $(srcdir)/rktio_dll.c $(RKTIO_HEADERS) + $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_dll.@LTO@ -c $(srcdir)/rktio_dll.c + rktio_error.@LTO@: $(srcdir)/rktio_error.c $(RKTIO_HEADERS) $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.@LTO@ -c $(srcdir)/rktio_error.c diff --git a/racket/src/rktio/parse.rkt b/racket/src/rktio/parse.rkt index b6cd9c8a5b..38911e24f2 100644 --- a/racket/src/rktio/parse.rkt +++ b/racket/src/rktio/parse.rkt @@ -45,7 +45,8 @@ (EOF WHITESPACE OPEN CLOSE COPEN CCLOSE SEMI COMMA STAR LSHIFT EQUAL __RKTIO_H__ EXTERN EXTERN/NOERR EXTERN/STEP EXTERN/ERR - DEFINE TYPEDEF ENUM STRUCT VOID UNSIGNED SHORT INT CONST)) + DEFINE TYPEDEF ENUM STRUCT VOID UNSIGNED SHORT INT + CONST NULLABLE)) (define lex (lexer-src-pos @@ -73,6 +74,7 @@ ["RKTIO_EXTERN_NOERR" 'EXTERN/NOERR] ["RKTIO_EXTERN_STEP" 'EXTERN/STEP] ["RKTIO_EXTERN_ERR" 'EXTERN/ERR] + ["RKTIO_NULLABLE" 'NULLABLE] [(:seq (:or #\_ (:/ #\A #\Z #\a #\z)) (:* (:or #\_ (:/ #\A #\Z #\a #\z #\0 #\9)))) (token-ID (string->symbol lexeme))] @@ -106,6 +108,7 @@ [(DEFINE EXTERN/NOERR EXTERN) #f] [(DEFINE EXTERN/STEP EXTERN) #f] [(DEFINE EXTERN/ERR OPEN ID CLOSE EXTERN) #f] + [(DEFINE NULLABLE) #f] [(STRUCT ID SEMI) #f] [(TYPEDEF SEMI) (if (eq? $2 $3) @@ -147,6 +150,7 @@ [(OPEN LSHIFT CLOSE) `(<< ,$2 ,$4)]) ( [(ID) $1] [(CONST ) $2] + [(NULLABLE ) `(nullable ,$2)] [(UNSIGNED SHORT) `unsigned-short] [(UNSIGNED INT) `unsigned] [(UNSIGNED) 'unsigned] @@ -248,7 +252,8 @@ [(and (pair? t) (eq? (car t) '*ref)) (let ([s (update-type (cadr t))]) (if (and as-argument? - (or (pair? s) + (or (and (pair? s) + (not (eq? (car s) 'nullable))) (hash-ref defined-types s #f))) `(*ref ,s) `(ref ,s)))] diff --git a/racket/src/rktio/rktio.h b/racket/src/rktio/rktio.h index afd1f6cf7a..3533b96804 100644 --- a/racket/src/rktio/rktio.h +++ b/racket/src/rktio/rktio.h @@ -28,7 +28,7 @@ Return type conventions: information about a 0 result. - A return type `rktio_tri_t` (alias for `int`) means that 0 is - returned for an expected failuree, some `RKTIO_...` (alias for 1) + returned for an expected failure, some `RKTIO_...` (alias for 1) is returned for success, and `RKTIO_...ERROR` (alias for -2) is returned for some error. The function will be annotated with `RKTIO_EXTERN_ERR(...)` to indicate the error value. Use @@ -87,6 +87,8 @@ Thread and signal conventions: #define RKTIO_EXTERN_NOERR RKTIO_EXTERN #define RKTIO_EXTERN_STEP RKTIO_EXTERN +#define RKTIO_NULLABLE /* empty */ + /*************************************************/ /* Initialization and general datatypes */ @@ -125,6 +127,11 @@ typedef unsigned short rktio_char16_t; /* A UTF-16 code unit. A `rktio_char16_t *` is meant to be the same as `wchar_t *` on Windows. */ +typedef const char *rktio_const_string_t; +/* An argument that is a NUL-terminated string, as opposed to a buffer + where a length is provided separately and doesn't need to be + NUL-terminated. */ + /*************************************************/ /* DLL paths */ @@ -202,7 +209,7 @@ RKTIO_EXTERN_NOERR int rktio_fd_modes(rktio_t *rktio, rktio_fd_t *rfd); `rktio_system_fd` and those that are inferred. The `RKTIO_OPEN_INIT` flag is not recorded, however. */ -RKTIO_EXTERN rktio_fd_t *rktio_open(rktio_t *rktio, const char *src, int modes); +RKTIO_EXTERN rktio_fd_t *rktio_open(rktio_t *rktio, rktio_const_string_t src, int modes); /* Can report `RKTIO_ERROR_DOES_NOT_EXIST` in place of a system error in read mode, and can report `RKTIO_ERROR_IS_A_DIRECTORY`, `RKTIO_ERROR_EXISTS`, or `RKTIO_ERROR_ACCESS_DENIED` in place of a @@ -295,9 +302,8 @@ rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd); (because the sent data doesn't persist beyond closing the pipe). */ RKTIO_EXTERN_ERR(RKTIO_LOCK_ERROR) -rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl); -RKTIO_EXTERN_ERR(RKTIO_LOCK_ERROR) -rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd); +rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, rktio_bool_t excl); +RKTIO_EXTERN rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd); /* Advisory file locks, where `excl` attempts to claim an exclusive lock. Whether these work in various situations depend on many OS details, where the differences involve promoting from non-exlcusive @@ -348,7 +354,7 @@ typedef struct rktio_addrinfo_lookup_t rktio_addrinfo_lookup_t; typedef struct rktio_addrinfo_t rktio_addrinfo_t; RKTIO_EXTERN rktio_addrinfo_lookup_t *rktio_start_addrinfo_lookup(rktio_t *rktio, - const char *hostname, int portno, + rktio_const_string_t hostname, int portno, int family, rktio_bool_t passive, rktio_bool_t tcp); /* The `family` argument should be one of the following: */ #define RKTIO_FAMILY_ANY (-1) @@ -385,7 +391,9 @@ rktio_tri_t rktio_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener); RKTIO_EXTERN rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener); /* Accepts one connection on a listener. */ -RKTIO_EXTERN rktio_connect_t *rktio_start_connect(rktio_t *rktio, rktio_addrinfo_t *remote, rktio_addrinfo_t *local); +RKTIO_EXTERN rktio_connect_t *rktio_start_connect(rktio_t *rktio, + rktio_addrinfo_t *remote, + RKTIO_NULLABLE rktio_addrinfo_t *local); /* Starts a connection request. Addreses must not be freed until the connection is complete, errored, or stopped. */ @@ -417,7 +425,7 @@ RKTIO_EXTERN rktio_ok_t rktio_socket_shutdown(rktio_t *rktio, rktio_fd_t *rfd, i #define RKTIO_SHUTDOWN_READ 0 #define RKTIO_SHUTDOWN_WRITE 1 -RKTIO_EXTERN rktio_fd_t *rktio_udp_open(rktio_t *rktio, rktio_addrinfo_t *addr, int family); +RKTIO_EXTERN rktio_fd_t *rktio_udp_open(rktio_t *rktio, RKTIO_NULLABLE rktio_addrinfo_t *addr, int family); /* The `addr` argument can be NULL to create a socket without specifying an interface, and `family` is used only if `addr` is not specified. */ @@ -428,11 +436,16 @@ RKTIO_EXTERN rktio_ok_t rktio_udp_bind(rktio_t *rktio, rktio_fd_t *rfd, rktio_ad RKTIO_EXTERN rktio_ok_t rktio_udp_connect(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr); RKTIO_EXTERN_ERR(RKTIO_WRITE_ERROR) -intptr_t rktio_udp_sendto(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr, +intptr_t rktio_udp_sendto(rktio_t *rktio, rktio_fd_t *rfd, RKTIO_NULLABLE rktio_addrinfo_t *addr, const char *buffer, intptr_t len); /* Extends `rktio_write` to accept a destination `addr`, and binds `rfd` if it is not bound aready. The `addr` can be NULL if the socket is connected. */ +RKTIO_EXTERN_ERR(RKTIO_WRITE_ERROR) +intptr_t rktio_udp_sendto_in(rktio_t *rktio, rktio_fd_t *rfd, RKTIO_NULLABLE rktio_addrinfo_t *addr, + const char *buffer, intptr_t start, intptr_t end); +/* Like `rktio_udp_sendto`, but with starting and ending offsets within `buffer`. */ + typedef struct rktio_length_and_addrinfo_t { intptr_t len; char **address; /* like the result of `rktio_socket_address` */ @@ -444,6 +457,10 @@ RKTIO_EXTERN rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rkt be `RKTIO_ERROR_TRY_AGAIN` or `RKTIO_ERROR_INFO_TRY_AGAIN`, where the latter can happen if the sock claims to be ready to read. */ +RKTIO_EXTERN rktio_length_and_addrinfo_t *rktio_udp_recvfrom_in(rktio_t *rktio, rktio_fd_t *rfd, + char *buffer, intptr_t start, intptr_t end); +/* Like `rktio_udp_recvfrom`, but with starting and ending offsets. */ + RKTIO_EXTERN_ERR(RKTIO_PROP_ERROR) rktio_tri_t rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd); RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, rktio_bool_t on); RKTIO_EXTERN_ERR(RKTIO_PROP_ERROR) rktio_tri_t rktio_udp_get_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd); @@ -451,19 +468,14 @@ RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_ttl(rktio_t *rktio, rktio_fd_t * #define RKTIO_PROP_ERROR (-2) -RKTIO_EXTERN char **rktio_socket_address(rktio_t *rktio, rktio_fd_t *rfd); -RKTIO_EXTERN char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd); -RKTIO_EXTERN char **rktio_listener_address(rktio_t *rktio, rktio_listener_t *lnr); -/* These return two strings in an array (where the array itself should - be deallocated): address and service. */ - RKTIO_EXTERN char *rktio_udp_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd); -RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr); +RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd, + RKTIO_NULLABLE rktio_addrinfo_t *addr); /* The `addr` argument can be NULL to auto-select the interface. */ RKTIO_EXTERN rktio_ok_t rktio_udp_change_multicast_group(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *group_addr, - rktio_addrinfo_t *intf_addr, + RKTIO_NULLABLE rktio_addrinfo_t *intf_addr, int action); /* `action` values: */ enum { @@ -471,10 +483,16 @@ enum { RKTIO_DROP_MEMBERSHIP }; +RKTIO_EXTERN char **rktio_socket_address(rktio_t *rktio, rktio_fd_t *rfd); +RKTIO_EXTERN char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd); +RKTIO_EXTERN char **rktio_listener_address(rktio_t *rktio, rktio_listener_t *lnr); +/* These return two strings in an array (where the array itself should + be deallocated): address and service. */ + /*************************************************/ /* Environment variables */ -RKTIO_EXTERN rktio_bool_t rktio_is_ok_envvar_name(rktio_t *rktio, const char *name); +RKTIO_EXTERN rktio_bool_t rktio_is_ok_envvar_name(rktio_t *rktio, rktio_const_string_t name); /* Checks whether a string is valid as a new (e.g., no "="). */ RKTIO_EXTERN rktio_bool_t rktio_are_envvar_names_case_insensitive(rktio_t *rktio); @@ -482,12 +500,12 @@ RKTIO_EXTERN rktio_bool_t rktio_are_envvar_names_case_insensitive(rktio_t *rktio That doesn't mean that clients need to case-fold names, but clients may want to immitate the OS. */ -RKTIO_EXTERN char *rktio_getenv(rktio_t *rktio, const char *name); +RKTIO_EXTERN char *rktio_getenv(rktio_t *rktio, rktio_const_string_t name); /* Gets an environment variable value, or reports `RKTIO_ERROR_NO_SUCH_ENVVAR` when returning NULL; the result must be freed. */ -RKTIO_EXTERN rktio_ok_t rktio_setenv(rktio_t *rktio, const char *name, const char *val); +RKTIO_EXTERN rktio_ok_t rktio_setenv(rktio_t *rktio, rktio_const_string_t name, rktio_const_string_t val); /* Set an environment variable's value, where a NULL value for `val` unsets it. */ @@ -505,8 +523,8 @@ RKTIO_EXTERN rktio_envvars_t *rktio_envvars_copy(rktio_t *rktio, rktio_envvars_t RKTIO_EXTERN void rktio_envvars_free(rktio_t *rktio, rktio_envvars_t *envvars); /* Deallocates an environment-variables record: */ -RKTIO_EXTERN char *rktio_envvars_get(rktio_t *rktio, rktio_envvars_t *envvars, const char *name); -RKTIO_EXTERN void rktio_envvars_set(rktio_t *rktio, rktio_envvars_t *envvars, const char *name, const char *value); +RKTIO_EXTERN char *rktio_envvars_get(rktio_t *rktio, rktio_envvars_t *envvars, rktio_const_string_t name); +RKTIO_EXTERN void rktio_envvars_set(rktio_t *rktio, rktio_envvars_t *envvars, rktio_const_string_t name, rktio_const_string_t value); /* Access/update environment-variables record by name. */ RKTIO_EXTERN_NOERR intptr_t rktio_envvars_count(rktio_t *rktio, rktio_envvars_t *envvars); @@ -527,9 +545,9 @@ typedef struct rktio_process_result_t { } rktio_process_result_t; RKTIO_EXTERN rktio_process_result_t *rktio_process(rktio_t *rktio, - const char *command, int argc, char **argv, + rktio_const_string_t command, int argc, rktio_const_string_t *argv, rktio_fd_t *stdout_fd, rktio_fd_t *stdin_fd, rktio_fd_t *stderr_fd, - const char *current_directory, rktio_envvars_t *envvars, + rktio_const_string_t current_directory, rktio_envvars_t *envvars, int flags); /* `flags` flags: */ #define RKTIO_PROCESS_NEW_GROUP (1<<0) @@ -586,7 +604,7 @@ RKTIO_EXTERN_NOERR int rktio_fs_change_properties(rktio_t *rktio); typedef struct rktio_fs_change_t rktio_fs_change_t; struct rktio_ltps_t; /* forward reference */ -RKTIO_EXTERN rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, const char *path, +RKTIO_EXTERN rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, rktio_const_string_t path, struct rktio_ltps_t *ltps); /* Creates a filesystem-change tracker that reports changes in `path` after creation of the tracker. The properties repotred by @@ -721,33 +739,33 @@ RKTIO_EXTERN void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds /*************************************************/ /* Files, directories, and links */ -RKTIO_EXTERN rktio_bool_t rktio_file_exists(rktio_t *rktio, const char *filename); -RKTIO_EXTERN rktio_bool_t rktio_directory_exists(rktio_t *rktio, const char *dirname); -RKTIO_EXTERN rktio_bool_t rktio_link_exists(rktio_t *rktio, const char *filename); -RKTIO_EXTERN rktio_bool_t rktio_is_regular_file(rktio_t *rktio, const char *filename); +RKTIO_EXTERN rktio_bool_t rktio_file_exists(rktio_t *rktio, rktio_const_string_t filename); +RKTIO_EXTERN rktio_bool_t rktio_directory_exists(rktio_t *rktio, rktio_const_string_t dirname); +RKTIO_EXTERN rktio_bool_t rktio_link_exists(rktio_t *rktio, rktio_const_string_t filename); +RKTIO_EXTERN rktio_bool_t rktio_is_regular_file(rktio_t *rktio, rktio_const_string_t filename); -RKTIO_EXTERN rktio_ok_t rktio_delete_file(rktio_t *rktio, const char *fn, rktio_bool_t enable_write_on_fail); +RKTIO_EXTERN rktio_ok_t rktio_delete_file(rktio_t *rktio, rktio_const_string_t fn, rktio_bool_t enable_write_on_fail); -RKTIO_EXTERN rktio_ok_t rktio_rename_file(rktio_t *rktio, const char *dest, const char *src, rktio_bool_t exists_ok); +RKTIO_EXTERN rktio_ok_t rktio_rename_file(rktio_t *rktio, rktio_const_string_t dest, rktio_const_string_t src, rktio_bool_t exists_ok); /* Can report `RKTIO_ERROR_EXISTS`. */ RKTIO_EXTERN char *rktio_get_current_directory(rktio_t *rktio); -RKTIO_EXTERN rktio_ok_t rktio_set_current_directory(rktio_t *rktio, const char *path); +RKTIO_EXTERN rktio_ok_t rktio_set_current_directory(rktio_t *rktio, rktio_const_string_t path); -RKTIO_EXTERN rktio_ok_t rktio_make_directory(rktio_t *rktio, const char *filename); +RKTIO_EXTERN rktio_ok_t rktio_make_directory(rktio_t *rktio, rktio_const_string_t filename); /* Can report `RKTIO_ERROR_EXISTS`. */ -RKTIO_EXTERN rktio_ok_t rktio_delete_directory(rktio_t *rktio, const char *filename, const char *current_directory, +RKTIO_EXTERN rktio_ok_t rktio_delete_directory(rktio_t *rktio, rktio_const_string_t filename, rktio_const_string_t current_directory, rktio_bool_t enable_write_on_fail); /* The `current_directory` argument is used on Windows to avoid being in `filename` (instead) as a directory while trying to delete it. The `enable_write_on_fail` argument also applied to Windows. */ -RKTIO_EXTERN char *rktio_readlink(rktio_t *rktio, const char *fullfilename); +RKTIO_EXTERN char *rktio_readlink(rktio_t *rktio, rktio_const_string_t fullfilename); /* Argument should not have a trailing separator. Can report `RKTIO_ERROR_NOT_A_LINK`. */ -RKTIO_EXTERN rktio_ok_t rktio_make_link(rktio_t *rktio, const char *src, const char *dest, +RKTIO_EXTERN rktio_ok_t rktio_make_link(rktio_t *rktio, rktio_const_string_t src, rktio_const_string_t dest, rktio_bool_t dest_is_directory); /* The `dest_is_directory` argument is used only on Windows. Can report `RKTIO_ERROR_EXISTS`. */ @@ -757,10 +775,10 @@ RKTIO_EXTERN rktio_ok_t rktio_make_link(rktio_t *rktio, const char *src, const c typedef intptr_t rktio_timestamp_t; -RKTIO_EXTERN rktio_filesize_t *rktio_file_size(rktio_t *rktio, const char *filename); +RKTIO_EXTERN rktio_filesize_t *rktio_file_size(rktio_t *rktio, rktio_const_string_t filename); -RKTIO_EXTERN rktio_timestamp_t *rktio_get_file_modify_seconds(rktio_t *rktio, const char *file); -RKTIO_EXTERN rktio_ok_t rktio_set_file_modify_seconds(rktio_t *rktio, const char *file, rktio_timestamp_t secs); +RKTIO_EXTERN rktio_timestamp_t *rktio_get_file_modify_seconds(rktio_t *rktio, rktio_const_string_t file); +RKTIO_EXTERN rktio_ok_t rktio_set_file_modify_seconds(rktio_t *rktio, rktio_const_string_t file, rktio_timestamp_t secs); typedef struct rktio_identity_t { uintptr_t a, b, c; @@ -768,7 +786,7 @@ typedef struct rktio_identity_t { } rktio_identity_t; RKTIO_EXTERN rktio_identity_t *rktio_fd_identity(rktio_t *rktio, rktio_fd_t *fd); -RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, const char *path, rktio_bool_t follow_links); +RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, rktio_const_string_t path, rktio_bool_t follow_links); /*************************************************/ /* Permissions */ @@ -781,11 +799,11 @@ RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, const char *p #define RKTIO_PERMISSION_ERROR (-1) RKTIO_EXTERN_ERR(RKTIO_PERMISSION_ERROR) -int rktio_get_file_or_directory_permissions(rktio_t *rktio, const char *filename, rktio_bool_t all_bits); +int rktio_get_file_or_directory_permissions(rktio_t *rktio, rktio_const_string_t filename, rktio_bool_t all_bits); /* Result is `RKTIO_PERMISSION_ERROR` for error, otherwise a combination of bits. If not `all_bits`, then use constants above. */ -RKTIO_EXTERN rktio_ok_t rktio_set_file_or_directory_permissions(rktio_t *rktio, const char *filename, int new_bits); +RKTIO_EXTERN rktio_ok_t rktio_set_file_or_directory_permissions(rktio_t *rktio, rktio_const_string_t filename, int new_bits); /* The `new_bits` format corresponds to `all_bits` for getting permissions. Can report `RKTIO_ERROR_BAD_PERMISSION` for bits that make no sense. */ @@ -794,7 +812,7 @@ RKTIO_EXTERN rktio_ok_t rktio_set_file_or_directory_permissions(rktio_t *rktio, typedef struct rktio_directory_list_t rktio_directory_list_t; -RKTIO_EXTERN rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, const char *dirname); +RKTIO_EXTERN rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, rktio_const_string_t dirname); /* On Windows, the given `dirname` must be normalized and not have `.` or `..`: */ @@ -816,7 +834,7 @@ RKTIO_EXTERN char **rktio_filesystem_roots(rktio_t *rktio); typedef struct rktio_file_copy_t rktio_file_copy_t; -RKTIO_EXTERN_STEP rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, const char *dest, const char *src, +RKTIO_EXTERN_STEP rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, rktio_const_string_t dest, rktio_const_string_t src, rktio_bool_t exists_ok); /* Starts a file copy. Depending on the OS, this step may perform the whole copy, or it may just get started. Can report @@ -870,7 +888,7 @@ enum { RKTIO_PATH_INIT_FILE }; -RKTIO_EXTERN char *rktio_expand_user_tilde(rktio_t *rktio, const char *filename); +RKTIO_EXTERN char *rktio_expand_user_tilde(rktio_t *rktio, rktio_const_string_t filename); /* Path must start with tilde, otherwise `RKTIO_ERROR_NO_TILDE`. Other possible errors are `RKTIO_ERROR_ILL_FORMED_USER` and `RKTIO_ERROR_UNKNOWN_USER`. */ @@ -902,6 +920,23 @@ RKTIO_EXTERN void rktio_flush_signals_received(rktio_t *rktio); /* Clears any pending signal so that it doesn't interrupt the next `rktio_sleep`. */ +RKTIO_EXTERN void rktio_install_os_signal_handler(rktio_t *rktio); +/* Installs OS-level handlers for SIGINT, SIGTERM, and SIGHUP (or + Ctl-C on Windows) to signal the handle of `rktio` and also record + the signal for reporting via `rktio_poll_os_signal`. Only one + `rktio` can be registered this way at a time. This function must + not be called in two threads at the same time. */ + +RKTIO_EXTERN_NOERR int rktio_poll_os_signal(rktio_t *rktio); +/* Returns one of the following, not counting the last one: */ +#define RKTIO_OS_SIGNAL_NONE (-1) +enum { + RKTIO_OS_SIGNAL_INT, + RKTIO_OS_SIGNAL_TERM, + RKTIO_OS_SIGNAL_HUP, + RKTIO_NUM_OS_SIGNALS +}; + /*************************************************/ /* Time and date */ @@ -943,10 +978,10 @@ enum { }; RKTIO_EXTERN rktio_ok_t rktio_shell_execute(rktio_t *rktio, - const char *verb, - const char *target, - const char *arg, - const char *dir, + rktio_const_string_t verb, + rktio_const_string_t target, + rktio_const_string_t arg, + rktio_const_string_t dir, int show_mode); /* Supported only on Windows to run `ShellExecute`. The `dir` argument needs to have normalized path separators. */ @@ -954,7 +989,7 @@ RKTIO_EXTERN rktio_ok_t rktio_shell_execute(rktio_t *rktio, /*************************************************/ /* Path conversion */ -RKTIO_EXTERN rktio_char16_t *rktio_path_to_wide_path(rktio_t *rktio, const char *p); +RKTIO_EXTERN rktio_char16_t *rktio_path_to_wide_path(rktio_t *rktio, rktio_const_string_t p); RKTIO_EXTERN_NOERR char *rktio_wide_path_to_path(rktio_t *rktio, const rktio_char16_t *wp); /* Convert to/from the OS's native path representation. These functions are useful only on Windows. The `rktio_path_to_wide_path` @@ -963,8 +998,8 @@ RKTIO_EXTERN_NOERR char *rktio_wide_path_to_path(rktio_t *rktio, const rktio_cha /*************************************************/ /* Logging */ -RKTIO_EXTERN rktio_ok_t rktio_syslog(rktio_t *rktio, int level, const char *name, const char *msg, - const char *exec_name); +RKTIO_EXTERN rktio_ok_t rktio_syslog(rktio_t *rktio, int level, rktio_const_string_t name, rktio_const_string_t msg, + rktio_const_string_t exec_name); /* Adds a message to the system log. The `name` argument can be NULL, and it is added to the front of the message with a separating ": " if non_NULL. The `exec_name` is the current executable name; it's @@ -991,7 +1026,7 @@ RKTIO_EXTERN_NOERR int rktio_convert_properties(rktio_t *rktio); typedef struct rktio_converter_t rktio_converter_t; -RKTIO_EXTERN rktio_converter_t *rktio_converter_open(rktio_t *rktio, const char *to_enc, const char *from_enc); +RKTIO_EXTERN rktio_converter_t *rktio_converter_open(rktio_t *rktio, rktio_const_string_t to_enc, rktio_const_string_t from_enc); /* Creates an encoding converter. */ RKTIO_EXTERN void rktio_converter_close(rktio_t *rktio, rktio_converter_t *cvt); @@ -1014,15 +1049,30 @@ intptr_t rktio_convert(rktio_t *rktio, #define RKTIO_CONVERT_ERROR (-1) -RKTIO_EXTERN char *rktio_locale_recase(rktio_t *rktio, - rktio_bool_t to_up, - char *in); +typedef struct rktio_convert_result_t { + intptr_t in_consumed; /* input bytes converted */ + intptr_t out_produced; /* output bytes produced */ + intptr_t converted; /* characters converted, can be `RKTIO_CONVERT_ERROR` */ +} rktio_convert_result_t; + +RKTIO_EXTERN rktio_convert_result_t *rktio_convert_in(rktio_t *rktio, + rktio_converter_t *cvt, + char *in, intptr_t in_start, intptr_t in_end, + char *out, intptr_t out_start, intptr_t out_end); +/* The same as rktio_convert`, but accepting start and end positions + and returning results as an allocated struct. A conversion error + doesn't return a NULL result; instead, `converted` in the result + reports the error. */ + +RKTIO_EXTERN_NOERR char *rktio_locale_recase(rktio_t *rktio, + rktio_bool_t to_up, + rktio_const_string_t in); /* Upcases (of `to_up`) or downcases (if `!to_up`) the content of `in` using the current locale's encoding and case conversion. */ -RKTIO_EXTERN rktio_char16_t *rktio_recase_utf16(rktio_t *rktio, - rktio_bool_t to_up, rktio_char16_t *s1, - intptr_t len, intptr_t *olen); +RKTIO_EXTERN_NOERR rktio_char16_t *rktio_recase_utf16(rktio_t *rktio, + rktio_bool_t to_up, rktio_char16_t *s1, + intptr_t len, intptr_t *olen); /* Converts the case of a string encoded in UTF-16 for the system's default locale if the OS provided direct support for it. The `RKTIO_CONVERT_RECASE_UTF16 property from @@ -1030,7 +1080,7 @@ RKTIO_EXTERN rktio_char16_t *rktio_recase_utf16(rktio_t *rktio, Takes and optionally returns a length (`olen` can be NULL), but the UTF-16 sequence is expected to have no nuls. */ -RKTIO_EXTERN_NOERR int rktio_locale_strcoll(rktio_t *rktio, char *s1, char *s2); +RKTIO_EXTERN_NOERR int rktio_locale_strcoll(rktio_t *rktio, rktio_const_string_t s1, rktio_const_string_t s2); /* Returns -1 if `s1` is less than `s2` by the current locale's comparison, positive is `s1` is greater, and 0 if the strings are equal. */ @@ -1049,7 +1099,7 @@ RKTIO_EXTERN_NOERR int rktio_strcoll_utf16(rktio_t *rktio, RKTIO_EXTERN char *rktio_locale_encoding(rktio_t *rktio); /* Returns the name of the current locale's encoding. */ -RKTIO_EXTERN void rktio_set_locale(rktio_t *rktio, char *name); +RKTIO_EXTERN void rktio_set_locale(rktio_t *rktio, rktio_const_string_t name); /* Sets the current locale, which affects string comparisons and conversions. It can also affect the C library's character-property predicates and number printing/parsing. The empty string @@ -1065,6 +1115,38 @@ RKTIO_EXTERN char *rktio_system_language_country(rktio_t *rktio); /* Returns the current system's language in country in a 5-character format such as "en_US". */ +/*************************************************/ +/* Dynamically loaded libraries */ + +typedef struct rktio_dll_t rktio_dll_t; + +RKTIO_EXTERN rktio_dll_t *rktio_dll_open(rktio_t *rktio, rktio_const_string_t name, rktio_bool_t as_global); +/* Loads a DLL using system-provided functions and search rules, such + as dlopen() and its rules. If `as_global` is true, then the library + is loaded in "global" mode, which has implications for other + libraries trying to find bindings and for searching within the + specific library for a binding. The `name` argument can be NULL + to mean "the current executable". + + Some system error-reporting protocols do not fit nicely into the + normal rktio error model. If the `RKTIO_ERROR_DLL` error is + reported, then rktio_dll_get_error() must be used before any other + `rktio_dll_...` call to get an error string. + + Currently, there's no way to close and unload a DLL. Even when the + given `rktio` is closed with `rktio_destroy`, loaded libraries + remain in the process. */ + +RKTIO_EXTERN void *rktio_dll_find_object(rktio_t *rktio, rktio_dll_t *dll, rktio_const_string_t name); +/* Find an address within `dll` for the `name` export. + + An error result can be `RKTIO_ERROR_DLL` as for `rktio_dll_open`. */ + +RKTIO_EXTERN char *rktio_dll_get_error(rktio_t *rktio); +/* Returns an error for a previous `rktio_dll_...` call, or NULL + if no error string is available or has already been returned. + See `rktio_dll_open` for more information. */ + /*************************************************/ /* Errors */ @@ -1113,6 +1195,7 @@ enum { RKTIO_ERROR_CONVERT_BAD_SEQUENCE, RKTIO_ERROR_CONVERT_PREMATURE_END, RKTIO_ERROR_CONVERT_OTHER, + RKTIO_ERROR_DLL, /* use `rktio_dll_get_error` atomically to get error */ }; RKTIO_EXTERN_NOERR int rktio_get_last_error_step(rktio_t *rktio); @@ -1130,9 +1213,9 @@ RKTIO_EXTERN void rktio_remap_last_error(rktio_t *rktio); RKTIO_EXTERN_NOERR const char *rktio_get_last_error_string(rktio_t *rktio); RKTIO_EXTERN_NOERR const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid); -/* The returned strings for `rktio_...error_string` should not be +/* The returned string for `rktio_...error_string` should not be deallocated, but it only lasts reliably until the next call to - either of the functions. */ + either of the functions. */ /*************************************************/ diff --git a/racket/src/rktio/rktio_convert.c b/racket/src/rktio/rktio_convert.c index fd422e8458..fd6c3a9296 100644 --- a/racket/src/rktio/rktio_convert.c +++ b/racket/src/rktio/rktio_convert.c @@ -205,7 +205,7 @@ int rktio_convert_properties(rktio_t *rktio) /* Current locale */ /*============================================================*/ -void rktio_set_locale(rktio_t *rktio, char *name) +void rktio_set_locale(rktio_t *rktio, const char *name) { /* We only need CTYPE and COLLATE; two calls seem to be much faster than one call with ALL */ @@ -463,13 +463,36 @@ intptr_t rktio_convert(rktio_t *rktio, return (intptr_t)r; } +rktio_convert_result_t *rktio_convert_in(rktio_t *rktio, + rktio_converter_t *cvt, + char *in, intptr_t in_start, intptr_t in_end, + char *out, intptr_t out_start, intptr_t out_end) +{ + intptr_t converted; + intptr_t in_left = in_end - in_start; + intptr_t out_left = out_end - out_start; + char *in_p = in + in_start; + char *out_p = out + out_start; + rktio_convert_result_t *r; + + converted = rktio_convert(rktio, cvt, (in ? &in_p : NULL), &in_left, &out_p, &out_left); + + r = malloc(sizeof(rktio_convert_result_t)); + + r->in_consumed = in_p - (in + in_start); + r->out_produced = out_p - (out + out_start); + r->converted = converted; + + return r; +} + /*============================================================*/ /* Case conversion */ /*============================================================*/ char *rktio_locale_recase(rktio_t *rktio, rktio_bool_t to_up, - char *in) + const char *in) { char *out; @@ -627,7 +650,7 @@ rktio_char16_t *rktio_recase_utf16(rktio_t *rktio, rktio_bool_t to_up, rktio_cha /* Native string comparison */ /*============================================================*/ -int rktio_locale_strcoll(rktio_t *rktio, char *s1, char *s2) +int rktio_locale_strcoll(rktio_t *rktio, const char *s1, const char *s2) { return strcoll(s1, s2); } diff --git a/racket/src/rktio/rktio_dll.c b/racket/src/rktio/rktio_dll.c new file mode 100644 index 0000000000..416265a72a --- /dev/null +++ b/racket/src/rktio/rktio_dll.c @@ -0,0 +1,350 @@ +#include "rktio.h" +#include "rktio_private.h" +#include +#include + +typedef struct rktio_dll_object_t rktio_dll_object_t; + +#ifdef RKTIO_SYSTEM_UNIX +static void get_dl_error(rktio_t *rktio); +#endif + +/*========================================================================*/ +/* Opening a DLL */ +/*========================================================================*/ + +#ifdef RKTIO_SYSTEM_UNIX +#include +typedef void *dll_handle_t; +#endif + +#ifdef RKTIO_SYSTEM_WINDOWS +typedef HANDLE dll_handle_t; +#endif + +struct rktio_dll_t { + void *handle; + char *name; + rktio_hash_t *objects_by_name; + rktio_dll_object_t *all_objects; + int search_exe; + rktio_dll_t *all_next; /* chain for all DLLs */ + rktio_dll_t *hash_next; /* chain for hash collisions */ +}; + +rktio_dll_t *rktio_dll_open(rktio_t *rktio, rktio_const_string_t name, rktio_bool_t as_global) +{ + rktio_dll_t *dll, *dlls; + intptr_t key; + dll_handle_t handle; + int null_ok = 0; + + if (!rktio->dlls_by_name) + rktio->dlls_by_name = rktio_hash_new(); + + if (name) + key = rktio_hash_string(name); + else + key = 0; + + dll = dlls = rktio_hash_get(rktio->dlls_by_name, key); + + while (dll) { + if (!name) { + if (!dll->name) + break; + } else if (!strcmp(dll->name, name)) { + break; + } + dll = dll->hash_next; + } + + if (dll) + return dll; + +#ifdef RKTIO_SYSTEM_UNIX +# if defined(__ANDROID__) + if (!name) handle = RTLD_DEFAULT; else +# elif defined(__CYGWIN32__) + if (!name) { handle = RTLD_DEFAULT; null_ok = 1; } else +# endif + handle = dlopen(name, RTLD_NOW | (as_global ? RTLD_GLOBAL : RTLD_LOCAL)); + + if (!handle && !null_ok) + get_dl_error(rktio); +#endif + +#ifdef RKTIO_SYSTEM_WINDOWS + if (!name) { + /* openning the executable is marked by a NULL handle */ + handle = NULL; + null_ok = 1; + } else { + handle = LoadLibraryW(WIDE_PATH_temp(name)); + if (!handle) + get_windows_error(); + } +#endif + + if (!handle && !null_ok) + return NULL; + + dll = malloc(sizeof(rktio_dll_t)); + dll->handle = handle; + dll->name = (name ? MSC_IZE(strdup)(name) : NULL); + dll->objects_by_name = rktio_hash_new(); + dll->all_objects = NULL; + dll->search_exe = (name == NULL); + + dll->all_next = rktio->all_dlls; + rktio->all_dlls = dll; + + dll->hash_next = dlls; + rktio_hash_set(rktio->dlls_by_name, key, dll); + + return dll; +} + +/*========================================================================*/ +/* Searching all DLLs on Windows */ +/*========================================================================*/ + +#ifdef RKTIO_SYSTEM_WINDOWS + +/* We'd like to use EnumProcessModules to find all loaded DLLs, but it's + only available in NT 4.0 and later. The alternative, Module32{First,Next}, + is available *except* for NT 4.0! So we try EnumProcessModules first. */ + +int epm_tried = 0; +typedef BOOL (WINAPI *EnumProcessModules_t)(HANDLE hProcess, + HMODULE* lphModule, + DWORD cb, + LPDWORD lpcbNeeded); +EnumProcessModules_t _EnumProcessModules; +#include + +static BOOL do_EnumProcessModules(HANDLE hProcess, HMODULE* lphModule, + DWORD cb, LPDWORD lpcbNeeded) +{ + if (!epm_tried) { + HMODULE hm; + hm = LoadLibraryW(L"psapi.dll"); + if (hm) + _EnumProcessModules = (EnumProcessModules_t)GetProcAddress(hm, "EnumProcessModules"); + if (!_EnumProcessModules) { + hm = LoadLibraryW(L"kernel32.dll"); + if (hm) + _EnumProcessModules = (EnumProcessModules_t)GetProcAddress(hm, "EnumProcessModules"); + } + epm_tried = 1; + } + + if (_EnumProcessModules) + return _EnumProcessModules(hProcess, lphModule, cb, lpcbNeeded); + else { + HANDLE snapshot; + MODULEENTRY32 mod; + int i, ok; + + snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, + GetCurrentProcessId()); + if (snapshot == INVALID_HANDLE_VALUE) + return FALSE; + + for (i = 0; 1; i++) { + mod.dwSize = sizeof(mod); + if (!i) + ok = Module32First(snapshot, &mod); + else + ok = Module32Next(snapshot, &mod); + if (!ok) + break; + if (cb >= sizeof(HMODULE)) { + lphModule[i] = mod.hModule; + cb -= sizeof(HMODULE); + } + } + + CloseHandle(snapshot); + *lpcbNeeded = i * sizeof(HMODULE); + return GetLastError() == ERROR_NO_MORE_FILES; + } +} + +#endif + +/*========================================================================*/ +/* Searching for an object in a DLL */ +/*========================================================================*/ + +#ifdef __ANDROID__ +static int adjustment_set; +static uintptr_t adjustment; +#endif + +struct rktio_dll_object_t { + char *name; + void *address; + rktio_dll_object_t *all_next; /* chain for all object */ + rktio_dll_object_t *hash_next; /* chain for hash collisions */ +}; + +void *rktio_dll_find_object(rktio_t *rktio, rktio_dll_t *dll, rktio_const_string_t name) +{ + rktio_dll_object_t *objs, *obj; + intptr_t key; + void *address; + + key = rktio_hash_string(name); + objs = rktio_hash_get(dll->objects_by_name, key); + + for (obj = objs; obj; obj = obj->hash_next) + if (!strcmp(name, obj->name)) + break; + + if (obj) + return obj->address; + +#ifdef RKTIO_SYSTEM_UNIX + address = dlsym(dll->handle, name); + +# ifdef __ANDROID__ + if (address && (dll->handle == RTLD_DEFAULT)) { + /* Compensate for a bug in dlsym() that gets the address wrong by + an offset (incorrect use of `link_bias'?): */ + if (!adjustment_set) { + adjustment = ((uintptr_t)scheme_start_atomic_no_break + - (uintptr_t)dlsym(RTLD_DEFAULT, "rktio_dll_find_object")); + adjustment_set = 1; + } + address = (char *)address + adjustment; + } +# endif + + if (!address && dll->search_exe) { + /* Try every handle in the table of opened libraries. */ + for (dll = rktio->all_dlls; dll; dll = dll->all_next) { + address = dlsym(dll->handle, name); + if (address) break; + } + } + + if (!address) { + get_dl_error(rktio); + return NULL; + } +#endif + +#ifdef RKTIO_SYSTEM_WINDOWS + if (dll->handle) + address = GetProcAddress(dll->handle, name); + else { + /* this is for the executable-open case, which was marked by a NULL + * handle; deal with it by searching all current modules */ +# define NUM_QUICK_MODS 16 + HMODULE *mods, me, quick_mods[NUM_QUICK_MODS]; + DWORD cnt = NUM_QUICK_MODS * sizeof(HMODULE), actual_cnt, i; + me = GetCurrentProcess(); + mods = quick_mods; + if (do_EnumProcessModules(me, mods, cnt, &actual_cnt)) { + if (actual_cnt > cnt) { + cnt = actual_cnt; + mods = malloc(cnt); + if (!do_EnumProcessModules(me, mods, cnt, &actual_cnt)) + mods = NULL; + } else + cnt = actual_cnt; + } else + mods = NULL; + if (mods) { + cnt /= sizeof(HMODULE); + for (i = 0; i < cnt; i++) { + address = GetProcAddress(mods[i], name); + if (address) break; + } + } else + address = NULL; + if (mods != quick_mods) + free(mods); + } + + if (!address) { + get_windows_error(); + return NULL; + } +#endif + + obj = malloc(sizeof(rktio_dll_object_t)); + obj->name = MSC_IZE(strdup)(name); + obj->address = address; + + obj->hash_next = objs; + rktio_hash_set(dll->objects_by_name, key, obj); + + obj->all_next = dll->all_objects; + dll->all_objects = obj; + + return address; +} + +/*========================================================================*/ +/* Errors */ +/*========================================================================*/ + +#ifdef RKTIO_SYSTEM_UNIX +static void get_dl_error(rktio_t *rktio) +{ + char *s = dlerror(); + + if (rktio->dll_error) + free(rktio->dll_error); + + if (s) + rktio->dll_error = strdup(s); + else + rktio->dll_error = strdup("unknown error"); +} +#endif + +RKTIO_EXTERN char *rktio_dll_get_error(rktio_t *rktio) +{ +#ifdef RKTIO_SYSTEM_UNIX + char *s = rktio->dll_error; + rktio->dll_error = NULL; + return s; +#else + return NULL; +#endif +} + +/*========================================================================*/ +/* Clean up */ +/*========================================================================*/ + +void rktio_dll_clean(rktio_t *rktio) +{ + rktio_dll_t *dll, *next_dll; + rktio_dll_object_t *obj, *next_obj; + + for (dll = rktio->all_dlls; dll; dll = next_dll) { + next_dll = dll->all_next; + for (obj = dll->all_objects; obj; obj = next_obj) { + next_obj = obj->all_next; + free(obj->name); + free(obj); + } + if (dll->name) + free(dll->name); + if (dll->objects_by_name) + rktio_hash_free(dll->objects_by_name, 0); + free(dll); + } + + if (rktio->dlls_by_name) + rktio_hash_free(rktio->dlls_by_name, 0); + +#ifdef RKTIO_SYSTEM_UNIX + if (rktio->dll_error) + free(rktio->dll_error); +#endif +} diff --git a/racket/src/rktio/rktio_error.c b/racket/src/rktio/rktio_error.c index 5f77b8b12f..3133775159 100644 --- a/racket/src/rktio/rktio_error.c +++ b/racket/src/rktio/rktio_error.c @@ -39,6 +39,7 @@ err_str_t err_strs[] = { { RKTIO_ERROR_CONVERT_BAD_SEQUENCE, "ill-formed input encountered in encoding conversion" }, { RKTIO_ERROR_CONVERT_PREMATURE_END, "input encoding ended prematurely" }, { RKTIO_ERROR_CONVERT_OTHER, "encoding conversion encountered an error" }, + { RKTIO_ERROR_DLL, "error is from dlopen" }, { 0, NULL } }; diff --git a/racket/src/rktio/rktio_fs.c b/racket/src/rktio/rktio_fs.c index 0684d58a94..0b4a234284 100644 --- a/racket/src/rktio/rktio_fs.c +++ b/racket/src/rktio/rktio_fs.c @@ -444,7 +444,6 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir, } do { - init_procs(); if (dest) free(dest); dest_len = len + 1; dest = malloc(dest_len); diff --git a/racket/src/rktio/rktio_hash.c b/racket/src/rktio/rktio_hash.c index d41fe58353..98b9343c6a 100644 --- a/racket/src/rktio/rktio_hash.c +++ b/racket/src/rktio/rktio_hash.c @@ -2,14 +2,16 @@ #include "rktio_private.h" #include +/* A hash key must be non-negative, and each value must be non-NULL */ + struct rktio_hash_t { struct bucket_t *buckets; intptr_t size, count; }; typedef struct bucket_t { - /* v is non-NULL => bucket is filled */ - /* v is NULL and fd is -1 => was removed */ + /* `v` is non-NULL => bucket is filled */ + /* `v` is NULL and `key` is -1 => was removed */ intptr_t key; void *v; } bucket_t; @@ -177,3 +179,26 @@ void rktio_hash_set(rktio_hash_t *ht, intptr_t key, void *v) do_rehash(ht, ht->size << 1); } } + +intptr_t rktio_hash_string(const char *s) +{ + intptr_t key; + uintptr_t k = 0; + int c; + + while (1) { + c = *((unsigned char *)s); + if (!c) + break; + k += c; + k += (k << 10); + k ^= (k >> 6); + s++; + } + + key = k; + if (key < 0) + key = (k >> 1); + + return key; +} diff --git a/racket/src/rktio/rktio_main.c b/racket/src/rktio/rktio_main.c index 480ad62c8c..0f068d36ac 100644 --- a/racket/src/rktio/rktio_main.c +++ b/racket/src/rktio/rktio_main.c @@ -39,6 +39,7 @@ rktio_t *rktio_init(void) void rktio_destroy(rktio_t *rktio) { rktio_syslog_clean(rktio); + rktio_dll_clean(rktio); rktio_error_clean(rktio); rktio_process_deinit(rktio); rktio_free_ghbn(rktio); diff --git a/racket/src/rktio/rktio_network.c b/racket/src/rktio/rktio_network.c index fa68d7dce8..0916106988 100644 --- a/racket/src/rktio/rktio_network.c +++ b/racket/src/rktio/rktio_network.c @@ -1823,6 +1823,12 @@ intptr_t rktio_udp_sendto(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *add return do_socket_write(rktio, rfd, buffer, len, addr); } +intptr_t rktio_udp_sendto_in(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr, const char *buffer, + intptr_t start, intptr_t end) +{ + return rktio_udp_sendto(rktio, rfd, addr, buffer + start, end - start); +} + rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len) { rktio_socket_t s = rktio_fd_socket(rktio, rfd); @@ -1874,6 +1880,12 @@ rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd, return r; } +rktio_length_and_addrinfo_t *rktio_udp_recvfrom_in(rktio_t *rktio, rktio_fd_t *rfd, + char *buffer, intptr_t start, intptr_t end) +{ + return rktio_udp_recvfrom(rktio, rfd, buffer + start, end - start); +} + int rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd) { rktio_socket_t s = rktio_fd_socket(rktio, rfd); diff --git a/racket/src/rktio/rktio_private.h b/racket/src/rktio/rktio_private.h index f25ecaca1c..ef843e5bdd 100644 --- a/racket/src/rktio/rktio_private.h +++ b/racket/src/rktio/rktio_private.h @@ -99,6 +99,14 @@ struct rktio_t { #ifdef RKTIO_SYSTEM_WINDOWS HANDLE hEventLog; #endif + + int pending_os_signals[RKTIO_NUM_OS_SIGNALS]; + + struct rktio_dll_t *all_dlls; + struct rktio_hash_t *dlls_by_name; +#ifdef RKTIO_SYSTEM_UNIX + char *dll_error; +#endif }; /*========================================================================*/ @@ -255,6 +263,8 @@ void rktio_hash_set(rktio_hash_t *ht, intptr_t key, void *v); intptr_t rktio_hash_size(rktio_hash_t *ht); intptr_t rktio_hash_get_key(rktio_hash_t *ht, intptr_t i); +intptr_t rktio_hash_string(const char *s); + /*========================================================================*/ /* Misc */ /*========================================================================*/ @@ -274,6 +284,8 @@ void rktio_set_windows_error(rktio_t *rktio, int errid); void rktio_error_clean(rktio_t *rktio); +void rktio_dll_clean(rktio_t *rktio); + #if defined(USE_FNDELAY_O_NONBLOCK) # define RKTIO_NONBLOCKING FNDELAY #else @@ -324,3 +336,8 @@ void rktio_syslog_clean(rktio_t* rktio); #endif char *rktio_strndup(char *s, intptr_t len); + +#ifdef RKTIO_SYSTEM_UNIX +void rktio_set_signal_handler(int sig_id, void (*proc)(int)); +#endif +void rktio_forget_os_signal_handler(rktio_t *rktio); diff --git a/racket/src/rktio/rktio_process.c b/racket/src/rktio/rktio_process.c index 6af69e76c3..d82fddfabb 100644 --- a/racket/src/rktio/rktio_process.c +++ b/racket/src/rktio/rktio_process.c @@ -53,15 +53,6 @@ static int extract_child_status(int status) return status; } -static void set_signal_handler(int sig_id, void (*proc)(int)) -{ - struct sigaction sa; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = proc; - sigaction(sig_id, &sa, NULL); -} - #endif /*========================================================================*/ @@ -433,7 +424,7 @@ void centralized_starting_child() does not block SIGCHLD. Solaris, meanwhile, seems to unmask SIGCHLD as a result of setting a handler, so do this before masking the signal. */ - set_signal_handler(SIGCHLD, got_sigchld); + rktio_set_signal_handler(SIGCHLD, got_sigchld); /* Block SIGCLHD (again), because the worker thread will use sigwait(). */ block_sigchld(); @@ -585,7 +576,7 @@ static void init_sigchld(rktio_t *rktio) { #if !defined(CENTRALIZED_SIGCHILD) if (!sigchld_installed) { - set_signal_handler(SIGCHLD, child_done); + rktio_set_signal_handler(SIGCHLD, child_done); sigchld_installed = 1; } @@ -1206,7 +1197,7 @@ int rktio_process_allowed_flags(rktio_t *rktio) /*========================================================================*/ rktio_process_result_t *rktio_process(rktio_t *rktio, - const char *command, int argc, char **argv, + const char *command, int argc, rktio_const_string_t *argv, rktio_fd_t *stdout_fd, rktio_fd_t *stdin_fd, rktio_fd_t *stderr_fd, const char *current_directory, rktio_envvars_t *envvars, int flags) @@ -1471,7 +1462,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio, { int err, i; - char **new_argv; + rktio_const_string_t *new_argv; /* add a NULL terminator */ new_argv = malloc(sizeof(char *) * (argc + 1)); @@ -1483,7 +1474,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio, if (!env) env = rktio_get_environ_array(); - err = MSC_IZE(execve)(command, new_argv, (char **)env); + err = MSC_IZE(execve)(command, (char **)new_argv, (char **)env); if (err) err = errno; diff --git a/racket/src/rktio/rktio_signal.c b/racket/src/rktio/rktio_signal.c new file mode 100644 index 0000000000..f2a9cdeae4 --- /dev/null +++ b/racket/src/rktio/rktio_signal.c @@ -0,0 +1,102 @@ +#include "rktio.h" +#include "rktio_private.h" +#include +#include +#include +#if defined(RKTIO_SYSTEM_UNIX) +# include +#endif + +static int handlers_installed = 0; +static rktio_t *signal_rktio = NULL; + +/*========================================================================*/ +/* Signal handlers */ +/*========================================================================*/ + +/* Called by signal handlers: */ +static void signal_received(int i) +{ + if (signal_rktio) { + signal_rktio->pending_os_signals[i] = 1; + rktio_signal_received(signal_rktio); + } +} + +#if defined(RKTIO_SYSTEM_WINDOWS) +static BOOL WINAPI ConsoleBreakHandler(DWORD op) +{ + signal_received(RKTIO_OS_SIGNAL_INT); + return TRUE; +} +#endif + +#if defined(RKTIO_SYSTEM_UNIX) +static void user_break_hit(int ignore) { + signal_received(RKTIO_OS_SIGNAL_INT); +} + +static void term_hit(int ignore) +{ + signal_received(RKTIO_OS_SIGNAL_TERM); +} + +static void hup_hit(int ignore) +{ + signal_received(RKTIO_OS_SIGNAL_HUP); +} +#endif + +/*========================================================================*/ +/* Manage signal handlers */ +/*========================================================================*/ + +void rktio_install_os_signal_handler(rktio_t *rktio) +{ + signal_rktio = rktio; + if (handlers_installed) + return; + + handlers_installed = 1; + +#if defined(RKTIO_SYSTEM_UNIX) + rktio_set_signal_handler(SIGINT, user_break_hit); + rktio_set_signal_handler(SIGTERM, term_hit); + rktio_set_signal_handler(SIGHUP, hup_hit); +#endif + +#if defined(RKTIO_SYSTEM_WINDOWS) + SetConsoleCtrlHandler(ConsoleBreakHandler, TRUE); +#endif +} + +void rktio_forget_os_signal_handler(rktio_t *rktio) +{ + if (signal_rktio == rktio) { + signal_rktio = NULL; + } +} + +int rktio_poll_os_signal(rktio_t *rktio) +{ + int i; + for (i = 0; i < RKTIO_NUM_OS_SIGNALS; i++) { + if (rktio->pending_os_signals[i]) { + rktio->pending_os_signals[i] = 0; + return i; + } + } + + return RKTIO_OS_SIGNAL_NONE; +} + +#if defined(RKTIO_SYSTEM_UNIX) +void rktio_set_signal_handler(int sig_id, void (*proc)(int)) +{ + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = proc; + sigaction(sig_id, &sa, NULL); +} +#endif diff --git a/racket/src/worksp/librktio/librktio.vcproj b/racket/src/worksp/librktio/librktio.vcproj index ca0f3cd121..fdb622825e 100644 --- a/racket/src/worksp/librktio/librktio.vcproj +++ b/racket/src/worksp/librktio/librktio.vcproj @@ -142,6 +142,10 @@ RelativePath="..\..\rktio\rktio_process.c" > + + @@ -170,6 +174,10 @@ RelativePath="..\..\rktio\rktio_convert.c" > + + diff --git a/racket/src/worksp/librktio/librktio.vcxproj b/racket/src/worksp/librktio/librktio.vcxproj index acb76a18ba..702136645f 100644 --- a/racket/src/worksp/librktio/librktio.vcxproj +++ b/racket/src/worksp/librktio/librktio.vcxproj @@ -124,6 +124,7 @@ + @@ -131,6 +132,7 @@ +