rktio: add file locking

This commit is contained in:
Matthew Flatt 2017-06-13 09:38:27 -06:00
parent 03c3655b1f
commit c006e951f4
10 changed files with 521 additions and 134 deletions

View File

@ -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

View File

@ -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");

View File

@ -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 */

View File

@ -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

View File

@ -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);

View 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;
}

View 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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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;