rktio: first cut at moving Racket OS wrappers to a library

The world doesn't need yet another cross-platform I/O library, but
it's getting one. This one has exactly the things that Racket needs,
and pulling it out will make it reusable from other VMs while
improving the Racket code organization.

This first step just gets started.
This commit is contained in:
Matthew Flatt 2017-06-09 10:53:53 -06:00
parent 5d4bf33906
commit 64146e94dc
13 changed files with 9569 additions and 2 deletions

View File

@ -838,7 +838,8 @@ LDFLAGS
LIBS LIBS
CPPFLAGS CPPFLAGS
CPP' CPP'
ac_subdirs_all='foreign/libffi ' ac_subdirs_all='foreign/libffi
rktio '
# Initialize some variables set by options. # Initialize some variables set by options.
ac_init_help= ac_init_help=
@ -7150,6 +7151,9 @@ else
fi fi
makefiles="$makefiles foreign/Makefile" makefiles="$makefiles foreign/Makefile"
subdirs="$subdirs rktio"
# Remove any --enable or --disable arguments from `ac_configure_args': # Remove any --enable or --disable arguments from `ac_configure_args':
new_configure_args= new_configure_args=
fixup_prev= fixup_prev=

View File

@ -1,7 +1,7 @@
################################################################# #################################################################
# This is the source for the `configure' script, to be compiled # # This is the source for the `configure' script, to be compiled #
# by autoconf (use make-configure in this directory). # # by autoconf (use `make-configure` in this directory). #
################################################################# #################################################################
# Remember: # Remember:
@ -1938,6 +1938,8 @@ else
fi fi
makefiles="$makefiles foreign/Makefile" makefiles="$makefiles foreign/Makefile"
AC_CONFIG_SUBDIRS( rktio )
# Remove any --enable or --disable arguments from `ac_configure_args': # Remove any --enable or --disable arguments from `ac_configure_args':
new_configure_args= new_configure_args=
fixup_prev= fixup_prev=

View File

@ -10,6 +10,11 @@ if [ -e "$tgt" ]; then
fi fi
autoconf "$src" | racket "$0" > "$tgt" autoconf "$src" | racket "$0" > "$tgt"
chmod +x "$tgt" chmod +x "$tgt"
src="../rktio/configure.ac"
tgt="../rktio/configure"
echo "Creating $tgt from $src"
autoconf "$src" > "$tgt"
chmod +x "$tgt"
exit 0 exit 0
|# |#
#lang racket/base #lang racket/base

View File

@ -0,0 +1,21 @@
srcdir = @srcdir@
CC = @CC@
CFLAGS = @CFLAGS@ @CPPFLAGS@
RKTIO_HEADERS = $(srcdir)/rktio.h $(srcdir)/rktio_private.h rktio_config.h
all: rktio_filesystem.o rktio_read_write.o rktio_poll_set.o rktio_error.o
rktio_filesystem.o: $(srcdir)/rktio_filesystem.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_filesystem.o -c $(srcdir)/rktio_filesystem.c
rktio_read_write.o: $(srcdir)/rktio_read_write.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_read_write.o -c $(srcdir)/rktio_read_write.c
rktio_poll_set.o: $(srcdir)/rktio_poll_set.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_poll_set.o -c $(srcdir)/rktio_poll_set.c
rktio_error.o: $(srcdir)/rktio_error.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.o -c $(srcdir)/rktio_error.c

5110
racket/src/rktio/configure vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,196 @@
#################################################################
# This is the source for the `configure` script, to be compiled #
# by autoconf (use `make-configure` in "../racket"). #
#################################################################
AC_INIT([rktio.h])
AC_CONFIG_HEADERS([rktio_config.h])
AC_CONFIG_AUX_DIR(../lt)
AC_CANONICAL_SYSTEM
###### Autoconfigure #######
AC_PROG_CC
AC_CHECK_LIB(dl, dlopen)
############## platform tests ################
case "$host_os" in
*)
;;
esac
############## C flags ################
AC_LANG_C
AC_TYPE_INTPTR_T
AC_TYPE_UINTPTR_T
AC_MSG_CHECKING([for getaddrinfo])
AC_TRY_LINK([#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>],
[getaddrinfo(0, 0, 0, 0);],
AC_DEFINE(HAVE_GETADDRINFO,1,[Have getaddrinfo])
have_getaddrinfo=yes,
have_getaddrinfo=no)
AC_MSG_RESULT($have_getaddrinfo)
iconv_lib_flag=""
if test "${skip_iconv_check}" = "no" ; then
if test "${enable_iconv}" = "yes" ; then
AC_CHECK_HEADER(iconv.h, enable_iconv=yes, enable_iconv=no)
if test "${enable_iconv}" = "yes" ; then
# Does it all work, now?
AC_TRY_RUN(
[ #include <iconv.h>]
[ #include <langinfo.h>]
int main() {
[ iconv_open("UTF-8", "UTF-8");]
return 0;
}, enable_iconv=yes, enable_iconv=no, enable_iconv=yes)
if test "${enable_iconv}" = "no" ; then
# Try adding -liconv ?
# We did not use AC_CHECK_LIB because iconv is sometimes macro-renamed
ORIG_LIBS="$LIBS"
LIBS="$LIBS -liconv"
AC_TRY_RUN(
[ #include <iconv.h>]
[ #include <langinfo.h>]
int main() {
[ iconv_open("UTF-8", "UTF-8");]
return 0;
}, enable_iconv=yes, enable_iconv=no, enable_iconv=yes)
if test "${enable_iconv}" = "no" ; then
LIBS="$ORIG_LIBS"
else
iconv_lib_flag=" -liconv"
fi
fi
fi
fi
[ msg="iconv is usable" ]
AC_MSG_CHECKING($msg)
iconv_usage_result="$enable_iconv$iconv_lib_flag"
AC_MSG_RESULT($iconv_usage_result)
if test "${enable_iconv}" = "no" ; then
CFLAGS="$CFLAGS -DRKTIO_NO_ICONV"
fi
fi
[ msg="for mbsrtowcs" ]
AC_MSG_CHECKING($msg)
AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <wchar.h>
#include <strings.h>
int main() {
mbstate_t state;
char *src = "X";
bzero(&state, sizeof(mbstate_t));
mbsrtowcs(0, &src, 0, &state);
return 0;
}])], mbsrtowcs=yes, mbsrtowcs=no)
if test "$mbsrtowcs" = "no" ; then
CFLAGS="$CFLAGS -DNO_MBTOWC_FUNCTIONS"
fi
AC_MSG_RESULT($mbsrtowcs)
if test "${try_poll_syscall}" = "yes" ; then
[ msg="for poll" ]
AC_MSG_CHECKING($msg)
AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <poll.h>
int main() {
struct pollfd pfd;
int r;
pfd.fd = 0;
pfd.events = POLLIN;
r = poll(&pfd, 1, 0);
return 0;
}])], use_poll=yes, use_poll=no)
AC_MSG_RESULT($use_poll)
if test "${use_poll}" = "yes" ; then
AC_DEFINE(HAVE_POLL_SYSCALL,1,[Have poll])
fi
fi
if test "${try_epoll_syscall}" = "yes" ; then
[ msg="for epoll" ]
AC_MSG_CHECKING($msg)
AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <sys/epoll.h>
int main() {
int fd;
struct epoll_event ev;
fd = epoll_create(5);
ev.events = EPOLLIN | EPOLLONESHOT;
epoll_ctl(fd, EPOLL_CTL_ADD, 0, &ev);
return 0;
}])], use_epoll=yes, use_epoll=no)
AC_MSG_RESULT($use_epoll)
if test "${use_epoll}" = "yes" ; then
AC_DEFINE(HAVE_EPOLL_SYSCALL,1,[Have epoll])
fi
fi
if test "${try_inotify_syscall}" = "yes" ; then
[ msg="for inotify" ]
AC_MSG_CHECKING($msg)
AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <sys/inotify.h>
int main() {
int fd;
int wd;
fd = inotify_init();
wd = inotify_add_watch(fd, "/tmp",
(IN_CREATE | IN_DELETE | IN_DELETE_SELF
| IN_MODIFY | IN_MOVE_SELF | IN_MOVED_TO));
return 0;
}])], use_inotify=yes, use_inotify=no)
AC_MSG_RESULT($use_inotify)
if test "${use_inotify}" = "yes" ; then
AC_DEFINE(HAVE_INOTIFY_SYSCALL,1,[Have inotify])
fi
fi
if test "${try_kqueue_syscall}" = "yes" ; then
[ msg="for kqueue" ]
AC_MSG_CHECKING($msg)
AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
int main() {
int kq;
struct kevent kev;
struct timespec timeout = {0, 0};
kq = kqueue();
EV_SET(&kev, 0, EVFILT_READ, EV_ADD, 0, 0, NULL);
kevent(kq, &kev, 1, NULL, 0, &timeout);
return 0;
}])], use_kqueue=yes, use_kqueue=no)
AC_MSG_RESULT($use_kqueue)
if test "${use_kqueue}" = "yes" ; then
AC_DEFINE(HAVE_KQUEUE_SYSCALL,1,[Have kqueue])
fi
fi
LFS_CFLAGS=`getconf LFS_CFLAGS 2> /dev/null`
if test "${LFS_CFLAGS}" != "" && test "${LFS_CFLAGS}" != "undefined"; then
echo "Large-file support: ${LFS_CFLAGS}"
CFLAGS="${CFLAGS} ${LFS_CFLAGS}"
fi
############## final output ################
AC_SUBST(CC)
AC_SUBST(CFLAGS)
AC_SUBST(LDFLAGS)
makefiles="Makefile"
AC_OUTPUT($makefiles)

167
racket/src/rktio/rktio.h Normal file
View File

@ -0,0 +1,167 @@
#ifndef __RKTIO_H__
#define __RKTIO_H__
#include "rktio_config.h"
/*************************************************/
/* Reading and writing files */
typedef struct rktio_fd_t rktio_fd_t;
#define RKTIO_OPEN_READ (1<<0)
#define RKTIO_OPEN_WRITE (1<<1)
#define RKTIO_OPEN_TRUNCATE (1<<2)
#define RKTIO_OPEN_APPEND (1<<3)
#define RKTIO_OPEN_REPLACE (1<<4)
#define RKTIO_OPEN_MUST_EXIST (1<<5)
#define RKTIO_OPEN_CAN_EXIST (1<<6)
rktio_fd_t *rktio_fd(intptr_t system_fd, int modes);
rktio_fd_t *rktio_open(char *src, int modes);
int rktio_close(rktio_fd_t *fd);
#define RKTIO_READ_EOF (-1)
#define RKTIO_READ_ERROR (-2)
#define RKTIO_WRITE_ERROR (-2)
#define RKTIO_POLL_ERROR (-2)
intptr_t rktio_read(rktio_fd_t *fd, char *buffer, intptr_t len);
intptr_t rktio_write(rktio_fd_t *fd, char *buffer, intptr_t len);
int rktio_poll_read_ready(rktio_fd_t *rfd);
int rktio_poll_write_ready(rktio_fd_t *rfd);
int rktio_poll_write_flushed(rktio_fd_t *rfd);
/*************************************************/
/* File-descriptor sets */
typedef struct rktio_poll_set_t rktio_poll_set_t;
#define RKTIO_POLL_READ RKTIO_OPEN_READ
#define RKTIO_POLL_WRITE RKTIO_OPEN_WRITE
void rktio_poll_add(rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes);
/*************************************************/
/* Files, directories, and links */
int rktio_file_exists(char *filename);
int rktio_directory_exists(char *dirname);
int rktio_link_exists(char *filename);
int rktio_is_regular_file(char *filename);
int rktio_delete_file(char *fn, int enable_write_on_fail);
int rktio_rename_file(char *dest, char *src, int exists_ok);
char *rktio_get_current_directory();
int rktio_set_current_directory(char *expanded);
int rktio_make_directory(char *filename);
int rktio_delete_directory(char *filename, char *current_directory, int enable_write_on_fail);
char *rktio_readlink(char *fullfilename);
int rktio_make_link(char *src, char *dest, int dest_is_directory);
/*************************************************/
/* File attributes */
typedef struct {
unsigned lo, hi;
} rktio_size_t;
typedef intptr_t rktio_timestamp_t;
typedef struct {
uintptr_t a, b, c;
} rktio_identity_t;
rktio_size_t *rktio_file_size(char *filename);
rktio_timestamp_t *rktio_get_file_modify_seconds(char *file);
int rktio_set_file_modify_seconds(char *file, rktio_timestamp_t secs);
rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path);
/*************************************************/
/* Permissions */
/* Must match OS bits: */
#define RKTIO_PERMISSION_READ 0x1
#define RKTIO_PERMISSION_WRITE 0x2
#define RKTIO_PERMISSION_EXEC 0x4
int rktio_get_file_or_directory_permissions(char *filename, int all_bits);
int rktio_set_file_or_directory_permissions(char *filename, int new_bits);
/*************************************************/
/* Directory listing */
typedef struct rktio_directory_list_t rktio_directory_list_t;
rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive);
char *rktio_directory_list_step(rktio_directory_list_t *dl);
char **rktio_filesystem_root_list();
/*************************************************/
/* File copying */
typedef struct rktio_file_copy_t rktio_file_copy_t;
rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok);
int rktio_copy_file_is_done(rktio_file_copy_t *fc);
int rktio_copy_file_step(rktio_file_copy_t *fc);
void rktio_copy_file_stop(rktio_file_copy_t *fc);
/*************************************************/
/* System paths */
enum {
RKTIO_PATH_SYS_DIR,
RKTIO_PATH_TEMP_DIR,
RKTIO_PATH_PREF_DIR,
RKTIO_PATH_PREF_FILE,
RKTIO_PATH_ADDON_DIR,
RKTIO_PATH_HOME_DIR,
RKTIO_PATH_DESK_DIR,
RKTIO_PATH_DOC_DIR,
RKTIO_PATH_INIT_DIR,
RKTIO_PATH_INIT_FILE
};
char *rktio_system_path(int which);
char *rktio_expand_user_tilde(char *filename);
/*************************************************/
/* Errors */
/* Kinds of error values: */
enum {
RKTIO_ERROR_KIND_POSIX,
RKTIO_ERROR_KIND_WINDOWS,
RKTIO_ERROR_KIND_GAI,
RKTIO_ERROR_KIND_RACKET
};
/* Error IDs of kind RKTIO_ERROR_KIND_RACKET */
enum {
RKTIO_ERROR_UNSUPPORTED,
RKTIO_ERROR_EXISTS,
RKTIO_ERROR_LINK_FAILED,
RKTIO_ERROR_NOT_A_LINK,
RKTIO_ERROR_BAD_PERMISSION,
RKTIO_ERROR_IS_A_DIRECTORY,
RKTIO_ERROR_NOT_A_DIRECTORY,
RKTIO_ERROR_NO_TILDE,
RKTIO_ERROR_ILL_FORMED_USER,
RKTIO_ERROR_UNKNOWN_USER
};
int rktio_get_last_error(void);
int rktio_get_last_error_kind(void);
char *rktio_get_error_string(int kind, int errid);
/*************************************************/
#endif

View File

@ -0,0 +1,21 @@
/* Whether `intptr_t' is available. */
#undef HAVE_INTPTR_T
/* Whether `uintptr_t' is available. */
#undef HAVE_UINTPTR_T
#ifdef HAVE_INTPTR_T
# include <inttypes.h>
#endif
#ifndef HAVE_INTPTR_T
typedef long intptr_t;
#endif
#ifndef HAVE_UINTPTR_T
typedef unsigned long uintptr_t;
#endif
/* When poll(), epoll(), kqueue(), etc. is available: */
#undef HAVE_POLL_SYSCALL
#undef HAVE_EPOLL_SYSCALL
#undef HAVE_INOTIFY_SYSCALL
#undef HAVE_KQUEUE_SYSCALL

View File

@ -0,0 +1,44 @@
#include "rktio.h"
#include "rktio_private.h"
#ifdef RKTIO_SYSTEM_WINDOWS
# include <windows.h>
#endif
#include <errno.h>
THREAD_LOCAL_DECL(static intptr_t errid);
THREAD_LOCAL_DECL(static int errkind);
void rktio_get_posix_error(void)
{
errid = errno;
errkind = RKTIO_ERROR_KIND_POSIX;
}
void rktio_set_racket_error(int new_errid)
{
errid = new_errid;
errkind = RKTIO_ERROR_KIND_RACKET;
}
#ifdef RKTIO_SYSTEM_WINDOWS
void rktio_get_windows_error(void)
{
errid = GetLastError();
errkind = RKTIO_ERROR_KIND_WINDOWS;
}
#endif
int rktio_get_last_error(void)
{
return errid;
}
int rktio_get_last_error_kind(void)
{
return errkind;
}
char *rktio_get_error_string(int kind, int errid)
{
return "???";
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,779 @@
#include "rktio.h"
#include "rktio_private.h"
#ifdef RKTIO_SYSTEM_UNIX
# include <sys/select.h>
# include <unistd.h>
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
# include <windows.h>
#endif
#include <stdlib.h>
/* Generalize fd arrays (FD_SET, etc) with a runtime-determined size,
special hooks for Windows "descriptors" like even queues and
semaphores, etc. */
#ifdef USE_FAR_RKTIO_FDCALLS
THREAD_LOCAL_DECL(rktio_poll_set_t *rktio_global_poll_set);
#endif
void rktio_alloc_global_poll_set() {
#ifdef USE_FAR_RKTIO_FDCALLS
rktio_global_poll_set = rktio_alloc_fdset_array(3);
#endif
}
/************************************************************/
/* Poll variant */
/************************************************************/
#ifdef HAVE_POLL_SYSCALL
# define PFD_EXTRA_SPACE 1
struct rktio_poll_set_t {
struct rktio_fd_set_data_t *data;
rktio_poll_set_t *w;
rktio_poll_set_t *e;
int flags;
};
struct rktio_fd_set_data_t {
struct pollfd *pfd;
intptr_t size, count;
};
rktio_poll_set_t *rktio_alloc_fdset_array(int count)
{
struct rktio_fd_set_data_t *data;
rktio_poll_set_t *r, *w, *e;
struct pollfd *pfd;
data = malloc(sizeof(struct rktio_fd_set_data_t));
r = malloc(sizeof(struct rktio_poll_set_t));
w = malloc(sizeof(struct rktio_poll_set_t));
e = malloc(sizeof(struct rktio_poll_set_t));
r->w = w;
r->e = e;
r->data = data;
w->data = data;
e->data = data;
r->flags = POLLIN;
w->flags = POLLOUT;
e->flags = 0;
data->size = 32;
data->count = 0;
pfd = malloc(sizeof(struct pollfd) * (32 + PFD_EXTRA_SPACE));
data->pfd = pfd;
return data;
}
rktio_poll_set_t *rktio_init_fdset_array(rktio_poll_set_t *fdarray, int count)
{
((struct rktio_fd_set *)fdarray)->data->count = 0;
return fdarray;
}
rktio_poll_set_t *rktio_get_fdset(rktio_poll_set_t *fdarray, int pos)
{
switch (pos) {
case 0:
return fdarray;
case 1:
return fdarray->w;
case 2:
default:
return fdarray->e;
}
}
void rktio_fdzero(rktio_poll_set_t *fd)
{
fd->data->count = 0;
}
static int find_fd_pos(struct rktio_fd_set_data_t *data, int n)
{
intptr_t count = data->count;
intptr_t i;
/* This linear search probably isn't good enough for hundreds or
thousands of descriptors, but epoll()/kqueue() mode should handle
that case, anyway. */
for (i = 0; i < count; i++) {
if (data->pfd[i].fd == n) {
return i;
}
}
return -1;
}
void rktio_fdclr(rktio_poll_set_t *fd, int n)
{
struct rktio_fd_set_data_t *data = fd->data;
intptr_t flag = fd->flags;
intptr_t pos;
if (!flag) return;
pos = find_fd_pos(data, n);
if (pos >= 0) {
data->pfd[pos].events -= (data->pfd[pos].events & flag);
}
}
void rktio_fdset(rktio_poll_set_t *fd, int n)
{
struct rktio_fd_set_data_t *data = fd->data;
intptr_t flag = fd->flags;
intptr_t count, size, pos;
struct pollfd *pfd;
if (!flag) return;
pos = find_fd_pos(data, n);
if (pos >= 0) {
data->pfd[pos].events |= flag;
return;
}
count = data->count;
size = data->size;
if (count >= size) {
size = size * 2;
pfd = malloc(sizeof(struct pollfd) * (size + PFD_EXTRA_SPACE));
memcpy(pfd, data->pfd, sizeof(struct pollfd) * count);
free(data->pfd);
data->pfd = pfd;
data->size = size;
}
data->pfd[count].fd = n;
data->pfd[count].events = flag;
count++;
data->count = count;
}
int rktio_fdisset(rktio_poll_set_t *fd, int n)
{
struct rktio_fd_set_data_t *data = data->data;
intptr_t flag = fd->flags;
intptr_t pos;
if (!flag) flag = (POLLERR | POLLHUP);
pos = find_fd_pos(data, n);
if (pos >= 0) {
if (data->pfd[pos].revents & flag)
return 1;
else
return 0;
}
return 0;
}
static int cmp_fd(const void *_a, const void *_b)
{
struct pollfd *a = (struct pollfd *)_a;
struct pollfd *b = (struct pollfd *)_b;
return a->fd - b->fd;
}
rktio_poll_set_t *rktio_merge_fd_sets(rktio_poll_set_t *fds, rktio_poll_set_t *src_fds)
{
struct rktio_fd_set_data_t *data = fds->data;
struct rktio_fd_set_data_t *src_data = src_fds->data;
int i, si, c, sc, j, nc;
struct pollfd *pfds;
rktio_clean_fd_set(fds);
rktio_clean_fd_set(src_fds);
c = data->count;
sc = src_data->count;
if (!c)
return src_fds;
if (!sc)
return fds;
qsort(data->pfd, c, sizeof(struct pollfd), cmp_fd);
qsort(src_data->pfd, sc, sizeof(struct pollfd), cmp_fd);
nc = c + sc;
pfds = (struct pollfd *)rktio_malloc_atomic(sizeof(struct pollfd) * (nc + PFD_EXTRA_SPACE));
j = 0;
for (i = 0, si = 0; (i < c) && (si < sc); ) {
if (data->pfd[i].fd == src_data->pfd[si].fd) {
pfds[j].fd = data->pfd[i].fd;
pfds[j].events = (data->pfd[i].events | src_data->pfd[si].events);
i++;
si++;
} else if (data->pfd[i].fd < src_data->pfd[si].fd) {
pfds[j].fd = data->pfd[i].fd;
pfds[j].events = data->pfd[i].events;
i++;
} else {
pfds[j].fd = src_data->pfd[si].fd;
pfds[j].events = src_data->pfd[si].events;
si++;
}
j++;
}
for ( ; i < c; i++, j++) {
pfds[j].fd = data->pfd[i].fd;
pfds[j].events = data->pfd[i].events;
}
for ( ; si < sc; si++, j++) {
pfds[j].fd = src_data->pfd[si].fd;
pfds[j].events = src_data->pfd[si].events;
}
if (nc > RKTIO_INT_VAL(data->size)) {
data->pfd = pfds;
data->size = rktio_make_integer(nc);
} else
memcpy(data->pfd, pfds, j * sizeof(struct pollfd));
data->count = rktio_make_integer(j);
return fds;
}
void rktio_clean_fd_set(rktio_poll_set_t *fds)
{
struct rktio_fd_set_data_t *data = fds->data;
intptr_t count = data->count;
intptr_t i, j = 0;
for (i = 0; i < count; i++) {
if (data->pfd[i].events) {
if (j < i) {
data->pfd[j].fd = data->pfd[i].fd;
data->pfd[j].events = data->pfd[i].events;
}
j++;
}
}
count = j;
data->count = count;
}
int rktio_get_fd_limit(rktio_poll_set_t *fds)
{
return 0;
}
#elif defined(USE_DYNAMIC_FDSET_SIZE)
/************************************************************/
/* Variant with run-time determined fd_set length */
/************************************************************/
struct rktio_poll_set_t {
fd_set data;
};
/* initialized early via rktio_alloc_global_poll_set */
static int dynamic_fd_size;
# define STORED_ACTUAL_FDSET_LIMIT
# define FDSET_LIMIT(fd) (*(int *)((char *)fd + dynamic_fd_size))
rktio_poll_set_t *rktio_alloc_fdset_array(int count)
{
if (!dynamic_fd_size) {
# ifdef USE_ULIMIT
dynamic_fd_size = ulimit(4, 0);
# else
dynamic_fd_size = getdtablesize();
# endif
/* divide by bits-per-byte: */
dynamic_fd_size = (dynamic_fd_size + 7) >> 3;
/* word-align: */
if (dynamic_fd_size % sizeof(void*))
dynamic_fd_size += sizeof(void*) - (dynamic_fd_size % sizeof(void*));
}
return malloc(count * (dynamic_fd_size + sizeof(intptr_t)));
}
rktio_poll_set_t *rktio_init_fdset_array(rktio_poll_set_t *fdarray, int count)
{
return fdarray;
}
rktio_poll_set_t *rktio_get_fdset(rktio_poll_set_t *fdarray, int pos)
{
return (rktio_poll_set_t *)(((char *)fdarray) + (pos * (dynamic_fd_size + sizeof(intptr_t))));
}
void rktio_fdzero(rktio_poll_set_t *fd)
{
memset(fd, 0, dynamic_fd_size + sizeof(intptr_t));
}
#elif defined (RKTIO_SYSTEM_WINDOWS)
/************************************************************/
/* Windows variant */
/************************************************************/
typedef struct {
SOCKET *sockets;
intptr_t added, alloc, last_alloc;
intptr_t num_handles, alloc_handles, last_alloc_handles;
OS_SEMAPHORE_TYPE *handles;
int *repost_sema;
int no_sleep; /* boolean */
intptr_t wait_event_mask;
HANDLE *wait_array;
HANDLE *combined_wait_array;
intptr_t combined_len;
} rktio_poll_set_t;
rktio_poll_set_t *rktio_alloc_fdset_array(int count)
{
rktio_poll_set_t *fdarray;
if (count) {
fdarray = calloc(count, sizeof(rktio_poll_set_t));
rktio_init_fdset_array(fdarray, count);
} else
fdarray = NULL;
return fdarray;
}
static void reset_wait_array(rktio_poll_set_t *efd)
{
/* Allocate an array that may be big enough to hold all events
when we eventually call WaitForMultipleObjects. One of the three
arrays will be big enough. */
int sz = (3 * (efd->alloc + efd->alloc_handles)) + 2;
HANDLE *wa;
if (efd->wait_array) free(efd->wait_array);
wa = calloc(sz, sizeof(HANDLE));
efd->wait_array = wa;
}
rktio_poll_set_t *rktio_init_fdset_array(rktio_poll_set_t *fdarray, int count)
{
if (count) {
int i;
rktio_poll_set_t *fd;
for (i = 0; i < count; i++) {
int reset = 0;
fd = rktio_get_fdset(fdarray, i);
fd->added = 0;
if (RKTIO_INT_VAL(fd->alloc) > (2 * RKTIO_INT_VAL(fd->last_alloc))) {
fd->alloc = 0;
if (fd->sockets) free(fd->sockets);
fd->sockets = NULL;
reset = 1;
}
fd->last_alloc = 0;
fd->num_handles = 0;
if (RKTIO_INT_VAL(fd->alloc_handles) > (2 * RKTIO_INT_VAL(fd->last_alloc_handles))) {
fd->alloc_handles = 0;
if (fd->handles) free(fd->handles);
if (fd->repost_sema) free(fd->repost_sema);
fd->handles = NULL;
fd->repost_sema = NULL;
reset = 1;
}
fd->last_alloc_handles = 0;
fd->no_sleep = 0;
fd->wait_event_mask = 0;
if (reset)
reset_wait_array(fdarray);
}
}
}
rktio_poll_set_t *rktio_get_fdset(rktio_poll_set_t *fdarray, int pos)
{
return fdarray + pos;
}
void rktio_fdzero(rktio_poll_set_t *fd)
{
rktio_init_fdset_array(fd, 1);
}
void rktio_fdclr(rktio_poll_set_t *fd, int n)
{
int i;
for (i = fd->added; i--; ) {
if (fd->sockets[i] == n)
fd->sockets[i] = INVALID_SOCKET;
}
}
static int next_size(int v) { return (v ? (2 * v) : 10); }
void rktio_fdset(rktio_poll_set_t *fd, int n)
{
if (fd->added >= fd->last_alloc) {
int na;
na = next_size(fd->last_alloc);
efd->last_alloc = na;
}
if (fd->added >= fd->alloc) {
SOCKET *naya;
int na;
na = next_size(fd->alloc);
naya = malloc(na * sizeof(SOCKET));
memcpy(naya, fd->sockets, RKTIO_INT_VAL(fd->alloc) * sizeof(SOCKET));
if (fd->sockets) free(fd->sockets);
fd->sockets = naya;
fd->alloc = na;
reset_wait_array(fd);
}
fd->sockets[fd->added++] = n;
}
int rktio_fdisset(rktio_poll_set_t *fd, int n)
{
int i;
for (i = fd->added; i--; ) {
if (fd->sockets[i] == n)
return 1;
}
return 0;
}
rktio_poll_set_t *rktio_merge_fd_sets(rktio_poll_set_t *fds, rktio_poll_set_t *src_fds)
{
int i;
for (i = src_fd->added; i--; ) {
if (stv_fd->sockets[i] != INVALID_SOCKET)
rktio_fdset(fds, src_fd->sockets[i]);
}
return fds;
}
void rktio_clean_fd_set(rktio_poll_set_t *fds)
{
}
int rktio_get_fd_limit(rktio_poll_set_t *fds)
{
return 0;
}
void rktio_fdset_add_handle(HANDLE h, rktio_poll_set_t *fds, int repost)
{
rktio_poll_set_t *efd = fds;
OS_SEMAPHORE_TYPE *hs;
int i, new_i, *rps;
if (efd->num_handles == efd->last_alloc_handles) {
i = next_size(efd->last_alloc_handles);
efd->last_alloc_handles = 1;
}
if (efd->num_handles == efd->alloc_handles) {
i = efd->alloc_handles;
new_i = next_size(i);
hs = malloc(sizeof(HANDLE) * new_i);
rps = malloc(sizeof(int) * new_i);
memcpy(hs, efd->handles, sizeof(HANDLE)*i);
memcpy(rps, efd->repost_sema, sizeof(int)*i);
if (efd->handles) free(efd->handles);
if (efd->repost_sema) free(efd->repost_sema);
efd->handles = hs;
efd->repost_sema = rps;
efd->alloc_handles = new_i;
reset_wait_array(efd);
}
i = efd->num_handles;
efd->handles[i] = h;
efd->repost_sema[i] = repost;
efd->num_handles++;
}
void rktio_add_fd_nosleep(rktio_poll_set_t *fds)
{
fds->no_sleep = 1;
}
void rktio_fdset_add_eventmask(rktio_poll_set_t *fds, int mask)
{
fds->wait_event_mask |= mask;
}
void WSAEventSelect_plus_check(SOCKET s, WSAEVENT e, long mask)
{
fd_set rd[1], wr[1], ex[1];
struct timeval t = {0, 0};
WSAEventSelect(s, e, mask);
/* double-check with select(), because WSAEventSelect only
handles new activity (I think) */
FD_ZERO(rd);
FD_ZERO(wr);
FD_ZERO(ex);
if (mask & FD_READ)
FD_SET(s, rd);
if (mask & FD_WRITE)
FD_SET(s, wr);
if (mask & FD_OOB)
FD_SET(s, ex);
if (select(1, rd, wr, ex, &t)) {
/* already ready */
WSAEventSelect(s, NULL, 0);
SetEvent(e);
}
}
void rktio_collapse_win_fd(rktio_poll_set_t *fds)
{
rktio_poll_set_t *rfd, *wfd, *efd;
HANDLE *wa, e;
int i, p = 0, mask, j;
SOCKET s;
rfd = fds;
wfd = rktio_get_fdset(fds, 1);
efd = rktio_get_fdset(fds, 2);
if (rfd->combined_wait_array) {
/* clean up */
for (i = rfd->added; i--; ) {
if (rfd->sockets[i] != INVALID_SOCKET)
WSAEventSelect(rfd->sockets[i], NULL, 0);
}
for (i = wfd->added; i--; ) {
if (wfd->sockets[i] != INVALID_SOCKET)
WSAEventSelect(wfd->sockets[i], NULL, 0);
}
for (i = efd->added; i--; ) {
if (efd->sockets[i] != INVALID_SOCKET)
WSAEventSelect(efd->sockets[i], NULL, 0);
}
p = rfd->num_handles;
for (i = rfd->combined_len; i-- > p; ) {
WSACloseEvent(rfd->combined_wait_array[i]);
}
rfd->combined_wait_array = NULL;
} else {
/* merge */
if (rfd->alloc < RKTIO_INT_VAL(wfd->alloc)) {
if (wfd->alloc < efd->alloc)
wa = efd->wait_array;
else
wa = wfd->wait_array;
} else {
if (rfd->alloc < efd->alloc)
wa = efd->wait_array;
else
wa = rfd->wait_array;
}
rfd->combined_wait_array = wa;
p = rfd->num_handles;
for (i = 0; i < p; i++) {
wa[i] = rfd->handles[i];
}
for (i = rfd->added; i--; ) {
s = rfd->sockets[i];
if (s != INVALID_SOCKET) {
mask = FD_READ | FD_ACCEPT | FD_CLOSE;
for (j = wfd->added; j--; ) {
if (wfd->sockets[j] == s) {
mask |= FD_WRITE;
break;
}
}
for (j = efd->added; j--; ) {
if (efd->sockets[j] == s) {
mask |= FD_OOB;
break;
}
}
e = WSACreateEvent();
wa[p++] = e;
WSAEventSelect_plus_check(s, e, mask);
}
}
for (i = wfd->added; i--; ) {
s = wfd->sockets[i];
if (s != INVALID_SOCKET) {
mask = FD_WRITE | FD_CONNECT | FD_CLOSE;
for (j = rfd->added; j--; ) {
if (rfd->sockets[j] == s) {
mask = 0;
break;
}
}
if (mask) {
for (j = efd->added; j--; ) {
if (efd->sockets[j] == s) {
mask |= FD_OOB;
break;
}
}
e = WSACreateEvent();
wa[p++] = e;
WSAEventSelect_plus_check(s, e, mask);
}
}
}
for (i = efd->added; i--; ) {
s = efd->sockets[i];
if (s != INVALID_SOCKET) {
mask = FD_OOB | FD_CLOSE;
for (j = rfd->added; j--; ) {
if (rfd->sockets[j] == s) {
mask = 0;
break;
}
}
if (mask) {
for (j = wfd->added; j--; ) {
if (wfd->sockets[j] == s) {
mask = 0;
break;
}
}
if (mask) {
e = WSACreateEvent();
wa[p++] = e;
WSAEventSelect_plus_check(s, e, mask);
}
}
}
}
rfd->combined_len = p;
}
}
#else
/************************************************************/
/* Plain fd_set variant */
/************************************************************/
rktio_poll_set_t *rktio_alloc_fdset_array(int count)
{
return malloc(count * sizeof(fd_set));
}
rktio_poll_set_t *rktio_init_fdset_array(rktio_poll_set_t *fdarray, int count)
{
return fdarray;
}
rktio_poll_set_t *rktio_get_fdset(rktio_poll_set_t *fdarray, int pos)
{
return fdarray + pos;
}
void rktio_fdzero(rktio_poll_set_t *fd)
{
FD_ZERO(&(fd)->data);
}
void rktio_fdclr(rktio_poll_set_t *fd, int n)
{
FD_CLR(n, &(fd)->data);
}
void rktio_fdset(rktio_poll_set_t *fd, int n)
{
# ifdef STORED_ACTUAL_FDSET_LIMIT
int mx;
mx = FDSET_LIMIT(fd);
if (n > mx)
FDSET_LIMIT(fd) = n;
# endif
FD_SET(n, &(fd)->data);
}
int rktio_fdisset(rktio_poll_set_t *fd, int n)
{
return FD_ISSET(n, &(fd)->data);
}
rktio_poll_set_t *rktio_merge_fd_sets(rktio_poll_set_t *fds, rktio_poll_set_t *src_fds)
{
int i, j;
unsigned char *p, *sp;
for (j = 0; j < 3; j++) {
p = (unsigned char *)rktio_get_fdset(fds, j);
sp = (unsigned char *)rktio_get_fdset(src_fds, j);
# ifdef STORED_ACTUAL_FDSET_LIMIT
if (FDSET_LIMIT(sp) > FDSET_LIMIT(p)) {
i = FDSET_LIMIT(sp);
FDSET_LIMIT(p) = i;
}
# endif
# if defined(USE_DYNAMIC_FDSET_SIZE)
i = dynamic_fd_size;
# else
i = sizeof(fd_set);
# endif
for (; i--; p++, sp++) {
*p |= *sp;
}
}
return fds;
}
void rktio_clean_fd_set(rktio_poll_set_t *fds)
{
}
int rktio_get_fd_limit(rktio_poll_set_t *fds)
{
int actual_limit;
# ifdef STORED_ACTUAL_FDSET_LIMIT
actual_limit = FDSET_LIMIT(rd);
if (FDSET_LIMIT(wr) > actual_limit)
actual_limit = FDSET_LIMIT(wr);
if (FDSET_LIMIT(ex) > actual_limit)
actual_limit = FDSET_LIMIT(ex);
actual_limit++;
# elif defined (USE_ULIMIT)
actual_limit = ulimit(4, 0);
#elif defined(FIXED_FD_LIMIT)
actual_limit = FIXED_FD_LIMIT;
#else
actual_limit = getdtablesize();
# endif
return actual_limit;
}
#endif

View File

@ -0,0 +1,86 @@
#if ((defined(_MSC_VER) || defined(__MINGW32__)) \
&& (defined(__WIN32__) || defined(WIN32) || defined(_WIN32)))
# define RKTIO_SYSTEM_WINDOWS
# define MSC_IZE(n) _ ## n
# define MSC_W_IZE(n) _w ## n
# define MSC_WIDE_PATH_temp(n) WIDE_PATH_temp(n)
#else
# define RKTIO_SYSTEM_UNIX
# define MSC_IZE(n) n
# define MSC_W_IZE(n) MSC_IZE(n)
# define MSC_WIDE_PATH_temp(n) n
#endif
#define THREAD_LOCAL_DECL(decl) decl
void rktio_get_posix_error(void);
#define get_posix_error() rktio_get_posix_error()
void rktio_set_racket_error(int errid);
#define set_racket_error(e) rktio_set_racket_error(e)
#ifdef RKTIO_SYSTEM_WINDOWS
void rktio_get_windows_error(void);
# define get_windows_error() rktio_get_windows_error()
#endif
intptr_t rktio_fd_value(rktio_fd_t *fd);
/*******************************************************************/
typedef struct rktio_poll_set_t rktio_poll_set_t;
#if RKTIO_SYSTEM_WINDOWS
# define USE_FAR_RKTIO_FDCALLS
#endif
#ifdef USE_DYNAMIC_FDSET_SIZE
# define USE_FAR_RKTIO_FDCALLS
#endif
#ifdef HAVE_POLL_SYSCALL
# define USE_FAR_RKTIO_FDCALLS
#endif
#ifdef USE_FAR_RKTIO_FDCALLS
/* A single fdset that can be reused for immediate actions: */
THREAD_LOCAL_DECL(extern rktio_poll_set_t *rktio_global_fd_set);
# define DECL_FDSET(n, c) fd_set *n
# define INIT_DECL_FDSET(r, w, e) { \
r = RKTIO_GET_FDSET(rktio_global_poll_set, 0 ); \
w = RKTIO_GET_FDSET(rktio_global_poll_set, 1 ); \
e = RKTIO_GET_FDSET(rktio_global_poll_set, 2 ); \
}
# define INIT_DECL_RD_FDSET(r) r = RKTIO_GET_FDSET(rktio_global_poll_set, 0 )
# define INIT_DECL_WR_FDSET(r) r = RKTIO_GET_FDSET(rktio_global_poll_set, 1 )
# define INIT_DECL_ER_FDSET(r) r = RKTIO_GET_FDSET(rktio_global_poll_set, 2 )
# define RKTIO_GET_FDSET(p, n) rktio_get_fdset(p, n)
# define RKTIO_FD_ZERO(p) rktio_fdzero(p)
# define RKTIO_FD_SET(n, p) rktio_fdset(p, n)
# define RKTIO_FD_CLR(n, p) rktio_fdclr(p, n)
# define RKTIO_FD_ISSET(n, p) rktio_fdisset(p, n)
#else
#include <sys/select.h>
struct rktio_poll_set_t { fd_set data; };
# define DECL_FDSET(n, c) rktio_poll_set_t n[c]
# define INIT_DECL_FDSET(r, w, e) /* empty */
# define INIT_DECL_RD_FDSET(r) /* empty */
# define INIT_DECL_WR_FDSET(r) /* empty */
# define INIT_DECL_ER_FDSET(r) /* empty */
# define RKTIO_FDS(p) (&(p)->data)
# define RKTIO_GET_FDSET(p, n) ((p)+(n))
# define RKTIO_FD_ZERO(p) FD_ZERO(RKTIO_FDS(p))
# define RKTIO_FD_SET(n, p) FD_SET(n, RKTIO_FDS(p))
# define RKTIO_FD_CLR(n, p) FD_CLR(n, RKTIO_FDS(p))
# define RKTIO_FD_ISSET(n, p) FD_ISSET(n, RKTIO_FDS(p))
#endif
rktio_poll_set_t *rktio_merge_fd_sets(rktio_poll_set_t *fds, rktio_poll_set_t *src_fds);
void rktio_clean_fd_set(rktio_poll_set_t *fds);
int rktio_get_fd_limit(rktio_poll_set_t *fds);

File diff suppressed because it is too large Load Diff