rktio: add file locking
This commit is contained in:
parent
03c3655b1f
commit
c006e951f4
|
@ -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
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
244
racket/src/rktio/rktio_flock.c
Normal file
244
racket/src/rktio/rktio_flock.c
Normal file
|
@ -0,0 +1,244 @@
|
|||
#include "rktio.h"
|
||||
#include "rktio_private.h"
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 <sys/file.h>
|
||||
#endif
|
||||
|
||||
#if defined(USE_FCNTL_AND_FORK_FOR_FILE_LOCKS)
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
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;
|
||||
}
|
140
racket/src/rktio/rktio_hash.c
Normal file
140
racket/src/rktio/rktio_hash.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include "rktio.h"
|
||||
#include "rktio_private.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -21,6 +21,10 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user