rktio: move dlopen/dlsym/etc. adapter to rktio

Also, sync header-annotation improvements from the racket7 branch.
This commit is contained in:
Matthew Flatt 2017-08-20 10:09:04 -06:00
parent c87cdf5988
commit 98a78add9f
19 changed files with 790 additions and 459 deletions

View File

@ -11,6 +11,7 @@ CPPFLAGS = @PREFLAGS@
ALL_CFLAGS = $(CFLAGS) $(CPPFLAGS) @OPTIONS@ @MZOPTIONS@ \ ALL_CFLAGS = $(CFLAGS) $(CPPFLAGS) @OPTIONS@ @MZOPTIONS@ \
-I$(builddir)/../racket \ -I$(builddir)/../racket \
-I$(srcdir)/../racket/include -I$(srcdir)/../racket/src \ -I$(srcdir)/../racket/include -I$(srcdir)/../racket/src \
-I$(srcdir)/../rktio -I$(builddir)/../rktio \
$(LIBFFI_LOCAL_INCLUDE_@OWN_LIBFFI@) $(LIBFFI_LOCAL_INCLUDE_@OWN_LIBFFI@)
ARFLAGS = @ARFLAGS@ ARFLAGS = @ARFLAGS@
NOOP = : NOOP = :

View File

@ -8,6 +8,7 @@
#include "schpriv.h" #include "schpriv.h"
#include "schmach.h" #include "schmach.h"
#include "schrktio.h"
#ifndef DONT_USE_FOREIGN #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); 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 <tlhelp32.h>
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 */ /* Library objects */
@ -204,9 +135,8 @@ END_XFORM_SKIP;
static Scheme_Type ffi_lib_tag; static Scheme_Type ffi_lib_tag;
typedef struct ffi_lib_struct { typedef struct ffi_lib_struct {
Scheme_Object so; Scheme_Object so;
NON_GCBALE_PTR(void) handle; NON_GCBALE_PTR(rktio_dll_t) handle;
Scheme_Object* name; Scheme_Object* name;
Scheme_Hash_Table* objects;
int is_global; int is_global;
} ffi_lib_struct; } ffi_lib_struct;
#define SCHEME_FFILIBP(x) (SCHEME_TYPE(x)==ffi_lib_tag) #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) { int ffi_lib_MARK(void *p) {
ffi_lib_struct *s = (ffi_lib_struct *)p; ffi_lib_struct *s = (ffi_lib_struct *)p;
gcMARK(s->name); gcMARK(s->name);
gcMARK(s->objects);
return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct)); return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct));
} }
int ffi_lib_FIXUP(void *p) { int ffi_lib_FIXUP(void *p) {
ffi_lib_struct *s = (ffi_lib_struct *)p; ffi_lib_struct *s = (ffi_lib_struct *)p;
gcFIXUP(s->name); gcFIXUP(s->name);
gcFIXUP(s->objects);
return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct)); return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct));
} }
END_XFORM_SKIP; END_XFORM_SKIP;
@ -245,8 +173,8 @@ static Scheme_Object *foreign_ffi_lib(int argc, Scheme_Object *argv[])
{ {
char *name; char *name;
Scheme_Object *path, *hashname; Scheme_Object *path, *hashname;
void *handle; rktio_dll_t *handle;
int null_ok = 0, as_global = 0; int as_global = 0;
ffi_lib_struct *lib; ffi_lib_struct *lib;
if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0]))) if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0])))
scheme_wrong_contract(MYNAME, "(or/c string? #f)", 0, argc, argv); 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); hashname = (Scheme_Object*)((name==NULL) ? "" : name);
lib = (ffi_lib_struct*)scheme_hash_get(opened_libs, hashname); lib = (ffi_lib_struct*)scheme_hash_get(opened_libs, hashname);
if (!lib) { if (!lib) {
Scheme_Hash_Table *ht; handle = rktio_dll_open(scheme_rktio, name, as_global);
# ifdef WINDOWS_DYNAMIC_LOAD if (!handle) {
if (name==NULL) { char *msg;
/* openning the executable is marked by a NULL handle */ msg = rktio_dll_get_error(scheme_rktio);
handle = NULL; if (argc > 1 && SCHEME_TRUEP(argv[1])) {
null_ok = 1; if (msg) free(msg);
} else { return scheme_false;
wchar_t *wp; } else {
wp = scheme_path_to_wide_path(MYNAME, name); if (msg) {
handle = LoadLibraryW(wp); msg = scheme_strdup_and_free(msg);
} scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
# else /* WINDOWS_DYNAMIC_LOAD undefined */ MYNAME": couldn't open %V (%s)", argv[0], msg);
# ifdef __ANDROID__ } else
if (!name) handle = RTLD_DEFAULT; else scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
# endif /* __ANDROID__ */ MYNAME": couldn't open %V (%R)", argv[0]);
# 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 */
} }
} }
ht = scheme_make_hash_table(SCHEME_hash_string);
lib = (ffi_lib_struct*)scheme_malloc_tagged(sizeof(ffi_lib_struct)); lib = (ffi_lib_struct*)scheme_malloc_tagged(sizeof(ffi_lib_struct));
lib->so.type = ffi_lib_tag; lib->so.type = ffi_lib_tag;
lib->handle = (handle); lib->handle = (handle);
lib->name = (argv[0]); lib->name = (argv[0]);
lib->objects = (ht);
lib->is_global = (!name); lib->is_global = (!name);
scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib); scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib);
/* no dlclose finalizer - since the hash table always keeps a reference */ /* no dlclose finalizer - since the hash table always keeps a reference */
@ -354,18 +263,13 @@ int ffi_obj_FIXUP(void *p) {
END_XFORM_SKIP; END_XFORM_SKIP;
#endif #endif
#ifdef __ANDROID__
static int adjustment_set;
static uintptr_t adjustment;
#endif /* __ANDROID__ */
/* (ffi-obj objname ffi-lib-or-libname) -> ffi-obj */ /* (ffi-obj objname ffi-lib-or-libname) -> ffi-obj */
#define MYNAME "ffi-obj" #define MYNAME "ffi-obj"
static Scheme_Object *foreign_ffi_obj(int argc, Scheme_Object *argv[]) static Scheme_Object *foreign_ffi_obj(int argc, Scheme_Object *argv[])
{ {
ffi_obj_struct *obj; ffi_obj_struct *obj;
void *dlobj; void *dlobj;
ffi_lib_struct *lib = NULL, *lib2; ffi_lib_struct *lib = NULL;
char *dlname; char *dlname;
if (SCHEME_FFILIBP(argv[1])) if (SCHEME_FFILIBP(argv[1]))
lib = (ffi_lib_struct*)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])) if (!SCHEME_BYTE_STRINGP(argv[0]))
scheme_wrong_contract(MYNAME, "bytes?", 0, argc, argv); scheme_wrong_contract(MYNAME, "bytes?", 0, argc, argv);
dlname = SCHEME_BYTE_STR_VAL(argv[0]); dlname = SCHEME_BYTE_STR_VAL(argv[0]);
obj = (ffi_obj_struct*)scheme_hash_get(lib->objects, (Scheme_Object*)dlname);
if (!obj) { dlobj = rktio_dll_find_object(scheme_rktio, lib->handle, dlname);
# ifdef WINDOWS_DYNAMIC_LOAD if (!dlobj) {
if (lib->handle) { char *msg;
dlobj = GetProcAddress(lib->handle, dlname); msg = rktio_dll_get_error(scheme_rktio);
} else { if (msg) {
/* this is for the executable-open case, which was marked by a NULL msg = scheme_strdup_and_free(msg);
* 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();
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
MYNAME": couldn't get \"%s\" from %V (%E)", MYNAME": couldn't get \"%s\" from %V (%s)",
dlname, lib->name, err); dlname, lib->name, msg);
} } else
# else /* WINDOWS_DYNAMIC_LOAD undefined */ scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
dlobj = dlsym(lib->handle, dlname); MYNAME": couldn't get \"%s\" from %V (%R)",
# ifdef __ANDROID__ dlname, lib->name);
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 (dlobj) {
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 */
obj = (ffi_obj_struct*)scheme_malloc_tagged(sizeof(ffi_obj_struct)); obj = (ffi_obj_struct*)scheme_malloc_tagged(sizeof(ffi_obj_struct));
obj->so.type = ffi_obj_tag; obj->so.type = ffi_obj_tag;
obj->obj = (dlobj); obj->obj = (dlobj);
obj->name = (dlname); obj->name = (dlname);
obj->lib = (lib); obj->lib = (lib);
scheme_hash_set(lib->objects, (Scheme_Object*)dlname, (Scheme_Object*)obj); return (Scheme_Object *)obj;
} } else
return (obj == NULL) ? scheme_false : (Scheme_Object*)obj; return scheme_false;
} }
#undef MYNAME #undef MYNAME

View File

@ -11,6 +11,7 @@ exec racket "$0" > `echo "$0" | sed 's/rktc$/c/'` "$0"
#include "schpriv.h" #include "schpriv.h"
#include "schmach.h" #include "schmach.h"
#include "schrktio.h"
#ifndef DONT_USE_FOREIGN #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); 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 <tlhelp32.h>
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 */ /* Library objects */
@cdefstruct[ffi-lib [] @cdefstruct[ffi-lib []
[handle "NON_GCBALE_PTR(void)"] [handle "NON_GCBALE_PTR(rktio_dll_t)"]
[name "Scheme_Object*"] [name "Scheme_Object*"]
[objects "Scheme_Hash_Table*"]
[is_global "int"]] [is_global "int"]]
THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); 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]{ @cdefine[ffi-lib 1 3]{
char *name; char *name;
Scheme_Object *path, *hashname; Scheme_Object *path, *hashname;
void *handle; rktio_dll_t *handle;
int null_ok = 0, as_global = 0; int as_global = 0;
ffi_lib_struct *lib; ffi_lib_struct *lib;
if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0]))) if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0])))
scheme_wrong_contract(MYNAME, "(or/c string? #f)", 0, argc, argv); 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); hashname = (Scheme_Object*)((name==NULL) ? "" : name);
lib = (ffi_lib_struct*)scheme_hash_get(opened_libs, hashname); lib = (ffi_lib_struct*)scheme_hash_get(opened_libs, hashname);
if (!lib) { if (!lib) {
Scheme_Hash_Table *ht; handle = rktio_dll_open(scheme_rktio, name, as_global);
@@@IFDEF{WINDOWS_DYNAMIC_LOAD}{ if (!handle) {
if (name==NULL) { char *msg;
/* openning the executable is marked by a NULL handle */ msg = rktio_dll_get_error(scheme_rktio);
handle = NULL; if (argc > 1 && SCHEME_TRUEP(argv[1])) {
null_ok = 1; if (msg) free(msg);
return scheme_false;
} else { } else {
wchar_t *wp; if (msg) {
wp = scheme_path_to_wide_path(MYNAME, name); msg = scheme_strdup_and_free(msg);
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();
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, 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, 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]" "!name"]
@cmake["lib" ffi-lib "handle" "argv[0]" "ht" "!name"]
scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib); scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib);
/* no dlclose finalizer - since the hash table always keeps a reference */ /* no dlclose finalizer - since the hash table always keeps a reference */
/* maybe add some explicit unload at some point */ /* maybe add some explicit unload at some point */
@ -282,16 +198,11 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs);
[name "char*"] [name "char*"]
[lib "NON_GCBALE_PTR(ffi_lib_struct)"]] [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 */ /* (ffi-obj objname ffi-lib-or-libname) -> ffi-obj */
@cdefine[ffi-obj 2]{ @cdefine[ffi-obj 2]{
ffi_obj_struct *obj; ffi_obj_struct *obj;
void *dlobj; void *dlobj;
ffi_lib_struct *lib = NULL, *lib2; ffi_lib_struct *lib = NULL;
char *dlname; char *dlname;
if (SCHEME_FFILIBP(argv[1])) if (SCHEME_FFILIBP(argv[1]))
lib = (ffi_lib_struct*)argv[1]; lib = (ffi_lib_struct*)argv[1];
@ -302,83 +213,27 @@ static uintptr_t adjustment;
if (!SCHEME_BYTE_STRINGP(argv[0])) if (!SCHEME_BYTE_STRINGP(argv[0]))
scheme_wrong_contract(MYNAME, "bytes?", 0, argc, argv); scheme_wrong_contract(MYNAME, "bytes?", 0, argc, argv);
dlname = SCHEME_BYTE_STR_VAL(argv[0]); dlname = SCHEME_BYTE_STR_VAL(argv[0]);
obj = (ffi_obj_struct*)scheme_hash_get(lib->objects, (Scheme_Object*)dlname);
if (!obj) { dlobj = rktio_dll_find_object(scheme_rktio, lib->handle, dlname);
@@@IFDEF{WINDOWS_DYNAMIC_LOAD}{ if (!dlobj) {
if (lib->handle) { char *msg;
dlobj = GetProcAddress(lib->handle, dlname); msg = rktio_dll_get_error(scheme_rktio);
} else { if (msg) {
/* this is for the executable-open case, which was marked by a NULL msg = scheme_strdup_and_free(msg);
* 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();
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
MYNAME": couldn't get \"%s\" from %V (%E)", MYNAME": couldn't get \"%s\" from %V (%s)",
dlname, lib->name, err); dlname, lib->name, msg);
} } else
}{ scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
dlobj = dlsym(lib->handle, dlname); MYNAME": couldn't get \"%s\" from %V (%R)",
@@IFDEF{__ANDROID__}{ dlname, lib->name);
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);
} }
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 */ /* (ffi-obj-lib ffi-obj) -> ffi-lib */

View File

@ -6120,7 +6120,7 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[])
block_timer_signals(1); block_timer_signals(1);
result = rktio_process(scheme_rktio, result = rktio_process(scheme_rktio,
command, argc, argv, command, argc, (rktio_const_string_t *)argv,
stdout_fd, stdin_fd, stderr_fd, stdout_fd, stdin_fd, stderr_fd,
SCHEME_PATH_VAL(current_dir), envvars, SCHEME_PATH_VAL(current_dir), envvars,
flags); flags);

View File

@ -31,6 +31,7 @@ OBJS = rktio_fs.@LTO@ \
rktio_network.@LTO@ \ rktio_network.@LTO@ \
rktio_pipe.@LTO@ \ rktio_pipe.@LTO@ \
rktio_process.@LTO@ \ rktio_process.@LTO@ \
rktio_signal.@LTO@ \
rktio_envvars.@LTO@ \ rktio_envvars.@LTO@ \
rktio_fs_change.@LTO@ \ rktio_fs_change.@LTO@ \
rktio_flock.@LTO@ \ rktio_flock.@LTO@ \
@ -38,6 +39,7 @@ OBJS = rktio_fs.@LTO@ \
rktio_time.@LTO@ \ rktio_time.@LTO@ \
rktio_syslog.@LTO@ \ rktio_syslog.@LTO@ \
rktio_convert.@LTO@ \ rktio_convert.@LTO@ \
rktio_dll.@LTO@ \
rktio_error.@LTO@ \ rktio_error.@LTO@ \
rktio_hash.@LTO@ \ rktio_hash.@LTO@ \
rktio_wide.@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) rktio_process.@LTO@: $(srcdir)/rktio_process.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_process.@LTO@ -c $(srcdir)/rktio_process.c $(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) rktio_envvars.@LTO@: $(srcdir)/rktio_envvars.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_envvars.@LTO@ -c $(srcdir)/rktio_envvars.c $(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) rktio_convert.@LTO@: $(srcdir)/rktio_convert.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_convert.@LTO@ -c $(srcdir)/rktio_convert.c $(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) rktio_error.@LTO@: $(srcdir)/rktio_error.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.@LTO@ -c $(srcdir)/rktio_error.c $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.@LTO@ -c $(srcdir)/rktio_error.c

View File

@ -45,7 +45,8 @@
(EOF WHITESPACE (EOF WHITESPACE
OPEN CLOSE COPEN CCLOSE SEMI COMMA STAR LSHIFT EQUAL OPEN CLOSE COPEN CCLOSE SEMI COMMA STAR LSHIFT EQUAL
__RKTIO_H__ EXTERN EXTERN/NOERR EXTERN/STEP EXTERN/ERR __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 (define lex
(lexer-src-pos (lexer-src-pos
@ -73,6 +74,7 @@
["RKTIO_EXTERN_NOERR" 'EXTERN/NOERR] ["RKTIO_EXTERN_NOERR" 'EXTERN/NOERR]
["RKTIO_EXTERN_STEP" 'EXTERN/STEP] ["RKTIO_EXTERN_STEP" 'EXTERN/STEP]
["RKTIO_EXTERN_ERR" 'EXTERN/ERR] ["RKTIO_EXTERN_ERR" 'EXTERN/ERR]
["RKTIO_NULLABLE" 'NULLABLE]
[(:seq (:or #\_ (:/ #\A #\Z #\a #\z)) [(:seq (:or #\_ (:/ #\A #\Z #\a #\z))
(:* (:or #\_ (:/ #\A #\Z #\a #\z #\0 #\9)))) (:* (:or #\_ (:/ #\A #\Z #\a #\z #\0 #\9))))
(token-ID (string->symbol lexeme))] (token-ID (string->symbol lexeme))]
@ -106,6 +108,7 @@
[(DEFINE EXTERN/NOERR EXTERN) #f] [(DEFINE EXTERN/NOERR EXTERN) #f]
[(DEFINE EXTERN/STEP EXTERN) #f] [(DEFINE EXTERN/STEP EXTERN) #f]
[(DEFINE EXTERN/ERR OPEN ID CLOSE EXTERN) #f] [(DEFINE EXTERN/ERR OPEN ID CLOSE EXTERN) #f]
[(DEFINE NULLABLE) #f]
[(STRUCT ID SEMI) #f] [(STRUCT ID SEMI) #f]
[(TYPEDEF <type> <id> SEMI) [(TYPEDEF <type> <id> SEMI)
(if (eq? $2 $3) (if (eq? $2 $3)
@ -147,6 +150,7 @@
[(OPEN <expr> LSHIFT <expr> CLOSE) `(<< ,$2 ,$4)]) [(OPEN <expr> LSHIFT <expr> CLOSE) `(<< ,$2 ,$4)])
(<type> [(ID) $1] (<type> [(ID) $1]
[(CONST <type>) $2] [(CONST <type>) $2]
[(NULLABLE <type>) `(nullable ,$2)]
[(UNSIGNED SHORT) `unsigned-short] [(UNSIGNED SHORT) `unsigned-short]
[(UNSIGNED INT) `unsigned] [(UNSIGNED INT) `unsigned]
[(UNSIGNED) 'unsigned] [(UNSIGNED) 'unsigned]
@ -248,7 +252,8 @@
[(and (pair? t) (eq? (car t) '*ref)) [(and (pair? t) (eq? (car t) '*ref))
(let ([s (update-type (cadr t))]) (let ([s (update-type (cadr t))])
(if (and as-argument? (if (and as-argument?
(or (pair? s) (or (and (pair? s)
(not (eq? (car s) 'nullable)))
(hash-ref defined-types s #f))) (hash-ref defined-types s #f)))
`(*ref ,s) `(*ref ,s)
`(ref ,s)))] `(ref ,s)))]

View File

@ -28,7 +28,7 @@ Return type conventions:
information about a 0 result. information about a 0 result.
- A return type `rktio_tri_t` (alias for `int`) means that 0 is - 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 is returned for success, and `RKTIO_...ERROR` (alias for -2) is
returned for some error. The function will be annotated with returned for some error. The function will be annotated with
`RKTIO_EXTERN_ERR(...)` to indicate the error value. Use `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_NOERR RKTIO_EXTERN
#define RKTIO_EXTERN_STEP RKTIO_EXTERN #define RKTIO_EXTERN_STEP RKTIO_EXTERN
#define RKTIO_NULLABLE /* empty */
/*************************************************/ /*************************************************/
/* Initialization and general datatypes */ /* 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 /* A UTF-16 code unit. A `rktio_char16_t *` is meant to be the same as
`wchar_t *` on Windows. */ `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 */ /* 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_system_fd` and those that are inferred. The
`RKTIO_OPEN_INIT` flag is not recorded, however. */ `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 /* Can report `RKTIO_ERROR_DOES_NOT_EXIST` in place of a system error
in read mode, and can report `RKTIO_ERROR_IS_A_DIRECTORY`, in read mode, and can report `RKTIO_ERROR_IS_A_DIRECTORY`,
`RKTIO_ERROR_EXISTS`, or `RKTIO_ERROR_ACCESS_DENIED` in place of a `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). */ (because the sent data doesn't persist beyond closing the pipe). */
RKTIO_EXTERN_ERR(RKTIO_LOCK_ERROR) RKTIO_EXTERN_ERR(RKTIO_LOCK_ERROR)
rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl); rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, rktio_bool_t excl);
RKTIO_EXTERN_ERR(RKTIO_LOCK_ERROR) RKTIO_EXTERN rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd);
rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd);
/* Advisory file locks, where `excl` attempts to claim an exclusive /* Advisory file locks, where `excl` attempts to claim an exclusive
lock. Whether these work in various situations depend on many OS lock. Whether these work in various situations depend on many OS
details, where the differences involve promoting from non-exlcusive 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; typedef struct rktio_addrinfo_t rktio_addrinfo_t;
RKTIO_EXTERN rktio_addrinfo_lookup_t *rktio_start_addrinfo_lookup(rktio_t *rktio, 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); int family, rktio_bool_t passive, rktio_bool_t tcp);
/* The `family` argument should be one of the following: */ /* The `family` argument should be one of the following: */
#define RKTIO_FAMILY_ANY (-1) #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); RKTIO_EXTERN rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener);
/* Accepts one connection on a 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 /* Starts a connection request. Addreses must not be freed until the
connection is complete, errored, or stopped. */ 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_READ 0
#define RKTIO_SHUTDOWN_WRITE 1 #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 /* The `addr` argument can be NULL to create a socket without
specifying an interface, and `family` is used only if `addr` is not specifying an interface, and `family` is used only if `addr` is not
specified. */ 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 rktio_ok_t rktio_udp_connect(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr);
RKTIO_EXTERN_ERR(RKTIO_WRITE_ERROR) 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); const char *buffer, intptr_t len);
/* Extends `rktio_write` to accept a destination `addr`, and binds `rfd` if it /* 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. */ 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 { typedef struct rktio_length_and_addrinfo_t {
intptr_t len; intptr_t len;
char **address; /* like the result of `rktio_socket_address` */ 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 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. */ 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_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 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); 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) #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 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. */ /* 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_EXTERN rktio_ok_t rktio_udp_change_multicast_group(rktio_t *rktio, rktio_fd_t *rfd,
rktio_addrinfo_t *group_addr, rktio_addrinfo_t *group_addr,
rktio_addrinfo_t *intf_addr, RKTIO_NULLABLE rktio_addrinfo_t *intf_addr,
int action); int action);
/* `action` values: */ /* `action` values: */
enum { enum {
@ -471,10 +483,16 @@ enum {
RKTIO_DROP_MEMBERSHIP 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 */ /* 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 "="). */ /* 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); 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 That doesn't mean that clients need to case-fold names, but clients
may want to immitate the OS. */ 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 /* Gets an environment variable value, or reports
`RKTIO_ERROR_NO_SUCH_ENVVAR` when returning NULL; the result must `RKTIO_ERROR_NO_SUCH_ENVVAR` when returning NULL; the result must
be freed. */ 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` /* Set an environment variable's value, where a NULL value for `val`
unsets it. */ 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); RKTIO_EXTERN void rktio_envvars_free(rktio_t *rktio, rktio_envvars_t *envvars);
/* Deallocates an environment-variables record: */ /* Deallocates an environment-variables record: */
RKTIO_EXTERN char *rktio_envvars_get(rktio_t *rktio, rktio_envvars_t *envvars, const char *name); 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, const char *name, const char *value); 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. */ /* Access/update environment-variables record by name. */
RKTIO_EXTERN_NOERR intptr_t rktio_envvars_count(rktio_t *rktio, rktio_envvars_t *envvars); 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_process_result_t;
RKTIO_EXTERN rktio_process_result_t *rktio_process(rktio_t *rktio, 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, 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); int flags);
/* `flags` flags: */ /* `flags` flags: */
#define RKTIO_PROCESS_NEW_GROUP (1<<0) #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; typedef struct rktio_fs_change_t rktio_fs_change_t;
struct rktio_ltps_t; /* forward reference */ 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); struct rktio_ltps_t *ltps);
/* Creates a filesystem-change tracker that reports changes in `path` /* Creates a filesystem-change tracker that reports changes in `path`
after creation of the tracker. The properties repotred by 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 */ /* Files, directories, and links */
RKTIO_EXTERN rktio_bool_t rktio_file_exists(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, const char *dirname); 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, const char *filename); 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, const char *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`. */ /* Can report `RKTIO_ERROR_EXISTS`. */
RKTIO_EXTERN char *rktio_get_current_directory(rktio_t *rktio); 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`. */ /* 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); rktio_bool_t enable_write_on_fail);
/* The `current_directory` argument is used on Windows to avoid being /* The `current_directory` argument is used on Windows to avoid being
in `filename` (instead) as a directory while trying to delete it. in `filename` (instead) as a directory while trying to delete it.
The `enable_write_on_fail` argument also applied to Windows. */ 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 /* Argument should not have a trailing separator. Can report
`RKTIO_ERROR_NOT_A_LINK`. */ `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); rktio_bool_t dest_is_directory);
/* The `dest_is_directory` argument is used only /* The `dest_is_directory` argument is used only
on Windows. Can report `RKTIO_ERROR_EXISTS`. */ 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; 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_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, const char *file, rktio_timestamp_t secs); 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 { typedef struct rktio_identity_t {
uintptr_t a, b, c; uintptr_t a, b, c;
@ -768,7 +786,7 @@ typedef struct rktio_identity_t {
} 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_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 */ /* Permissions */
@ -781,11 +799,11 @@ RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, const char *p
#define RKTIO_PERMISSION_ERROR (-1) #define RKTIO_PERMISSION_ERROR (-1)
RKTIO_EXTERN_ERR(RKTIO_PERMISSION_ERROR) 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 /* Result is `RKTIO_PERMISSION_ERROR` for error, otherwise a combination of
bits. If not `all_bits`, then use constants above. */ 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. /* The `new_bits` format corresponds to `all_bits` for getting permissions.
Can report `RKTIO_ERROR_BAD_PERMISSION` for bits that make no sense. */ 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; 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 /* On Windows, the given `dirname` must be normalized and not have
`.` or `..`: */ `.` or `..`: */
@ -816,7 +834,7 @@ RKTIO_EXTERN char **rktio_filesystem_roots(rktio_t *rktio);
typedef struct rktio_file_copy_t rktio_file_copy_t; 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); rktio_bool_t exists_ok);
/* Starts a file copy. Depending on the OS, this step may perform the /* Starts a file copy. Depending on the OS, this step may perform the
whole copy, or it may just get started. Can report whole copy, or it may just get started. Can report
@ -870,7 +888,7 @@ enum {
RKTIO_PATH_INIT_FILE 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`. /* Path must start with tilde, otherwise `RKTIO_ERROR_NO_TILDE`.
Other possible errors are `RKTIO_ERROR_ILL_FORMED_USER` and Other possible errors are `RKTIO_ERROR_ILL_FORMED_USER` and
`RKTIO_ERROR_UNKNOWN_USER`. */ `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 /* Clears any pending signal so that it doesn't interrupt the next
`rktio_sleep`. */ `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 */ /* Time and date */
@ -943,10 +978,10 @@ enum {
}; };
RKTIO_EXTERN rktio_ok_t rktio_shell_execute(rktio_t *rktio, RKTIO_EXTERN rktio_ok_t rktio_shell_execute(rktio_t *rktio,
const char *verb, rktio_const_string_t verb,
const char *target, rktio_const_string_t target,
const char *arg, rktio_const_string_t arg,
const char *dir, rktio_const_string_t dir,
int show_mode); int show_mode);
/* Supported only on Windows to run `ShellExecute`. The `dir` argument /* Supported only on Windows to run `ShellExecute`. The `dir` argument
needs to have normalized path separators. */ needs to have normalized path separators. */
@ -954,7 +989,7 @@ RKTIO_EXTERN rktio_ok_t rktio_shell_execute(rktio_t *rktio,
/*************************************************/ /*************************************************/
/* Path conversion */ /* 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); 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 /* Convert to/from the OS's native path representation. These
functions are useful only on Windows. The `rktio_path_to_wide_path` 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 */ /* Logging */
RKTIO_EXTERN rktio_ok_t rktio_syslog(rktio_t *rktio, int level, const char *name, const char *msg, RKTIO_EXTERN rktio_ok_t rktio_syslog(rktio_t *rktio, int level, rktio_const_string_t name, rktio_const_string_t msg,
const char *exec_name); rktio_const_string_t exec_name);
/* Adds a message to the system log. The `name` argument can be NULL, /* 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 ": " 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 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; 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. */ /* Creates an encoding converter. */
RKTIO_EXTERN void rktio_converter_close(rktio_t *rktio, rktio_converter_t *cvt); 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) #define RKTIO_CONVERT_ERROR (-1)
RKTIO_EXTERN char *rktio_locale_recase(rktio_t *rktio, typedef struct rktio_convert_result_t {
rktio_bool_t to_up, intptr_t in_consumed; /* input bytes converted */
char *in); 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` /* Upcases (of `to_up`) or downcases (if `!to_up`) the content of `in`
using the current locale's encoding and case conversion. */ using the current locale's encoding and case conversion. */
RKTIO_EXTERN rktio_char16_t *rktio_recase_utf16(rktio_t *rktio, RKTIO_EXTERN_NOERR rktio_char16_t *rktio_recase_utf16(rktio_t *rktio,
rktio_bool_t to_up, rktio_char16_t *s1, rktio_bool_t to_up, rktio_char16_t *s1,
intptr_t len, intptr_t *olen); intptr_t len, intptr_t *olen);
/* Converts the case of a string encoded in UTF-16 for the system's /* 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 default locale if the OS provided direct support for it. The
`RKTIO_CONVERT_RECASE_UTF16 property from `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 Takes and optionally returns a length (`olen` can be NULL), but the
UTF-16 sequence is expected to have no nuls. */ 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 /* Returns -1 if `s1` is less than `s2` by the current locale's
comparison, positive is `s1` is greater, and 0 if the strings comparison, positive is `s1` is greater, and 0 if the strings
are equal. */ 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); RKTIO_EXTERN char *rktio_locale_encoding(rktio_t *rktio);
/* Returns the name of the current locale's encoding. */ /* 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 /* Sets the current locale, which affects string comparisons and
conversions. It can also affect the C library's character-property conversions. It can also affect the C library's character-property
predicates and number printing/parsing. The empty string 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 /* Returns the current system's language in country in a 5-character
format such as "en_US". */ 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 */ /* Errors */
@ -1113,6 +1195,7 @@ enum {
RKTIO_ERROR_CONVERT_BAD_SEQUENCE, RKTIO_ERROR_CONVERT_BAD_SEQUENCE,
RKTIO_ERROR_CONVERT_PREMATURE_END, RKTIO_ERROR_CONVERT_PREMATURE_END,
RKTIO_ERROR_CONVERT_OTHER, 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); 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_last_error_string(rktio_t *rktio);
RKTIO_EXTERN_NOERR const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid); 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 deallocated, but it only lasts reliably until the next call to
either of the functions. */ either of the functions. */
/*************************************************/ /*************************************************/

View File

@ -205,7 +205,7 @@ int rktio_convert_properties(rktio_t *rktio)
/* Current locale */ /* 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 /* We only need CTYPE and COLLATE; two calls seem to be much
faster than one call with ALL */ faster than one call with ALL */
@ -463,13 +463,36 @@ intptr_t rktio_convert(rktio_t *rktio,
return (intptr_t)r; 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 */ /* Case conversion */
/*============================================================*/ /*============================================================*/
char *rktio_locale_recase(rktio_t *rktio, char *rktio_locale_recase(rktio_t *rktio,
rktio_bool_t to_up, rktio_bool_t to_up,
char *in) const char *in)
{ {
char *out; 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 */ /* 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); return strcoll(s1, s2);
} }

View File

@ -0,0 +1,350 @@
#include "rktio.h"
#include "rktio_private.h"
#include <stdlib.h>
#include <string.h>
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 <dlfcn.h>
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 <tlhelp32.h>
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
}

View File

@ -39,6 +39,7 @@ err_str_t err_strs[] = {
{ RKTIO_ERROR_CONVERT_BAD_SEQUENCE, "ill-formed input encountered in encoding conversion" }, { RKTIO_ERROR_CONVERT_BAD_SEQUENCE, "ill-formed input encountered in encoding conversion" },
{ RKTIO_ERROR_CONVERT_PREMATURE_END, "input encoding ended prematurely" }, { RKTIO_ERROR_CONVERT_PREMATURE_END, "input encoding ended prematurely" },
{ RKTIO_ERROR_CONVERT_OTHER, "encoding conversion encountered an error" }, { RKTIO_ERROR_CONVERT_OTHER, "encoding conversion encountered an error" },
{ RKTIO_ERROR_DLL, "error is from dlopen" },
{ 0, NULL } { 0, NULL }
}; };

View File

@ -444,7 +444,6 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir,
} }
do { do {
init_procs();
if (dest) free(dest); if (dest) free(dest);
dest_len = len + 1; dest_len = len + 1;
dest = malloc(dest_len); dest = malloc(dest_len);

View File

@ -2,14 +2,16 @@
#include "rktio_private.h" #include "rktio_private.h"
#include <stdlib.h> #include <stdlib.h>
/* A hash key must be non-negative, and each value must be non-NULL */
struct rktio_hash_t { struct rktio_hash_t {
struct bucket_t *buckets; struct bucket_t *buckets;
intptr_t size, count; intptr_t size, count;
}; };
typedef struct bucket_t { typedef struct bucket_t {
/* v is non-NULL => bucket is filled */ /* `v` is non-NULL => bucket is filled */
/* v is NULL and fd is -1 => was removed */ /* `v` is NULL and `key` is -1 => was removed */
intptr_t key; intptr_t key;
void *v; void *v;
} bucket_t; } 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); 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;
}

View File

@ -39,6 +39,7 @@ rktio_t *rktio_init(void)
void rktio_destroy(rktio_t *rktio) void rktio_destroy(rktio_t *rktio)
{ {
rktio_syslog_clean(rktio); rktio_syslog_clean(rktio);
rktio_dll_clean(rktio);
rktio_error_clean(rktio); rktio_error_clean(rktio);
rktio_process_deinit(rktio); rktio_process_deinit(rktio);
rktio_free_ghbn(rktio); rktio_free_ghbn(rktio);

View File

@ -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); 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_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); 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; 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) int rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd)
{ {
rktio_socket_t s = rktio_fd_socket(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);

View File

@ -99,6 +99,14 @@ struct rktio_t {
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
HANDLE hEventLog; HANDLE hEventLog;
#endif #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_size(rktio_hash_t *ht);
intptr_t rktio_hash_get_key(rktio_hash_t *ht, intptr_t i); intptr_t rktio_hash_get_key(rktio_hash_t *ht, intptr_t i);
intptr_t rktio_hash_string(const char *s);
/*========================================================================*/ /*========================================================================*/
/* Misc */ /* Misc */
/*========================================================================*/ /*========================================================================*/
@ -274,6 +284,8 @@ void rktio_set_windows_error(rktio_t *rktio, int errid);
void rktio_error_clean(rktio_t *rktio); void rktio_error_clean(rktio_t *rktio);
void rktio_dll_clean(rktio_t *rktio);
#if defined(USE_FNDELAY_O_NONBLOCK) #if defined(USE_FNDELAY_O_NONBLOCK)
# define RKTIO_NONBLOCKING FNDELAY # define RKTIO_NONBLOCKING FNDELAY
#else #else
@ -324,3 +336,8 @@ void rktio_syslog_clean(rktio_t* rktio);
#endif #endif
char *rktio_strndup(char *s, intptr_t len); 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);

View File

@ -53,15 +53,6 @@ static int extract_child_status(int status)
return 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 #endif
/*========================================================================*/ /*========================================================================*/
@ -433,7 +424,7 @@ void centralized_starting_child()
does not block SIGCHLD. does not block SIGCHLD.
Solaris, meanwhile, seems to unmask SIGCHLD as a result of Solaris, meanwhile, seems to unmask SIGCHLD as a result of
setting a handler, so do this before masking the signal. */ 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 SIGCLHD (again), because the worker thread will use sigwait(). */
block_sigchld(); block_sigchld();
@ -585,7 +576,7 @@ static void init_sigchld(rktio_t *rktio)
{ {
#if !defined(CENTRALIZED_SIGCHILD) #if !defined(CENTRALIZED_SIGCHILD)
if (!sigchld_installed) { if (!sigchld_installed) {
set_signal_handler(SIGCHLD, child_done); rktio_set_signal_handler(SIGCHLD, child_done);
sigchld_installed = 1; sigchld_installed = 1;
} }
@ -1206,7 +1197,7 @@ int rktio_process_allowed_flags(rktio_t *rktio)
/*========================================================================*/ /*========================================================================*/
rktio_process_result_t *rktio_process(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, rktio_fd_t *stdout_fd, rktio_fd_t *stdin_fd, rktio_fd_t *stderr_fd,
const char *current_directory, rktio_envvars_t *envvars, const char *current_directory, rktio_envvars_t *envvars,
int flags) int flags)
@ -1471,7 +1462,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
{ {
int err, i; int err, i;
char **new_argv; rktio_const_string_t *new_argv;
/* add a NULL terminator */ /* add a NULL terminator */
new_argv = malloc(sizeof(char *) * (argc + 1)); new_argv = malloc(sizeof(char *) * (argc + 1));
@ -1483,7 +1474,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
if (!env) if (!env)
env = rktio_get_environ_array(); 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) if (err)
err = errno; err = errno;

View File

@ -0,0 +1,102 @@
#include "rktio.h"
#include "rktio_private.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if defined(RKTIO_SYSTEM_UNIX)
# include <signal.h>
#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

View File

@ -142,6 +142,10 @@
RelativePath="..\..\rktio\rktio_process.c" RelativePath="..\..\rktio\rktio_process.c"
> >
</File> </File>
<File
RelativePath="..\..\rktio\rktio_signal.c"
>
</File>
<File <File
RelativePath="..\..\rktio\rktio_envvars.c" RelativePath="..\..\rktio\rktio_envvars.c"
> >
@ -170,6 +174,10 @@
RelativePath="..\..\rktio\rktio_convert.c" RelativePath="..\..\rktio\rktio_convert.c"
> >
</File> </File>
<File
RelativePath="..\..\rktio\rktio_dll.c"
>
</File>
<File <File
RelativePath="..\..\rktio\rktio_error.c" RelativePath="..\..\rktio\rktio_error.c"
> >

View File

@ -124,6 +124,7 @@
<ClCompile Include="..\..\rktio\rktio_network.c" /> <ClCompile Include="..\..\rktio\rktio_network.c" />
<ClCompile Include="..\..\rktio\rktio_pipe.c" /> <ClCompile Include="..\..\rktio\rktio_pipe.c" />
<ClCompile Include="..\..\rktio\rktio_process.c" /> <ClCompile Include="..\..\rktio\rktio_process.c" />
<ClCompile Include="..\..\rktio\rktio_signal.c" />
<ClCompile Include="..\..\rktio\rktio_envvars.c" /> <ClCompile Include="..\..\rktio\rktio_envvars.c" />
<ClCompile Include="..\..\rktio\rktio_fs_change.c" /> <ClCompile Include="..\..\rktio\rktio_fs_change.c" />
<ClCompile Include="..\..\rktio\rktio_flock.c" /> <ClCompile Include="..\..\rktio\rktio_flock.c" />
@ -131,6 +132,7 @@
<ClCompile Include="..\..\rktio\rktio_time.c" /> <ClCompile Include="..\..\rktio\rktio_time.c" />
<ClCompile Include="..\..\rktio\rktio_syslog.c" /> <ClCompile Include="..\..\rktio\rktio_syslog.c" />
<ClCompile Include="..\..\rktio\rktio_convert.c" /> <ClCompile Include="..\..\rktio\rktio_convert.c" />
<ClCompile Include="..\..\rktio\rktio_dll.c" />
<ClCompile Include="..\..\rktio\rktio_error.c" /> <ClCompile Include="..\..\rktio\rktio_error.c" />
<ClCompile Include="..\..\rktio\rktio_hash.c" /> <ClCompile Include="..\..\rktio\rktio_hash.c" />
<ClCompile Include="..\..\rktio\rktio_wide.c" /> <ClCompile Include="..\..\rktio\rktio_wide.c" />