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_process.@LTO@ \
|
||||||
rktio_envvars.@LTO@ \
|
rktio_envvars.@LTO@ \
|
||||||
rktio_fs_change.@LTO@ \
|
rktio_fs_change.@LTO@ \
|
||||||
|
rktio_flock.@LTO@ \
|
||||||
rktio_error.@LTO@ \
|
rktio_error.@LTO@ \
|
||||||
|
rktio_hash.@LTO@ \
|
||||||
rktio_wide.@LTO@ \
|
rktio_wide.@LTO@ \
|
||||||
rktio_main.@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)
|
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
|
$(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)
|
rktio_error.@LTO@: $(srcdir)/rktio_error.c $(RKTIO_HEADERS)
|
||||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.@LTO@ -c $(srcdir)/rktio_error.c
|
$(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)
|
rktio_wide.@LTO@: $(srcdir)/rktio_wide.c $(RKTIO_HEADERS)
|
||||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_wide.@LTO@ -c $(srcdir)/rktio_wide.c
|
$(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);
|
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)
|
if (verbose)
|
||||||
printf("done\n");
|
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_ready(rktio_t *rktio, rktio_fd_t *rfd);
|
||||||
int rktio_poll_write_flushed(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 */
|
/* Network */
|
||||||
|
|
||||||
|
|
|
@ -35,3 +35,6 @@ typedef unsigned long uintptr_t;
|
||||||
|
|
||||||
/* In case you want to avoid dynamic sizing of `fd_set` arrays: */
|
/* In case you want to avoid dynamic sizing of `fd_set` arrays: */
|
||||||
#undef RKTIO_STATIC_FDSET_SIZE
|
#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 RKTIO_SYSTEM_UNIX
|
||||||
# ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
# ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||||
if (!(rfd->modes & RKTIO_OPEN_SOCKET))
|
if (!(rfd->modes & RKTIO_OPEN_SOCKET))
|
||||||
release_lockf(rfd->fd);
|
rktio_release_lockf(rktio, rfd->fd);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
rktio_reliably_close(rfd->fd);
|
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 <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef RKTIO_SYSTEM_UNIX
|
||||||
|
# define LTPS_USE_HASH_TABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
struct rktio_ltps_t {
|
struct rktio_ltps_t {
|
||||||
#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL)
|
#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL)
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -29,9 +33,10 @@ struct rktio_ltps_t {
|
||||||
#endif
|
#endif
|
||||||
/* List of pending signaled handles: */
|
/* List of pending signaled handles: */
|
||||||
struct rktio_ltps_handle_t *signaled;
|
struct rktio_ltps_handle_t *signaled;
|
||||||
|
#ifdef LTPS_USE_HASH_TABLE
|
||||||
/* Hash table mapping fds to handles */
|
/* Hash table mapping fds to handles */
|
||||||
struct ltps_bucket_t *buckets;
|
rktio_hash_t *fd_handles;
|
||||||
intptr_t size, count;
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rktio_ltps_handle_t {
|
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_t *write_handle;
|
||||||
} rktio_ltps_handle_pair_t;
|
} 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 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_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_remove(rktio_ltps_t *lt, intptr_t fd);
|
||||||
static void ltps_hash_init(rktio_ltps_t *lt);
|
static void ltps_hash_init(rktio_ltps_t *lt);
|
||||||
static void ltps_hash_free(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
|
#endif
|
||||||
|
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
|
@ -105,7 +107,7 @@ rktio_ltps_t *rktio_open_ltps(rktio_t *rktio)
|
||||||
|
|
||||||
lt->signaled = NULL;
|
lt->signaled = NULL;
|
||||||
|
|
||||||
#ifdef RKTIO_SYSTEM_UNIX
|
#ifdef LTPS_USE_HASH_TABLE
|
||||||
ltps_hash_init(lt);
|
ltps_hash_init(lt);
|
||||||
#endif
|
#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)))
|
while ((s = rktio_ltps_get_signaled_handle(rktio, lt)))
|
||||||
free(s);
|
free(s);
|
||||||
|
|
||||||
#ifdef RKTIO_SYSTEM_UNIX
|
#ifdef LTPS_USE_HASH_TABLE
|
||||||
ltps_hash_free(lt);
|
ltps_hash_free(lt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -495,7 +497,7 @@ int rktio_ltps_poll(rktio_t *rktio, rktio_ltps_t *lt)
|
||||||
int key;
|
int key;
|
||||||
int sr, hit = 0;
|
int sr, hit = 0;
|
||||||
|
|
||||||
if (ltps_is_hash_empty(lt))
|
if (rktio_hash_is_empty(lt->handle_map))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rktio_clean_fd_set(lt->fd_set);
|
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(set1);
|
||||||
RKTIO_FD_ZERO(set2);
|
RKTIO_FD_ZERO(set2);
|
||||||
|
|
||||||
if (ltps_is_hash_empty(lt))
|
if (rktio_hash_is_empty(lt->handle_map))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rktio_merge_fd_sets(fds, lt->fd_set);
|
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
|
#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)
|
static rktio_ltps_handle_pair_t *ltps_hash_get(rktio_ltps_t *lt, intptr_t fd)
|
||||||
{
|
{
|
||||||
if (lt->buckets) {
|
return (rktio_ltps_handle_pair_t *)rktio_hash_get(lt->fd_handles, fd);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ltps_hash_set(rktio_ltps_t *lt, intptr_t fd, rktio_ltps_handle_pair_t *v)
|
static void ltps_hash_set(rktio_ltps_t *lt, intptr_t fd, rktio_ltps_handle_pair_t *v)
|
||||||
{
|
{
|
||||||
if (!lt->buckets) {
|
rktio_hash_set(lt->fd_handles, fd, v);
|
||||||
lt->size = 16;
|
}
|
||||||
lt->buckets = calloc(lt->size, sizeof(ltps_bucket_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
static void ltps_hash_remove(rktio_ltps_t *lt, intptr_t fd)
|
||||||
intptr_t mask = (lt->size - 1);
|
{
|
||||||
intptr_t hc = fd & mask;
|
rktio_hash_remove(lt->fd_handles, fd);
|
||||||
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++;
|
|
||||||
|
|
||||||
if (2 * lt->count >= lt->size)
|
|
||||||
ltps_rehash(lt, lt->size << 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ltps_hash_init(rktio_ltps_t *lt)
|
static void ltps_hash_init(rktio_ltps_t *lt)
|
||||||
{
|
{
|
||||||
lt->buckets = NULL;
|
lt->fd_handles = rktio_hash_new();
|
||||||
lt->size = 0;
|
|
||||||
lt->count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ltps_hash_free(rktio_ltps_t *lt)
|
static void ltps_hash_free(rktio_ltps_t *lt)
|
||||||
{
|
{
|
||||||
if (lt->buckets) {
|
rktio_hash_free(lt->fd_handles, 1);
|
||||||
intptr_t i;
|
|
||||||
|
|
||||||
for (i = lt->size; --i; ) {
|
|
||||||
if (lt->buckets[i].v)
|
|
||||||
free(lt->buckets[i].v);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(lt->buckets);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
#endif
|
||||||
|
|
|
@ -83,6 +83,10 @@ struct rktio_t {
|
||||||
intptr_t wide_buffer_size;
|
intptr_t wide_buffer_size;
|
||||||
wchar_t *wide_buffer;
|
wchar_t *wide_buffer;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||||
|
struct rktio_hash_t *locked_fd_process_map;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
|
@ -214,6 +218,21 @@ char *rktio_convert_from_wchar(const wchar_t *ws, int free_given);
|
||||||
|
|
||||||
#endif
|
#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 */
|
/* Misc */
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
|
@ -243,6 +262,7 @@ void rktio_set_windows_error(rktio_t *rktio, int errid);
|
||||||
|
|
||||||
#ifdef RKTIO_SYSTEM_UNIX
|
#ifdef RKTIO_SYSTEM_UNIX
|
||||||
void rktio_reliably_close(intptr_t s);
|
void rktio_reliably_close(intptr_t s);
|
||||||
|
void rktio_close_fds_after_fork(int skip1, int skip2, int skip3);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int rktio_system_fd_is_terminal(rktio_t *rktio, intptr_t fd);
|
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);
|
void rktio_winsock_done(rktio_t *rktio);
|
||||||
#endif
|
#endif
|
||||||
void rktio_init_wide(rktio_t *rktio);
|
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
|
#define CENTRALIZED_SIGCHILD
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef RKTIO_SYSTEM_UNIX
|
|
||||||
static void close_fds_after_fork(int skip1, int skip2, int skip3);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
/* Process data structure */
|
/* 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: */
|
/* Set real CWD: */
|
||||||
|
@ -1588,7 +1584,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RKTIO_SYSTEM_UNIX
|
#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;
|
int i;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user