rktio: repairs to kqueue-based fs-change events

This commit is contained in:
Matthew Flatt 2017-06-17 05:21:54 -06:00
parent a1cf37eb0f
commit c02eacd5d2
9 changed files with 150 additions and 71 deletions

View File

@ -792,8 +792,10 @@ Whether @var{close} is zero or not, closing the resulting ports
So, passing zero for @var{close} and also using the file descriptor
with other ports or with @cpp{scheme_fd_to_semaphore} will not work right.
@history["6.9.0.6" @elem{Changed ports to always unregister with @cpp{scheme_fd_to_semaphore},
since it's not safe to skip that step.}]}
@history[#:changed "6.9.0.6" @elem{Changed ports to always unregister
with @cpp{scheme_fd_to_semaphore},
since it's not safe to skip that
step.}]}
@function[(Scheme_Object* scheme_fd_to_semaphore

View File

@ -195,6 +195,7 @@ typedef struct Thread_Local_Variables {
struct Scheme_Object *scheme_orig_stderr_port_;
struct Scheme_Object *scheme_orig_stdin_port_;
struct rktio_ltps_t *scheme_semaphore_fd_set_;
struct Scheme_Object *fs_change_props_;
struct Scheme_Custodian *new_port_cust_;
char *read_string_byte_buffer_;
struct ITimer_Data *itimerdata_;
@ -589,6 +590,7 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL;
#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_semaphore_fd_set XOA (scheme_get_thread_local_variables()->scheme_semaphore_fd_set_)
#define fs_change_props XOA (scheme_get_thread_local_variables()->fs_change_props_)
#define new_port_cust XOA (scheme_get_thread_local_variables()->new_port_cust_)
#define read_string_byte_buffer XOA (scheme_get_thread_local_variables()->read_string_byte_buffer_)
#define itimerdata XOA (scheme_get_thread_local_variables()->itimerdata_)

View File

@ -534,6 +534,7 @@ static Scheme_Env *place_instance_init(void *stack_base, int initial_main_os_thr
scheme_init_error_escape_proc(NULL);
scheme_init_print_buffers_places();
scheme_init_thread_places();
scheme_init_fd_semaphores();
scheme_init_string_places();
scheme_init_logger();
scheme_init_eval_places();
@ -541,7 +542,6 @@ 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_fd_semaphores();
#ifndef DONT_USE_FOREIGN
scheme_init_foreign_places();
#endif
@ -647,10 +647,6 @@ void scheme_place_instance_destroy(int force)
else
scheme_run_atexit_closers_on_all(force_more_closed_after);
#ifdef WINDOWS_PROCESSES
scheme_release_process_job_object();
#endif
scheme_release_fd_semaphores();
scheme_release_file_descriptor();

View File

@ -4300,6 +4300,11 @@ Scheme_Object *scheme_file_unlock(int argc, Scheme_Object **argv)
/* filesystem change events */
/*========================================================================*/
static void filesystem_change_evt_fnl(void *fc, void *data)
{
scheme_filesystem_change_evt_cancel((Scheme_Object *)fc, NULL);
}
Scheme_Object *scheme_filesystem_change_evt(Scheme_Object *path, int flags, int signal_errs)
{
char *filename;
@ -4309,7 +4314,7 @@ Scheme_Object *scheme_filesystem_change_evt(Scheme_Object *path, int flags, int
"filesystem-change-evt",
NULL,
SCHEME_GUARD_FILE_EXISTS);
rfc = rktio_fs_change(scheme_rktio, filename);
rfc = rktio_fs_change(scheme_rktio, filename, scheme_semaphore_fd_set);
if (!rfc) {
if (scheme_last_error_is_racket(RKTIO_ERROR_UNSUPPORTED)) {
@ -4339,6 +4344,8 @@ Scheme_Object *scheme_filesystem_change_evt(Scheme_Object *path, int flags, int
mref = scheme_add_managed(NULL, (Scheme_Object *)fc, scheme_filesystem_change_evt_cancel, NULL, 1);
fc->mref = mref;
scheme_add_finalizer(fc, filesystem_change_evt_fnl, NULL);
return (Scheme_Object *)fc;
}
}
@ -4351,6 +4358,11 @@ void scheme_filesystem_change_evt_cancel(Scheme_Object *evt, void *ignored_data)
rktio_fs_change_forget(scheme_rktio, fc->rfc);
fc->rfc = NULL;
}
if (fc->mref) {
scheme_remove_managed(fc->mref, (Scheme_Object *)fc);
fc->mref = NULL;
}
}
static int filesystem_change_evt_ready(Scheme_Object *evt, Scheme_Schedule_Info *sinfo)
@ -4379,6 +4391,9 @@ void scheme_fs_change_properties(int *_supported, int *_scalable, int *_low_late
int props;
props = rktio_fs_change_properties(scheme_rktio);
if ((props & RKTIO_FS_CHANGE_NEED_LTPS) && !scheme_semaphore_fd_set)
props = 0;
*_supported = ((props & RKTIO_FS_CHANGE_SUPPORTED) ? 1 : 0);
*_scalable = ((props & RKTIO_FS_CHANGE_SCALABLE) ? 1 : 0);
*_low_latency = ((props & RKTIO_FS_CHANGE_LOW_LATENCY) ? 1 : 0);

View File

@ -389,7 +389,7 @@ SHARED_OK static char *embedding_banner;
SHARED_OK static Scheme_Object *vers_str;
SHARED_OK static Scheme_Object *banner_str;
SHARED_OK static Scheme_Object *fs_change_props;
THREAD_LOCAL_DECL(static Scheme_Object *fs_change_props);
READ_ONLY static Scheme_Object *complete_symbol, *continues_symbol, *aborts_symbol, *error_symbol;
@ -472,31 +472,6 @@ scheme_init_string (Scheme_Env *env)
REGISTER_SO(vers_str);
REGISTER_SO(banner_str);
REGISTER_SO(fs_change_props);
{
int supported, scalable, low_latency, file_level;
Scheme_Object *s;
scheme_fs_change_properties(&supported, &scalable, &low_latency, &file_level);
fs_change_props = scheme_make_vector(4, scheme_false);
if (supported) {
s = scheme_intern_symbol("supported");
SCHEME_VEC_ELS(fs_change_props)[0] = s;
}
if (scalable) {
s = scheme_intern_symbol("scalable");
SCHEME_VEC_ELS(fs_change_props)[1] = s;
}
if (low_latency) {
s = scheme_intern_symbol("low-latency");
SCHEME_VEC_ELS(fs_change_props)[2] = s;
}
if (file_level) {
s = scheme_intern_symbol("file-level");
SCHEME_VEC_ELS(fs_change_props)[3] = s;
}
SCHEME_SET_IMMUTABLE(fs_change_props);
}
vers_str = scheme_make_utf8_string(scheme_version());
SCHEME_SET_CHAR_STRING_IMMUTABLE(vers_str);
banner_str = scheme_make_utf8_string(scheme_banner());
@ -1014,6 +989,31 @@ scheme_init_string (Scheme_Env *env)
void scheme_init_string_places(void) {
REGISTER_SO(current_locale_name_ptr);
current_locale_name_ptr = (void *)xes_char_string;
REGISTER_SO(fs_change_props);
{
int supported, scalable, low_latency, file_level;
Scheme_Object *s;
scheme_fs_change_properties(&supported, &scalable, &low_latency, &file_level);
fs_change_props = scheme_make_vector(4, scheme_false);
if (supported) {
s = scheme_intern_symbol("supported");
SCHEME_VEC_ELS(fs_change_props)[0] = s;
}
if (scalable) {
s = scheme_intern_symbol("scalable");
SCHEME_VEC_ELS(fs_change_props)[1] = s;
}
if (low_latency) {
s = scheme_intern_symbol("low-latency");
SCHEME_VEC_ELS(fs_change_props)[2] = s;
}
if (file_level) {
s = scheme_intern_symbol("file-level");
SCHEME_VEC_ELS(fs_change_props)[3] = s;
}
SCHEME_SET_IMMUTABLE(fs_change_props);
}
}
/**********************************************************************/

View File

@ -909,12 +909,18 @@ int main(int argc, char **argv)
char *path = "test1";
rktio_fs_change_t *fc;
rktio_poll_set_t *ps;
rktio_ltps_t *lt;
double start;
if (verbose)
printf("fs change\n");
fc = rktio_fs_change(rktio, path);
if (rktio_fs_change_properties(rktio) & RKTIO_FS_CHANGE_NEED_LTPS)
lt = rktio_ltps_open(rktio);
else
lt = NULL;
fc = rktio_fs_change(rktio, path, lt);
check_valid(fc);
check_valid(!rktio_poll_fs_change_ready(rktio, fc));
@ -945,6 +951,9 @@ int main(int argc, char **argv)
rktio_poll_set_forget(rktio, ps);
rktio_fs_change_forget(rktio, fc);
if (lt)
rktio_ltps_close(rktio, lt);
}
if (verbose)

View File

@ -502,10 +502,20 @@ RKTIO_EXTERN int rktio_fs_change_properties(rktio_t *rktio);
#define RKTIO_FS_CHANGE_SCALABLE (1 << 1)
#define RKTIO_FS_CHANGE_LOW_LATENCY (1 << 2)
#define RKTIO_FS_CHANGE_FILE_LEVEL (1 << 3)
#define RKTIO_FS_CHANGE_NEED_LTPS (1 << 4)
typedef struct rktio_fs_change_t rktio_fs_change_t;
struct rktio_ltps_t; /* forward reference */
RKTIO_EXTERN rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, const char *path);
RKTIO_EXTERN rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, const char *path,
struct rktio_ltps_t *ltps);
/* Creates a filesystem-change tracker that reports changes in `path`
after creation of the tracker. The properties repotred by
`rktio_fs_change_properties` report various aspects of how the
tracket behaves. In particular, the `ltps` argument can be NULL
unless the `RKTIO_FS_CHANGE_NEED_LTPS` property is reported; if
`lt` is provided, then the tracker must be canceled or discovered
ready before `ltps` is closed. */
RKTIO_EXTERN void rktio_fs_change_forget(rktio_t *rktio, rktio_fs_change_t *fc);
@ -598,8 +608,8 @@ enum {
RKTIO_LTPS_REMOVE_VNODE
};
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 void rktio_ltps_handle_set_data(rktio_t *rktio, rktio_ltps_handle_t *h, void *data);
RKTIO_EXTERN void *rktio_ltps_handle_get_data(rktio_t *rktio, rktio_ltps_handle_t *h);
void rktio_ltps_remove_all(rktio_t *rktio, rktio_ltps_t *lt);
/* Removes all additions, signaling all handles. */
@ -610,6 +620,19 @@ RKTIO_EXTERN rktio_ok_t 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_ltps_handle_set_auto(rktio_t *rktio, rktio_ltps_handle_t *lth, int auto_mode);
/* An alternative to receiving the handle via `rktio_ltps_get_signaled_handle`;
have signaling automatically either zero the handle content (so the
client can detect signaling) or free the handle (bcause the client
is no longer watching it). If `auto_mode` is `RKTIO_LTPS_HANDLE_NONE`,
automatic handling is disabled for the handle. */
/* `auto_mode` values: */
enum {
RKTIO_LTPS_HANDLE_NONE,
RKTIO_LTPS_HANDLE_ZERO,
RKTIO_LTPS_HANDLE_FREE
};
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. */

View File

@ -52,7 +52,9 @@ int rktio_fs_change_properties(rktio_t *rktio)
#ifdef NO_FILESYSTEM_CHANGE_EVTS
#else
flags |= RKTIO_FS_CHANGE_SUPPORTED;
# if !defined(HAVE_KQUEUE_SYSCALL)
# if defined(HAVE_KQUEUE_SYSCALL)
flags |= RKTIO_FS_CHANGE_NEED_LTPS;
# else
flags |= RKTIO_FS_CHANGE_SCALABLE;
# endif
# if !defined(HAVE_INOTIFY_SYSCALL)
@ -66,12 +68,11 @@ int rktio_fs_change_properties(rktio_t *rktio)
return flags;
}
rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, const char *path)
rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, const char *path, rktio_ltps_t *lt)
{
int ok = 0;
#ifndef NO_FILESYSTEM_CHANGE_EVTS
# if defined(HAVE_KQUEUE_SYSCALL)
rktio_ltps_t *lt;
rktio_ltps_handle_t *lth;
# endif
#endif
@ -86,24 +87,30 @@ rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, const char *path)
#elif defined(FILESYSTEM_NEVER_CHANGES)
ok = 1;
#elif defined(HAVE_KQUEUE_SYSCALL)
do {
fd = open(path, RKTIO_BINARY, 0666);
} while ((fd == -1) && (errno == EINTR));
if (fd == -1)
get_posix_error();
else {
rktio_fd_t *rfd;
rfd = rktio_system_fd(rktio, fd, 0);
lt = rktio_ltps_open(rktio);
if (lt)
if (!lt) {
set_racket_error(RKTIO_ERROR_UNSUPPORTED);
ok = 0;
} else {
do {
fd = open(path, RKTIO_BINARY, 0666);
} while ((fd == -1) && (errno == EINTR));
if (fd == -1)
get_posix_error();
else {
rktio_fd_t *rfd;
rfd = rktio_system_fd(rktio, fd, 0);
lth = rktio_ltps_add(rktio, lt, rfd, RKTIO_LTPS_CREATE_VNODE);
if (!lt || !lth) {
if (lt)
rktio_ltps_close(rktio, lt);
rktio_reliably_close(fd);
} else
ok = 1;
rktio_forget(rktio, rfd);
if (!lth) {
rktio_reliably_close(fd);
} else {
/* Put any pointer in the handle, and set it to auto-handle mode
to clear the pointer if it gets signalled. */
rktio_ltps_handle_set_data(rktio, lth, lth);
rktio_ltps_handle_set_auto(rktio, lth, RKTIO_LTPS_HANDLE_ZERO);
ok = 1;
}
rktio_forget(rktio, rfd);
}
}
#elif defined(HAVE_INOTIFY_SYSCALL)
do_inotify_init(rktio);
@ -162,8 +169,18 @@ static void fs_change_release(rktio_t *rktio, rktio_fs_change_t *fc)
# elif defined(HAVE_INOTIFY_SYSCALL)
do_inotify_remove(rktio, fc->fd);
# elif defined(HAVE_KQUEUE_SYSCALL)
rktio_ltps_close(rktio, fc->lt); /* frees lth */
rktio_reliably_close(fc->fd);
if (rktio_ltps_handle_get_data(rktio, fc->lth)) {
/* Not zeroed, so never signaled. Change the auto behavior
to free the handle, and deregsiter the file descriptor. */
rktio_fd_t *rfd;
rktio_ltps_handle_set_auto(rktio, fc->lth, RKTIO_LTPS_HANDLE_FREE);
rfd = rktio_system_fd(rktio, fc->fd, 0);
(void)rktio_ltps_add(rktio, fc->lt, rfd, RKTIO_LTPS_REMOVE_VNODE);
rktio_close(rktio, rfd);
} else {
/* Was signaled, so we need to free it. */
free(fc->lth);
}
#endif
fc->done = 1;
@ -200,9 +217,11 @@ int rktio_poll_fs_change_ready(rktio_t *rktio, rktio_fs_change_t *fc)
return 0;
#elif defined(HAVE_KQUEUE_SYSCALL)
if (!fc->done) {
if (rktio_ltps_poll(rktio, fc->lt))
if (rktio_ltps_get_signaled_handle(rktio, fc->lt) == fc->lth)
fs_change_release(rktio, fc);
(void)rktio_ltps_poll(rktio, fc->lt);
if (!rktio_ltps_handle_get_data(rktio, fc->lth)) {
/* NULL value means that it was signaled; can free, etc. */
fs_change_release(rktio, fc);
}
}
return (fc->done ? RKTIO_POLL_READY : 0);

View File

@ -43,6 +43,7 @@ struct rktio_ltps_t {
};
struct rktio_ltps_handle_t {
int auto_mode;
void *data; /* arbitrary data from client */
struct rktio_ltps_handle_t *next; /* in signaled chain */
};
@ -75,6 +76,7 @@ rktio_ltps_handle_t *make_ltps_handle()
{
rktio_ltps_handle_t *s;
s = malloc(sizeof(rktio_ltps_handle_t));
s->auto_mode = RKTIO_LTPS_HANDLE_NONE;
s->data = NULL;
s->next = NULL;
return s;
@ -82,8 +84,18 @@ rktio_ltps_handle_t *make_ltps_handle()
void ltps_signal_handle(rktio_ltps_t *lt, rktio_ltps_handle_t *s)
{
s->next = lt->signaled;
lt->signaled = s;
switch (s->auto_mode) {
case RKTIO_LTPS_HANDLE_NONE:
s->next = lt->signaled;
lt->signaled = s;
break;
case RKTIO_LTPS_HANDLE_ZERO:
s->data = NULL;
break;
case RKTIO_LTPS_HANDLE_FREE:
free(s);
break;
}
}
void rktio_ltps_handle_set_data(rktio_t *rktio, rktio_ltps_handle_t *s, void *data)
@ -96,6 +108,11 @@ void *rktio_ltps_handle_get_data(rktio_t *rktio, rktio_ltps_handle_t *s)
return s->data;
}
void rktio_ltps_handle_set_auto(rktio_t *rktio, rktio_ltps_handle_t *s, int auto_mode)
{
s->auto_mode = auto_mode;
}
/*========================================================================*/
rktio_ltps_t *rktio_ltps_open(rktio_t *rktio)
@ -144,12 +161,8 @@ int rktio_ltps_close(rktio_t *rktio, rktio_ltps_t *lt)
#endif
#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL)
if (lt->fd >= 0) {
intptr_t rc;
do {
rc = close(lt->fd);
} while ((rc == -1) && (errno == EINTR));
}
if (lt->fd >= 0)
rktio_reliably_close(lt->fd);
free(lt);
#else
rktio_poll_set_forget(rktio, lt->fd_set);