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@ \
-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 = :

View File

@ -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 <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 */
@ -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

View File

@ -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 <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 */
@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 */

View File

@ -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);

View File

@ -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

View File

@ -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 <type> <id> SEMI)
(if (eq? $2 $3)
@ -147,6 +150,7 @@
[(OPEN <expr> LSHIFT <expr> CLOSE) `(<< ,$2 ,$4)])
(<type> [(ID) $1]
[(CONST <type>) $2]
[(NULLABLE <type>) `(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)))]

View File

@ -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. */
/*************************************************/

View File

@ -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);
}

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_PREMATURE_END, "input encoding ended prematurely" },
{ RKTIO_ERROR_CONVERT_OTHER, "encoding conversion encountered an error" },
{ RKTIO_ERROR_DLL, "error is from dlopen" },
{ 0, NULL }
};

View File

@ -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);

View File

@ -2,14 +2,16 @@
#include "rktio_private.h"
#include <stdlib.h>
/* 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;
}

View File

@ -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);

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);
}
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);

View File

@ -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);

View File

@ -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;

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"
>
</File>
<File
RelativePath="..\..\rktio\rktio_signal.c"
>
</File>
<File
RelativePath="..\..\rktio\rktio_envvars.c"
>
@ -170,6 +174,10 @@
RelativePath="..\..\rktio\rktio_convert.c"
>
</File>
<File
RelativePath="..\..\rktio\rktio_dll.c"
>
</File>
<File
RelativePath="..\..\rktio\rktio_error.c"
>

View File

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