diff --git a/racket/src/rktio/Makefile.in b/racket/src/rktio/Makefile.in index 00f6c0d617..a3ce9e2403 100644 --- a/racket/src/rktio/Makefile.in +++ b/racket/src/rktio/Makefile.in @@ -23,7 +23,9 @@ OBJS = rktio_fs.@LTO@ \ rktio_process.@LTO@ \ rktio_envvars.@LTO@ \ rktio_fs_change.@LTO@ \ + rktio_flock.@LTO@ \ rktio_error.@LTO@ \ + rktio_hash.@LTO@ \ rktio_wide.@LTO@ \ rktio_main.@LTO@ @@ -67,9 +69,15 @@ rktio_envvars.@LTO@: $(srcdir)/rktio_envvars.c $(RKTIO_HEADERS) rktio_fs_change.@LTO@: $(srcdir)/rktio_fs_change.c $(RKTIO_HEADERS) $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_fs_change.@LTO@ -c $(srcdir)/rktio_fs_change.c +rktio_flock.@LTO@: $(srcdir)/rktio_flock.c $(RKTIO_HEADERS) + $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_flock.@LTO@ -c $(srcdir)/rktio_flock.c + rktio_error.@LTO@: $(srcdir)/rktio_error.c $(RKTIO_HEADERS) $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.@LTO@ -c $(srcdir)/rktio_error.c +rktio_hash.@LTO@: $(srcdir)/rktio_hash.c $(RKTIO_HEADERS) + $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_hash.@LTO@ -c $(srcdir)/rktio_hash.c + rktio_wide.@LTO@: $(srcdir)/rktio_wide.c $(RKTIO_HEADERS) $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_wide.@LTO@ -c $(srcdir)/rktio_wide.c diff --git a/racket/src/rktio/demo.c b/racket/src/rktio/demo.c index b25b673b15..baa800f6db 100644 --- a/racket/src/rktio/demo.c +++ b/racket/src/rktio/demo.c @@ -933,6 +933,78 @@ int main(int argc, char **argv) rktio_fs_change_forget(rktio, fc); } + if (verbose) + printf("file lock\n"); + + { + int r; + rktio_fd_t *fd3, *fd4; + + fd = rktio_open(rktio, "test1", RKTIO_OPEN_READ); + check_valid(fd); + r = rktio_file_lock_try(rktio, fd, 0); + if (r == RKTIO_LOCK_ACQUIRED) { + if (verbose) + printf(" ... supported\n"); + + check_valid(rktio_file_unlock(rktio, fd)); + + fd2 = rktio_open(rktio, "test1", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST); + check_valid(fd2); + fd3 = rktio_open(rktio, "test1", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST); + check_valid(fd3); + fd4 = rktio_open(rktio, "test1", RKTIO_OPEN_READ); + check_valid(fd4); + + check_valid(rktio_file_lock_try(rktio, fd, 0) == RKTIO_LOCK_ACQUIRED); + + /* Redundant lock acquire: */ + check_valid(rktio_file_lock_try(rktio, fd, 0) == RKTIO_LOCK_ACQUIRED); +#if defined(RKTIO_SYSTEM_WINDOWS) + /* Balance unlocks (Windows only) */ + check_valid(rktio_file_unlock(rktio, fd2)); +#endif + + /* Ok to take another non-exclusive lock: */ + check_valid(rktio_file_lock_try(rktio, fd4, 0) == RKTIO_LOCK_ACQUIRED); + check_valid(rktio_file_unlock(rktio, fd4)); + + /* Can't take exlcusive lock right now: */ + check_valid(!rktio_file_lock_try(rktio, fd2, 1)); + + check_valid(rktio_file_unlock(rktio, fd)); + + /* Can take exlcusive lock now: */ + check_valid(rktio_file_lock_try(rktio, fd2, 1) == RKTIO_LOCK_ACQUIRED); + +#if !defined(RKTIO_SYSTEM_WINDOWS) + /* Redundant lock acquire (non-Windows) */ + check_valid(rktio_file_lock_try(rktio, fd2, 1) == RKTIO_LOCK_ACQUIRED); +#endif + + /* Can't take any lock now: */ + check_valid(!rktio_file_lock_try(rktio, fd, 0)); + check_valid(!rktio_file_lock_try(rktio, fd3, 1)); + + check_valid(rktio_file_unlock(rktio, fd2)); + + /* Shared lock ok again: */ + check_valid(rktio_file_lock_try(rktio, fd, 0) == RKTIO_LOCK_ACQUIRED); + + check_valid(rktio_file_unlock(rktio, fd)); + + rktio_close(rktio, fd2); + rktio_close(rktio, fd3); + rktio_close(rktio, fd4); + } else if ((r != RKTIO_LOCK_ERROR) + || (rktio_get_last_error_kind(rktio) != RKTIO_ERROR_KIND_RACKET) + || (rktio_get_last_error(rktio) != RKTIO_ERROR_UNSUPPORTED)) { + check_valid(r == RKTIO_LOCK_ACQUIRED); + } + + rktio_close(rktio, fd); + } + if (verbose) printf("done\n"); diff --git a/racket/src/rktio/rktio.h b/racket/src/rktio/rktio.h index 200706e19a..0bf2dcdbb7 100644 --- a/racket/src/rktio/rktio.h +++ b/racket/src/rktio/rktio.h @@ -65,6 +65,12 @@ int rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd); int rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd); int rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd); +#define RKTIO_LOCK_ERROR (-2) +#define RKTIO_LOCK_ACQUIRED 1 + +int rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl); +int rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd); + /*************************************************/ /* Network */ diff --git a/racket/src/rktio/rktio_config.h.in b/racket/src/rktio/rktio_config.h.in index 76108094a4..44283a24ff 100644 --- a/racket/src/rktio/rktio_config.h.in +++ b/racket/src/rktio/rktio_config.h.in @@ -35,3 +35,6 @@ typedef unsigned long uintptr_t; /* In case you want to avoid dynamic sizing of `fd_set` arrays: */ #undef RKTIO_STATIC_FDSET_SIZE + +/* In case you want to use fcntl for file locks */ +#undef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS diff --git a/racket/src/rktio/rktio_fd.c b/racket/src/rktio/rktio_fd.c index 9622830698..d26b1c48b5 100644 --- a/racket/src/rktio/rktio_fd.c +++ b/racket/src/rktio/rktio_fd.c @@ -310,7 +310,7 @@ int rktio_close(rktio_t *rktio, rktio_fd_t *rfd) #ifdef RKTIO_SYSTEM_UNIX # ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS if (!(rfd->modes & RKTIO_OPEN_SOCKET)) - release_lockf(rfd->fd); + rktio_release_lockf(rktio, rfd->fd); # endif rktio_reliably_close(rfd->fd); diff --git a/racket/src/rktio/rktio_flock.c b/racket/src/rktio/rktio_flock.c new file mode 100644 index 0000000000..c8040e2a6b --- /dev/null +++ b/racket/src/rktio/rktio_flock.c @@ -0,0 +1,244 @@ +#include "rktio.h" +#include "rktio_private.h" +#include +#include +#include + +#if defined(RKTIO_SYSTEM_UNIX) && !defined(USE_FCNTL_AND_FORK_FOR_FILE_LOCKS) +# define USE_FLOCK_FOR_FILE_LOCKS +#endif + +#ifdef USE_FLOCK_FOR_FILE_LOCKS +#include +#endif + +#if defined(USE_FCNTL_AND_FORK_FOR_FILE_LOCKS) +#include +#include +typedef struct pair_t { int car, cdr; } pair_t; +#endif + +int rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl) +{ +#ifdef RKTIO_SYSTEM_UNIX +# ifdef USE_FLOCK_FOR_FILE_LOCKS + { + intptr_t fd = rktio_fd_system_fd(rktio, rfd); + int ok; + + do { + ok = flock(fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB); + } while ((ok == -1) && (errno == EINTR)); + + if (ok == 0) + return RKTIO_LOCK_ACQUIRED; + + if (errno == EWOULDBLOCK) + return 0; + + get_posix_error(); + return RKTIO_LOCK_ERROR; + } +# elif defined(USE_FCNTL_AND_FORK_FOR_FILE_LOCKS) + /* An lockf() is cancelled if *any* file descriptor to the same file + is closed within the same process. We avoid that problem by forking + a new process whose only job is to use lockf(). */ + { + intptr_t fd = rktio_fd_system_fd(rktio, rfd); + int ifds[2], ofds[2], cr; + + if (rktio->locked_fd_process_map) + if (rktio_hash_get(rktio->locked_fd_process_map, fd)) + /* already have a lock */ + return RKTIO_LOCK_ACQUIRED; + + if (!pipe(ifds)) { + if (!pipe(ofds)) { + int pid; + +#ifdef SUBPROCESS_USE_FORK1 + pid = fork1(); +#else + pid = fork(); +#endif + + if (pid > 0) { + /* Original process: */ + int errid = 0; + + rktio_reliably_close(ifds[1]); + rktio_reliably_close(ofds[0]); + + do{ + cr = read(ifds[0], &errid, sizeof(int)); + } while ((cr == -1) && (errno == EINTR)); + if (cr == -1) + errid = errno; + + rktio_reliably_close(ifds[0]); + + if (errid) { + rktio_reliably_close(ofds[1]); + + if (errid == EAGAIN) + return 0; + else { + errno = errid; + get_posix_error(); + return RKTIO_LOCK_ERROR; + } + } else { + pair_t *pr; + + /* got lock; record fd -> pipe mapping */ + if (!rktio->locked_fd_process_map) { + rktio->locked_fd_process_map = rktio_hash_new(); + } + + pr = malloc(sizeof(pair_t)); + pr->car = ofds[1]; + pr->cdr = pid; + + rktio_hash_set(rktio->locked_fd_process_map, fd, pr); + return RKTIO_LOCK_ACQUIRED; + } + } else if (!pid) { + /* Child process */ + int ok = 0; + struct flock fl; + + rktio_reliably_close(ifds[0]); + rktio_reliably_close(ofds[1]); + rktio_close_fds_after_fork(ifds[1], ofds[0], fd); + + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = (excl ? F_WRLCK : F_RDLCK); + fl.l_whence = SEEK_SET; + fl.l_pid = getpid(); + + if (!fcntl(fd, F_SETLK, &fl)) { + /* report success: */ + do { + cr = write(ifds[1], &ok, sizeof(int)); + } while ((cr == -1) && (errno == EINTR)); + /* wait until a signal to exit: */ + do { + cr = read(ofds[0], &ok, sizeof(int)); + } while ((cr == -1) && (errno == EINTR)); + } + + if (!ok) { + int errid = errno; + do { + cr = write(ifds[1], &errid, sizeof(int)); + } while ((cr == -1) && (errno == EINTR)); + } + _exit(0); + } else { + /* Child process creation failed */ + get_posix_error(); + int i; + for (i = 0; i < 2; i++) { + rktio_reliably_close(ifds[i]); + rktio_reliably_close(ofds[i]); + } + return RKTIO_LOCK_ERROR; + } + } else { + /* Second pipe creation failed */ + int i; + get_posix_error(); + for (i = 0; i < 2; i++) { + rktio_reliably_close(ifds[i]); + } + return RKTIO_LOCK_ERROR; + } + } else { + /* First pipe creation failed */ + get_posix_error(); + return RKTIO_LOCK_ERROR; + } + } +# else + set_racket_error(RKTIO_ERROR_UNSUPPORTED); + return RKTIO_LOCK_ERROR; +# endif +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + { + HANDLE fd = (HANDLE)rktio_fd_system_fd(rktio, rfd); + OVERLAPPED o; + int errid; + +# define LOCK_ALL_FILE_LO 0 +# define LOCK_ALL_FILE_HI 0x10000 + + memset(&o, 0, sizeof(OVERLAPPED)); + if (LockFileEx(fd, + (LOCKFILE_FAIL_IMMEDIATELY + | (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0)), + 0, + LOCK_ALL_FILE_LO, LOCK_ALL_FILE_HI, + &o)) + return RKTIO_LOCK_ACQUIRED; + + errid = GetLastError(); + if (errid == ERROR_LOCK_VIOLATION) + return 0; + else { + get_windows_error(); + return RKTIO_LOCK_ERROR; + } + } +#endif +} + +#ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS +void rktio_release_lockf(rktio_t *rktio, int fd) +{ + if (rktio->locked_fd_process_map) { + pair_t *pr; + pr = rktio_hash_get(rktio->locked_fd_process_map, fd); + if (pr) { + int fd2, pid, status; + + fd2 = pr->car; + pid = pr->cdr; + rktio_hash_remove(rktio->locked_fd_process_map, fd); + free(pr); + + rktio_reliably_close(fd2); /* makes the fork()ed process exit */ + waitpid(pid, &status, 0); + } + } +} +#endif + +int rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd) +{ + intptr_t fd = rktio_fd_system_fd(rktio, rfd); + int ok; + +#ifdef RKTIO_SYSTEM_UNIX +# ifdef USE_FLOCK_FOR_FILE_LOCKS + do { + ok = flock(fd, LOCK_UN); + } while ((ok == -1) && (errno == EINTR)); + ok = !ok; + if (!ok) get_posix_error(); +# elif defined(USE_FCNTL_AND_FORK_FOR_FILE_LOCKS) + rktio_release_lockf(rktio, fd); + ok = 1; +# else + ok = 0; + set_racket_error(RKTIO_ERROR_UNSUPPORTED); +# endif +#endif +#ifdef WINDOWS_FILE_HANDLES + ok = UnlockFile((HANDLE)fd, 0, 0, LOCK_ALL_FILE_LO, LOCK_ALL_FILE_HI); + if (!ok) + get_windows_error(); +#endif + return ok; +} diff --git a/racket/src/rktio/rktio_hash.c b/racket/src/rktio/rktio_hash.c new file mode 100644 index 0000000000..7d4ac18ea6 --- /dev/null +++ b/racket/src/rktio/rktio_hash.c @@ -0,0 +1,140 @@ +#include "rktio.h" +#include "rktio_private.h" +#include + +struct rktio_hash_t { + struct bucket_t *buckets; + intptr_t size, count; +}; + +typedef struct bucket_t { + /* v is non-NULL => bucket is filled */ + /* v is NULL and fd is -1 => was removed */ + int used; + intptr_t key; + void *v; +} bucket_t; + +rktio_hash_t *rktio_hash_new(void) +{ + return calloc(1, sizeof(rktio_hash_t)); +} + +void rktio_hash_free(rktio_hash_t *ht, int free_values) +{ + if (ht->buckets) { + intptr_t i; + + if (free_values) { + for (i = ht->size; --i; ) { + if (ht->buckets[i].v) + free(ht->buckets[i].v); + } + } + + free(ht->buckets); + } +} + +int rktio_hash_is_empty(rktio_hash_t *ht) +{ + return (ht->count == 0); +} + +static void do_rehash(rktio_hash_t *ht, intptr_t new_size) +{ + if (new_size >= 16) { + bucket_t *old_buckets = ht->buckets; + intptr_t old_size = ht->size, i; + + ht->size = new_size; + ht->buckets = calloc(new_size, sizeof(bucket_t)); + ht->count = 0; + + for (i = old_size; --i; ) { + if (ht->buckets[i].v) + rktio_hash_set(ht, ht->buckets[i].key, ht->buckets[i].v); + } + + free(old_buckets); + } +} + +void *rktio_hash_get(rktio_hash_t *ht, intptr_t key) +{ + if (ht->buckets) { + intptr_t mask = (ht->size - 1); + intptr_t hc = key & mask; + intptr_t d = ((key >> 3) & mask) | 0x1; + + while (1) { + if (ht->buckets[hc].key == key) + return ht->buckets[hc].v; + else if (ht->buckets[hc].v + || (ht->buckets[hc].key == -1)) { + /* keep looking */ + hc = (hc + d) & mask; + } else + return NULL; + } + } else + return NULL; +} + +void rktio_hash_remove(rktio_hash_t *ht, intptr_t key) +{ + if (ht->buckets) { + intptr_t mask = (ht->size - 1); + intptr_t hc = key & mask; + intptr_t d = ((key >> 3) & mask) | 0x1; + + while (1) { + if (ht->buckets[hc].key == 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); + } else if (ht->buckets[hc].v + || (ht->buckets[hc].key == -1)) { + /* keep looking */ + hc = (hc + d) & mask; + } else + break; + } + } +} + +void rktio_hash_set(rktio_hash_t *ht, intptr_t key, void *v) +{ + if (!ht->buckets) { + ht->size = 16; + ht->buckets = calloc(ht->size, sizeof(bucket_t)); + } + + { + intptr_t mask = (ht->size - 1); + intptr_t hc = key & mask; + intptr_t d = ((key >> 3) & mask) | 0x1; + + while (1) { + if (ht->buckets[hc].v) { + if (ht->buckets[hc].key == -1) { + /* use bucket whose content ws previously removed */ + break; + } else { + /* keep looking for a spot */ + hc = (hc + d) & mask; + } + } else + break; + } + + ht->buckets[hc].key = key; + ht->buckets[hc].v = v; + ht->count++; + + if (2 * ht->count >= ht->size) + do_rehash(ht, ht->size << 1); + } +} diff --git a/racket/src/rktio/rktio_ltps.c b/racket/src/rktio/rktio_ltps.c index a2de75f69e..5c4cc64c40 100644 --- a/racket/src/rktio/rktio_ltps.c +++ b/racket/src/rktio/rktio_ltps.c @@ -21,6 +21,10 @@ #include #include +#ifdef RKTIO_SYSTEM_UNIX +# define LTPS_USE_HASH_TABLE +#endif + struct rktio_ltps_t { #if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL) int fd; @@ -29,9 +33,10 @@ struct rktio_ltps_t { #endif /* List of pending signaled handles: */ struct rktio_ltps_handle_t *signaled; +#ifdef LTPS_USE_HASH_TABLE /* Hash table mapping fds to handles */ - struct ltps_bucket_t *buckets; - intptr_t size, count; + rktio_hash_t *fd_handles; +#endif }; struct rktio_ltps_handle_t { @@ -44,15 +49,12 @@ typedef struct rktio_ltps_handle_pair_t { rktio_ltps_handle_t *write_handle; } rktio_ltps_handle_pair_t; -#ifdef RKTIO_SYSTEM_UNIX +#ifdef LTPS_USE_HASH_TABLE static rktio_ltps_handle_pair_t *ltps_hash_get(rktio_ltps_t *lt, intptr_t fd); static void ltps_hash_set(rktio_ltps_t *lt, intptr_t fd, rktio_ltps_handle_pair_t *v); static void ltps_hash_remove(rktio_ltps_t *lt, intptr_t fd); static void ltps_hash_init(rktio_ltps_t *lt); static void ltps_hash_free(rktio_ltps_t *lt); -#if !defined(HAVE_KQUEUE_SYSCALL) && !defined(HAVE_EPOLL_SYSCALL) -static int ltps_is_hash_empty(rktio_ltps_t *lt); -#endif #endif /*========================================================================*/ @@ -105,7 +107,7 @@ rktio_ltps_t *rktio_open_ltps(rktio_t *rktio) lt->signaled = NULL; -#ifdef RKTIO_SYSTEM_UNIX +#ifdef LTPS_USE_HASH_TABLE ltps_hash_init(lt); #endif @@ -132,7 +134,7 @@ int rktio_ltps_close(rktio_t *rktio, rktio_ltps_t *lt) while ((s = rktio_ltps_get_signaled_handle(rktio, lt))) free(s); -#ifdef RKTIO_SYSTEM_UNIX +#ifdef LTPS_USE_HASH_TABLE ltps_hash_free(lt); #endif @@ -495,7 +497,7 @@ int rktio_ltps_poll(rktio_t *rktio, rktio_ltps_t *lt) int key; int sr, hit = 0; - if (ltps_is_hash_empty(lt)) + if (rktio_hash_is_empty(lt->handle_map)) return 0; rktio_clean_fd_set(lt->fd_set); @@ -560,7 +562,7 @@ int rktio_ltps_poll(rktio_t *rktio, rktio_ltps_t *lt) RKTIO_FD_ZERO(set1); RKTIO_FD_ZERO(set2); - if (ltps_is_hash_empty(lt)) + if (rktio_hash_is_empty(lt->handle_map)) return 0; rktio_merge_fd_sets(fds, lt->fd_set); @@ -616,137 +618,29 @@ int rktio_ltps_poll(rktio_t *rktio, rktio_ltps_t *lt) #ifdef RKTIO_SYSTEM_UNIX -typedef struct ltps_bucket_t { - /* v is non-NULL => bucket is filled */ - /* v is NULL and fd is -1 => was removed */ - intptr_t fd; - rktio_ltps_handle_pair_t *v; -} ltps_bucket_t; - -static void ltps_rehash(rktio_ltps_t *lt, intptr_t new_size) -{ - if (new_size >= 16) { - ltps_bucket_t *old_buckets = lt->buckets; - intptr_t old_size = lt->size, i; - - lt->size = new_size; - lt->buckets = calloc(new_size, sizeof(ltps_bucket_t)); - lt->count = 0; - - for (i = old_size; --i; ) { - if (lt->buckets[i].v) - ltps_hash_set(lt, lt->buckets[i].fd, lt->buckets[i].v); - } - - free(old_buckets); - } -} - static rktio_ltps_handle_pair_t *ltps_hash_get(rktio_ltps_t *lt, intptr_t fd) { - if (lt->buckets) { - intptr_t mask = (lt->size - 1); - intptr_t hc = fd & mask; - intptr_t d = ((fd >> 3) & mask) | 0x1; - - while (1) { - if (lt->buckets[hc].fd == fd) - return lt->buckets[hc].v; - else if (lt->buckets[hc].v - || (lt->buckets[hc].fd == -1)) { - /* keep looking */ - hc = (hc + d) & mask; - } else - return NULL; - } - } else - return NULL; -} - -static void ltps_hash_remove(rktio_ltps_t *lt, intptr_t fd) -{ - if (lt->buckets) { - intptr_t mask = (lt->size - 1); - intptr_t hc = fd & mask; - intptr_t d = ((fd >> 3) & mask) | 0x1; - - while (1) { - if (lt->buckets[hc].fd == fd) { - lt->buckets[hc].fd = -1; - lt->buckets[hc].v = NULL; - --lt->count; - if (4 * lt->count <= lt->size) - ltps_rehash(lt, lt->size >> 1); - } else if (lt->buckets[hc].v - || (lt->buckets[hc].fd == -1)) { - /* keep looking */ - hc = (hc + d) & mask; - } else - break; - } - } + return (rktio_ltps_handle_pair_t *)rktio_hash_get(lt->fd_handles, fd); } static void ltps_hash_set(rktio_ltps_t *lt, intptr_t fd, rktio_ltps_handle_pair_t *v) { - if (!lt->buckets) { - lt->size = 16; - lt->buckets = calloc(lt->size, sizeof(ltps_bucket_t)); - } - - { - intptr_t mask = (lt->size - 1); - intptr_t hc = fd & mask; - intptr_t d = ((fd >> 3) & mask) | 0x1; - - while (1) { - if (lt->buckets[hc].v) { - if (lt->buckets[hc].fd == -1) { - /* use bucket whos content ws previouslt removed */ - break; - } else { - /* keep looking for a spot */ - hc = (hc + d) & mask; - } - } else - break; - } - - lt->buckets[hc].fd = fd; - lt->buckets[hc].v = v; - lt->count++; + rktio_hash_set(lt->fd_handles, fd, v); +} - if (2 * lt->count >= lt->size) - ltps_rehash(lt, lt->size << 1); - } +static void ltps_hash_remove(rktio_ltps_t *lt, intptr_t fd) +{ + rktio_hash_remove(lt->fd_handles, fd); } static void ltps_hash_init(rktio_ltps_t *lt) { - lt->buckets = NULL; - lt->size = 0; - lt->count = 0; + lt->fd_handles = rktio_hash_new(); } static void ltps_hash_free(rktio_ltps_t *lt) { - if (lt->buckets) { - intptr_t i; - - for (i = lt->size; --i; ) { - if (lt->buckets[i].v) - free(lt->buckets[i].v); - } - - free(lt->buckets); - } + rktio_hash_free(lt->fd_handles, 1); } -#if !defined(HAVE_KQUEUE_SYSCALL) && !defined(HAVE_EPOLL_SYSCALL) -static int ltps_is_hash_empty(rktio_ltps_t *lt) -{ - return (lt->count == 0); -} -#endif - #endif diff --git a/racket/src/rktio/rktio_private.h b/racket/src/rktio/rktio_private.h index f57aff05e6..291a8818c0 100644 --- a/racket/src/rktio/rktio_private.h +++ b/racket/src/rktio/rktio_private.h @@ -83,6 +83,10 @@ struct rktio_t { intptr_t wide_buffer_size; wchar_t *wide_buffer; #endif + +#ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS + struct rktio_hash_t *locked_fd_process_map; +#endif }; /*========================================================================*/ @@ -213,7 +217,22 @@ char *rktio_convert_from_wchar(const wchar_t *ws, int free_given); # define NARROW_PATH_copy_then_free(ws) rktio_convert_from_wchar(ws, 1) #endif - + +/*========================================================================*/ +/* Hash table */ +/*========================================================================*/ + +/* Maps keys that aren't -1 to non-NULL values */ + +typedef struct rktio_hash_t rktio_hash_t; + +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_set(rktio_hash_t *ht, intptr_t key, void *v); + /*========================================================================*/ /* Misc */ /*========================================================================*/ @@ -243,6 +262,7 @@ void rktio_set_windows_error(rktio_t *rktio, int errid); #ifdef RKTIO_SYSTEM_UNIX void rktio_reliably_close(intptr_t s); +void rktio_close_fds_after_fork(int skip1, int skip2, int skip3); #endif int rktio_system_fd_is_terminal(rktio_t *rktio, intptr_t fd); @@ -256,3 +276,7 @@ int rktio_winsock_init(rktio_t *rktio); void rktio_winsock_done(rktio_t *rktio); #endif void rktio_init_wide(rktio_t *rktio); + +#ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS +void rktio_release_lockf(rktio_t *rktio, int fd); +#endif diff --git a/racket/src/rktio/rktio_process.c b/racket/src/rktio/rktio_process.c index f1af4d7b5c..a34b4aee98 100644 --- a/racket/src/rktio/rktio_process.c +++ b/racket/src/rktio/rktio_process.c @@ -15,10 +15,6 @@ #define CENTRALIZED_SIGCHILD #endif -#ifdef RKTIO_SYSTEM_UNIX -static void close_fds_after_fork(int skip1, int skip2, int skip3); -#endif - /*========================================================================*/ /* Process data structure */ /*========================================================================*/ @@ -1486,7 +1482,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio, } } - close_fds_after_fork(0, 1, 2); + rktio_close_fds_after_fork(0, 1, 2); } /* Set real CWD: */ @@ -1588,7 +1584,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio, } #ifdef RKTIO_SYSTEM_UNIX -static void close_fds_after_fork(int skip1, int skip2, int skip3) +void rktio_close_fds_after_fork(int skip1, int skip2, int skip3) { int i;