rktio: most of switch to rktio fd

Doesn't work, yet...
This commit is contained in:
Matthew Flatt 2017-06-15 11:24:51 -06:00
parent 63505d3e16
commit 2b439fc554
29 changed files with 1827 additions and 7423 deletions

View File

@ -2141,34 +2141,11 @@ extern Scheme_Extension_Table *scheme_extension_table;
/* file descriptors */
/*========================================================================*/
#if defined(DETECT_WIN32_CONSOLE_STDIN) || defined(WINDOWS_PROCESSES)
# ifndef NO_STDIO_THREADS
# define USE_FAR_MZ_FDCALLS
# endif
#endif
#ifdef USE_DYNAMIC_FDSET_SIZE
# define USE_FAR_MZ_FDCALLS
#endif
#ifdef USE_BEOS_PORT_THREADS
# define USE_FAR_MZ_FDCALLS
#endif
#ifdef HAVE_POLL_SYSCALL
# define USE_FAR_MZ_FDCALLS
#endif
#ifdef USE_FAR_MZ_FDCALLS
# define MZ_GET_FDSET(p, n) scheme_get_fdset(p, n)
# define MZ_FD_ZERO(p) scheme_fdzero(p)
# define MZ_FD_SET(n, p) scheme_fdset(p, n)
# define MZ_FD_CLR(n, p) scheme_fdclr(p, n)
# define MZ_FD_ISSET(n, p) scheme_fdisset(p, n)
#else
# define MZ_GET_FDSET(p, n) ((void *)(((fd_set *)p) XFORM_OK_PLUS n))
# define MZ_FD_ZERO(p) XFORM_HIDE_EXPR(FD_ZERO((fd_set *)(p)))
# define MZ_FD_SET(n, p) FD_SET(n, (fd_set *)(p))
# define MZ_FD_CLR(n, p) FD_CLR(n, (fd_set *)(p))
# define MZ_FD_ISSET(n, p) FD_ISSET(n, (fd_set *)(p))
#endif
/* For scheme_fd_to_semaphore(): */
#define MZFD_CREATE_READ 1
@ -2176,9 +2153,6 @@ extern Scheme_Extension_Table *scheme_extension_table;
#define MZFD_CHECK_READ 3
#define MZFD_CHECK_WRITE 4
#define MZFD_REMOVE 5
#define MZFD_CREATE_VNODE 6
#define MZFD_CHECK_VNODE 7
#define MZFD_REMOVE_VNODE 8
/*========================================================================*/

View File

@ -194,21 +194,11 @@ typedef struct Thread_Local_Variables {
struct Scheme_Object *scheme_orig_stdout_port_;
struct Scheme_Object *scheme_orig_stderr_port_;
struct Scheme_Object *scheme_orig_stdin_port_;
struct mz_fd_set *scheme_fd_set_;
struct mz_fd_set *scheme_semaphore_fd_set_;
struct Scheme_Hash_Table *scheme_semaphore_fd_mapping_;
int scheme_semaphore_fd_kqueue_;
struct rktio_ltps_t *scheme_semaphore_fd_set_;
#ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
struct Scheme_Hash_Table *locked_fd_process_map_;
#endif
struct Scheme_Custodian *new_port_cust_;
#if (defined(__WIN32__) || defined(WIN32) || defined(_WIN32))
void *scheme_break_semaphore_;
void *process_job_object_;
#else
int external_event_fd_;
int put_external_event_fd_;
#endif
char *read_string_byte_buffer_;
struct ITimer_Data *itimerdata_;
char *quick_buffer_;
@ -380,7 +370,6 @@ typedef struct Thread_Local_Variables {
void *on_atomic_timeout_data_;
int atomic_timeout_auto_suspend_;
int atomic_timeout_atomic_level_;
void *scheme_inotify_server_;
struct Scheme_Object *configuration_callback_cache_[2];
struct FFI_Orig_Place_Call *cached_orig_place_todo_;
struct Scheme_Hash_Table *ffi_lock_ht_;
@ -602,16 +591,9 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL;
#define scheme_orig_stdout_port XOA (scheme_get_thread_local_variables()->scheme_orig_stdout_port_)
#define scheme_orig_stderr_port XOA (scheme_get_thread_local_variables()->scheme_orig_stderr_port_)
#define scheme_orig_stdin_port XOA (scheme_get_thread_local_variables()->scheme_orig_stdin_port_)
#define scheme_fd_set XOA (scheme_get_thread_local_variables()->scheme_fd_set_)
#define scheme_semaphore_fd_set XOA (scheme_get_thread_local_variables()->scheme_semaphore_fd_set_)
#define scheme_semaphore_fd_mapping XOA (scheme_get_thread_local_variables()->scheme_semaphore_fd_mapping_)
#define scheme_semaphore_fd_kqueue XOA (scheme_get_thread_local_variables()->scheme_semaphore_fd_kqueue_)
#define locked_fd_process_map XOA (scheme_get_thread_local_variables()->locked_fd_process_map_)
#define new_port_cust XOA (scheme_get_thread_local_variables()->new_port_cust_)
#define scheme_break_semaphore XOA (scheme_get_thread_local_variables()->scheme_break_semaphore_)
#define process_job_object XOA (scheme_get_thread_local_variables()->process_job_object_)
#define external_event_fd XOA (scheme_get_thread_local_variables()->external_event_fd_)
#define put_external_event_fd XOA (scheme_get_thread_local_variables()->put_external_event_fd_)
#define read_string_byte_buffer XOA (scheme_get_thread_local_variables()->read_string_byte_buffer_)
#define itimerdata XOA (scheme_get_thread_local_variables()->itimerdata_)
#define quick_buffer XOA (scheme_get_thread_local_variables()->quick_buffer_)
@ -784,7 +766,6 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL;
#define on_atomic_timeout_data XOA (scheme_get_thread_local_variables()->on_atomic_timeout_data_)
#define atomic_timeout_auto_suspend XOA (scheme_get_thread_local_variables()->atomic_timeout_auto_suspend_)
#define atomic_timeout_atomic_level XOA (scheme_get_thread_local_variables()->atomic_timeout_atomic_level_)
#define scheme_inotify_server XOA (scheme_get_thread_local_variables()->scheme_inotify_server_)
#define configuration_callback_cache XOA (scheme_get_thread_local_variables()->configuration_callback_cache_)
#define cached_orig_place_todo XOA (scheme_get_thread_local_variables()->cached_orig_place_todo_)
#define ffi_lock_ht XOA (scheme_get_thread_local_variables()->ffi_lock_ht_)

View File

@ -398,7 +398,7 @@ optimize.@LTO@: $(COMMON_HEADERS) \
$(srcdir)/stypes.h $(srcdir)/mzmark_optimize.inc
place.@LTO@: $(COMMON_HEADERS) \
$(srcdir)/stypes.h $(srcdir)/schfd.h $(srcdir)/mzmark_place.inc
port.@LTO@: $(COMMON_HEADERS) \
port.@LTO@: $(COMMON_HEADERS) $(RKTIO_HEADERS) \
$(srcdir)/stypes.h $(srcdir)/schfd.h $(srcdir)/mzmark_port.inc \
$(srcdir)/inotify.inc
portfun.@LTO@: $(COMMON_HEADERS) $(srcdir)/schvers.h \

View File

@ -554,7 +554,7 @@ static Scheme_Env *place_instance_init(void *stack_base, int initial_main_os_thr
scheme_init_regexp_places();
scheme_init_sema_places();
scheme_init_gmp_places();
scheme_init_kqueue();
scheme_init_fd_semaphores();
scheme_alloc_global_fdset();
#ifndef DONT_USE_FOREIGN
scheme_init_foreign_places();
@ -629,8 +629,10 @@ Scheme_Env *scheme_place_instance_init(void *stack_base, struct NewGC *parent_gc
scheme_rktio = rktio_init();
env = place_instance_init(stack_base, 0);
# if defined(MZ_PRECISE_GC)
signal_fd = scheme_get_signal_handle();
GC_set_put_external_event_fd(signal_fd);
if (scheme_rktio) {
signal_fd = scheme_get_signal_handle();
GC_set_put_external_event_fd(signal_fd);
}
# endif
scheme_set_can_break(1);
return env;
@ -665,6 +667,8 @@ void scheme_place_instance_destroy(int force)
scheme_release_process_job_object();
#endif
scheme_release_fd_semaphores();
scheme_release_file_descriptor();
scheme_end_futures_per_place();
@ -677,8 +681,8 @@ void scheme_place_instance_destroy(int force)
#endif
scheme_free_all_code();
scheme_free_ghbn_data();
scheme_release_kqueue();
scheme_release_inotify();
scheme_free_global_fdset();
rktio_destroy(scheme_rktio);
}
static void make_kernel_env(void)

View File

@ -1,267 +0,0 @@
/* #included by "port.c" */
/* Multiplex multiple filesystem change events onto a single
inotify connection. That's almost as easy as using watch
descriptors in place of file descriptors, but using the
same filesystem path multiple times produces the same
watch descriptors, so reference-count it. Also, each watch
can be removed as soon as it fires, since filesystem
change events are single-shot.
The values returned by mz_inotify_add() are indices into an array
of watch descriptors. There's room for a better data structure if
the watch-descriptor-to-index mapping becomes too slow. */
#ifdef MZ_XFORM
START_XFORM_SUSPEND;
#endif
typedef struct mz_wd_t {
int wd;
int refcount;
int val;
} mz_wd_t;
typedef struct mz_inotify_state_t {
int ready, errid, fd;
mz_wd_t *wds;
int size, count;
int got;
} mz_inotify_state_t;
static int mzi_find_wd(int wd, mz_wd_t *wds, int size)
{
int i;
for (i = 0; i < size; i++) {
if (wds[i].wd == wd) return i;
}
return -1;
}
static int mzi_add_wd(int wd, mz_wd_t *wds, int size)
{
int i;
for (i = 0; i < size; i++) {
if (wds[i].wd == wd) {
wds[i].refcount++;
return i;
}
}
for (i = 0; i < size; i++) {
if (!wds[i].refcount) {
wds[i].wd = wd;
wds[i].refcount = 1;
wds[i].val = 0;
return i;
}
}
abort();
return -1;
}
static int mzi_pull_events(int fd, mz_wd_t *wds, int size)
{
struct inotify_event _ev, *ev;
void *b = NULL;
int rc, p, got = 0;
int bsize;
struct pollfd pfd[1];
ev = &_ev;
bsize = sizeof(_ev);
pfd[0].fd = fd;
pfd[0].events = POLLIN;
while (poll(pfd, 1, 0)) {
rc = read(fd, ev, bsize);
if (rc > 0) {
p = mzi_find_wd(ev->wd, wds, size);
if (p != -1) {
got = 1;
wds[p].val = 1;
wds[p].wd = -1;
inotify_rm_watch(fd, ev->wd);
}
} else if (rc == -1) {
if (errno == EAGAIN)
break;
else if (errno == EINTR) {
/* try again */
} else if (errno == EINVAL) {
bsize *= 2;
if (b) free(b);
b = malloc(bsize);
ev = (struct inotify_event *)b;
} else
scheme_signal_error("inotify read failed on %d (%e)", fd, errno);
} else
break;
}
if (b)
free (b);
return got;
}
static void mz_inotify_start(mz_inotify_state_t *s)
{
int fd;
fd = inotify_init();
if (fd == -1) {
s->errid = errno;
} else {
s->errid = 0;
s->ready = 1;
s->fd = fd;
}
}
static void mz_inotify_end(mz_inotify_state_t *s)
{
int rc;
if (s->ready) {
do {
rc = close(s->fd);
} while (rc == -1 && errno == EINTR);
}
if (s->wds) free(s->wds);
free(s);
}
static void mz_inotify_init()
{
mz_inotify_state_t *s = scheme_inotify_server;
if (!s) {
s = (mz_inotify_state_t *)malloc(sizeof(mz_inotify_state_t));
memset(s, 0, sizeof(mz_inotify_state_t));
scheme_inotify_server = s;
}
if (!s->ready)
mz_inotify_start(s);
}
static int mz_inotify_ready()
{
mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server;
return s->ready;
}
static int mz_inotify_errid()
{
mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server;
return s->errid;
}
/* Other functions are called only if mz_inotify_ready() returns 1. */
static int mz_inotify_add(char *filename)
{
mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server;
int wd;
if (s->count == s->size) {
int new_size = (s->size ? (2 * s->size) : 32);
mz_wd_t *new_wds;
int i;
new_wds = (mz_wd_t *)malloc(sizeof(mz_wd_t) * new_size);
memcpy(new_wds, s->wds, s->size * sizeof(mz_wd_t));
if (s->wds) free(s->wds);
s->wds = new_wds;
s->size = new_size;
for (i = s->count; i < s->size; i++)
{
s->wds[i].wd = -1;
s->wds[i].refcount = 0;
}
}
wd = inotify_add_watch(s->fd, filename,
(IN_CREATE | IN_DELETE | IN_DELETE_SELF
| IN_MODIFY | IN_MOVE_SELF | IN_MOVED_TO
| IN_ATTRIB | IN_ONESHOT));
if (wd == -1)
return -1;
else {
int p;
p = mzi_add_wd(wd, s->wds, s->size);
if (s->wds[p].refcount == 1)
s->count++;
return p+1;
}
}
static void mz_inotify_remove(int p2)
{
mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server;
int p = p2 - 1;
if (s->wds[p].refcount == 1) {
if (s->wds[p].wd != -1) {
inotify_rm_watch(s->fd, s->wds[p].wd);
s->wds[p].wd = -1;
/* in case the wd gets reused: */
if (mzi_pull_events(s->fd, s->wds, s->size))
s->got = 1;
}
--s->count;
}
s->wds[p].refcount -= 1;
}
static int mz_inotify_poll(int p2)
{
mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server;
int p = p2 - 1;
if (mzi_pull_events(s->fd, s->wds, s->size))
s->got = 1;
if (s->wds[p].val)
return 1;
else
return 0;
}
static void mz_inotify_stop()
{
mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server;
if (s) {
mz_inotify_end(s);
scheme_inotify_server = NULL;
}
}
static int mz_inotify_fd()
{
mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server;
if (s->got) {
/* In case we received something for Y in a poll for X */
s->got = 0;
return -2;
}
return s->fd;
}
#ifdef MZ_XFORM
END_XFORM_SUSPEND;
#endif

View File

@ -100,6 +100,7 @@ static int mark_input_fd_MARK(void *p, struct NewGC *gc) {
gcMARK2(fd->buffer, gc);
gcMARK2(fd->refcount, gc);
gcMARK2(fd->flush_handle, gc);
gcMARK2(fd->widths, gc);
# ifdef GC_NO_SIZE_NEEDED_FROM_PROCS
return 0;
@ -117,6 +118,7 @@ static int mark_input_fd_FIXUP(void *p, struct NewGC *gc) {
gcFIXUP2(fd->buffer, gc);
gcFIXUP2(fd->refcount, gc);
gcFIXUP2(fd->flush_handle, gc);
gcFIXUP2(fd->widths, gc);
# ifdef GC_NO_SIZE_NEEDED_FROM_PROCS
return 0;

View File

@ -1739,6 +1739,7 @@ mark_input_fd {
gcMARK2(fd->buffer, gc);
gcMARK2(fd->refcount, gc);
gcMARK2(fd->flush_handle, gc);
gcMARK2(fd->widths, gc);
size:
gcBYTES_TO_WORDS(sizeof(Scheme_FD));
@ -1794,7 +1795,6 @@ mark_read_write_evt {
mark_filesystem_change_evt {
mark:
Scheme_Filesystem_Change_Evt *fc = (Scheme_Filesystem_Change_Evt *)p;
gcMARK2(fc->sema, gc);
gcMARK2(fc->mref, gc);
size:
gcBYTES_TO_WORDS(sizeof(Scheme_Filesystem_Change_Evt));

File diff suppressed because it is too large Load Diff

View File

@ -1055,7 +1055,7 @@ void scheme_wait_resume()
{
mzrt_mutex_unlock(child_wait_lock);
}
b
void scheme_starting_child()
{
mzrt_mutex_lock(child_wait_lock);
@ -2785,7 +2785,8 @@ static void *place_start_proc_after_stack(void *data_arg, void *stack_base) {
if (!scheme_setjmp(new_error_buf)) {
Scheme_Object *dynamic_require;
scheme_check_place_port_ok();
if (!scheme_rktio)
scheme_signal_error("place: I/O manager initialization failed");
dynamic_require = scheme_builtin_value("dynamic-require");
place_main = scheme_apply(dynamic_require, 2, a);

File diff suppressed because it is too large Load Diff

View File

@ -2556,7 +2556,7 @@ make_output_port (int argc, Scheme_Object *argv[])
static Scheme_Object *
open_input_file (int argc, Scheme_Object *argv[])
{
return scheme_do_open_input_file("open-input-file", 0, argc, argv, 0, NULL, NULL, 0);
return scheme_do_open_input_file("open-input-file", 0, argc, argv, 0, 0);
}
static Scheme_Object *
@ -2602,13 +2602,13 @@ open_input_char_string (int argc, Scheme_Object *argv[])
static Scheme_Object *
open_output_file (int argc, Scheme_Object *argv[])
{
return scheme_do_open_output_file("open-output-file", 0, argc, argv, 0, 0, NULL, NULL);
return scheme_do_open_output_file("open-output-file", 0, argc, argv, 0, 0);
}
static Scheme_Object *
open_input_output_file (int argc, Scheme_Object *argv[])
{
return scheme_do_open_output_file("open-input-output-file", 0, argc, argv, 1, 0, NULL, NULL);
return scheme_do_open_output_file("open-input-output-file", 0, argc, argv, 1, 0);
}
static Scheme_Object *
@ -2745,7 +2745,7 @@ call_with_output_file (int argc, Scheme_Object *argv[])
scheme_check_proc_arity("call-with-output-file", 1, 1, argc, argv);
port = scheme_do_open_output_file("call-with-output-file", 1, argc, argv, 0, 0, NULL, NULL);
port = scheme_do_open_output_file("call-with-output-file", 1, argc, argv, 0, 0);
v = _scheme_apply_multi(argv[1], 1, &port);
@ -2770,7 +2770,7 @@ call_with_input_file(int argc, Scheme_Object *argv[])
scheme_check_proc_arity("call-with-input-file", 1, 1, argc, argv);
port = scheme_do_open_input_file("call-with-input-file", 1, argc, argv, 0, NULL, NULL, 0);
port = scheme_do_open_input_file("call-with-input-file", 1, argc, argv, 0, 0);
v = _scheme_apply_multi(argv[1], 1, &port);
@ -2807,7 +2807,7 @@ with_output_to_file (int argc, Scheme_Object *argv[])
scheme_check_proc_arity("with-output-to-file", 0, 1, argc, argv);
port = scheme_do_open_output_file("with-output-to-file", 1, argc, argv, 0, 0, NULL, NULL);
port = scheme_do_open_output_file("with-output-to-file", 1, argc, argv, 0, 0);
config = scheme_extend_config(scheme_current_config(),
MZCONFIG_OUTPUT_PORT,
@ -2841,7 +2841,7 @@ with_input_from_file(int argc, Scheme_Object *argv[])
scheme_check_proc_arity("with-input-from-file", 0, 1, argc, argv);
port = scheme_do_open_input_file("with-input-from-file", 1, argc, argv, 0, NULL, NULL, 0);
port = scheme_do_open_input_file("with-input-from-file", 1, argc, argv, 0, 0);
config = scheme_extend_config(scheme_current_config(),
MZCONFIG_INPUT_PORT,
@ -4899,7 +4899,7 @@ static Scheme_Object *default_load(int argc, Scheme_Object *argv[])
"(or/c #f symbol? (cons/c (or/c #f symbol?) (non-empty-listof symbol?)))",
1, argc, argv);
port = scheme_do_open_input_file("default-load-handler", 0, 1, argv, 0, NULL, NULL, SCHEME_TRUEP(expected_module));
port = scheme_do_open_input_file("default-load-handler", 0, 1, argv, 0, SCHEME_TRUEP(expected_module));
/* Turn on line/column counting, unless it's a .zo file: */
if (SCHEME_PATHP(argv[0])) {

View File

@ -1,37 +0,0 @@
#ifdef USE_FAR_MZ_FDCALLS
THREAD_LOCAL_DECL(extern struct mz_fd_set *scheme_fd_set);
# ifdef HAVE_POLL_SYSCALL
struct mz_fd_set {
struct mz_fd_set_data *data;
struct mz_fd_set *w;
struct mz_fd_set *e;
Scheme_Object *flags;
};
struct mz_fd_set_data {
struct pollfd *pfd;
Scheme_Object *size, *count;
};
# else
struct mz_fd_set { fd_set data; };
# endif
#define DECL_FDSET(n, c) fd_set *n
#define INIT_DECL_FDSET(r, w, e) { \
r = MZ_GET_FDSET(&scheme_fd_set->data, 0 ); \
w = MZ_GET_FDSET(&scheme_fd_set->data, 1 ); \
e = MZ_GET_FDSET(&scheme_fd_set->data, 2 ); \
}
# define INIT_DECL_RD_FDSET(r) r = MZ_GET_FDSET(&scheme_fd_set->data, 0 )
# define INIT_DECL_WR_FDSET(r) r = MZ_GET_FDSET(&scheme_fd_set->data, 1 )
# define INIT_DECL_ER_FDSET(r) r = MZ_GET_FDSET(&scheme_fd_set->data, 2 )
#else
# define DECL_FDSET(n, c) fd_set n[c]
# define INIT_DECL_FDSET(r, w, e) /* empty */
# define INIT_DECL_RD_FDSET(r) /* empty */
# define INIT_DECL_WR_FDSET(r) /* empty */
# define INIT_DECL_ER_FDSET(r) /* empty */
#endif
void *scheme_merge_fd_sets(void *fds, void *src_fds);
void scheme_clean_fd_set(void *fds);
int scheme_get_fd_limit(void *fds);

View File

@ -436,6 +436,7 @@ void scheme_register_network_evts();
void scheme_free_dynamic_extensions(void);
void scheme_free_all_code(void);
void scheme_free_ghbn_data(void);
void scheme_free_global_fdset(void);
XFORM_NONGCING int scheme_is_multithreaded(int now);
@ -4351,7 +4352,7 @@ void scheme_flush_if_output_fds(Scheme_Object *o);
Scheme_Object *scheme_file_stream_port_p(int, Scheme_Object *[]);
Scheme_Object *scheme_terminal_port_p(int, Scheme_Object *[]);
Scheme_Object *scheme_do_open_input_file(char *name, int offset, int argc, Scheme_Object *argv[],
int internal, char **err, int *eerrno, int for_module);
int internal, int for_module);
Scheme_Object *scheme_do_open_output_file(char *name, int offset, int argc, Scheme_Object *argv[], int and_read,
int internal, char **err, int *eerrno);
Scheme_Object *scheme_file_position(int argc, Scheme_Object *argv[]);
@ -4365,9 +4366,7 @@ Scheme_Object *scheme_file_unlock(int argc, Scheme_Object **argv);
void scheme_reserve_file_descriptor(void);
void scheme_release_file_descriptor(void);
void scheme_init_kqueue(void);
void scheme_release_kqueue(void);
void scheme_release_inotify(void);
int scheme_get_port_rktio_file_descriptor(Scheme_Object *p, struct rktio_fd_t *_fd);
void scheme_fs_change_properties(int *_supported, int *_scalable, int *_low_latency, int *_file_level);
@ -4428,8 +4427,13 @@ intptr_t scheme_redirect_get_or_peek_bytes(Scheme_Input_Port *orig_port,
Scheme_Object *scheme_filesystem_change_evt(Scheme_Object *path, int flags, int report_errs);
void scheme_filesystem_change_evt_cancel(Scheme_Object *evt, void *ignored_data);
int scheme_fd_regular_file(intptr_t fd, int dir_ok);
void scheme_init_fd_semaphores(void);
void scheme_release_fd_semaphores(void);
void scheme_check_fd_semaphores(void);
Scheme_Object *scheme_rktio_fd_to_semaphore(struct rktio_fd_t *fd, int mode);
rktio_envvars_t *scheme_environment_variables_to_envvars(Scheme_Object *ev);
/*========================================================================*/
/* memory debugging */
@ -4743,7 +4747,6 @@ Scheme_Object *scheme_make_place_object();
void scheme_place_instance_destroy(int force);
void scheme_kill_green_thread_timer();
void scheme_place_check_for_interruption();
void scheme_check_place_port_ok();
void scheme_place_set_memory_use(intptr_t amt);
void scheme_place_check_memory_use();
void scheme_clear_place_ifs_stack();

View File

@ -2485,52 +2485,27 @@ static Scheme_Object *sch_getenv_names(int argc, Scheme_Object *argv[])
return r;
}
/* Temporarily use internal function: */
extern void *rktio_envvars_to_block(rktio_t *rktio, rktio_envvars_t *envvars);
/* This will go away when we use rktio processes: */
void *scheme_environment_variables_to_block(Scheme_Object *ev, int *_need_free)
rktio_envvars_t *scheme_environment_variables_to_envvars(Scheme_Object *ev)
{
Scheme_Hash_Tree *ht = SCHEME_ENVVARS_TABLE(ev);
rktio_envvars_t *envvars;
mzlonglong i;
Scheme_Hash_Tree *ht;
Scheme_Object *key, *val;
void *p;
if (!ht)
return NULL;
*_need_free = 1;
envvars = rktio_empty_envvars(scheme_rktio);
ht = SCHEME_ENVVARS_TABLE(ev);
if (!ht) {
rktio_envvars_t *envvars;
envvars = rktio_envvars(scheme_rktio);
for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
scheme_hash_tree_index(ht, i, &key, &val);
p = rktio_envvars_to_block(scheme_rktio, envvars);
rktio_envvars_free(scheme_rktio, envvars);
return p;
rktio_envvars_set(scheme_rktio,
envvars,
SCHEME_BYTE_STR_VAL(key),
SCHEME_BYTE_STR_VAL(val));
}
{
rktio_envvars_t *envvars;
mzlonglong i;
envvars = rktio_empty_envvars(scheme_rktio);
for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
scheme_hash_tree_index(ht, i, &key, &val);
rktio_envvars_set(scheme_rktio,
envvars,
SCHEME_BYTE_STR_VAL(key),
SCHEME_BYTE_STR_VAL(val));
}
p = rktio_envvars_to_block(scheme_rktio, envvars);
rktio_envvars_free(scheme_rktio, envvars);
return p;
}
return envvars;
}
/***********************************************************************/

View File

@ -41,42 +41,10 @@
#include "schpriv.h"
#include "schmach.h"
#include "schgc.h"
#include "schrktio.h"
#ifdef MZ_USE_FUTURES
# include "future.h"
#endif
#ifndef PALMOS_STUFF
# include <time.h>
#endif
#ifdef FILES_HAVE_FDS
# include <sys/types.h>
# include <sys/time.h>
# ifdef SELECT_INCLUDE
# include <sys/select.h>
# endif
# ifdef USE_BEOS_SOCKET_INCLUDE
# include <be/net/socket.h>
# endif
# ifdef HAVE_POLL_SYSCALL
# include <poll.h>
# endif
# ifdef HAVE_EPOLL_SYSCALL
# include <sys/epoll.h>
# endif
# ifdef HAVE_KQUEUE_SYSCALL
# include <sys/types.h>
# include <sys/event.h>
# include <sys/time.h>
# endif
# include <errno.h>
#endif
#ifdef USE_WINSOCK_TCP
# ifdef USE_TCP
# include <winsock.h>
# endif
#endif
#ifdef USE_BEOS_PORT_THREADS
# include <be/net/socket.h>
#endif
#ifdef USE_STACKAVAIL
# include <malloc.h>
#endif
@ -88,11 +56,6 @@
# define SIGMZTHREAD SIGUSR2
#endif
#if defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES)
# include <windows.h>
THREAD_LOCAL_DECL(extern void *scheme_break_semaphore;)
#endif
#if defined(FILES_HAVE_FDS) \
|| defined(USE_BEOS_PORT_THREADS) \
|| (defined(USE_WINSOCK_TCP) && defined(USE_TCP)) \
@ -103,8 +66,6 @@ THREAD_LOCAL_DECL(extern void *scheme_break_semaphore;)
# endif
#endif
#include "schfd.h"
#define DEFAULT_INIT_STACK_SIZE 1000
#define MAX_INIT_STACK_SIZE 100000
@ -193,7 +154,7 @@ THREAD_LOCAL_DECL(MZ_MARK_STACK_TYPE scheme_current_cont_mark_stack);
THREAD_LOCAL_DECL(MZ_MARK_POS_TYPE scheme_current_cont_mark_pos);
#endif
THREAD_LOCAL_DECL(int scheme_semaphore_fd_kqueue);
THREAD_LOCAL_DECL(struct rktio_ltps_t *scheme_semaphore_fd_set);
THREAD_LOCAL_DECL(static Scheme_Custodian *main_custodian);
THREAD_LOCAL_DECL(static Scheme_Hash_Table *limited_custodians = NULL);
@ -3853,471 +3814,122 @@ static Scheme_Object *call_as_nested_thread(int argc, Scheme_Object *argv[])
/* thread scheduling and termination */
/*========================================================================*/
void scheme_init_kqueue(void)
void scheme_init_fd_semaphores(void)
{
#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL)
scheme_semaphore_fd_kqueue = -1;
#endif
scheme_semaphore_fd_set = rktio_open_ltps(scheme_rktio);
}
void scheme_release_kqueue(void)
void scheme_release_fd_semaphores(void)
{
#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL)
if (scheme_semaphore_fd_kqueue >= 0) {
intptr_t rc;
do {
rc = close(scheme_semaphore_fd_kqueue);
} while ((rc == -1) && (errno == EINTR));
if (scheme_semaphore_fd_set) {
rktio_ltps_remove_all(scheme_rktio, scheme_semaphore_fd_set);
(void)check_fd_semaphores();
rktio_ltps_close(scheme_semaphore_fd_set);
}
#endif
}
#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL)
static void log_kqueue_error(const char *action, int kr)
static void log_fd_semaphore_error()
{
if (kr < 0) {
{
Scheme_Logger *logger;
logger = scheme_get_main_logger();
scheme_log(logger, SCHEME_LOG_WARNING, 0,
#ifdef HAVE_KQUEUE_SYSCALL
"kqueue"
#else
"epoll"
#endif
" error at %s: %E",
action, errno);
"error for long-term poll set: %R");
}
}
static void log_kqueue_fd(int fd, int flags)
{
Scheme_Logger *logger;
logger = scheme_get_main_logger();
scheme_log(logger, SCHEME_LOG_WARNING, 0,
#ifdef HAVE_KQUEUE_SYSCALL
"kqueue"
#else
"epoll"
#endif
" expected event %d %d",
fd, flags);
}
#endif
Scheme_Object *scheme_fd_to_semaphore(intptr_t fd, int mode, int is_socket)
{
#ifdef USE_WINSOCK_TCP
return NULL;
#else
Scheme_Object *key, *v, *s = NULL;
#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL)
# else
void *r, *w, *e;
# endif
rktio_fd_t *rfd;
if (!scheme_semaphore_fd_mapping)
return NULL;
# ifdef HAVE_KQUEUE_SYSCALL
if (!is_socket) {
/* kqueue() might not work on devices, such as ttys; also, while
Mac OS X kqueue() claims to work on FIFOs, there are problems:
watching for reads on a FIFO sometimes disables watching for
writes on the same FIFO with a different file descriptor */
if (!scheme_fd_regular_file(fd, 1))
return NULL;
}
if (scheme_semaphore_fd_kqueue < 0) {
scheme_semaphore_fd_kqueue = kqueue();
if (scheme_semaphore_fd_kqueue < 0) {
log_kqueue_error("create", scheme_semaphore_fd_kqueue);
return NULL;
}
}
# endif
# ifdef HAVE_EPOLL_SYSCALL
if (scheme_semaphore_fd_kqueue < 0) {
scheme_semaphore_fd_kqueue = epoll_create(5);
if (scheme_semaphore_fd_kqueue < 0) {
log_kqueue_error("create", scheme_semaphore_fd_kqueue);
return NULL;
}
}
# endif
rfd = rktio_system_fd(fd, (RKTIO_OPEN_READ
| RKTIO_OPEN_WRITE
| (is_socket ? RKTIO_OPEN_SOCKET : 0)));
key = scheme_make_integer_value(fd);
v = scheme_hash_get(scheme_semaphore_fd_mapping, key);
if (!v && ((mode == MZFD_CHECK_READ)
|| (mode == MZFD_CHECK_WRITE)
|| (mode == MZFD_CHECK_VNODE)
|| (mode == MZFD_REMOVE)
|| (mode == MZFD_REMOVE_VNODE)))
sema = scheme_rktio_fd_to_semaphore(rfd, mode);
rktio_forget(rfd);
return sema;
}
Scheme_Object *scheme_rktio_fd_to_semaphore(rktio_fd_t *fd, int mode)
{
rktio_handle_t *h;
void **ib;
if (!scheme_semaphore_fd_mapping)
return NULL;
if (!v) {
v = scheme_make_vector(2, scheme_false);
scheme_hash_set(scheme_semaphore_fd_mapping, key, v);
switch(mode) {
case MZFD_CREATE_READ:
mode = RKTIO_LTPS_CREATE_READ;
break;
case MZFD_CREATE_WRITE:
mode = RKTIO_LTPS_CREATE_WRITE;
break;
case MZFD_CHECK_READ:
mode = RKTIO_LTPS_CHECK_READ;
break;
case MZFD_CHECK_WRITE:
mode = RKTIO_LTPS_CHECK_WRITE;
break;
case MZFD_REMOVE:
mode = RKTIO_LTPS_REMOVE;
break;
}
# if !defined(HAVE_KQUEUE_SYSCALL) && !defined(HAVE_EPOLL_SYSCALL)
r = MZ_GET_FDSET(scheme_semaphore_fd_set, 0);
w = MZ_GET_FDSET(scheme_semaphore_fd_set, 1);
e = MZ_GET_FDSET(scheme_semaphore_fd_set, 2);
# endif
h = rktio_ltps_add(scheme_rktio, scheme_semaphore_fd_mapping, fd, mode);
if ((mode == MZFD_REMOVE) || (mode == MZFD_REMOVE_VNODE)) {
s = SCHEME_VEC_ELS(v)[0];
if (!SCHEME_FALSEP(s))
scheme_post_sema_all(s);
s = SCHEME_VEC_ELS(v)[1];
if (!SCHEME_FALSEP(s))
scheme_post_sema_all(s);
s = NULL;
scheme_hash_set(scheme_semaphore_fd_mapping, key, NULL);
# ifdef HAVE_KQUEUE_SYSCALL
{
GC_CAN_IGNORE struct kevent kev[2];
struct timespec timeout = {0, 0};
int kr, pos = 0;
if (mode == MZFD_REMOVE_VNODE) {
EV_SET(&kev[pos], fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
pos++;
} else {
if (SCHEME_TRUEP(SCHEME_VEC_ELS(v)[0])) {
EV_SET(&kev[pos], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
pos++;
}
if (SCHEME_TRUEP(SCHEME_VEC_ELS(v)[1])) {
EV_SET(&kev[pos], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
pos++;
}
}
do {
kr = kevent(scheme_semaphore_fd_kqueue, kev, pos, NULL, 0, &timeout);
} while ((kr == -1) && (errno == EINTR));
log_kqueue_error("remove", kr);
}
# elif defined(HAVE_EPOLL_SYSCALL)
{
int kr;
kr = epoll_ctl(scheme_semaphore_fd_kqueue, EPOLL_CTL_DEL, fd, NULL);
log_kqueue_error("remove", kr);
}
# else
MZ_FD_CLR(fd, r);
MZ_FD_CLR(fd, w);
MZ_FD_CLR(fd, e);
# endif
s = NULL;
} else if ((mode == MZFD_CHECK_READ)
|| (mode == MZFD_CREATE_READ)
|| (mode == MZFD_CHECK_VNODE)
|| (mode == MZFD_CREATE_VNODE)) {
s = SCHEME_VEC_ELS(v)[0];
if (SCHEME_FALSEP(s)) {
if ((mode == MZFD_CREATE_READ)
|| (mode == MZFD_CREATE_VNODE)) {
s = scheme_make_sema(0);
SCHEME_VEC_ELS(v)[0] = s;
# ifdef HAVE_KQUEUE_SYSCALL
{
GC_CAN_IGNORE struct kevent kev;
struct timespec timeout = {0, 0};
int kr;
if (mode == MZFD_CREATE_READ)
EV_SET(&kev, fd, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, NULL);
else
EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT,
(NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND
| NOTE_RENAME | NOTE_ATTRIB),
0, NULL);
do {
kr = kevent(scheme_semaphore_fd_kqueue, &kev, 1, NULL, 0, &timeout);
} while ((kr == -1) && (errno == EINTR));
log_kqueue_error("read", kr);
}
# elif defined(HAVE_EPOLL_SYSCALL)
{
GC_CAN_IGNORE struct epoll_event ev;
int already = !SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1]), kr;
memset(&ev, 0, sizeof(ev));
ev.data.fd = fd;
ev.events = EPOLLIN | (already ? EPOLLOUT : 0);
kr = epoll_ctl(scheme_semaphore_fd_kqueue,
(already ? EPOLL_CTL_MOD : EPOLL_CTL_ADD), fd, &ev);
log_kqueue_error("read", kr);
}
# else
MZ_FD_SET(fd, r);
MZ_FD_SET(fd, e);
#endif
} else
s = NULL;
}
} else if ((mode == MZFD_CHECK_WRITE)
|| (mode == MZFD_CREATE_WRITE)) {
s = SCHEME_VEC_ELS(v)[1];
if (SCHEME_FALSEP(s)) {
if (mode == MZFD_CREATE_WRITE) {
s = scheme_make_sema(0);
SCHEME_VEC_ELS(v)[1] = s;
# ifdef HAVE_KQUEUE_SYSCALL
{
GC_CAN_IGNORE struct kevent kev;
struct timespec timeout = {0, 0};
int kr;
EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL);
do {
kr = kevent(scheme_semaphore_fd_kqueue, &kev, 1, NULL, 0, &timeout);
} while ((kr == -1) && (errno == EINTR));
log_kqueue_error("write", kr);
}
# elif defined(HAVE_EPOLL_SYSCALL)
{
GC_CAN_IGNORE struct epoll_event ev;
int already = !SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0]), kr;
memset(&ev, 0, sizeof(ev));
ev.data.fd = fd;
ev.events = EPOLLOUT | (already ? EPOLLIN : 0);
kr = epoll_ctl(scheme_semaphore_fd_kqueue,
(already ? EPOLL_CTL_MOD : EPOLL_CTL_ADD), fd, &ev);
log_kqueue_error("write", kr);
}
# else
MZ_FD_SET(fd, w);
MZ_FD_SET(fd, e);
#endif
} else
s = NULL;
if (!h) {
if (scheme_last_error_is_racket(RKTIO_ERROR_LTPS_REMOVED)
|| scheme_last_error_is_racket(RKTIO_ERROR_LTPS_NOT_FOUND)) {
/* That's a kind of success, not failure. */
return NULL;
}
log_fd_semaphore_error();
return NULL;
}
return s;
#endif
ib = rktio_ltps_handle_get_data(scheme_rktio, h);
if (!ib) {
ib = scheme_malloc_immobile_box(scheme_make_sema(0));
rktio_ltps_handle_set_data(scheme_rktio, ib);
}
return *(Scheme_Object **)p;
}
static int check_fd_semaphores()
{
#ifdef USE_WINSOCK_TCP
return 0;
#elif defined(HAVE_KQUEUE_SYSCALL)
Scheme_Object *v, *s, *key;
GC_CAN_IGNORE struct kevent kev;
struct timespec timeout = {0, 0};
int kr, hit = 0;
rktio_ltps_handle_t *h;
int did = 0;
if (!scheme_semaphore_fd_mapping || (scheme_semaphore_fd_kqueue < 0))
if (!scheme_semaphore_fd_set)
return 0;
while (1) {
do {
kr = kevent(scheme_semaphore_fd_kqueue, NULL, 0, &kev, 1, &timeout);
} while ((kr == -1) && (errno == EINTR));
log_kqueue_error("wait", kr);
h = rktio_ltps_get_signaled_handle(scheme_rktio, scheme_semaphore_fd_set);
if (h) {
void *p;
p = rktio_ltps_handle_get_data(scheme_rktio, h);
free(h);
if (kr > 0) {
key = scheme_make_integer_value(kev.ident);
v = scheme_hash_get(scheme_semaphore_fd_mapping, key);
if (v) {
if ((kev.filter == EVFILT_READ) || (kev.filter == EVFILT_VNODE)) {
s = SCHEME_VEC_ELS(v)[0];
if (!SCHEME_FALSEP(s)) {
scheme_post_sema_all(s);
hit = 1;
SCHEME_VEC_ELS(v)[0] = scheme_false;
}
} else if (kev.filter == EVFILT_WRITE) {
s = SCHEME_VEC_ELS(v)[1];
if (!SCHEME_FALSEP(s)) {
scheme_post_sema_all(s);
hit = 1;
SCHEME_VEC_ELS(v)[1] = scheme_false;
}
}
if (SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0])
&& SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1]))
scheme_hash_set(scheme_semaphore_fd_mapping, key, NULL);
} else {
log_kqueue_fd(kev.ident, kev.filter);
}
sema = *(Scheme_Object **)p;
scheme_free_immobile_box(p);
scheme_post_sema_all(sema);
did = 1;
} else
break;
}
return hit;
#elif defined(HAVE_EPOLL_SYSCALL)
Scheme_Object *v, *s, *key;
int kr, hit = 0;
GC_CAN_IGNORE struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
if (!scheme_semaphore_fd_mapping || (scheme_semaphore_fd_kqueue < 0))
return 0;
while (1) {
do {
kr = epoll_wait(scheme_semaphore_fd_kqueue, &ev, 1, 0);
} while ((kr == -1) && (errno == EINTR));
log_kqueue_error("wait", kr);
if (kr > 0) {
key = scheme_make_integer_value(ev.data.fd);
v = scheme_hash_get(scheme_semaphore_fd_mapping, key);
if (v) {
if (ev.events & (POLLIN | POLLHUP | POLLERR)) {
s = SCHEME_VEC_ELS(v)[0];
if (!SCHEME_FALSEP(s)) {
scheme_post_sema_all(s);
hit = 1;
SCHEME_VEC_ELS(v)[0] = scheme_false;
}
}
if (ev.events & (POLLOUT | POLLHUP | POLLERR)) {
s = SCHEME_VEC_ELS(v)[1];
if (!SCHEME_FALSEP(s)) {
scheme_post_sema_all(s);
hit = 1;
SCHEME_VEC_ELS(v)[1] = scheme_false;
}
}
if (SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0])
&& SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1])) {
scheme_hash_set(scheme_semaphore_fd_mapping, key, NULL);
kr = epoll_ctl(scheme_semaphore_fd_kqueue, EPOLL_CTL_DEL, ev.data.fd, NULL);
log_kqueue_error("remove*", kr);
} else {
ev.events = ((SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0]) ? 0 : POLLIN)
| (SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1]) ? 0 : POLLOUT));
kr = epoll_ctl(scheme_semaphore_fd_kqueue, EPOLL_CTL_MOD, ev.data.fd, &ev);
log_kqueue_error("update", kr);
}
} else {
log_kqueue_fd(ev.data.fd, ev.events);
}
} else
break;
}
return hit;
#elif defined(HAVE_POLL_SYSCALL)
struct pollfd *pfd;
intptr_t i, c;
Scheme_Object *v, *s, *key;
int sr, hit = 0;
if (!scheme_semaphore_fd_mapping || !scheme_semaphore_fd_mapping->count)
return 0;
scheme_clean_fd_set(scheme_semaphore_fd_set);
c = SCHEME_INT_VAL(scheme_semaphore_fd_set->data->count);
pfd = scheme_semaphore_fd_set->data->pfd;
do {
sr = poll(pfd, c, 0);
} while ((sr == -1) && (errno == EINTR));
if (sr > 0) {
for (i = 0; i < c; i++) {
if (pfd[i].revents) {
key = scheme_make_integer_value(pfd[i].fd);
v = scheme_hash_get(scheme_semaphore_fd_mapping, key);
if (v) {
if (pfd[i].revents & (POLLIN | POLLHUP | POLLERR)) {
s = SCHEME_VEC_ELS(v)[0];
if (!SCHEME_FALSEP(s)) {
scheme_post_sema_all(s);
hit = 1;
SCHEME_VEC_ELS(v)[0] = scheme_false;
}
pfd[i].events -= (pfd[i].events & POLLIN);
}
if (pfd[i].revents & (POLLOUT | POLLHUP | POLLERR)) {
s = SCHEME_VEC_ELS(v)[1];
if (!SCHEME_FALSEP(s)) {
scheme_post_sema_all(s);
hit = 1;
SCHEME_VEC_ELS(v)[1] = scheme_false;
}
pfd[i].events -= (pfd[i].events & POLLOUT);
}
if (SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0])
&& SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1]))
scheme_hash_set(scheme_semaphore_fd_mapping, key, NULL);
}
}
}
}
return hit;
#else
void *fds;
struct timeval time = {0, 0};
int i, actual_limit, r, w, e, sr, hit = 0;
Scheme_Object *key, *v, *s;
DECL_FDSET(set, 3);
fd_set *set1, *set2;
if (!scheme_semaphore_fd_mapping || !scheme_semaphore_fd_mapping->count)
return 0;
INIT_DECL_FDSET(set, set1, set2);
set1 = (fd_set *) MZ_GET_FDSET(set, 1);
set2 = (fd_set *) MZ_GET_FDSET(set, 2);
fds = (void *)set;
MZ_FD_ZERO(set);
MZ_FD_ZERO(set1);
MZ_FD_ZERO(set2);
scheme_merge_fd_sets(fds, scheme_semaphore_fd_set);
actual_limit = scheme_get_fd_limit(fds);
do {
sr = select(actual_limit, set, set1, set2, &time);
} while ((sr == -1) && (errno == EINTR));
if (sr > 0) {
for (i = 0; i < actual_limit; i++) {
r = MZ_FD_ISSET(i, set);
w = MZ_FD_ISSET(i, set1);
e = MZ_FD_ISSET(i, set2);
if (r || w || e) {
key = scheme_make_integer_value(i);
v = scheme_hash_get(scheme_semaphore_fd_mapping, key);
if (v) {
if (r || e) {
s = SCHEME_VEC_ELS(v)[0];
if (!SCHEME_FALSEP(s)) {
scheme_post_sema_all(s);
hit = 1;
SCHEME_VEC_ELS(v)[0] = scheme_false;
}
MZ_FD_CLR(i, MZ_GET_FDSET(scheme_semaphore_fd_set, 0));
}
if (w || e) {
s = SCHEME_VEC_ELS(v)[1];
if (!SCHEME_FALSEP(s)) {
scheme_post_sema_all(s);
hit = 1;
SCHEME_VEC_ELS(v)[1] = scheme_false;
}
MZ_FD_CLR(i, MZ_GET_FDSET(scheme_semaphore_fd_set, 1));
}
if (SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0])
&& SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1])) {
MZ_FD_CLR(i, MZ_GET_FDSET(scheme_semaphore_fd_set, 2));
scheme_hash_set(scheme_semaphore_fd_mapping, key, NULL);
}
}
}
}
}
return hit;
#endif
return did;
}
void scheme_check_fd_semaphores(void)
@ -4435,18 +4047,7 @@ static int check_sleep(int need_activity, int sleep_now)
if (have_activity && scheme_notify_multithread)
scheme_notify_multithread(0);
#if defined(USING_FDS)
INIT_DECL_FDSET(set, set1, set2);
set1 = (fd_set *) MZ_GET_FDSET(set, 1);
set2 = (fd_set *) MZ_GET_FDSET(set, 2);
fds = (void *)set;
MZ_FD_ZERO(set);
MZ_FD_ZERO(set1);
MZ_FD_ZERO(set2);
#else
fds = NULL;
#endif
fds = rktio_make_poll_set(scheme_rktio);
needs_sleep_cancelled = 0;
@ -4497,24 +4098,16 @@ static int check_sleep(int need_activity, int sleep_now)
p = p->next;
}
if (needs_sleep_cancelled)
if (needs_sleep_cancelled) {
rktio_poll_set_close(scheme_rktio, fds);
return 0;
}
if (post_system_idle()) {
rktio_poll_set_close(scheme_rktio, fds);
return 0;
}
# if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL)
if (scheme_semaphore_fd_mapping && (scheme_semaphore_fd_kqueue >= 0)) {
MZ_FD_SET(scheme_semaphore_fd_kqueue, set);
MZ_FD_SET(scheme_semaphore_fd_kqueue, set2);
}
# else
fds = scheme_merge_fd_sets(fds, scheme_semaphore_fd_set);
# endif
scheme_clean_fd_set(fds);
if (sleep_now) {
float mst = (float)max_sleep_time;
@ -4535,6 +4128,8 @@ static int check_sleep(int need_activity, int sleep_now)
} else if (scheme_wakeup_on_input)
scheme_wakeup_on_input(fds);
rktio_poll_set_forget(scheme_rktio, fds);
return 1;
}
@ -4897,10 +4492,6 @@ void scheme_break_kind_thread(Scheme_Thread *p, int kind)
}
}
scheme_weak_resume_thread(p);
# if defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES)
if (SAME_OBJ(p, scheme_main_thread))
ReleaseSemaphore((HANDLE)scheme_break_semaphore, 1, NULL);
# endif
}
void scheme_break_thread(Scheme_Thread *p)

View File

@ -189,7 +189,7 @@ static void wait_read(rktio_t *rktio, rktio_fd_t *fd)
check_valid(ps);
rktio_poll_add(rktio, fd, ps, RKTIO_POLL_READ);
rktio_sleep(rktio, 0, ps, NULL);
rktio_poll_set_close(rktio, ps);
rktio_poll_set_forget(rktio, ps);
}
static void check_read_write_pair(rktio_t *rktio, rktio_fd_t *fd, rktio_fd_t *fd2, int immediate_available)
@ -337,7 +337,7 @@ void check_many_lookup(rktio_t *rktio)
}
rktio_sleep(rktio, 0, ps, NULL);
rktio_poll_set_close(rktio, ps);
rktio_poll_set_forget(rktio, ps);
for (i = 0; i < LOOKUPS_N; i++) {
if (lookup[i] && (rktio_poll_addrinfo_lookup_ready(rktio, lookup[i]) == RKTIO_POLL_READY)) {
@ -346,7 +346,7 @@ void check_many_lookup(rktio_t *rktio)
else {
addr = rktio_addrinfo_lookup_get(rktio, lookup[i]);
check_valid(addr);
rktio_free_addrinfo(rktio, addr);
rktio_addrinfo_free(rktio, addr);
}
lookup[i] = NULL;
break;
@ -371,7 +371,7 @@ rktio_addrinfo_t *lookup_loop(rktio_t *rktio,
rktio_poll_add_addrinfo_lookup(rktio, lookup, ps);
rktio_sleep(rktio, 0, ps, NULL);
rktio_poll_set_close(rktio, ps);
rktio_poll_set_forget(rktio, ps);
check_valid(rktio_poll_addrinfo_lookup_ready(rktio, lookup) == RKTIO_POLL_READY);
addr = rktio_addrinfo_lookup_get(rktio, lookup);
@ -396,7 +396,7 @@ static void pause_for_process(rktio_t *rktio, rktio_process_t *process, int dont
} else {
rktio_sleep(rktio, 0, ps, NULL);
}
rktio_poll_set_close(rktio, ps);
rktio_poll_set_forget(rktio, ps);
done = rktio_poll_process_done(rktio, process);
check_valid(done != RKTIO_PROCESS_ERROR);
} while (!done);
@ -417,7 +417,7 @@ static rktio_fd_t *connect_loop(rktio_t *rktio, rktio_addrinfo_t *addr, rktio_ad
rktio_poll_add_connect(rktio, conn, ps);
rktio_sleep(rktio, 0, ps, NULL);
rktio_poll_set_close(rktio, ps);
rktio_poll_set_forget(rktio, ps);
check_valid(rktio_poll_connect_ready(rktio, conn) == RKTIO_POLL_READY);
fd = rktio_connect_finish(rktio, conn);
@ -452,7 +452,7 @@ static char *week_day_name(rktio_t *rktio, int dow)
int main(int argc, char **argv)
{
rktio_t *rktio;
rktio_size_t *sz;
rktio_filesize_t *sz;
rktio_fd_t *fd, *fd2;
intptr_t amt, i, saw_file;
int perms;
@ -506,8 +506,7 @@ int main(int argc, char **argv)
sz = rktio_file_size(rktio, "test1");
check_valid(sz);
check_valid(sz->lo == 5);
check_valid(sz->hi == 0);
check_valid(*sz == 5);
free(sz);
fd = rktio_open(rktio, "test2", RKTIO_OPEN_WRITE | RKTIO_OPEN_MUST_EXIST);
@ -655,7 +654,7 @@ int main(int argc, char **argv)
lnr = rktio_listen(rktio, addr, 5, 1);
check_valid(lnr);
rktio_free_addrinfo(rktio, addr);
rktio_addrinfo_free(rktio, addr);
check_valid(!rktio_poll_accept_ready(rktio, lnr));
@ -704,7 +703,7 @@ int main(int argc, char **argv)
check_read_write_pair(rktio, fd, fd2, 0);
fd = connect_loop(rktio, addr, NULL);
rktio_free_addrinfo(rktio, addr);
rktio_addrinfo_free(rktio, addr);
fd2 = rktio_accept(rktio, lnr);
@ -734,7 +733,7 @@ int main(int argc, char **argv)
addr = lookup_loop(rktio, NULL, 4536, -1, 1, 0);
check_valid(addr);
check_valid(rktio_udp_bind(rktio, fd, addr));
rktio_free_addrinfo(rktio, addr);
rktio_addrinfo_free(rktio, addr);
fd2 = rktio_udp_open(rktio, intf_addr);
check_valid(fd2);
@ -742,7 +741,7 @@ int main(int argc, char **argv)
addr = lookup_loop(rktio, "localhost", 4536, -1, 0, 0);
check_valid(addr);
check_valid(rktio_udp_connect(rktio, fd2, addr));
rktio_free_addrinfo(rktio, addr);
rktio_addrinfo_free(rktio, addr);
check_read_write_pair(rktio, fd, fd2, 0);
@ -755,7 +754,7 @@ int main(int argc, char **argv)
addr = lookup_loop(rktio, NULL, 4536, -1, 1, 0);
check_valid(addr);
check_valid(rktio_udp_bind(rktio, fd, addr));
rktio_free_addrinfo(rktio, addr);
rktio_addrinfo_free(rktio, addr);
addr = lookup_loop(rktio, "localhost", 4536, -1, 0, 0);
check_valid(addr);
@ -763,8 +762,8 @@ int main(int argc, char **argv)
check_fill_write(rktio, fd2, addr, AMOUNT_FOR_UDP);
check_drain_read(rktio, fd, AMOUNT_FOR_UDP+1);
rktio_free_addrinfo(rktio, addr);
rktio_free_addrinfo(rktio, intf_addr);
rktio_addrinfo_free(rktio, addr);
rktio_addrinfo_free(rktio, intf_addr);
check_valid(rktio_close(rktio, fd));
check_valid(rktio_close(rktio, fd2));
@ -927,7 +926,7 @@ int main(int argc, char **argv)
start = rktio_get_inexact_milliseconds();
rktio_sleep(rktio, 0.1, ps, NULL);
rktio_poll_set_close(rktio, ps);
rktio_poll_set_forget(rktio, ps);
check_valid(rktio_get_inexact_milliseconds() - start > 0.1);
ps = rktio_make_poll_set(rktio);
@ -944,7 +943,7 @@ int main(int argc, char **argv)
check_valid(rktio_poll_fs_change_ready(rktio, fc) == RKTIO_POLL_READY);
check_valid(rktio_close(rktio, fd2));
rktio_poll_set_close(rktio, ps);
rktio_poll_set_forget(rktio, ps);
rktio_fs_change_forget(rktio, fc);
}

View File

@ -7,87 +7,184 @@
# define RKTIO_EXTERN extern
#endif
typedef struct rktio_t rktio_t;
/* A rktio_t value represents an instance of the Racket I/O system.
Almost every rktio_...() function takes it as the first argument. */
typedef struct rktio_t rktio_t;
RKTIO_EXTERN rktio_t *rktio_init(void);
/* Call rktio_init() before anything else. The first call to
rktio_init() must return before any additional calls (in other
threads), but there's no ordering requirement after that. */
RKTIO_EXTERN rktio_t *rktio_init(void);
RKTIO_EXTERN void rktio_destroy(rktio_t *);
/* Call rktio_destroy() as the last thing. Everything else must be
explicitly deallocated/closed/forgotten before calling
rktio_destroy(). */
RKTIO_EXTERN void rktio_destroy(rktio_t *);
RKTIO_EXTERN void rktio_free(void *p);
/* Normally equivalent to free(), but ensures the same malloc()/free()
that rktio function use: */
RKTIO_EXTERN void rktio_free(void *p);
typedef int rktio_ok_t;
/* A result of this type is 0 for failure (in which case an error is
available from `rktio_get_last_error`) and 1 for success. */
typedef int rktio_tri_t;
/* A result of this type is a boolean, but a `...ERROR` value means
that an error value is available from `rktio_get_last_error`. */
typedef int rktio_bool_t;
/* 0 or 1. */
/*************************************************/
/* Reading and writing files */
typedef struct rktio_fd_t rktio_fd_t;
/* Mode flags shared in part by `rktio_open` and `rktio_system_fd`. */
/* Accepted by both, but `RKTIO_OPEN_READ` and `RKTIO_OPEN_WRITE` are
merely advisory for `rktio_system_fd` */
#define RKTIO_OPEN_READ (1<<0)
#define RKTIO_OPEN_WRITE (1<<1)
#define RKTIO_OPEN_TRUNCATE (1<<2)
#define RKTIO_OPEN_APPEND (1<<3)
#define RKTIO_OPEN_REPLACE (1<<4)
#define RKTIO_OPEN_MUST_EXIST (1<<5)
#define RKTIO_OPEN_CAN_EXIST (1<<6)
#define RKTIO_OPEN_SOCKET (1<<7)
#define RKTIO_OPEN_UDP (1<<8)
#define RKTIO_OPEN_TEXT (1<<2)
/* Used for `rktio_open` with `RKTIO_OPEN_WRITE`: */
#define RKTIO_OPEN_TRUNCATE (1<<3)
#define RKTIO_OPEN_APPEND (1<<4)
#define RKTIO_OPEN_REPLACE (1<<5)
#define RKTIO_OPEN_MUST_EXIST (1<<6)
#define RKTIO_OPEN_CAN_EXIST (1<<7)
/* Used for `rktio_system_fd`: */
#define RKTIO_OPEN_SOCKET (1<<8)
#define RKTIO_OPEN_UDP (1<<9)
#define RKTIO_OPEN_REGFILE (1<<10)
#define RKTIO_OPEN_NOT_REGFILE (1<<11)
/* If neither RKTIO_OPEN_REGILE nor RKTIO_OPEN_NOT_REGILE
are specified, then the value is inferred */
are specified, then the value is inferred by `rtkio_system_fd`. */
#define RKTIO_OPEN_INIT (1 << 12)
/* Make `rtkio_system_fd` set a socket as nonblocking, etc. */
#define RKTIO_OPEN_OWN (1 << 13)
/* Make `rtkio_system_fd` record a socket for reliable clean up on pre-NT Windows. */
/* A socket registered this way should be non-blocking: */
RKTIO_EXTERN rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes);
RKTIO_EXTERN intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd);
/* A socket (as opposed to other file descriptors) registered this way
should include include `RKTIO_OPEN_SOCKET` and be non-blocking or
use `RKTIO_OPEN_INIT`. */
RKTIO_EXTERN int rktio_fd_is_regular_file(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN int rktio_fd_is_socket(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN int rktio_fd_is_udp(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN int rktio_fd_is_terminal(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd);
/* Extracts a native file descriptor or socket. */
RKTIO_EXTERN rktio_bool_t rktio_fd_is_regular_file(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_bool_t rktio_fd_is_socket(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_bool_t rktio_fd_is_udp(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_bool_t rktio_fd_is_terminal(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_bool_t rktio_fd_is_text_converted(rktio_t *rktio, rktio_fd_t *rfd);
/* The functions mostly report values of recorded mode flags. */
RKTIO_EXTERN int rktio_fd_modes(rktio_t *rktio, rktio_fd_t *rfd);
/* Returns all of the recorded mode flags. */
RKTIO_EXTERN rktio_fd_t *rktio_open(rktio_t *rktio, char *src, int modes);
/* Can report `RKTIO_ERROR_DOES_NOT_EXIST` in place of system error,
and can report `RKTIO_ERROR_UNSUPPORTED_TEXT_MODE` on Windows:=. */
RKTIO_EXTERN rktio_ok_t rktio_close(rktio_t *rktio, rktio_fd_t *fd);
/* Can report `RKTIO_ERROR_EXISTS` in place of system error,
and can report `RKTIO_ERROR_UNSUPPORTED_TEXT_MODE` on Windows.
See also `rktio_write` and `rktio_poll_write_flushed. */
RKTIO_EXTERN rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd);
/* Copies a file descriptor, where each must be closed or forgotten
independenty. */
RKTIO_EXTERN void rktio_forget(rktio_t *rktio, rktio_fd_t *fd);
/* Deallocates a `rktio_fd_t` without closing the file descriptor,
but the descriptor is no longer recorded if it was opened with
`RKTIO_OPEN_OWN`. */
RKTIO_EXTERN rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which);
/* Gets stdin/stdout/stderr.
`which` values: */
#define RKTIO_STDIN 0
#define RKTIO_STDOUT 1
#define RKTIO_STDERR 2
RKTIO_EXTERN intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
/* Returns the number of bytes read, possibly 0, in non-blocking mode.
Alternatively, the result can be `RKTIO_READ_EOF` for end-of-file
or `RKTIO_READ_ERROR` for an error. Although rktio_read is intended
to have no buffering, text-mode conversion (on Windows) and certain
uncooperative OS corners can buffer 1 byte. */
#define RKTIO_READ_EOF (-1)
#define RKTIO_READ_ERROR (-2)
RKTIO_EXTERN intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
/* Returns the number of bytes written, possibly 0, in non-blocking
mode. Alternatively, the result can be `RKTIO_WRITE_ERROR` for an
error. Although rktio_write() is intended to write only bytes that
can be fully delivered to the OS, there may be OS limitations that
require buffering (e.g., on Windows). Use
rktio_poll_write_flushed() to make sure it's completely flushed
before closing. */
#define RKTIO_WRITE_ERROR (-2)
/* The read and write functions return the number of bytes read/write
in non-blocking mode, possibly 0. A read can produce `RKTIO_READ_EOF`
for end-of-file or `RKTIO_READ_ERROR` for an error. Similarly, write
can produce `RKTIO_WRITE_ERROR`. */
RKTIO_EXTERN intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
RKTIO_EXTERN intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
RKTIO_EXTERN intptr_t rktio_read_converted(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len,
char *is_converted);
/* Like rktio_read(), but also reports whether each character was
original two characters that were converted to a single newline for
text mode. */
#define RKTIO_POLL_ERROR (-2)
#define RKTIO_POLL_READY 1
RKTIO_EXTERN intptr_t rktio_buffered_byte_count(rktio_t *rktio, rktio_fd_t *fd);
/* Reports the number of bytes that are buffered kfrom the file descriptor.
The result is normally zero, but text-mode conversion and the rare
uncooperative corner of an OS can make the result 1 byte. */
RKTIO_EXTERN rktio_tri_t rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_tri_t rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd);
/* Each polling function returns one of the following: */
#define RKTIO_POLL_NOT_READY 0
#define RKTIO_POLL_READY 1
#define RKTIO_POLL_ERROR (-2)
#define RKTIO_LOCK_ERROR (-2)
#define RKTIO_LOCK_ACQUIRED 1
RKTIO_EXTERN rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd);
/* See `rktio_write` above. */
RKTIO_EXTERN rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl);
RKTIO_EXTERN rktio_tri_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd);
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
to exclusive, taking a lock that is already held, getting an
exclusive lock for a file descriptor in read mode, getting a
non-exclusive lock in write mode, and whether a lock prevents
opening or using another file descriptor. */
#define RKTIO_LOCK_ERROR (-2)
#define RKTIO_LOCK_ACQUIRED 1
#define RKTIO_LOCK_NOT_ACQUIRED 0
typedef rktio_int64_t rktio_filesize_t;
rktio_ok_t rktio_set_file_position(rktio_t *rktio, rktio_fd_t *rfd, rktio_filesize_t pos, int whence);
/* Can report `RKTIO_ERROR_CANNOT_SET_FILE_POSITION` on Windows. */
/* For `whence`: */
enum {
RKTIO_POSITION_FROM_START,
RKTIO_POSITION_FROM_END
};
rktio_filesize_t *rktio_get_file_position(rktio_t *rktio, rktio_fd_t *rfd);
/* Returns the file position, not taking into account rare input
buffering (see `rktio_read`). On Windows, can report
`RKTIO_ERROR_CANNOT_SET_FILE_POSITION`, which doesn't have a
corresponding Windows error code. */
rktio_ok_t rktio_set_file_size(rktio_t *rktio, rktio_fd_t *rfd, rktio_filesize_t sz);
/* Can report `RKTIO_ERROR_CANNOT_SET_FILE_POSITION` on Windows. */
/*************************************************/
/* Network */
@ -95,37 +192,64 @@ RKTIO_EXTERN rktio_tri_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd);
typedef struct rktio_addrinfo_lookup_t rktio_addrinfo_lookup_t;
typedef struct rktio_addrinfo_t rktio_addrinfo_t;
RKTIO_EXTERN int rktio_get_ipv4_family(rktio_t *rktio);
RKTIO_EXTERN rktio_addrinfo_lookup_t *rktio_start_addrinfo_lookup(rktio_t *rktio,
const char *hostname, int portno,
int family, int passive, int tcp);
RKTIO_EXTERN int rktio_poll_addrinfo_lookup_ready(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup);
RKTIO_EXTERN rktio_addrinfo_t *rktio_addrinfo_lookup_get(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup);
RKTIO_EXTERN void rktio_addrinfo_lookup_stop(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup);
int family, rktio_bool_t passive, rktio_bool_t tcp);
/* The `family` argument should be one of the following: */
#define RKTIO_FAMILY_ANY (-1)
RKTIO_EXTERN int rktio_get_ipv4_family(rktio_t *rktio);
RKTIO_EXTERN void rktio_free_addrinfo(rktio_t *rktio, struct rktio_addrinfo_t *a);
RKTIO_EXTERN rktio_tri_t rktio_poll_addrinfo_lookup_ready(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup);
/* Check whether an address is available for a lookup request. */
RKTIO_EXTERN rktio_addrinfo_t *rktio_addrinfo_lookup_get(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup);
/* Deallocates `lookup`. */
RKTIO_EXTERN void rktio_addrinfo_lookup_stop(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup);
/* Abandons a lookup whose result (or error) is not yet received. */
RKTIO_EXTERN void rktio_addrinfo_free(rktio_t *rktio, struct rktio_addrinfo_t *a);
/* Frees the result of a lookup. */
typedef struct rktio_listener_t rktio_listener_t;
typedef struct rktio_connect_t rktio_connect_t;
#define RKTIO_SHUTDOWN_READ RKTIO_OPEN_READ
#define RKTIO_SHUTDOWN_WRITE RKTIO_OPEN_WRITE
RKTIO_EXTERN rktio_listener_t *rktio_listen(rktio_t *rktio, rktio_addrinfo_t *local, int backlog, rktio_bool_t reuse);
/* Can fail with `RKTIO_ERROR_TRY_AGAIN_WITH_IPV4`, which suggests
trying an address using the family reported by
`rktio_get_ipv4_family` instead of `RKTIO_FAMILY_ANY`. */
RKTIO_EXTERN rktio_listener_t *rktio_listen(rktio_t *rktio, rktio_addrinfo_t *local, int backlog, int reuse);
RKTIO_EXTERN void rktio_listen_stop(rktio_t *rktio, rktio_listener_t *l);
RKTIO_EXTERN int 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);
/* Stops a listener. */
RKTIO_EXTERN rktio_tri_t rktio_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener);
/* Returns one of `RKTIO_POLL_READY`, etc. */
RKTIO_EXTERN rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener);
/* Accepts one connection on a listener. */
/* Addreses must not be freed until the connection is complete or stopped: */
RKTIO_EXTERN rktio_connect_t *rktio_start_connect(rktio_t *rktio, rktio_addrinfo_t *remote, rktio_addrinfo_t *local);
/* A `RKTIO_ERROR_CONNECT_TRYING_NEXT` error effectively means "try again",
and the connection object is still valid: */
/* Starts a connection request. Addreses must not be freed until the
connection is complete, errored, or stopped. */
RKTIO_EXTERN rktio_fd_t *rktio_connect_finish(rktio_t *rktio, rktio_connect_t *conn);
/* A `RKTIO_ERROR_CONNECT_TRYING_NEXT` error effectively means "try
again", and the connection object is still valid. On any other
error, or if the connection completes successfully, `conn` is
deallocated */
RKTIO_EXTERN void rktio_connect_stop(rktio_t *rktio, rktio_connect_t *conn);
RKTIO_EXTERN int rktio_poll_connect_ready(rktio_t *rktio, rktio_connect_t *conn);
/* Stops a connection whose result or error has not been received. */
RKTIO_EXTERN rktio_tri_t rktio_poll_connect_ready(rktio_t *rktio, rktio_connect_t *conn);
/* Returns one of `RKTIO_POLL_READY`, etc. */
RKTIO_EXTERN int rktio_socket_shutdown(rktio_t *rktio, rktio_fd_t *rfd, int mode);
/* Useful for TCP to report an EOF to the other end. Does not close the socket,
but may make it ineligible for forther use.
`mode` values: */
#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);
RKTIO_EXTERN int rktio_udp_disconnect(rktio_t *rktio, rktio_fd_t *rfd);
@ -142,80 +266,81 @@ typedef struct rktio_length_and_addrinfo_t {
RKTIO_EXTERN rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len);
#define RKTIO_PROP_ERROR (-2)
/* The following accessors return RKTIO_PROP_ERROR on failure */
/* The following accessors return `RKTIO_PROP_ERROR` on failure */
RKTIO_EXTERN int rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN int rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, int on);
RKTIO_EXTERN int rktio_udp_get_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN int rktio_udp_set_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd, int ttl_val);
#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 int rktio_udp_set_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr);
enum {
RKTIO_ADD_MEMBERSHIP,
RKTIO_DROP_MEMBERSHIP
};
RKTIO_EXTERN int rktio_udp_change_multicast_group(rktio_t *rktio, rktio_fd_t *rfd,
rktio_addrinfo_t *group_addr,
rktio_addrinfo_t *intf_addr,
int action);
/* `action` values: */
enum {
RKTIO_ADD_MEMBERSHIP,
RKTIO_DROP_MEMBERSHIP
};
/*************************************************/
/* Environment variables */
/* Check whether a string is valid as a new (e.g., no "=") */
RKTIO_EXTERN int rktio_is_ok_envvar_name(rktio_t *rktio, const char *name);
RKTIO_EXTERN rktio_bool_t rktio_is_ok_envvar_name(rktio_t *rktio, const char *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);
/* Checks whether environment variables are case-folded by the OS.
That doesn't mean that clients need to case-fold names, but clients
may want to immitate the OS. */
RKTIO_EXTERN int rktio_are_envvar_names_case_insensitive(rktio_t *rktio);
RKTIO_EXTERN char *rktio_getenv(rktio_t *rktio, const char *name);
/* Gets an environment variable value, or reports
`RKTIO_ERROR_NO_SUCH_ENVVAR` when returning NULL; the result must
be freed. */
RKTIO_EXTERN char *rktio_getenv(rktio_t *rktio, const char *name);
RKTIO_EXTERN rktio_ok_t rktio_setenv(rktio_t *rktio, const char *name, const char *val);
/* Set an environment variable's value, where a NULL value for `val`
unsets it. */
RKTIO_EXTERN rktio_ok_t rktio_setenv(rktio_t *rktio, const char *name, const char *val);
typedef struct rktio_envvars_t rktio_envvars_t;
/* Extracts all environment variables into a record */
RKTIO_EXTERN rktio_envvars_t *rktio_envvars(rktio_t *rktio);
/* Create an empty environment-variables record: */
RKTIO_EXTERN rktio_envvars_t *rktio_empty_envvars(rktio_t *rktio);
/* Clones an environment-variable record: */
RKTIO_EXTERN rktio_envvars_t *rktio_envvars_copy(rktio_t *rktio, rktio_envvars_t *envvars);
/* Deallocates an environment-variables record: */
RKTIO_EXTERN void rktio_envvars_free(rktio_t *rktio, rktio_envvars_t *envvars);
/* Extracts all environment variables into a record */
RKTIO_EXTERN rktio_envvars_t *rktio_empty_envvars(rktio_t *rktio);
/* Create an empty environment-variables record. */
RKTIO_EXTERN rktio_envvars_t *rktio_envvars_copy(rktio_t *rktio, rktio_envvars_t *envvars);
/* Clones an environment-variable record. */
RKTIO_EXTERN void rktio_envvars_free(rktio_t *rktio, rktio_envvars_t *envvars);
/* Deallocates an environment-variables record: */
/* Access/update environment-variables record by name: */
RKTIO_EXTERN char *rktio_envvars_get(rktio_t *rktio, rktio_envvars_t *envvars, char *name);
RKTIO_EXTERN void rktio_envvars_set(rktio_t *rktio, rktio_envvars_t *envvars, char *name, char *value);
/* Access/update environment-variables record by name. */
/* Access/update environment-variables record by index: */
RKTIO_EXTERN intptr_t rktio_envvars_count(rktio_t *rktio, rktio_envvars_t *envvars);
RKTIO_EXTERN char *rktio_envvars_name_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i);
RKTIO_EXTERN char *rktio_envvars_value_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i);
/* Access/update environment-variables record by index. */
/*************************************************/
/* Processes */
typedef struct rktio_process_t rktio_process_t;
#define RKTIO_PROCESS_NEW_GROUP (1<<0)
#define RKTIO_PROCESS_STDOUT_AS_STDERR (1<<1)
#define RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE (1<<2)
#define RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION (1<<3)
typedef struct rktio_process_result_t {
rktio_process_t *process;
rktio_fd_t *stdin_fd, *stdout_fd, *stderr_fd;
@ -227,67 +352,101 @@ RKTIO_EXTERN rktio_process_result_t *rktio_process(rktio_t *rktio,
const char *current_directory, rktio_envvars_t *envvars,
int flags,
void (*unix_child_process_callback)());
/* `flags` flags: */
#define RKTIO_PROCESS_NEW_GROUP (1<<0)
#define RKTIO_PROCESS_STDOUT_AS_STDERR (1<<1)
#define RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE (1<<2)
#define RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION (1<<3)
RKTIO_EXTERN int rktio_process_allowed_flags(rktio_t *rktio);
/* Reports the flags that are accepted by `rktio_process` on the
current OS. */
RKTIO_EXTERN int rktio_process_pid(rktio_t *rktio, rktio_process_t *sp);
/* Always succeeds, whether or not the process is still running. */
RKTIO_EXTERN rktio_ok_t rktio_process_kill(rktio_t *rktio, rktio_process_t *sp);
RKTIO_EXTERN rktio_ok_t rktio_process_interrupt(rktio_t *rktio, rktio_process_t *sp);
/* Interrupts or kills a process; does not deallocate the process record. */
RKTIO_EXTERN int rktio_process_kill(rktio_t *rktio, rktio_process_t *sp);
RKTIO_EXTERN int rktio_process_interrupt(rktio_t *rktio, rktio_process_t *sp);
RKTIO_EXTERN void rktio_process_forget(rktio_t *rktio, rktio_process_t *sp);
/* Deallocates a process record, whether or not the process has
stopped. */
#define RKTIO_PROCESS_ERROR (-2)
#define RKTIO_PROCESS_DONE 1
RKTIO_EXTERN int rktio_poll_process_done(rktio_t *rktio, rktio_process_t *sp);
RKTIO_EXTERN rktio_ok_t rktio_poll_process_done(rktio_t *rktio, rktio_process_t *sp);
/* Check whether a process has completed: */
#define RKTIO_PROCESS_ERROR (-2)
#define RKTIO_PROCESS_DONE 1
#define RKTIO_PROCESS_RUNNING 0
typedef struct rktio_status_t {
int running;
rktio_bool_t running;
int result;
} rktio_status_t;
RKTIO_EXTERN rktio_status_t *rktio_process_status(rktio_t *rktio, rktio_process_t *sp);
/* The `result` value is only value if `running` is 0. */
RKTIO_EXTERN void rktio_block_child_signals(rktio_t*rktio, int block);
/*************************************************/
/* Filesystem-change events */
RKTIO_EXTERN int rktio_fs_change_properties(rktio_t *rktio);
/* Reports properties of the filesystem-change event implementation: */
#define RKTIO_FS_CHANGE_SUPPORTED (1 << 0)
#define RKTIO_FS_CHANGE_SCALABLE (1 << 1)
#define RKTIO_FS_CHANGE_LOW_LATENCY (1 << 2)
#define RKTIO_FS_CHANGE_FILE_LEVEL (1 << 3)
RKTIO_EXTERN int rktio_fs_change_properties(rktio_t *rktio);
typedef struct rktio_fs_change_t rktio_fs_change_t;
RKTIO_EXTERN rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, char *path);
RKTIO_EXTERN void rktio_fs_change_forget(rktio_t *rktio, rktio_fs_change_t *fc);
RKTIO_EXTERN int rktio_poll_fs_change_ready(rktio_t *rktio, rktio_fs_change_t *fc);
RKTIO_EXTERN rktio_tri_t rktio_poll_fs_change_ready(rktio_t *rktio, rktio_fs_change_t *fc);
/* Returns one of `RKTIO_POLL_READY`, etc. */
/*************************************************/
/* File-descriptor sets for polling */
/* A poll set works for a single use via rktio_sleep(), as opposed to
"long-term" poll sets that can be used multiple times. */
"long-term" poll sets that can be used multiple times. The
`rktio_sleep` function accepts one of each and combines them. */
typedef struct rktio_poll_set_t rktio_poll_set_t;
#define RKTIO_POLL_READ RKTIO_OPEN_READ
#define RKTIO_POLL_WRITE RKTIO_OPEN_WRITE
RKTIO_EXTERN rktio_poll_set_t *rktio_make_poll_set(rktio_t *rktio);
RKTIO_EXTERN void rktio_poll_set_close(rktio_t *rktio, rktio_poll_set_t *fds);
RKTIO_EXTERN void rktio_poll_set_forget(rktio_t *rktio, rktio_poll_set_t *fds);
/* Don't reuse a poll set after calling `rktio_sleep`, but do
explicitly forget it afterward. */
RKTIO_EXTERN void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes);
RKTIO_EXTERN void rktio_poll_add_receive(rktio_t *rktio, rktio_listener_t *listener, rktio_poll_set_t *fds);
/* Registers a wait on a file descriptor in read and/or write mode or
flush mode. The flush mode corresponds to
`rktio_poll_write_flushed`.
`modes` values: */
#define RKTIO_POLL_READ RKTIO_OPEN_READ
#define RKTIO_POLL_WRITE RKTIO_OPEN_WRITE
#define RKTIO_POLL_FLUSH (RKTIO_OPEN_WRITE << 2)
RKTIO_EXTERN void rktio_poll_add_accept(rktio_t *rktio, rktio_listener_t *listener, rktio_poll_set_t *fds);
RKTIO_EXTERN void rktio_poll_add_connect(rktio_t *rktio, rktio_connect_t *conn, rktio_poll_set_t *fds);
RKTIO_EXTERN void rktio_poll_add_addrinfo_lookup(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup, rktio_poll_set_t *fds);
RKTIO_EXTERN void rktio_poll_add_process(rktio_t *rktio, rktio_process_t *sp, rktio_poll_set_t *fds);
RKTIO_EXTERN void rktio_poll_add_fs_change(rktio_t *rktio, rktio_fs_change_t *fc, rktio_poll_set_t *fds);
/* Registers various other waits. */
RKTIO_EXTERN void rktio_poll_set_add_nosleep(rktio_t *rktio, rktio_poll_set_t *fds);
/* Causes a sleep given `fds` to return immediately. */
#ifdef RKTIO_SYSTEM_WINDOWS
RKTIO_EXTERN void rktio_poll_set_add_handle(rktio_t *rktio, intptr_t h, rktio_poll_set_t *fds, int repost);
RKTIO_EXTERN void rktio_poll_set_add_eventmask(rktio_t *rktio, rktio_poll_set_t *fds, int mask);
/* When sleeping on Windows, extra handles or eventmasks can be added
to trigger a wake up */
#endif
/*************************************************/
@ -300,6 +459,23 @@ RKTIO_EXTERN void rktio_poll_set_add_eventmask(rktio_t *rktio, rktio_poll_set_t
typedef struct rktio_ltps_t rktio_ltps_t;
typedef struct rktio_ltps_handle_t rktio_ltps_handle_t;
RKTIO_EXTERN rktio_ltps_t *rktio_open_ltps(rktio_t *rktio);
RKTIO_EXTERN int rktio_ltps_close(rktio_t *rktio, rktio_ltps_t *lt);
/* Closing will signal all remianing handles and free all signaled
handles, but use `rktio_ltps_remove_all` and
`rktio_ltps_get_signaled_handle` is you need to clean up any
per-handle data: */
RKTIO_EXTERN rktio_ltps_handle_t *rktio_ltps_add(rktio_t *rktio, rktio_ltps_t *lt, rktio_fd_t *rfd, int mode);
/* Don't free the returned handle; use it with `rktio_ltps_handle_set_data`
and `rktio_ltps_handle_get_data`, and free it only when the same handle
is returned by `rktio_ltps_get_signaled_handle`. Using the `RKTIO_LTPS_REMOVE`
mode causes a previous created handle to be signaled. A successful remove
reports `RKTIO_ERROR_LTPS_REMOVED` while returning NULL. A `...CHECK...`
or `...REMOVE...` mode that doesn't find the handle reports
`RKTIO_ERROR_LTPS_NOT_FOUND`.
`mode` values: */
enum {
RKTIO_LTPS_CREATE_READ = 1,
RKTIO_LTPS_CREATE_WRITE,
@ -312,17 +488,21 @@ enum {
RKTIO_LTPS_REMOVE_VNODE
};
RKTIO_EXTERN rktio_ltps_t *rktio_open_ltps(rktio_t *rktio);
RKTIO_EXTERN int rktio_ltps_close(rktio_t *rktio, rktio_ltps_t *lt);
RKTIO_EXTERN void rktio_ltps_handle_set_data(rktio_t *rktio, rktio_ltps_handle_t *s, void *data);
RKTIO_EXTERN void *rktio_ltps_handle_get_data(rktio_t *rktio, rktio_ltps_handle_t *s);
RKTIO_EXTERN rktio_ltps_handle_t *rktio_ltps_add(rktio_t *rktio, rktio_ltps_t *lt, rktio_fd_t *rfd, int mode);
RKTIO_EXTERN void rktio_ltps_handle_set_data(rktio_ltps_t *lt, rktio_ltps_handle_t *s, void *data);
RKTIO_EXTERN void *rktio_ltps_handle_get_data(rktio_ltps_t *lt, rktio_ltps_handle_t *s);
void rktio_ltps_remove_all(rktio_t *rktio, rktio_ltps_t *lt);
/* Removes all additions, signaling all handles. */
RKTIO_EXTERN rktio_ok_t rktio_ltps_poll(rktio_t *rktio, rktio_ltps_t *lt);
/* Enqueues signaled handles for retreival via `rktio_ltps_get_signaled_handle`. */
RKTIO_EXTERN int rktio_ltps_poll(rktio_t *rktio, rktio_ltps_t *lt);
RKTIO_EXTERN rktio_ltps_handle_t *rktio_ltps_get_signaled_handle(rktio_t *rktio, rktio_ltps_t *lt);
/* Free the returned handle when you're done with it. */
RKTIO_EXTERN void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds, rktio_ltps_t *lt);
/* Waits up to `nsecs` seconds (or forever if `nsecs` is 0) or until
something registered with `fds` or `lt` is ready. */
/*************************************************/
/* Files, directories, and links */
@ -334,34 +514,33 @@ RKTIO_EXTERN int rktio_is_regular_file(rktio_t *rktio, char *filename);
RKTIO_EXTERN rktio_ok_t rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail);
/* Can report `RKTIO_ERROR_EXISTS`: */
RKTIO_EXTERN rktio_ok_t rktio_rename_file(rktio_t *rktio, char *dest, char *src, int 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);
/* Can report `RKTIO_ERROR_EXISTS`: */
RKTIO_EXTERN rktio_ok_t rktio_make_directory(rktio_t *rktio, char *filename);
/* Can report `RKTIO_ERROR_EXISTS`. */
RKTIO_EXTERN rktio_ok_t rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory,
int 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 rktio_ok_t rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory,
int enable_write_on_fail);
RKTIO_EXTERN char *rktio_readlink(rktio_t *rktio, char *fullfilename);
/* Argument should not have a trailing separator. Can report
`RKTIO_ERROR_NOT_A_LINK`. */
RKTIO_EXTERN char *rktio_readlink(rktio_t *rktio, char *fullfilename);
/* The `dest_is_directory` argument is used only
on Windows. Can report `RKTIO_ERROR_EXISTS`. */
RKTIO_EXTERN rktio_ok_t rktio_make_link(rktio_t *rktio, char *src, char *dest,
int dest_is_directory);
/* The `dest_is_directory` argument is used only
on Windows. Can report `RKTIO_ERROR_EXISTS`. */
/*************************************************/
/* File attributes */
typedef rktio_int64_t rktio_filesize_t;
typedef intptr_t rktio_timestamp_t;
RKTIO_EXTERN rktio_filesize_t *rktio_file_size(rktio_t *rktio, char *filename);
@ -387,43 +566,44 @@ RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, char *path, i
#define RKTIO_PERMISSION_ERROR (-1)
RKTIO_EXTERN int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int all_bits);
/* Result is `RKTIO_PERMISSION_ERROR` for error, otherwise a combination of
bits. If not `all_bits`, then use constants above. */
RKTIO_EXTERN int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int all_bits);
RKTIO_EXTERN rktio_ok_t rktio_set_file_or_directory_permissions(rktio_t *rktio, char *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. */
RKTIO_EXTERN rktio_ok_t rktio_set_file_or_directory_permissions(rktio_t *rktio, char *filename, int new_bits);
/*************************************************/
/* Directory listing */
typedef struct rktio_directory_list_t rktio_directory_list_t;
RKTIO_EXTERN rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename);
/* On Windows, the given `filename` must be normalized and not have
`.` or `..`: */
RKTIO_EXTERN rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename);
RKTIO_EXTERN char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl);
/* Returns an unallocated "" and deallocates `dl` when the iteration
is complete. A NULL result would mean an error without deallocating
`dl`, but that doesn't currently happen. */
RKTIO_EXTERN char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl);
RKTIO_EXTERN void rktio_directory_list_stop(rktio_t *rktio, rktio_directory_list_t *dl);
/* Interrupt a directory list in progress, not needed after
rktio_directory_list_step() returns "": */
RKTIO_EXTERN void rktio_directory_list_stop(rktio_t *rktio, rktio_directory_list_t *dl);
RKTIO_EXTERN char **rktio_filesystem_root_list(rktio_t *rktio);
/* Returns a NULL-terminated array. Free each string. Currently never
errors. */
RKTIO_EXTERN char **rktio_filesystem_root_list(rktio_t *rktio);
/*************************************************/
/* File copying */
typedef struct rktio_file_copy_t rktio_file_copy_t;
/* Can report `RKTIO_ERROR_EXISTS`: */
RKTIO_EXTERN rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, char *dest, char *src, int exists_ok);
RKTIO_EXTERN rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, char *dest, char *src,
rktio_bool_t exists_ok);
/* Can report `RKTIO_ERROR_EXISTS`. */
RKTIO_EXTERN int rktio_copy_file_is_done(rktio_t *rktio, rktio_file_copy_t *fc);
RKTIO_EXTERN rktio_ok_t rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc);
@ -432,6 +612,8 @@ RKTIO_EXTERN void rktio_copy_file_stop(rktio_t *rktio, rktio_file_copy_t *fc);
/*************************************************/
/* System paths */
RKTIO_EXTERN char *rktio_system_path(rktio_t *rktio, int which);
/* `which` values: */
enum {
RKTIO_PATH_SYS_DIR,
RKTIO_PATH_TEMP_DIR,
@ -445,12 +627,10 @@ enum {
RKTIO_PATH_INIT_FILE
};
RKTIO_EXTERN char *rktio_system_path(rktio_t *rktio, int which);
RKTIO_EXTERN char *rktio_expand_user_tilde(rktio_t *rktio, char *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`. */
RKTIO_EXTERN char *rktio_expand_user_tilde(rktio_t *rktio, char *filename);
/*************************************************/
/* Sleep and signals */
@ -461,6 +641,12 @@ RKTIO_EXTERN rktio_signal_handle_t *rktio_get_signal_handle(rktio_t *rktio);
RKTIO_EXTERN void rktio_signal_received_at(rktio_signal_handle_t *h);
RKTIO_EXTERN void rktio_signal_received(rktio_t *rktio);
RKTIO_EXTERN void rktio_wait_until_signal_received(rktio_t *rktio);
#ifdef RKTIO_SYSTEM_UNIX
RKTIO_EXTERN int rktio_signal_handle_to_fd();
#endif
/*************************************************/
/* Time and date */
@ -471,7 +657,7 @@ typedef struct rktio_date_t {
int day_of_year;
int is_dst;
int zone_offset;
char *zone_name; /* can be NULL */
char *zone_name; /* can be NULL; otherwise, free it */
} rktio_date_t;
RKTIO_EXTERN intptr_t rktio_get_milliseconds(void);
@ -486,23 +672,30 @@ RKTIO_EXTERN rktio_date_t *rktio_seconds_to_date(rktio_t *rktio, rktio_timestamp
/*************************************************/
/* Errors */
RKTIO_EXTERN int rktio_get_last_error_kind(rktio_t *rktio);
/* Kinds of error values: */
enum {
RKTIO_ERROR_KIND_POSIX,
RKTIO_ERROR_KIND_WINDOWS,
RKTIO_ERROR_KIND_GAI, /* => error sub-code available */
RKTIO_ERROR_KIND_GAI,
RKTIO_ERROR_KIND_RACKET
};
RKTIO_EXTERN int rktio_get_last_error(rktio_t *rktio);
/* Error IDs of kind RKTIO_ERROR_KIND_RACKET */
enum {
RKTIO_ERROR_UNSUPPORTED = 1,
RKTIO_ERROR_DOES_NOT_EXIST,
RKTIO_ERROR_EXISTS,
RKTIO_ERROR_LINK_FAILED,
RKTIO_ERROR_NOT_A_LINK,
RKTIO_ERROR_BAD_PERMISSION,
RKTIO_ERROR_IS_A_DIRECTORY,
RKTIO_ERROR_NOT_A_DIRECTORY,
RKTIO_ERROR_UNSUPPORTED_TEXT_MODE,
RKTIO_ERROR_CANNOT_FILE_POSITION,
RKTIO_ERROR_NO_TILDE,
RKTIO_ERROR_ILL_FORMED_USER,
RKTIO_ERROR_UNKNOWN_USER,
@ -519,20 +712,11 @@ enum {
RKTIO_ERROR_NO_SUCH_ENVVAR,
};
/* GAI error sub-codes */
enum {
RKTIO_ERROR_REMOTE_HOST_NOT_FOUND,
RKTIO_ERROR_LOCAL_HOST_NOT_FOUND,
};
RKTIO_EXTERN int rktio_get_last_error(rktio_t *rktio);
RKTIO_EXTERN int rktio_get_last_error_kind(rktio_t *rktio);
RKTIO_EXTERN const char *rktio_get_last_error_string(rktio_t *rktio);
RKTIO_EXTERN const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid);
/* The returned strings for `rktio_...error_string()` should not be
deallocated, but it only lasts reliably until the next call to
either of the functions. */
RKTIO_EXTERN const char *rktio_get_last_error_string(rktio_t *rktio);
RKTIO_EXTERN const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid);
/*************************************************/

View File

@ -19,6 +19,12 @@ extern char **environ;
# define GET_ENVIRON_ARRAY environ
#endif
#ifdef RKTIO_SYSTEM_UNIX
char **rktio_get_environ_array(void)
{
return GET_ENVIRON_ARRAY;
}
#endif
int rktio_is_ok_envvar_name(rktio_t *rktio, const char *s)
{

View File

@ -13,12 +13,15 @@ typedef struct err_str_t {
err_str_t err_strs[] = {
{ RKTIO_ERROR_UNSUPPORTED, "unsupported" },
{ RKTIO_ERROR_EXISTS, "file or directory already exists"},
{ RKTIO_ERROR_DOES_NOT_EXIST, "no such file or directory" },
{ RKTIO_ERROR_EXISTS, "file or directory already exists" },
{ RKTIO_ERROR_LINK_FAILED, "link creation failed" },
{ RKTIO_ERROR_NOT_A_LINK, "not a link" },
{ RKTIO_ERROR_BAD_PERMISSION, "unsupported permission value" },
{ RKTIO_ERROR_IS_A_DIRECTORY, "path refers to a directory" },
{ RKTIO_ERROR_NOT_A_DIRECTORY, "path does not refer to a directory" },
{ RKTIO_ERROR_UNSUPPORTED_TEXT_MODE, "cannot use text mode on a non-file device" },
{ RKTIO_ERROR_CANNOT_FILE_POSITION, "cannot get/set position/size on device" },
{ RKTIO_ERROR_NO_TILDE, "path does not start with a tilde" },
{ RKTIO_ERROR_ILL_FORMED_USER, "ill-formed username in path" },
{ RKTIO_ERROR_UNKNOWN_USER, "unknown username in path" },

View File

@ -39,6 +39,7 @@ struct rktio_fd_t {
struct Win_FD_Output_Thread *oth; /* output mode */
int unblocked; /* whether non-blocking mode is installed */
char *buffer; /* shared with reading thread */
int pending_cr; /* for text-mode input, may be dropped by a following lf */
#endif
};
@ -112,6 +113,10 @@ static CSI_proc get_csi(void)
return csi;
}
static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, intptr_t got);
static char *rktio_adjust_output_text(char *buffer, intptr_t *towrite);
static intptr_t rktio_recount_output_text(char *orig_buffer, char *buffer, intptr_t wrote);
#endif
/*========================================================================*/
@ -173,7 +178,7 @@ rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes)
{
rktio_fd_t *rfd;
rfd = malloc(sizeof(rktio_fd_t));
rfd = calloc(1, sizeof(rktio_fd_t));
rfd->modes = modes;
#ifdef RKTIO_SYSTEM_UNIX
@ -203,6 +208,12 @@ rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes)
if (modes & RKTIO_OPEN_READ)
init_read_fd(rktio, rfd);
if ((modes & RKTIO_OPEN_SOCKET) && (modes & RKTIO_OPEN_INIT))
rktio_socket_init(rktio, rfd);
if ((modes & RKTIO_OPEN_SOCKET) && (modes & RKTIO_OPEN_OWN))
rktio_socket_own(rktio, rfd);
return rfd;
}
@ -219,6 +230,30 @@ intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd)
#endif
}
rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which)
{
int mode = ((which == RKTIO_STDIN)
? RKTIO_OPEN_READ
: RKTIO_OPEN_WRITE);
#ifdef RKTIO_SYSTEM_UNIX
return rktio_system_fd(rktio, which, mode);
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
switch (which) {
case RKTIO_STDIN:
which = STD_INPUT_HANDLE;
break;
case RKTIO_STDOUT:
which = STD_OUTPUT_HANDLE;
break;
case RKTIO_STDERR:
which = STD_ERROR_HANDLE;
break;
}
return rktio_system_fd(rktio, (intptr_t)GetStdHandle(which), mode);
#endif
}
int rktio_fd_is_regular_file(rktio_t *rktio, rktio_fd_t *rfd)
{
return ((rfd->modes & RKTIO_OPEN_REGFILE) ? 1 : 0);
@ -261,6 +296,15 @@ int rktio_fd_is_terminal(rktio_t *rktio, rktio_fd_t *rfd)
return rktio_system_fd_is_terminal(rktio, (intptr_t)rfd->fd);
}
int rktio_fd_is_text_converted(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_WINDOWS
if (rfd->modes & RKTIO_OPEN_TEXT)
return 1;
#endif
return 0;
}
rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_UNIX
@ -382,12 +426,6 @@ int rktio_close(rktio_t *rktio, rktio_fd_t *rfd)
void rktio_forget(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_WINDOWS
if (rfd->modes & RKTIO_OPEN_SOCKET) {
rktio_socket_forget(rktio, rfd);
return;
}
#endif
free(rfd);
}
@ -661,6 +699,13 @@ void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int
else
rktio_poll_set_add_nosleep(rktio, fds);
}
if (modes & RKTIO_POLL_FLUSH) {
if (rfd->oth && !rktio_poll_flush_ready(rktio, rfd))
rktio_poll_set_add_handle(rktio, (intptr_t)rfd->oth->ready_sema, fds, 1);
else
rktio_poll_set_add_nosleep(rktio, fds);
}
}
#endif
}
@ -677,6 +722,14 @@ intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
if (rfd->modes & RKTIO_OPEN_SOCKET)
return rktio_socket_read(rktio, rfd, buffer, len);
# ifdef SOME_FDS_ARE_NOT_SELECTABLE
if (rfd->bufcount && len) {
buffer[0] = rfd->buffer[0];
rfd->bufcount = 0;
return 1;
}
# endif
if (rktio_fd_is_regular_file(rktio, rfd)) {
/* Reading regular file never blocks */
do {
@ -730,6 +783,11 @@ intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
reading never blocks. */
DWORD rgot;
if (rfd->pending_cr && len) {
/* just in case we need to add the cr */
len--;
}
if (!ReadFile((HANDLE)rfd->fd, buffer, len, &rgot, NULL)) {
get_windows_error();
return RKTIO_READ_ERROR;
@ -737,6 +795,8 @@ intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
if (!rgot)
return RKTIO_READ_EOF;
else if (rfd->modes & RKTIO_OPEN_TEXT)
return rktio_adjust_input_text(rfd, buffer, rgot);
else
return rgot;
} else {
@ -764,7 +824,46 @@ intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
#endif
}
RKTIO_EXTERN intptr_t rktio_buffered_byte_count(rktio_t *rktio, rktio_fd_t *fd)
{
#ifdef RKTIO_SYSTEM_UNIX
# ifdef SOME_FDS_ARE_NOT_SELECTABLE
return rfd->bufcount;
# else
return 0;
# endif
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
return (fd-?pending_cr : 1 : 0);
#endif
}
#ifdef RKTIO_SYSTEM_WINDOWS
static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, intptr_t got)
{
int i, j;
if (rfd->pending_cr) {
MSC_IZE(memmove)(buffer+1, buffer, got);
buffer[0] = '\r';
rfd->pending_cr = 0;
got++;
}
if (got && (buffer[got-1] == '\r')) {
rfd->pending_cr = 1;
--got;
}
for (i = 0, j = 0; i < got-1; i++) {
if ((buffer[i] == '\r') && (buffer[i+1] == '\n'))
buffer[j++] = '\n';
else
buffer[j++] = buffer[i++];
}
return j;
}
static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th)
{
@ -887,17 +986,21 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
if (rfd->modes & RKTIO_OPEN_SOCKET)
return rktio_socket_write(rktio, rfd, buffer, len);
if (rktio_fd_is_regular_file(rktio, rfd)) {
if (rktio_fd_is_regular_file(rktio, rfd)
|| rktio_fd_is_terminal(rktio, rfd)) {
/* Regular files never block, so this code looks like the Unix
code. We've cheated in the make_fd proc and called
consoles regular files, because they cannot block, either. */
code. */
/* If we try to write too much at once, the result
is ERROR_NOT_ENOUGH_MEMORY (as opposed to a partial write). */
int ok;
intptr_t towrite = len;
char *orig_buffer = buffer;
int err;
if (rfd->modes & RKTIO_OPEN_TEXT)
buffer = rktio_adjust_output_text(buffer, &towrite);
while (1) {
ok = WriteFile((HANDLE)rfd->fd, buffer, towrite, &winwrote, NULL);
if (!ok)
@ -905,6 +1008,11 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
if (!ok && (err == ERROR_NOT_ENOUGH_MEMORY)) {
towrite = towrite >> 1;
if (towrite && (buffer != orig_buffer)) {
/* don't write half of a CRLF: */
if ((buffer[towrite-1] == '\r') && (buffer[towrite-1] == '\n'))
--towrite;
}
if (!towrite)
break;
} else
@ -916,6 +1024,11 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
return RKTIO_WRITE_ERROR;
}
if (buffer != orig_buffer) {
/* Convert converted count back to original count: */
winwrote = rktio_recount_output_text(orig_buffer, buffer, winwrote);
}
return winwrote;
} else {
/* If we don't have a thread yet, we'll need to start it. If
@ -1152,6 +1265,54 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
#ifdef RKTIO_SYSTEM_WINDOWS
static char *rktio_adjust_output_text(char *buffer, intptr_t *towrite)
{
intptr_t len = *towrite, i, j, newlines = 0;
char *new_buffer;
/* Limit work done here to avoid O(N^2) work if a client tried
repeatedly to write a O(N)-sized buffer and only part goes out
each time. */
if (len > 4096)
len = 4096;
for (i = 0; i < len; i++) {
if (buffer[i] == '\n')
newlines++;
}
if (!newlines)
return buffer;
new_buffer = malloc(len + newlines);
*towrite = len + newlines;
for (i = 0, j = 0; i < len; i++) {
if (buffer[i] == '\n') {
new_buffer[j++] = '\r';
new_buffer[j++] = '\n';
} else
new_buffer[j++] = buffer[i];
}
return new_buffer;
}
static intptr_t rktio_recount_output_text(char *orig_buffer, char *buffer, intptr_t wrote)
{
intptr_t i = 0, j = 0;
while (j < wrote) {
if (buffer[i] == '\n')
j += 2;
or
j++;
i++;
}
return i;
}
static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth)
{
DWORD towrite, wrote, start;

View File

@ -12,9 +12,9 @@
# include <windows.h>
#endif
/*************************************************************/
/* opening a file fd */
/*************************************************************/
/*========================================================================*/
/* Opening a file */
/*========================================================================*/
static rktio_fd_t *open_read(rktio_t *rktio, char *filename)
{
@ -27,7 +27,10 @@ static rktio_fd_t *open_read(rktio_t *rktio, char *filename)
} while ((fd == -1) && (errno == EINTR));
if (fd == -1) {
get_posix_error();
if (errno == ENOENT) {
set_racket_error(RKTIO_ERROR_DOES_NOT_EXIST);
} else
get_posix_error();
return NULL;
} else {
int cr;
@ -60,6 +63,7 @@ static rktio_fd_t *open_read(rktio_t *rktio, char *filename)
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
HANDLE fd;
rktio_fd_t *rfd;
fd = CreateFileW(WIDE_PATH_temp(filename),
GENERIC_READ,
@ -70,11 +74,24 @@ static rktio_fd_t *open_read(rktio_t *rktio, char *filename)
NULL);
if (fd == INVALID_HANDLE_VALUE) {
get_windows_error();
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
set_racket_error(RKTIO_ERROR_DOES_NOT_EXIST);
} else
get_windows_error();
return NULL;
}
return rktio_system_fd(rktio, (intptr_t)fd, RKTIO_OPEN_READ);
rfd = rktio_system_fd(rktio, (intptr_t)fd, RKTIO_OPEN_READ);
if (modes & RKTIO_MODE_TEXT) {
if (!rktio_fd_is_regular_file(rfd)) {
rktio_fd_forget(rfd);
set_racket_error(RKTIO_ERROR_UNSUPPORTED_TEXT_MODE);
return NULL;
}
}
return rfd;
#endif
}
@ -222,6 +239,14 @@ static rktio_fd_t *open_write(rktio_t *rktio, char *filename, int modes)
rfd = rktio_system_fd(rktio, (intptr_t)fd, modes);
if (modes & RKTIO_MODE_TEXT) {
if (!rktio_fd_is_regular_file(rfd)) {
rktio_fd_forget(rfd);
set_racket_error(RKTIO_ERROR_UNSUPPORTED_TEXT_MODE);
return NULL;
}
}
if ((modes & RKTIO_OPEN_APPEND) && rktio_fd_is_regular_file(rktio, rfd)) {
SetFilePointer(fd, 0, NULL, FILE_END);
}
@ -238,3 +263,131 @@ rktio_fd_t *rktio_open(rktio_t *rktio, char *filename, int modes)
return open_read(rktio, filename);
}
/*========================================================================*/
/* File positions */
/*========================================================================*/
#ifdef WINDOWS_FILE_HANDLES
static int win_seekable(intptr_t fd)
{
/* SetFilePointer() requires " a file stored on a seeking device".
I'm not sure how to test that, so we approximate as "regular
file". */
return GetFileType((HANDLE)fd) == FILE_TYPE_DISK;
}
#endif
rktio_ok_t rktio_set_file_position(rktio_t *rktio, rktio_fd_t *rfd, rktio_filesize_t pos, int whence)
{
intptr_t fd = rktio_fd_system_fd(rktio, rfd);
#ifdef RKTIO_SYSTEM_UNIX
if (whence == RKTIO_POSITION_FROM_START)
whence = SEEK_SET;
else
whence = SEEK_END;
if (BIG_OFF_T_IZE(lseek)(fd, pos, whence) < 0) {
get_posix_error();
return 0;
}
return 1;
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
if (win_seekable(fd)) {
DWORD r;
LONG lo_w, hi_w;
lo_w = (LONG)(pos & 0xFFFFFFFF);
hi_w = (LONG)(pos >> 32);
r = SetFilePointer((HANDLE)fd, lo_w, &hi_w,
((whence == RKTIO_POSITION_FROM_START) ? FILE_BEGIN : FILE_END));
if ((r == INVALID_SET_FILE_POINTER)
&& GetLastError() != NO_ERROR) {
get_windows_error();
return 0;
} else
return 1;
} else {
set_racket_error(RKTIO_ERROR_CANNOT_SET_FILE_POSITION);
return 0;
}
#endif
}
rktio_filesize_t *rktio_get_file_position(rktio_t *rktio, rktio_fd_t *rfd)
{
intptr_t fd = rktio_fd_system_fd(rktio, rfd);
rktio_filesize_t pll, *r;
#ifdef RKTIO_SYSTEM_UNIX
pll = BIG_OFF_T_IZE(lseek)(fd, 0, 1);
if (pll < 0) {
get_posix_error();
return NULL;
}
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
if (win_seekable(fd)) {
DWORD lo_w, hi_w;
hi_w = 0;
lo_w = SetFilePointer((HANDLE)fd, 0, &hi_w, FILE_CURRENT);
if ((lo_w == INVALID_SET_FILE_POINTER)
&& GetLastError() != NO_ERROR) {
get_windows_error();
return NULL;
} else
pll = ((mzlonglong)hi_w << 32) | lo_w;
} else {
set_racket_error(RKTIO_ERROR_CANNOT_SET_FILE_POSITION);
return NULL;
}
#endif
r = malloc(sizeof(rktio_filesize_t));
*r = pll;
return r;
}
rktio_ok_t rktio_set_file_size(rktio_t *rktio, rktio_fd_t *rfd, rktio_filesize_t sz)
{
intptr_t fd = rktio_fd_system_fd(rktio, rfd);
#ifdef RKTIO_SYSTEM_UNIX
if (!BIG_OFF_T_IZE(ftruncate)(fd, sz))
return 1;
get_posix_error();
return 0;
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
if (win_seekable(fd)) {
DWORD r;
LONG lo_w, hi_w, old_lo_w, old_hi_w;
old_hi_w = 0;
old_lo_w = SetFilePointer((HANDLE)fd, 0, &old_hi_w, FILE_CURRENT);
if ((old_lo_w == INVALID_SET_FILE_POINTER)
&& GetLastError() != NO_ERROR) {
get_windows_error();
return 0;
} else {
lo_w = (LONG)(sz & 0xFFFFFFFF);
hi_w = (LONG)(sz >> 32);
r = SetFilePointer((HANDLE)fd, lo_w, &hi_w, FILE_BEGIN);
if ((r == INVALID_SET_FILE_POINTER)
&& GetLastError() != NO_ERROR) {
get_windows_error();
return 0;
} else {
if (SetEndOfFile((HANDLE)fd)) {
/* we assume that this works: */
(void)SetFilePointer((HANDLE)fd, lo_w, &hi_w, FILE_BEGIN);
return 1;
}
get_windows_error();
return 0;
}
}
} else {
set_racket_error(RKTIO_ERROR_CANNOT_SET_FILE_POSITION);
return 0;
}
#endif
}

View File

@ -215,7 +215,7 @@ void rktio_release_lockf(rktio_t *rktio, int fd)
}
#endif
int rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd)
rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd)
{
intptr_t fd = rktio_fd_system_fd(rktio, rfd);
int ok;
@ -240,5 +240,6 @@ int rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd)
if (!ok)
get_windows_error();
#endif
return ok;
}

View File

@ -46,12 +46,6 @@
#endif
#define IS_A_SEP(c) ((c) == A_PATH_SEP)
#ifdef USE_TRANSITIONAL_64_FILE_OPS
# define BIG_OFF_T_IZE(n) n ## 64
#else
# define BIG_OFF_T_IZE(n) n
#endif
#if defined(RKTIO_SYSTEM_UNIX) && !defined(NO_UNIX_USERS)
static int have_user_ids = 0;
static uid_t uid;

View File

@ -10,7 +10,6 @@ struct rktio_hash_t {
typedef struct bucket_t {
/* v is non-NULL => bucket is filled */
/* v is NULL and fd is -1 => was removed */
int used;
intptr_t key;
void *v;
} bucket_t;
@ -41,6 +40,19 @@ int rktio_hash_is_empty(rktio_hash_t *ht)
return (ht->count == 0);
}
intptr_t rktio_hash_size(rktio_hash_t *ht)
{
return ht->size;
}
intptr_t rktio_hash_get_key(rktio_hash_t *ht, intptr_t i)
{
if (ht->buckets[i].v)
return ht->buckets[i].key;
else
return -1;
}
static void do_rehash(rktio_hash_t *ht, intptr_t new_size)
{
if (new_size >= 16) {
@ -81,7 +93,7 @@ void *rktio_hash_get(rktio_hash_t *ht, intptr_t key)
return NULL;
}
void rktio_hash_remove(rktio_hash_t *ht, intptr_t key)
void rktio_hash_remove(rktio_hash_t *ht, intptr_t key, int dont_rehash)
{
if (ht->buckets) {
intptr_t mask = (ht->size - 1);
@ -93,8 +105,10 @@ void rktio_hash_remove(rktio_hash_t *ht, intptr_t key)
ht->buckets[hc].key = -1;
ht->buckets[hc].v = NULL;
--ht->count;
if (4 * ht->count <= ht->size)
do_rehash(ht, ht->size >> 1);
if (!dont_rehash) {
if (4 * ht->count <= ht->size)
do_rehash(ht, ht->size >> 1);
}
} else if (ht->buckets[hc].v
|| (ht->buckets[hc].key == -1)) {
/* keep looking */

View File

@ -82,12 +82,12 @@ void ltps_signal_handle(rktio_ltps_t *lt, rktio_ltps_handle_t *s)
lt->signaled = s;
}
void rktio_ltps_handle_set_data(rktio_ltps_t *lt, rktio_ltps_handle_t *s, void *data)
void rktio_ltps_handle_set_data(rktio_t *rktio, rktio_ltps_handle_t *s, void *data)
{
s->data = data;
}
void *rktio_ltps_handle_get_data(rktio_ltps_t *lt, rktio_ltps_handle_t *s)
void *rktio_ltps_handle_get_data(rktio_t *rktio, rktio_ltps_handle_t *s)
{
return s->data;
}
@ -131,6 +131,8 @@ int rktio_ltps_close(rktio_t *rktio, rktio_ltps_t *lt)
{
rktio_ltps_handle_t *s;
rktio_ltps_remove_all(rktio, lt);
while ((s = rktio_ltps_get_signaled_handle(rktio, lt)))
free(s);
@ -167,19 +169,17 @@ rktio_ltps_handle_t *rktio_ltps_get_signaled_handle(rktio_t *rktio, rktio_ltps_t
#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL)
static void log_kqueue_error(const char *action, int kr)
{
#if 0
if (kr < 0) {
fprintf(stderr, "%s error at %s: %d\n",
#ifdef HAVE_KQUEUE_SYSCALL
"kqueue",
#else
"epoll",
#endif
fprintf(stderr, "ltps error at %s: %d\n",
action, errno);
}
#endif
}
static void log_kqueue_fd(int fd, int flags)
{
/* ... "expected event %d %d" ... */
}
#endif
@ -254,6 +254,7 @@ rktio_ltps_handle_t *rktio_ltps_add(rktio_t *rktio, rktio_ltps_t *lt, rktio_fd_t
s = v->write_handle;
if (s) ltps_signal_handle(lt, s);
ltps_hash_remove(lt, fd);
/* `v` is freed below */
s = NULL;
# ifdef HAVE_KQUEUE_SYSCALL
{
@ -630,7 +631,7 @@ static void ltps_hash_set(rktio_ltps_t *lt, intptr_t fd, rktio_ltps_handle_pair_
static void ltps_hash_remove(rktio_ltps_t *lt, intptr_t fd)
{
rktio_hash_remove(lt->fd_handles, fd);
rktio_hash_remove(lt->fd_handles, fd, 0);
}
static void ltps_hash_init(rktio_ltps_t *lt)
@ -644,3 +645,29 @@ static void ltps_hash_free(rktio_ltps_t *lt)
}
#endif
void rktio_ltps_remove_all(rktio_t *rktio, rktio_ltps_t *lt)
{
#ifdef RKTIO_SYSTEM_UNIX
intptr_t sz, i;
sz = rktio_hash_size(lt->fd_handles);
for (i = 0; i < sz; i++) {
intptr_t fd;
fd = rktio_hash_get_key(lt->fd_handles, i);
if (fd != -1) {
rktio_ltps_handle_pair_t *v;
rktio_ltps_handle_t *s;
v = ltps_hash_get(lt, fd);
if (v) {
s = v->read_handle;
if (s) ltps_signal_handle(lt, s);
s = v->write_handle;
if (s) ltps_signal_handle(lt, s);
rktio_hash_remove(lt->fd_handles, fd, 1);
free(v);
}
}
}
#endif
}

View File

@ -726,7 +726,7 @@ rktio_addrinfo_lookup_t *rktio_start_addrinfo_lookup(rktio_t *rktio,
return start_lookup(rktio, lookup);
}
void rktio_free_addrinfo(rktio_t *rktio, rktio_addrinfo_t *a)
void rktio_addrinfo_free(rktio_t *rktio, rktio_addrinfo_t *a)
{
do_freeaddrinfo(RKTIO_AS_ADDRINFO(a));
}
@ -852,6 +852,38 @@ void rktio_winsock_done(rktio_t *rktio)
/* TCP sockets */
/*========================================================================*/
void rktio_socket_init(rktio_t *rktio, rktio_fd_t *rfd)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
#ifdef RKTIO_SYSTEM_UNIX
fcntl(s, F_SETFL, RKTIO_NONBLOCKING);
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
{
unsigned long ioarg = 1;
ioctlsocket(s, FIONBIO, &ioarg);
}
#endif
if (rktio_fd_is_udp(rktio, rfd)) {
#ifdef RKTIO_SYSTEM_UNIX
# ifdef SO_BROADCAST
{
int bc = 1;
setsockopt(s, SOL_SOCKET, SO_BROADCAST, &bc, sizeof(bc));
}
# endif
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
{
BOOL bc = 1;
setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)(&bc), sizeof(BOOL));
}
#endif
}
}
int rktio_socket_close(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_UNIX
@ -867,15 +899,19 @@ int rktio_socket_close(rktio_t *rktio, rktio_fd_t *rfd)
#endif
}
void rktio_socket_forget(rktio_t *rktio, rktio_fd_t *rfd)
void rktio_socket_own(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_UNIX
rktio_forget(rktio, rfd);
#ifdef RKTIO_SYSTEM_WINDOWS
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
REGISTER_SOCKET(s);
#endif
}
void rktio_socket_forget_owned(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_WINDOWS
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
UNREGISTER_SOCKET(s);
closesocket(s);
#endif
}
@ -947,19 +983,6 @@ int rktio_socket_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd)
#endif
}
static void init_socket(rktio_socket_t s)
{
#ifdef RKTIO_SYSTEM_UNIX
fcntl(s, F_SETFL, RKTIO_NONBLOCKING);
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
{
unsigned long ioarg = 1;
ioctlsocket(s, FIONBIO, &ioarg);
}
#endif
}
rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_UNIX
@ -980,8 +1003,7 @@ rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd)
get_socket_error();
return NULL;
}
REGISTER_SOCKET(nsocket);
return rktio_system_fd(rktio, nsocket, rktio_fd_modes(rktio, rfd));
return rktio_system_fd(rktio, nsocket, rktio_fd_modes(rktio, rfd) | RKTIO_OPEN_OWN);
#endif
}
@ -1137,9 +1159,7 @@ static rktio_connect_t *try_connect(rktio_t *rktio, rktio_connect_t *conn)
errno = status;
#endif
REGISTER_SOCKET(s);
conn->trying_fd = rktio_system_fd(rktio, s, RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE);
conn->trying_fd = rktio_system_fd(rktio, s, RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE | RKTIO_OPEN_OWN);
conn->inprogress = inprogress;
return conn;
@ -1212,8 +1232,6 @@ rktio_fd_t *rktio_connect_finish(rktio_t *rktio, rktio_connect_t *conn)
}
}
init_socket(rktio_fd_system_fd(rktio, rfd));
conn_free(conn);
return rfd;
@ -1519,7 +1537,7 @@ int rktio_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener)
return do_poll_accept_ready(rktio, listener, 0);
}
void rktio_poll_add_receive(rktio_t *rktio, rktio_listener_t *listener, rktio_poll_set_t *fds)
void rktio_poll_add_accept(rktio_t *rktio, rktio_listener_t *listener, rktio_poll_set_t *fds)
{
int i;
rktio_socket_t s;
@ -1562,10 +1580,7 @@ rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener)
RKTIO_WHEN_SET_SOCKBUF_SIZE(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(int)));
# endif
init_socket(s);
REGISTER_SOCKET(s);
return rktio_system_fd(rktio, s, RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE);
return rktio_system_fd(rktio, s, RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE | RKTIO_OPEN_OWN);
} else {
get_socket_error();
return NULL;
@ -1635,6 +1650,20 @@ char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd)
return get_numeric_strings(rktio, name, name_len);
}
char **rktio_listener_address(rktio_t *rktio, rktio_listener_t *lnr)
{
char name[RKTIO_SOCK_NAME_MAX_LEN];
rktio_sockopt_len_t name_len;
name_len = sizeof(name);
if (getsockname(lnr->s[0], (struct sockaddr *)name, &name_len)) {
get_socket_error();
return NULL;
}
return get_numeric_strings(rktio, name, name_len);
}
/*========================================================================*/
/* UDP */
/*========================================================================*/

View File

@ -898,7 +898,7 @@ rktio_poll_set_t *rktio_make_poll_set(rktio_t *rktio)
return fds;
}
void rktio_poll_set_close(rktio_t *rktio, rktio_poll_set_t *fds)
void rktio_poll_set_forget(rktio_t *rktio, rktio_poll_set_t *fds)
{
free_fdset_arrays(fds);
}

View File

@ -175,8 +175,11 @@ struct pollfd *rktio_get_poll_fd_array(rktio_poll_set_t *fds);
/* Network */
/*========================================================================*/
void rktio_socket_init(rktio_t *rktio, rktio_fd_t *rfd);
int rktio_socket_close(rktio_t *rktio, rktio_fd_t *rfd);
void rktio_socket_forget(rktio_t *rktio, rktio_fd_t *rfd);
void rktio_socket_own(rktio_t *rktio, rktio_fd_t *rfd);
void rktio_socket_forget_owned(rktio_t *rktio, rktio_fd_t *rfd);
rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd);
int rktio_socket_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd);
@ -235,9 +238,12 @@ rktio_hash_t *rktio_hash_new(void);
void rktio_hash_free(rktio_hash_t *ht, int free_values);
int rktio_hash_is_empty(rktio_hash_t *ht);
void *rktio_hash_get(rktio_hash_t *ht, intptr_t key);
void rktio_hash_remove(rktio_hash_t *ht, intptr_t key);
void rktio_hash_remove(rktio_hash_t *ht, intptr_t key, int dont_rehash);
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);
/*========================================================================*/
/* Misc */
/*========================================================================*/
@ -289,3 +295,13 @@ void rktio_init_wide(rktio_t *rktio);
#ifdef RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
void rktio_release_lockf(rktio_t *rktio, int fd);
#endif
#ifdef RKTIO_SYSTEM_UNIX
char **rktio_get_environ_array(void);
#endif
#ifdef USE_TRANSITIONAL_64_FILE_OPS
# define BIG_OFF_T_IZE(n) n ## 64
#else
# define BIG_OFF_T_IZE(n) n
#endif

View File

@ -1225,6 +1225,16 @@ static void CloseFileHandleForSubprocess(intptr_t *hs, int pos)
#endif
int rktio_process_allowed_flags(rktio_t *rktio)
{
int flags = (RKTIO_PROCESS_NEW_GROUP
| RKTIO_PROCESS_STDOUT_AS_STDERR);
#ifdef RKTIO_SYSTEM_WINDOWS
flags |= (RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE
| RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION)
#endif
}
/*========================================================================*/
/* Main process-creation function */
/*========================================================================*/
@ -1298,7 +1308,10 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
return NULL;
}
env = rktio_envvars_to_block(rktio, envvars);
if (envvars)
env = rktio_envvars_to_block(rktio, envvars);
else
env = NULL;
#if defined(RKTIO_SYSTEM_WINDOWS)
@ -1504,11 +1517,15 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
}
new_argv[i] = NULL;
if (!env)
env = rktio_get_environ_array();
err = MSC_IZE(execve)(command, new_argv, (char **)env);
if (err)
err = errno;
free(env);
if (envvars)
free(env);
/* If we get here it failed; give up */
@ -1583,6 +1600,11 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
return result;
}
int rktio_process_pid(rktio_t *rktio, rktio_process_t *sp)
{
return sp->pid;
}
#ifdef RKTIO_SYSTEM_UNIX
void rktio_close_fds_after_fork(int skip1, int skip2, int skip3)
{