diff --git a/racket/src/racket/include/scheme.h b/racket/src/racket/include/scheme.h index a2e362ee63..409eee44cb 100644 --- a/racket/src/racket/include/scheme.h +++ b/racket/src/racket/include/scheme.h @@ -2141,34 +2141,11 @@ extern Scheme_Extension_Table *scheme_extension_table; /* file descriptors */ /*========================================================================*/ -#if defined(DETECT_WIN32_CONSOLE_STDIN) || defined(WINDOWS_PROCESSES) -# ifndef NO_STDIO_THREADS -# define USE_FAR_MZ_FDCALLS -# endif -#endif -#ifdef USE_DYNAMIC_FDSET_SIZE -# define USE_FAR_MZ_FDCALLS -#endif -#ifdef USE_BEOS_PORT_THREADS -# define USE_FAR_MZ_FDCALLS -#endif -#ifdef HAVE_POLL_SYSCALL -# define USE_FAR_MZ_FDCALLS -#endif - -#ifdef USE_FAR_MZ_FDCALLS # define MZ_GET_FDSET(p, n) scheme_get_fdset(p, n) # define MZ_FD_ZERO(p) scheme_fdzero(p) # define MZ_FD_SET(n, p) scheme_fdset(p, n) # define MZ_FD_CLR(n, p) scheme_fdclr(p, n) # define MZ_FD_ISSET(n, p) scheme_fdisset(p, n) -#else -# define MZ_GET_FDSET(p, n) ((void *)(((fd_set *)p) XFORM_OK_PLUS n)) -# define MZ_FD_ZERO(p) XFORM_HIDE_EXPR(FD_ZERO((fd_set *)(p))) -# define MZ_FD_SET(n, p) FD_SET(n, (fd_set *)(p)) -# define MZ_FD_CLR(n, p) FD_CLR(n, (fd_set *)(p)) -# define MZ_FD_ISSET(n, p) FD_ISSET(n, (fd_set *)(p)) -#endif /* For scheme_fd_to_semaphore(): */ #define MZFD_CREATE_READ 1 @@ -2176,9 +2153,6 @@ extern Scheme_Extension_Table *scheme_extension_table; #define MZFD_CHECK_READ 3 #define MZFD_CHECK_WRITE 4 #define MZFD_REMOVE 5 -#define MZFD_CREATE_VNODE 6 -#define MZFD_CHECK_VNODE 7 -#define MZFD_REMOVE_VNODE 8 /*========================================================================*/ diff --git a/racket/src/racket/include/schthread.h b/racket/src/racket/include/schthread.h index c5ffec59fa..0fe3996d8f 100644 --- a/racket/src/racket/include/schthread.h +++ b/racket/src/racket/include/schthread.h @@ -194,21 +194,11 @@ typedef struct Thread_Local_Variables { struct Scheme_Object *scheme_orig_stdout_port_; struct Scheme_Object *scheme_orig_stderr_port_; struct Scheme_Object *scheme_orig_stdin_port_; - struct mz_fd_set *scheme_fd_set_; - struct mz_fd_set *scheme_semaphore_fd_set_; - struct Scheme_Hash_Table *scheme_semaphore_fd_mapping_; - int scheme_semaphore_fd_kqueue_; + struct rktio_ltps_t *scheme_semaphore_fd_set_; #ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS struct Scheme_Hash_Table *locked_fd_process_map_; #endif struct Scheme_Custodian *new_port_cust_; -#if (defined(__WIN32__) || defined(WIN32) || defined(_WIN32)) - void *scheme_break_semaphore_; - void *process_job_object_; -#else - int external_event_fd_; - int put_external_event_fd_; -#endif char *read_string_byte_buffer_; struct ITimer_Data *itimerdata_; char *quick_buffer_; @@ -380,7 +370,6 @@ typedef struct Thread_Local_Variables { void *on_atomic_timeout_data_; int atomic_timeout_auto_suspend_; int atomic_timeout_atomic_level_; - void *scheme_inotify_server_; struct Scheme_Object *configuration_callback_cache_[2]; struct FFI_Orig_Place_Call *cached_orig_place_todo_; struct Scheme_Hash_Table *ffi_lock_ht_; @@ -602,16 +591,9 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL; #define scheme_orig_stdout_port XOA (scheme_get_thread_local_variables()->scheme_orig_stdout_port_) #define scheme_orig_stderr_port XOA (scheme_get_thread_local_variables()->scheme_orig_stderr_port_) #define scheme_orig_stdin_port XOA (scheme_get_thread_local_variables()->scheme_orig_stdin_port_) -#define scheme_fd_set XOA (scheme_get_thread_local_variables()->scheme_fd_set_) #define scheme_semaphore_fd_set XOA (scheme_get_thread_local_variables()->scheme_semaphore_fd_set_) -#define scheme_semaphore_fd_mapping XOA (scheme_get_thread_local_variables()->scheme_semaphore_fd_mapping_) -#define scheme_semaphore_fd_kqueue XOA (scheme_get_thread_local_variables()->scheme_semaphore_fd_kqueue_) #define locked_fd_process_map XOA (scheme_get_thread_local_variables()->locked_fd_process_map_) #define new_port_cust XOA (scheme_get_thread_local_variables()->new_port_cust_) -#define scheme_break_semaphore XOA (scheme_get_thread_local_variables()->scheme_break_semaphore_) -#define process_job_object XOA (scheme_get_thread_local_variables()->process_job_object_) -#define external_event_fd XOA (scheme_get_thread_local_variables()->external_event_fd_) -#define put_external_event_fd XOA (scheme_get_thread_local_variables()->put_external_event_fd_) #define read_string_byte_buffer XOA (scheme_get_thread_local_variables()->read_string_byte_buffer_) #define itimerdata XOA (scheme_get_thread_local_variables()->itimerdata_) #define quick_buffer XOA (scheme_get_thread_local_variables()->quick_buffer_) @@ -784,7 +766,6 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL; #define on_atomic_timeout_data XOA (scheme_get_thread_local_variables()->on_atomic_timeout_data_) #define atomic_timeout_auto_suspend XOA (scheme_get_thread_local_variables()->atomic_timeout_auto_suspend_) #define atomic_timeout_atomic_level XOA (scheme_get_thread_local_variables()->atomic_timeout_atomic_level_) -#define scheme_inotify_server XOA (scheme_get_thread_local_variables()->scheme_inotify_server_) #define configuration_callback_cache XOA (scheme_get_thread_local_variables()->configuration_callback_cache_) #define cached_orig_place_todo XOA (scheme_get_thread_local_variables()->cached_orig_place_todo_) #define ffi_lock_ht XOA (scheme_get_thread_local_variables()->ffi_lock_ht_) diff --git a/racket/src/racket/src/Makefile.in b/racket/src/racket/src/Makefile.in index 76528c1549..e7d7aad77c 100644 --- a/racket/src/racket/src/Makefile.in +++ b/racket/src/racket/src/Makefile.in @@ -398,7 +398,7 @@ optimize.@LTO@: $(COMMON_HEADERS) \ $(srcdir)/stypes.h $(srcdir)/mzmark_optimize.inc place.@LTO@: $(COMMON_HEADERS) \ $(srcdir)/stypes.h $(srcdir)/schfd.h $(srcdir)/mzmark_place.inc -port.@LTO@: $(COMMON_HEADERS) \ +port.@LTO@: $(COMMON_HEADERS) $(RKTIO_HEADERS) \ $(srcdir)/stypes.h $(srcdir)/schfd.h $(srcdir)/mzmark_port.inc \ $(srcdir)/inotify.inc portfun.@LTO@: $(COMMON_HEADERS) $(srcdir)/schvers.h \ diff --git a/racket/src/racket/src/env.c b/racket/src/racket/src/env.c index 8684702f6e..3fa3ba2f32 100644 --- a/racket/src/racket/src/env.c +++ b/racket/src/racket/src/env.c @@ -554,7 +554,7 @@ static Scheme_Env *place_instance_init(void *stack_base, int initial_main_os_thr scheme_init_regexp_places(); scheme_init_sema_places(); scheme_init_gmp_places(); - scheme_init_kqueue(); + scheme_init_fd_semaphores(); scheme_alloc_global_fdset(); #ifndef DONT_USE_FOREIGN scheme_init_foreign_places(); @@ -629,8 +629,10 @@ Scheme_Env *scheme_place_instance_init(void *stack_base, struct NewGC *parent_gc scheme_rktio = rktio_init(); env = place_instance_init(stack_base, 0); # if defined(MZ_PRECISE_GC) - signal_fd = scheme_get_signal_handle(); - GC_set_put_external_event_fd(signal_fd); + if (scheme_rktio) { + signal_fd = scheme_get_signal_handle(); + GC_set_put_external_event_fd(signal_fd); + } # endif scheme_set_can_break(1); return env; @@ -665,6 +667,8 @@ void scheme_place_instance_destroy(int force) scheme_release_process_job_object(); #endif + scheme_release_fd_semaphores(); + scheme_release_file_descriptor(); scheme_end_futures_per_place(); @@ -677,8 +681,8 @@ void scheme_place_instance_destroy(int force) #endif scheme_free_all_code(); scheme_free_ghbn_data(); - scheme_release_kqueue(); - scheme_release_inotify(); + scheme_free_global_fdset(); + rktio_destroy(scheme_rktio); } static void make_kernel_env(void) diff --git a/racket/src/racket/src/inotify.inc b/racket/src/racket/src/inotify.inc deleted file mode 100644 index b9e235dd68..0000000000 --- a/racket/src/racket/src/inotify.inc +++ /dev/null @@ -1,267 +0,0 @@ -/* #included by "port.c" */ - -/* Multiplex multiple filesystem change events onto a single - inotify connection. That's almost as easy as using watch - descriptors in place of file descriptors, but using the - same filesystem path multiple times produces the same - watch descriptors, so reference-count it. Also, each watch - can be removed as soon as it fires, since filesystem - change events are single-shot. - - The values returned by mz_inotify_add() are indices into an array - of watch descriptors. There's room for a better data structure if - the watch-descriptor-to-index mapping becomes too slow. */ - -#ifdef MZ_XFORM -START_XFORM_SUSPEND; -#endif - -typedef struct mz_wd_t { - int wd; - int refcount; - int val; -} mz_wd_t; - -typedef struct mz_inotify_state_t { - int ready, errid, fd; - mz_wd_t *wds; - int size, count; - int got; -} mz_inotify_state_t; - -static int mzi_find_wd(int wd, mz_wd_t *wds, int size) -{ - int i; - for (i = 0; i < size; i++) { - if (wds[i].wd == wd) return i; - } - - return -1; -} - -static int mzi_add_wd(int wd, mz_wd_t *wds, int size) -{ - int i; - - for (i = 0; i < size; i++) { - if (wds[i].wd == wd) { - wds[i].refcount++; - return i; - } - } - - for (i = 0; i < size; i++) { - if (!wds[i].refcount) { - wds[i].wd = wd; - wds[i].refcount = 1; - wds[i].val = 0; - return i; - } - } - - abort(); - return -1; -} - -static int mzi_pull_events(int fd, mz_wd_t *wds, int size) -{ - struct inotify_event _ev, *ev; - void *b = NULL; - int rc, p, got = 0; - int bsize; - struct pollfd pfd[1]; - - ev = &_ev; - bsize = sizeof(_ev); - - pfd[0].fd = fd; - pfd[0].events = POLLIN; - - while (poll(pfd, 1, 0)) { - rc = read(fd, ev, bsize); - if (rc > 0) { - p = mzi_find_wd(ev->wd, wds, size); - if (p != -1) { - got = 1; - wds[p].val = 1; - wds[p].wd = -1; - inotify_rm_watch(fd, ev->wd); - } - } else if (rc == -1) { - if (errno == EAGAIN) - break; - else if (errno == EINTR) { - /* try again */ - } else if (errno == EINVAL) { - bsize *= 2; - if (b) free(b); - b = malloc(bsize); - ev = (struct inotify_event *)b; - } else - scheme_signal_error("inotify read failed on %d (%e)", fd, errno); - } else - break; - } - - if (b) - free (b); - - return got; -} - -static void mz_inotify_start(mz_inotify_state_t *s) -{ - int fd; - - fd = inotify_init(); - if (fd == -1) { - s->errid = errno; - } else { - s->errid = 0; - s->ready = 1; - s->fd = fd; - } -} - -static void mz_inotify_end(mz_inotify_state_t *s) -{ - int rc; - - if (s->ready) { - do { - rc = close(s->fd); - } while (rc == -1 && errno == EINTR); - } - - if (s->wds) free(s->wds); - - free(s); -} - -static void mz_inotify_init() -{ - mz_inotify_state_t *s = scheme_inotify_server; - - if (!s) { - s = (mz_inotify_state_t *)malloc(sizeof(mz_inotify_state_t)); - memset(s, 0, sizeof(mz_inotify_state_t)); - - scheme_inotify_server = s; - } - - if (!s->ready) - mz_inotify_start(s); -} - -static int mz_inotify_ready() -{ - mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server; - - return s->ready; -} - -static int mz_inotify_errid() -{ - mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server; - - return s->errid; -} - -/* Other functions are called only if mz_inotify_ready() returns 1. */ - -static int mz_inotify_add(char *filename) -{ - mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server; - int wd; - - if (s->count == s->size) { - int new_size = (s->size ? (2 * s->size) : 32); - mz_wd_t *new_wds; - int i; - new_wds = (mz_wd_t *)malloc(sizeof(mz_wd_t) * new_size); - memcpy(new_wds, s->wds, s->size * sizeof(mz_wd_t)); - if (s->wds) free(s->wds); - s->wds = new_wds; - s->size = new_size; - for (i = s->count; i < s->size; i++) - { - s->wds[i].wd = -1; - s->wds[i].refcount = 0; - } - } - - wd = inotify_add_watch(s->fd, filename, - (IN_CREATE | IN_DELETE | IN_DELETE_SELF - | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_TO - | IN_ATTRIB | IN_ONESHOT)); - - if (wd == -1) - return -1; - else { - int p; - - p = mzi_add_wd(wd, s->wds, s->size); - if (s->wds[p].refcount == 1) - s->count++; - - return p+1; - } -} - -static void mz_inotify_remove(int p2) -{ - mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server; - int p = p2 - 1; - - if (s->wds[p].refcount == 1) { - if (s->wds[p].wd != -1) { - inotify_rm_watch(s->fd, s->wds[p].wd); - s->wds[p].wd = -1; - /* in case the wd gets reused: */ - if (mzi_pull_events(s->fd, s->wds, s->size)) - s->got = 1; - } - --s->count; - } - s->wds[p].refcount -= 1; -} - -static int mz_inotify_poll(int p2) -{ - mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server; - int p = p2 - 1; - - if (mzi_pull_events(s->fd, s->wds, s->size)) - s->got = 1; - if (s->wds[p].val) - return 1; - else - return 0; -} - -static void mz_inotify_stop() -{ - mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server; - - if (s) { - mz_inotify_end(s); - scheme_inotify_server = NULL; - } -} - -static int mz_inotify_fd() -{ - mz_inotify_state_t *s = (mz_inotify_state_t *)scheme_inotify_server; - - if (s->got) { - /* In case we received something for Y in a poll for X */ - s->got = 0; - return -2; - } - - return s->fd; -} - -#ifdef MZ_XFORM -END_XFORM_SUSPEND; -#endif diff --git a/racket/src/racket/src/mzmark_port.inc b/racket/src/racket/src/mzmark_port.inc index 845feea427..283f0e55b0 100644 --- a/racket/src/racket/src/mzmark_port.inc +++ b/racket/src/racket/src/mzmark_port.inc @@ -100,6 +100,7 @@ static int mark_input_fd_MARK(void *p, struct NewGC *gc) { gcMARK2(fd->buffer, gc); gcMARK2(fd->refcount, gc); gcMARK2(fd->flush_handle, gc); + gcMARK2(fd->widths, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS return 0; @@ -117,6 +118,7 @@ static int mark_input_fd_FIXUP(void *p, struct NewGC *gc) { gcFIXUP2(fd->buffer, gc); gcFIXUP2(fd->refcount, gc); gcFIXUP2(fd->flush_handle, gc); + gcFIXUP2(fd->widths, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS return 0; diff --git a/racket/src/racket/src/mzmarksrc.c b/racket/src/racket/src/mzmarksrc.c index 8f20fb78ef..2d2457ad69 100644 --- a/racket/src/racket/src/mzmarksrc.c +++ b/racket/src/racket/src/mzmarksrc.c @@ -1739,6 +1739,7 @@ mark_input_fd { gcMARK2(fd->buffer, gc); gcMARK2(fd->refcount, gc); gcMARK2(fd->flush_handle, gc); + gcMARK2(fd->widths, gc); size: gcBYTES_TO_WORDS(sizeof(Scheme_FD)); @@ -1794,7 +1795,6 @@ mark_read_write_evt { mark_filesystem_change_evt { mark: Scheme_Filesystem_Change_Evt *fc = (Scheme_Filesystem_Change_Evt *)p; - gcMARK2(fc->sema, gc); gcMARK2(fc->mref, gc); size: gcBYTES_TO_WORDS(sizeof(Scheme_Filesystem_Change_Evt)); diff --git a/racket/src/racket/src/network.c b/racket/src/racket/src/network.c index 24c7e1283e..3059386168 100644 --- a/racket/src/racket/src/network.c +++ b/racket/src/racket/src/network.c @@ -26,128 +26,18 @@ /* This file implements the TCP and UDP interfaces. */ #include "schpriv.h" +#include "schrktio.h" #include #ifndef NO_TCP_SUPPORT #ifdef USE_TCP -#ifdef UNISTD_INCLUDE -# include -#endif -#ifdef USE_ULIMIT -# include -#endif -#ifdef FILES_HAVE_FDS -# include -# include -# ifdef BSTRING_INCLUDE -# include -# endif -# ifdef SELECT_INCLUDE -# include -# endif -# ifdef HAVE_POLL_SYSCALL -# include -# endif -#endif -#ifdef IO_INCLUDE -# include -#endif -#ifdef INCLUDE_OSKIT_SOCKET -# include -#endif -#ifdef NO_ERRNO_GLOBAL -static int mzerrno = 0; -# define errno mzerrno -#else -# include -#endif - -#ifdef USE_UNIX_SOCKETS_TCP -# include -# include -# include -# include -# define TCP_SOCKSENDBUF_SIZE 32768 -# define NOT_WINSOCK(x) x -# define SOCK_ERRNO() errno -# define WAS_EAGAIN(e) ((e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS) || (e == EALREADY)) -# define WAS_ECONNREFUSED(e) (e == ECONNREFUSED) -# define WAS_EBADADDRESS(e) (e == EINVAL) -# define WAS_WSAEMSGSIZE(e) 0 -# define mz_AFNOSUPPORT EAFNOSUPPORT -#endif - -#ifdef CANT_SET_SOCKET_BUFSIZE -# undef SET_SOCKET_BUFFSIZE_ON_CREATE -#endif - -#ifdef SET_SOCKET_BUFFSIZE_ON_CREATE -# define mzWHEN_SET_SOCKBUF_SIZE(x) x -#else -# define mzWHEN_SET_SOCKBUF_SIZE(x) /* empty */ -#endif - -#ifdef USE_WINSOCK_TCP -# include -# include -# include -# ifndef __MINGW32__ -# include -# else -typedef int (WINAPI*gai_t)(const char*, const char*, const struct mz_addrinfo *, struct mz_addrinfo **); -typedef void (WINAPI*fai_t)(struct mz_addrinfo *ai); -# endif -struct SOCKADDR_IN { - short sin_family; - unsigned short sin_port; - struct in_addr sin_addr; - char sin_zero[8]; -}; -# define NOT_WINSOCK(x) 0 -# define SOCK_ERRNO() WSAGetLastError() -# define WAS_EAGAIN(e) ((e == WSAEWOULDBLOCK) || (e == WSAEINPROGRESS)) -# define WAS_WSAEMSGSIZE(e) (e == WSAEMSGSIZE) -# define WAS_ECONNREFUSED(e) (e == WSAECONNREFUSED) -# define WAS_EBADADDRESS(e) 0 -# define mz_AFNOSUPPORT WSAEAFNOSUPPORT -extern int scheme_stupid_windows_machine; -# ifdef MZ_USE_PLACES -static HANDLE winsock_sema; -# endif -#endif - -intptr_t scheme_socket_errno() { - return SOCK_ERRNO(); -} - -#include "schfd.h" - #define TCP_BUFFER_SIZE 4096 -#ifdef USE_UNIX_SOCKETS_TCP -typedef intptr_t tcp_t; -# define INVALID_SOCKET (-1) -static void closesocket(intptr_t s) { - int cr; - do { - cr = close(s); - } while ((cr == -1) && (errno == EINTR)); -} -#endif - -#ifdef USE_WINSOCK_TCP -typedef SOCKET tcp_t; -#endif - typedef struct { Scheme_Object so; Scheme_Custodian_Reference *mref; - int count; -# ifdef HAVE_POLL_SYSCALL - struct pollfd *pfd; -# endif - tcp_t s[mzFLEX_ARRAY_DECL]; + rktio_listener_t *lnr; } listener_t; typedef struct Scheme_Tcp_Buf { @@ -162,51 +52,22 @@ typedef struct Scheme_Tcp_Buf { typedef struct Scheme_Tcp { Scheme_Tcp_Buf b; - tcp_t tcp; + rktio_fd_t *tcp; int flags; } Scheme_Tcp; # define MZ_TCP_ABANDON_OUTPUT 0x1 # define MZ_TCP_ABANDON_INPUT 0x2 -#define UDP_IS_SUPPORTED - -#ifdef UDP_IS_SUPPORTED - typedef struct Scheme_UDP { Scheme_Object so; /* scheme_udp_type */ MZ_HASH_KEY_EX - tcp_t s; /* ok, tcp_t was a bad name */ + rktio_fd_t *s; char bound, connected; Scheme_Object *previous_from_addr; Scheme_Custodian_Reference *mref; } Scheme_UDP; -#endif /* UDP_IS_SUPPORTED */ - -#endif /* USE_TCP */ - -#if defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES) -# define DECL_OS_FDSET(n) fd_set n[1] -# define INIT_DECL_OS_FDSET(r, w, e) /* empty */ -# define INIT_DECL_OS_RD_FDSET(r) /* empty */ -# define INIT_DECL_OS_WR_FDSET(r) /* empty */ -# define INIT_DECL_OS_ER_FDSET(r) /* empty */ -# define MZ_OS_FD_ZERO(p) FD_ZERO(p) -# define MZ_OS_FD_SET(n, p) FD_SET(n, p) -# define MZ_OS_FD_CLR(n, p) FD_CLR(n, p) -#else -# define DECL_OS_FDSET(n) DECL_FDSET(n, 1) -# define INIT_DECL_OS_FDSET(r, w, e) INIT_DECL_FDSET(r, w, e) -# define INIT_DECL_OS_RD_FDSET(r) INIT_DECL_RD_FDSET(r) -# define INIT_DECL_OS_WR_FDSET(r) INIT_DECL_WR_FDSET(r) -# define INIT_DECL_OS_ER_FDSET(r) INIT_DECL_ER_FDSET(r) -# define MZ_OS_FD_ZERO(p) MZ_FD_ZERO(p) -# define MZ_OS_FD_SET(n, p) MZ_FD_SET(n, p) -# define MZ_OS_FD_CLR(n, p) MZ_FD_CLR(n, p) -#endif -#define MZ_OS_FD_ISSET(n, p) FD_ISSET(n, p) - static Scheme_Object *tcp_connect(int argc, Scheme_Object *argv[]); static Scheme_Object *tcp_connect_break(int argc, Scheme_Object *argv[]); static Scheme_Object *tcp_listen(int argc, Scheme_Object *argv[]); @@ -252,10 +113,8 @@ static Scheme_Object *udp_multicast_leave_group(int argc, Scheme_Object *argv[]) static int tcp_check_accept_evt(Scheme_Object *ae, Scheme_Schedule_Info *sinfo); static void tcp_accept_evt_needs_wakeup(Scheme_Object *_ae, void *fds); -#ifdef UDP_IS_SUPPORTED static int udp_evt_check_ready(Scheme_Object *uw, Scheme_Schedule_Info *sinfo); static void udp_evt_needs_wakeup(Scheme_Object *_uw, void *fds); -#endif #ifdef MZ_PRECISE_GC static void register_traversers(void); @@ -318,22 +177,13 @@ void scheme_init_network(Scheme_Env *env) GLOBAL_PRIM_W_ARITY ( "udp-multicast-leave-group!", udp_multicast_leave_group, 3 , 3 , netenv ) ; scheme_finish_primitive_module(netenv); - -#ifdef USE_WINSOCK_TCP -# ifdef MZ_USE_PLACES - if (!winsock_sema) { - winsock_sema = CreateSemaphore(NULL, 1, 1, NULL); - } -# endif -#endif } -#ifdef USE_TCP -static int check_fd_sema(tcp_t s, int mode, Scheme_Schedule_Info *sinfo, Scheme_Object *orig) +static int check_fd_sema(rktio_fd_t s, int mode, Scheme_Schedule_Info *sinfo, Scheme_Object *orig) { Scheme_Object *sema; - sema = scheme_fd_to_semaphore(s, mode, 1); + sema = scheme_rktio_fd_to_semaphore(s, mode); if (sema) { if (!scheme_wait_sema(sema, 1)) { @@ -345,7 +195,6 @@ static int check_fd_sema(tcp_t s, int mode, Scheme_Schedule_Info *sinfo, Scheme_ return 1; } -#endif /*========================================================================*/ /* TCP glue */ @@ -934,99 +783,24 @@ static void TCP_INIT(char *name) /* TCP ports and listeners */ /*========================================================================*/ -#define LISTENER_WAS_CLOSED(x) (((listener_t *)(x))->s[0] == INVALID_SOCKET) - -/* Forward declaration */ -static int stop_listener(Scheme_Object *o); - -static Scheme_Object *listener_to_evt(listener_t *listener) -{ - Scheme_Object **a, *sema; - int i; - - a = MALLOC_N(Scheme_Object*, listener->count); - for (i = listener->count; i--; ) { - sema = scheme_fd_to_semaphore(listener->s[i], MZFD_CREATE_READ, 1); - if (!sema) - return NULL; - a[i] = sema; - } - - return scheme_make_evt_set(listener->count, a); -} +#define LISTENER_WAS_CLOSED(x) (!((listener_t *)(x))->lnr) static int tcp_check_accept(Scheme_Object *_listener, Scheme_Schedule_Info *sinfo) { listener_t *listener = (listener_t *)_listener; int sr, i; -# ifndef HAVE_POLL_SYSCALL - tcp_t s, mx; - DECL_OS_FDSET(readfds); - DECL_OS_FDSET(exnfds); - struct timeval time = {0, 0}; -# endif if (!sinfo || !sinfo->is_poll) { - for (i = listener->count; i--; ) { - if (check_fd_sema(listener->s[i], MZFD_CHECK_READ, NULL, NULL)) - break; - } - if (i < 0) return 0; + /* If listeners supported semaphores, we could have a check here + along the lines of check_fd_sema(). See CREATE_LISTEN_SEMA in + two places below. */ } -# ifdef HAVE_POLL_SYSCALL - if (LISTENER_WAS_CLOSED(listener)) - return 1; - - do { - sr = poll(listener->pfd, listener->count, 0); - } while ((sr == -1) && (errno == EINTR)); - - if (sr) { - for (i = listener->count; i--; ) { - if (listener->pfd[i].revents) - return i + 1; - } - } - - if (sr) - return sr; -# else - - INIT_DECL_OS_RD_FDSET(readfds); - INIT_DECL_OS_ER_FDSET(exnfds); - if (LISTENER_WAS_CLOSED(listener)) return 1; - MZ_OS_FD_ZERO(readfds); - MZ_OS_FD_ZERO(exnfds); - - mx = 0; - for (i = 0; i < listener->count; i++) { - s = listener->s[i]; - MZ_OS_FD_SET(s, readfds); - MZ_OS_FD_SET(s, exnfds); - if (s > mx) - mx = s; - } - - do { - sr = select(mx + 1, readfds, NULL, exnfds, &time); - } while ((sr == -1) && (NOT_WINSOCK(errno) == EINTR)); - - if (sr) { - for (i = 0; i < listener->count; i++) { - s = listener->s[i]; - if (MZ_OS_FD_ISSET(s, readfds) - || MZ_OS_FD_ISSET(s, exnfds)) - return i + 1; - } - } - - if (sr) - return sr; -# endif + if (rktio_poll_accept_ready(scheme_rktio, listener->lnr)) + return 1; if (sinfo && !sinfo->no_redirect) { Scheme_Object *evt; @@ -1034,105 +808,40 @@ static int tcp_check_accept(Scheme_Object *_listener, Scheme_Schedule_Info *sinf if (evt) scheme_set_sync_target(sinfo, evt, _listener, NULL, 0, 1, NULL); } else { - for (i = listener->count; i--; ) { - check_fd_sema(listener->s[i], MZFD_CREATE_READ, NULL, NULL); - } + /* CREATE_LISTEN_SEMA: This is where we'd create a semaphore for the listener, if that were possible */ } return 0; } +static int stop_listener(Scheme_Object *o) +{ + int was_closed = 0; + listener_t *listener = (listener_t *)o; + + if (listener->lnr) { + /* CREATE_LISTEN_SEMA: if we have listener semaphores, unregister + a semaphore here */ + + rktio_listen_stop(scheme_rktio, listener->lnr); + listener->lnr = NULL; + + scheme_remove_managed(((listener_t *)o)->mref, o); + } else { + was_closed = 1; + } + + return was_closed; +} + static void tcp_accept_needs_wakeup(Scheme_Object *_listener, void *fds) { if (!LISTENER_WAS_CLOSED(_listener)) { listener_t *listener = (listener_t *)_listener; - int i; - tcp_t s; - void *fds2; - - fds2 = MZ_GET_FDSET(fds, 2); - - for (i = 0; i < listener->count; i++) { - s = listener->s[i]; - MZ_FD_SET(s, (fd_set *)fds); - MZ_FD_SET(s, (fd_set *)fds2); - } + rktio_poll_add_accept(scheme_rktio, listener->lnr, fds); } } -static int tcp_check_connect(Scheme_Object *connector_p, Scheme_Schedule_Info *sinfo) -{ - tcp_t s; - int sr; - - s = *(tcp_t *)connector_p; - - if (!sinfo || !sinfo->is_poll) { - if (!check_fd_sema(s, MZFD_CHECK_WRITE, sinfo, NULL)) - return 0; - } - -# ifdef HAVE_POLL_SYSCALL - { - GC_CAN_IGNORE struct pollfd pfd[1]; - pfd[0].fd = s; - pfd[0].events = POLLOUT; - do { - sr = poll(pfd, 1, 0); - } while ((sr == -1) && (errno == EINTR)); - - if (!sr) { - /* fall through */ - } else if (pfd[0].revents & POLLOUT) - return 1; - else - return -1; - } -# else - { - DECL_OS_FDSET(writefds); - DECL_OS_FDSET(exnfds); - struct timeval time = {0, 0}; - - INIT_DECL_OS_WR_FDSET(writefds); - INIT_DECL_OS_ER_FDSET(exnfds); - - MZ_OS_FD_ZERO(writefds); - MZ_OS_FD_ZERO(exnfds); - - MZ_OS_FD_SET(s, writefds); - MZ_OS_FD_SET(s, exnfds); - - do { - sr = select(s + 1, NULL, writefds, exnfds, &time); - } while ((sr == -1) && (NOT_WINSOCK(errno) == EINTR)); - - if (!sr) { - /* fall through */ - } else if (FD_ISSET(s, exnfds)) - return -1; - else - return 1; - } -# endif - - check_fd_sema(s, MZFD_CREATE_WRITE, sinfo, NULL); - - return 0; -} - -static void tcp_connect_needs_wakeup(Scheme_Object *connector_p, void *fds) -{ - void *fds1, *fds2; - tcp_t s = *(tcp_t *)connector_p; - - fds1 = MZ_GET_FDSET(fds, 1); - fds2 = MZ_GET_FDSET(fds, 2); - - MZ_FD_SET(s, (fd_set *)fds1); - MZ_FD_SET(s, (fd_set *)fds2); -} - static int tcp_check_write(Scheme_Object *port, Scheme_Schedule_Info *sinfo) { Scheme_Tcp *data = (Scheme_Tcp *)((Scheme_Output_Port *)port)->port_data; @@ -1145,50 +854,8 @@ static int tcp_check_write(Scheme_Object *port, Scheme_Schedule_Info *sinfo) return 0; } -# ifdef HAVE_POLL_SYSCALL - { - GC_CAN_IGNORE struct pollfd pfd[1]; - int sr; - - pfd[0].fd = data->tcp; - pfd[0].events = POLLOUT; - do { - sr = poll(pfd, 1, 0); - } while ((sr == -1) && (errno == EINTR)); - - if (!sr) { - /* fall through */ - } else if (pfd[0].revents & POLLOUT) - return 1; - else - return -1; - } -# else - { - tcp_t s; - DECL_OS_FDSET(writefds); - DECL_OS_FDSET(exnfds); - struct timeval time = {0, 0}; - int sr; - - INIT_DECL_OS_WR_FDSET(writefds); - INIT_DECL_OS_ER_FDSET(exnfds); - - s = data->tcp; - - MZ_OS_FD_ZERO(writefds); - MZ_OS_FD_SET(s, writefds); - MZ_OS_FD_ZERO(exnfds); - MZ_OS_FD_SET(s, exnfds); - - do { - sr = select(s + 1, NULL, writefds, exnfds, &time); - } while ((sr == -1) && (NOT_WINSOCK(errno) == EINTR)); - - if (sr) - return sr; - } -# endif + if (rktio_poll_write_ready(scheme_rktio, data->tcp)) + return 1; check_fd_sema(data->tcp, MZFD_CREATE_WRITE, sinfo, port); @@ -1197,19 +864,13 @@ static int tcp_check_write(Scheme_Object *port, Scheme_Schedule_Info *sinfo) static void tcp_write_needs_wakeup(Scheme_Object *port, void *fds) { - Scheme_Object *conn = ((Scheme_Output_Port *)port)->port_data; - void *fds1, *fds2; - tcp_t s = ((Scheme_Tcp *)conn)->tcp; + rktio_fd_t s = ((Scheme_Tcp *)((Scheme_Output_Port *)port)->port_data)->tcp; - fds1 = MZ_GET_FDSET(fds, 1); - fds2 = MZ_GET_FDSET(fds, 2); - - MZ_FD_SET(s, (fd_set *)fds1); - MZ_FD_SET(s, (fd_set *)fds2); + rktio_poll_add(scheme_rktio, s, fds, RKTIO_POLL_WRITE); } -static Scheme_Tcp *make_tcp_port_data(tcp_t tcp, int refcount) +static Scheme_Tcp *make_tcp_port_data(rktio_fd_t *tcp, int refcount) { Scheme_Tcp *data; char *bfr; @@ -1230,36 +891,18 @@ static Scheme_Tcp *make_tcp_port_data(tcp_t tcp, int refcount) data->b.hiteof = 0; data->b.refcount = refcount; -#ifdef USE_WINSOCK_TCP - { - unsigned long ioarg = 1; - ioctlsocket(tcp, FIONBIO, &ioarg); - } -#else - fcntl(tcp, F_SETFL, MZ_NONBLOCKING); -#endif - return data; } static int tcp_byte_ready (Scheme_Input_Port *port, Scheme_Schedule_Info *sinfo) { Scheme_Tcp *data; - int sr; -# ifndef HAVE_POLL_SYSCALL - DECL_OS_FDSET(readfds); - DECL_OS_FDSET(exfds); - struct timeval time = {0, 0}; - - INIT_DECL_OS_RD_FDSET(readfds); - INIT_DECL_OS_ER_FDSET(exfds); -# endif if (port->closed) return 1; data = (Scheme_Tcp *)port->port_data; - + if (data->b.hiteof) return 1; if (data->b.bufpos < data->b.bufmax) @@ -1270,34 +913,8 @@ static int tcp_byte_ready (Scheme_Input_Port *port, Scheme_Schedule_Info *sinfo) return 0; } -# ifdef HAVE_POLL_SYSCALL - { - GC_CAN_IGNORE struct pollfd pfd[1]; - - pfd[0].fd = data->tcp; - pfd[0].events = POLLIN; - do { - sr = poll(pfd, 1, 0); - } while ((sr == -1) && (errno == EINTR)); - - if (sr) - return sr; - } -# else - { - MZ_OS_FD_ZERO(readfds); - MZ_OS_FD_ZERO(exfds); - MZ_OS_FD_SET(data->tcp, readfds); - MZ_OS_FD_SET(data->tcp, exfds); - - do { - sr = select(data->tcp + 1, readfds, NULL, exfds, &time); - } while ((sr == -1) && (NOT_WINSOCK(errno) == EINTR)); - - if (sr) - return sr; - } -# endif + if (rktio_poll_read_ready(scheme_rktio, data->tcp)) + return 1; check_fd_sema(data->tcp, MZFD_CREATE_READ, sinfo, (Scheme_Object *)port); @@ -1348,18 +965,15 @@ static intptr_t tcp_get_string(Scheme_Input_Port *port, read_amt = TCP_BUFFER_SIZE; else read_amt = size; - + { int rn; - do { - rn = recv(data->tcp, data->b.buffer, read_amt, 0); - } while ((rn == -1) && (NOT_WINSOCK(errno) == EINTR)); - data->b.bufmax = rn; + rn = rktio_read(scheme_rktio, data->tcp, data->b.buffer, read_amt, 0); + data->b.bufmax = rn; /* could be count, error, or EOF */ } - errid = SOCK_ERRNO(); - if ((data->b.bufmax != -1) || !WAS_EAGAIN(errid)) { - /* got data or error */ + if (data->b.bufmax) { + /* got data, error, or EOF */ break; } else { /* no data/error is immediately avaulable */ @@ -1367,7 +981,7 @@ static intptr_t tcp_get_string(Scheme_Input_Port *port, return 0; /* block until data is (probably) available */ - sema = scheme_fd_to_semaphore(data->tcp, MZFD_CREATE_READ, 1); + sema = scheme_rktio_fd_to_semaphore(data->tcp, MZFD_CREATE_READ, 1); if (sema) scheme_wait_sema(sema, nonblock ? -1 : 0); else @@ -1383,13 +997,15 @@ static intptr_t tcp_get_string(Scheme_Input_Port *port, /* getting here means that data or error was ready */ - if (data->b.bufmax == -1) { + if (data->b.bufmax == RKTIO_READ_ERROR) { + data->b.bufmax = 0; scheme_raise_exn(MZEXN_FAIL_NETWORK, "tcp-read: error reading\n" - " system error: %E", + " system error: %R", errid); return 0; - } else if (!data->b.bufmax) { + } else if (data->b.bufmax == RKTIO_READ_ERROR) { + data->b.bufmax = 0; data->b.hiteof = 1; return EOF; } @@ -1408,18 +1024,9 @@ static intptr_t tcp_get_string(Scheme_Input_Port *port, static void tcp_need_wakeup(Scheme_Input_Port *port, void *fds) { - Scheme_Tcp *data; + Scheme_Tcp *data = (Scheme_Tcp *)port->port_data; - data = (Scheme_Tcp *)port->port_data; - - { - void *fds2; - - fds2 = MZ_GET_FDSET(fds, 2); - - MZ_FD_SET(data->tcp, (fd_set *)fds); - MZ_FD_SET(data->tcp, (fd_set *)fds2); - } + rktio_poll_add(scheme_rktio, data->tcp, fds, RKTIO_POLL_READ); } static void tcp_close_input(Scheme_Input_Port *port) @@ -1428,20 +1035,15 @@ static void tcp_close_input(Scheme_Input_Port *port) data = (Scheme_Tcp *)port->port_data; - if (!(data->flags & MZ_TCP_ABANDON_INPUT)) { - int cr; - do { - cr = shutdown(data->tcp, 0); - } while ((cr == -1) && (errno == EINTR)); - } + if (!(data->flags & MZ_TCP_ABANDON_INPUT)) + rktio_socket_shutdown(scheme_rktio, data->tcp, RKTIO_SHUTDOWN_READ); if (--data->b.refcount) return; - UNREGISTER_SOCKET(data->tcp); - closesocket(data->tcp); + (void)scheme_rktio_fd_to_semaphore(data->tcp, MZFD_REMOVE, 1); - (void)scheme_fd_to_semaphore(data->tcp, MZFD_REMOVE, 1); + rktio_close(data->tcp); } static int @@ -1459,8 +1061,8 @@ tcp_in_buffer_mode(Scheme_Port *p, int mode) } static intptr_t tcp_do_write_string(Scheme_Output_Port *port, - const char *s, intptr_t offset, intptr_t len, - int rarely_block, int enable_break) + const char *s, intptr_t offset, intptr_t len, + int rarely_block, int enable_break) { /* We've already checked for buffering before we got here. */ /* If rarely_block is 1, it means only write as much as @@ -1477,51 +1079,26 @@ static intptr_t tcp_do_write_string(Scheme_Output_Port *port, top: - do { - sent = send(data->tcp, s XFORM_OK_PLUS offset, len, 0); - } while ((sent == -1) && (NOT_WINSOCK(errno) == EINTR)); + sent = rktio_write(scheme_rktio, data->tcp, s XFORM_OK_PLUS offset, len); if (sent != len) { -#ifdef USE_WINSOCK_TCP -# define SEND_BAD_MSG_SIZE(e) (e == WSAEMSGSIZE) -#else -# ifdef SEND_IS_NEVER_TOO_BIG -# define SEND_BAD_MSG_SIZE(errid) 0 -# else -# define SEND_BAD_MSG_SIZE(errid) (errid == EMSGSIZE) -# endif -#endif - errid = SOCK_ERRNO(); if (sent > 0) { /* Some data was sent. Return, or recur to handle the rest. */ if (rarely_block) return sent; else sent += tcp_do_write_string(port, s, offset + sent, len - sent, 0, enable_break); - errid = 0; - } else if ((len > 1) && SEND_BAD_MSG_SIZE(errid)) { - /* split the message and try again: */ - int half = (len / 2); - sent = tcp_do_write_string(port, s, offset, half, rarely_block, enable_break); - if (rarely_block) - return sent; - sent += tcp_do_write_string(port, s, offset + half, len - half, 0, enable_break); - errid = 0; - } else if (WAS_EAGAIN(errid)) { - errid = 0; - would_block = 1; } - } else - errid = 0; + } - if (would_block) { + if (sent == 0) { if (rarely_block == 2) return 0; /* Block for writing: */ { Scheme_Object *sema; - sema = scheme_fd_to_semaphore(data->tcp, MZFD_CREATE_WRITE, 1); + sema = scheme_rktio_fd_to_semaphore(data->tcp, MZFD_CREATE_WRITE, 1); if (sema) scheme_wait_sema(sema, enable_break ? -1 : 0); else @@ -1543,11 +1120,10 @@ static intptr_t tcp_do_write_string(Scheme_Output_Port *port, goto top; } - if (errid) + if (sent == RKTIO_WRITE_ERROR) scheme_raise_exn(MZEXN_FAIL_NETWORK, "tcp-write: error writing\n" - " system error: %E", - errid); + " system error: %R"); return sent; } @@ -1632,19 +1208,15 @@ static void tcp_close_output(Scheme_Output_Port *port) tcp_flush(port, 0, 0); if (!(data->flags & MZ_TCP_ABANDON_OUTPUT)) { - int cr; - do { - cr = shutdown(data->tcp, 1); - } while ((cr == -1) && (errno == EINTR)); + rktio_socket_shutdown(scheme_rktio, data->tcp, RKTIO_SHUTDOWN_WRITE); } if (--data->b.refcount) return; - UNREGISTER_SOCKET(data->tcp); - closesocket(data->tcp); + (void)scheme_rktio_fd_to_semaphore(data->tcp, MZFD_REMOVE, 1); - (void)scheme_fd_to_semaphore(data->tcp, MZFD_REMOVE, 1); + rktio_close(data->tcp); } static int @@ -1727,52 +1299,139 @@ make_tcp_output_port(void *data, const char *name, Scheme_Object *cust) return make_tcp_output_port_symbol_name(data, scheme_intern_symbol(name), cust); } -#else +/*========================================================================*/ +/* Hostname lookup helper */ +/*========================================================================*/ -void scheme_free_ghbn_data() { } +/* Various things to free if we ever give up on a connect: */ +typedef struct Connect_Progress_Data { + rktio_lookup_t *lookup; + rktio_connect_t *connect; + rktio_addrinfo_t *dest_addr; + rktio_addrinfo_t *src_addr; + rktio_fd_t *s; +} Connect_Progress_Data; -#endif /* USE_TCP */ +static Connect_Progress_Data *make_conect_progress_data() +{ + Connect_Progress_Data *pd; + + MALLOC_ONE_ATOMIC(Connect_Progress_Data); + pd->lookup = NULL; + pd->dest_addr = NULL; + pd->s = NULL; + + return pd; +} + +static void connect_cleanup(Connect_Progress_Data *pd) +{ + if (pd->lookup) { + rktio_addrinfo_lookup_stop(scheme_rktio, pd->lookup); + pd->lookup = NULL; + } + if (pd->connect) { + rktio_connect_stop(rktio, pd->connect); + pd->connect = NULL; + } + if (pd->dest_addr) { + rktio_addrinfo_free(scheme_rktio, pd->dest_addr); + pd->dest_addr = NULL; + } + if (pd->src_addr) { + rktio_addrinfo_free(scheme_rktio, pd->src_addr); + pd->src_addr = NULL; + } + if (pd->s) { + (void)scheme_rktio_fd_to_semaphore(s, MZFD_REMOVE, 1); + rktio_close(s); + pd->s = NULL; + } +} + +static int check_lookup(Connect_Progress_Data *pd, Scheme_Schedule_Info *sinfo) +{ + if (rktio_poll_addrinfo_lookup_ready(scheme_rktio, pd->lookup)) + return 1; + + return 0; +} + +static void lookup_needs_wakeup(Connect_Progress_Data *pd, void *fds) +{ + rktio_poll_add_addrinfo_lookup(scheme_rktio, pd->lookup, fds); +} + +static void wait_until_lookup(Connect_Progress_Data *pd) +{ + while (!rktio_poll_addrinfo_lookup_ready(scheme_rktio, lookup)) { + BEGIN_ESCAPEABLE(connect_cleanup, pd); + scheme_block_until((Scheme_Ready_Fun)check_lookup, + lookup_needs_wakeup, + (void *)pd, + (float)0.0); + END_ESCAPEABLE(); + } +} + +const char *scheme_hostname_error(int err) +{ + return rktio_get_error_string(scheme_rktio, RKTIO_ERROR_KIND_GAI, err); +} /*========================================================================*/ /* TCP Racket interface */ /*========================================================================*/ -#ifdef USE_TCP -typedef struct Close_Socket_Data { - tcp_t s; - struct mz_addrinfo *src_addr, *dest_addr; -} Close_Socket_Data; - -static void closesocket_w_decrement(Close_Socket_Data *csd) +static void connect_failed(Connect_Progress_Data *pd, const char *why, char *address, int id) { - closesocket(csd->s); - (void)scheme_fd_to_semaphore(csd->s, MZFD_REMOVE, 1); - if (csd->src_addr) - mz_freeaddrinfo(csd->src_addr); - mz_freeaddrinfo(csd->dest_addr); + if (pd) connect_cleanup(pd); + + scheme_raise_exn(MZEXN_FAIL_NETWORK, + "tcp-connect: connection failed%s%s" + " address: %s\n" + " port number: %d\n" + " system error: %R", + why ? ";\n " : "", + why ? why : "", + address, id); } -#endif -const char *scheme_hostname_error(int err) +static int tcp_check_connect(Connect_Progress_Data *pd, Scheme_Schedule_Info *sinfo) { -#ifdef USE_TCP - return mz_gai_strerror(err); -#else - return "?"; -#endif + + rktio_fd_t *s = (rktio_fd_t *)connector_p; + + if (!sinfo || !sinfo->is_poll) { + if (!check_fd_sema(s, MZFD_CHECK_WRITE, sinfo, NULL)) + return 0; + } + + if (rktio_poll_connect_ready(scheme->rktio, s)) + return 1; + + check_fd_sema(s, MZFD_CREATE_WRITE, sinfo, NULL); + + return 0; +} + +static void tcp_connect_needs_wakeup(Scheme_Object *connector_p, void *fds) +{ + rktio_fd_t *s = (rktio_fd_t *)connector_p; + rktio_poll_add_connect(scheme_rktio, s, fds); } static Scheme_Object *tcp_connect(int argc, Scheme_Object *argv[]) { - char * volatile address = "", * volatile src_address, * volatile errmsg = NULL; - unsigned short origid, id, src_origid, src_id; - int errpart = 0, errid = 0; - volatile int nameerr = 0, no_local_spec; + Connect_Progress_Data *pd; + char *address = "", *src_address, *errmsg = NULL; + unsigned short id, src_id; + int no_local_spec; Scheme_Object *bs, *src_bs; -#ifdef USE_TCP - GC_CAN_IGNORE struct mz_addrinfo *tcp_connect_dest; - GC_CAN_IGNORE struct mz_addrinfo * volatile tcp_connect_src; -#endif + rktio_addrinfo_t *tcp_address_dest, *tcp_address_src; + rktio_lookup_t *lookup; + rktio_connect_t *connect; + rktio_fd_t *s; if (!SCHEME_CHAR_STRINGP(argv[0])) scheme_wrong_contract("tcp-connect", "string?", 0, argc, argv); @@ -1785,16 +1444,12 @@ static Scheme_Object *tcp_connect(int argc, Scheme_Object *argv[]) if (SCHEME_TRUEP(argv[3]) && !CHECK_PORT_ID(argv[3])) scheme_wrong_contract("tcp-connect", "(or/c " PORT_ID_TYPE " #f)", 3, argc, argv); -#ifdef USE_TCP - TCP_INIT("tcp-connect"); -#endif - bs = argv[0]; if (SCHEME_CHAR_STRINGP(bs)) bs = scheme_char_string_to_byte_string(bs); address = SCHEME_BYTE_STR_VAL(bs); - origid = (unsigned short)SCHEME_INT_VAL(argv[1]); + id = (unsigned short)SCHEME_INT_VAL(argv[1]); if ((argc > 2) && SCHEME_TRUEP(argv[2])) { src_bs = scheme_char_string_to_byte_string(argv[2]); @@ -1804,10 +1459,10 @@ static Scheme_Object *tcp_connect(int argc, Scheme_Object *argv[]) if ((argc > 3) && SCHEME_TRUEP(argv[3])) { no_local_spec = 0; - src_origid = (unsigned short)SCHEME_INT_VAL(argv[3]); + src_id = (unsigned short)SCHEME_INT_VAL(argv[3]); } else { no_local_spec = 1; - src_origid = 0; + src_id = 0; if (src_address) { scheme_contract_error("tcp-connect", "no local port number supplied when local hostname was supplied", @@ -1816,166 +1471,94 @@ static Scheme_Object *tcp_connect(int argc, Scheme_Object *argv[]) } } - scheme_security_check_network("tcp-connect", address, origid, 1); + scheme_security_check_network("tcp-connect", address, id, 1); scheme_custodian_check_available(NULL, "tcp-connect", "network"); -#ifdef USE_TCP - id = origid; - src_id = src_origid; + pd = make_connect_progress_data(); + + lookup = rktio_start_addrinfo_lookup(scheme_rktio, address, id, RKTIO_FAMILTY_ANY, 0, 1); + if (!lookup) + connect_failed(pd, "host not found", address, id); + + pd->lookup = lookup; + wait_until_lookup(pd); + pd->lookup = NULL; - tcp_connect_dest = scheme_get_host_address(address, id, &errid, -1, 0, 1); - if (tcp_connect_dest) { - if (no_local_spec) - tcp_connect_src = NULL; - else - tcp_connect_src = scheme_get_host_address(src_address, src_id, &errid, -1, 1, 1); - if (no_local_spec || tcp_connect_src) { - GC_CAN_IGNORE struct mz_addrinfo * volatile addr; - for (addr = tcp_connect_dest; addr; addr = addr->ai_next) { - tcp_t s; - s = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); - if (s != INVALID_SOCKET) { - int status, inprogress; - if (no_local_spec - || !bind(s, tcp_connect_src->ai_addr, tcp_connect_src->ai_addrlen)) { -#ifdef USE_WINSOCK_TCP - unsigned long ioarg = 1; - ioctlsocket(s, FIONBIO, &ioarg); -#else - mzWHEN_SET_SOCKBUF_SIZE(int size = TCP_SOCKSENDBUF_SIZE); - fcntl(s, F_SETFL, MZ_NONBLOCKING); - mzWHEN_SET_SOCKBUF_SIZE(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(int))); -#endif - status = connect(s, addr->ai_addr, addr->ai_addrlen); -#ifdef USE_UNIX_SOCKETS_TCP - if (status) - status = errno; - if (status == EINTR) - status = EINPROGRESS; - - inprogress = (status == EINPROGRESS); -#endif -#ifdef USE_WINSOCK_TCP - if (status) - status = WSAGetLastError(); + tcp_connect_dest = rktio_addrinfo_lookup_get(scheme_rktio, lookup); + if (!tcp_connect_dest) + connect_failed(pd, "host not found", address, id); + + pd->dest_addr = tcp_connect_dest; + + if (!no_local_spec) { + lookup = rktio_start_addrinfo_lookup(scheme_rktio, src_address, src_id, RKTIO_FAMILTY_ANY, 1, 1); + if (!lookup) + connect_failed(pd, "local host not found", src_address, src_id); - inprogress = (status == WSAEWOULDBLOCK); - errno = status; -#endif + pd->lookup = lookup; + wait_until_lookup(pd); + pd->lookup = NULL; + + tcp_connect_dest = rktio_addrinfo_lookup_get(scheme_rktio, lookup); + if (!tcp_connect_dest) + connect_failed(pd, "local host not found", src_address, src_id); - - if (inprogress) { - tcp_t *sptr; - Close_Socket_Data *csd; - Scheme_Object *sema; + pd->lookup = lookup; + wait_until_lookup(pd); + pd->lookup = NULL; - sptr = (tcp_t *)scheme_malloc_atomic(sizeof(tcp_t)); - *sptr = s; - - csd = (Close_Socket_Data *)scheme_malloc_atomic(sizeof(Close_Socket_Data)); - csd->s = s; - csd->src_addr = tcp_connect_src; - csd->dest_addr = tcp_connect_dest; - - sema = scheme_fd_to_semaphore(s, MZFD_CREATE_WRITE, 1); - - BEGIN_ESCAPEABLE(closesocket_w_decrement, csd); - if (sema) - scheme_wait_sema(sema, 0); - else - scheme_block_until((Scheme_Ready_Fun)tcp_check_connect, - tcp_connect_needs_wakeup, - (void *)sptr, - (float)0.0); - END_ESCAPEABLE(); - - /* Check whether connect succeeded, or get error: */ - { - unsigned int so_len = sizeof(status); - if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&status, &so_len) != 0) { - status = SOCK_ERRNO(); - } - errno = status; /* for error reporting, below */ - } - -#ifdef USE_WINSOCK_TCP - if (scheme_stupid_windows_machine > 0) { - /* getsockopt() seems not to work in Windows 95, so use the - result from select(), which seems to reliably detect an error condition */ - if (!status) { - if (tcp_check_connect((Scheme_Object *)sptr, NULL) == -1) { - status = 1; - errno = WSAECONNREFUSED; /* guess! */ - } - } - } -#endif - } - - if (!status) { - Scheme_Object *v[2]; - Scheme_Tcp *tcp; - - if (tcp_connect_src) - mz_freeaddrinfo(tcp_connect_src); - mz_freeaddrinfo(tcp_connect_dest); - - tcp = make_tcp_port_data(s, 2); - - v[0] = make_tcp_input_port(tcp, address, NULL); - v[1] = make_tcp_output_port(tcp, address, NULL); - - REGISTER_SOCKET(s); - - return scheme_values(2, v); - } else { - errid = errno; - closesocket(s); - (void)scheme_fd_to_semaphore(s, MZFD_REMOVE, 1); - errpart = 6; - } - } else { - errpart = 5; - errid = SOCK_ERRNO(); - } - } else { - errpart = 4; - errid = SOCK_ERRNO(); - } - } - if (tcp_connect_src) - mz_freeaddrinfo(tcp_connect_src); - } else { - errpart = 2; - nameerr = 1; - errmsg = "local host not found"; - } - if (tcp_connect_dest) - mz_freeaddrinfo(tcp_connect_dest); - } else { - errpart = 1; - nameerr = 1; - errmsg = "host not found"; + tcp_connect_src = rktio_addrinfo_lookup_get(scheme_rktio, lookup); + if (!tcp_connect_src) + connect_failed(pd, "local host not found", src_address, src_id); } - scheme_raise_exn(MZEXN_FAIL_NETWORK, - "tcp-connect: connection failed\n" - "%s%s%s" - " address: %s\n" - " port number: %d\n" - " step: %d\n" - " system error: %N", - errmsg ? " detail: " : "", - errmsg ? errmsg : "", - errmsg ? "\n" : "", - address, origid, errpart, - nameerr, errid); -#else - scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, - "tcp-connect: " NOT_SUPPORTED_STR); -#endif + pd->src_addr = tcp_connect_src; - return NULL; + connect = rktio_start_connect(racket_rktio, tcp_connect_dest, tcp_connect_src); + if (!connect) + connect_failed(pd, NULL, address, id); + + pd->connect = connect; + + while (1) { + while (!rktio_poll_connect_ready(scheme_rktio, connect)) { + BEGIN_ESCAPEABLE(connect_cleanup, pd); + scheme_block_until((Scheme_Ready_Fun)tcp_check_connect, + tcp_connect_needs_wakeup, + (void *)pd, + (float)0.0); + END_ESCAPEABLE(); + } + + s = rktio_connect_finish(rktio_rktio, connect); + + if (!s && scheme_last_error_is_racket(RKTIO_ERROR_CONNECT_TRYING_NEXT)) { + /* try again */ + } else + break; + } + + pd->connect = NULL; + + if (!s) + connect_failed(s, NULL, address, id); + + connect_cleanup(pd); + + { + Scheme_Object *v[2]; + Scheme_Tcp *tcp; + + if (tcp_connect_src) + rktio_addrinfo_free(tcp_connect_src); + + tcp = make_tcp_port_data(s, 2); + + v[0] = make_tcp_input_port(tcp, address, NULL); + v[1] = make_tcp_output_port(tcp, address, NULL); + + return scheme_values(2, v); + } } static Scheme_Object * @@ -1984,41 +1567,35 @@ tcp_connect_break(int argc, Scheme_Object *argv[]) return scheme_call_enable_break(tcp_connect, argc, argv); } -#ifdef USE_TCP -static unsigned short get_no_portno(tcp_t socket, int *_errid) +static void listen_failed(Connect_Progress_Data *pd, const char *why, char *address, int id) { - char here[MZ_SOCK_NAME_MAX_LEN]; - struct sockaddr_in *addr_in; - unsigned int l = sizeof(here); - unsigned short no_port; + if (pd) connect_cleanup(pd); - - if (getsockname(socket, (struct sockaddr *)here, &l)) { - int errid; - errid = SOCK_ERRNO(); - *_errid = errid; - return 0; - } - - /* don't use ntohs, since the result is put back into another sin_port: */ - addr_in = (struct sockaddr_in *)here; - no_port = addr_in->sin_port; - if (!no_port) - *_errid = 0; - return no_port; + scheme_raise_exn(MZEXN_FAIL_NETWORK, + "tcp-listen: listen failed%s%s" + "%s%s%s" + " port number: %d\n" + " system error: %R", + why ? ";\n " : "", + why ? why : "", + address ? " address: " : "", + address ? address : "", + address? "%s\n" : "", + address, id); } -#endif static Scheme_Object * tcp_listen(int argc, Scheme_Object *argv[]) { - unsigned short id, origid; + unsigned short id; int backlog, errid; - int reuse = 0; -#ifdef MZ_TCP_LISTEN_IPV6_ONLY_SOCKOPT - int no_ipv6 = 0; -#endif + int reuse = 0, no_ipv6 = 0; const char *address; + Connect_Progress_Data *pd; + rktio_lookup_t *lookup; + rktio_addrinfo_t *tcp_src; + rktio_listener_t *lnr; + listener_t *l; if (!CHECK_LISTEN_PORT_ID(argv[0])) scheme_wrong_contract("tcp-listen", LISTEN_PORT_ID_TYPE, 0, argc, argv); @@ -2034,11 +1611,7 @@ tcp_listen(int argc, Scheme_Object *argv[]) scheme_wrong_contract("tcp-listen", "(or/c string? #f)", 3, argc, argv); } -#ifdef USE_TCP - TCP_INIT("tcp-listen"); -#endif - - origid = (unsigned short)SCHEME_INT_VAL(argv[0]); + id = (unsigned short)SCHEME_INT_VAL(argv[0]); if (argc > 1) { if (SCHEME_INTP(argv[1])) backlog = SCHEME_INT_VAL(argv[1]); @@ -2056,259 +1629,66 @@ tcp_listen(int argc, Scheme_Object *argv[]) scheme_security_check_network("tcp-listen", address, origid, 0); scheme_custodian_check_available(NULL, "tcp-listen", "network"); -#ifdef USE_TCP - id = origid; -#endif + pd = make_connect_progress_data(); -#ifdef MZ_TCP_LISTEN_IPV6_ONLY_SOCKOPT - retry: -#endif + while (1) { + int family; -#ifdef USE_TCP - { - GC_CAN_IGNORE struct mz_addrinfo *tcp_listen_addr, *addr; - int err, count = 0, pos = 0, i; - listener_t *l = NULL; -#ifdef MZ_TCP_LISTEN_IPV6_ONLY_SOCKOPT - int any_v4 = 0, any_v6 = 0; -#endif + if (no_ipv6) + family = rktio_get_ipv4_family(scheme_rktio); + else + family = RKTIO_FAMILTY_ANY; + + lookup = rktio_start_addrinfo_lookup(scheme_rktio, address, id, family, 1, 1); + if (!lookup) + listen_failed(pd, "address-resolution error", address, id); - tcp_listen_addr = scheme_get_host_address(address, id, &err, -#ifdef MZ_TCP_LISTEN_IPV6_ONLY_SOCKOPT - no_ipv6 ? MZ_PF_INET : -1, -#else - -1, -#endif - 1, 1); + pd->lookup = lookup; + wait_until_lookup(pd); + pd->lookup = NULL; - for (addr = tcp_listen_addr; addr; addr = addr->ai_next) { -#ifdef MZ_TCP_LISTEN_IPV6_ONLY_SOCKOPT - if (addr->ai_family == MZ_PF_INET) - any_v4 = 1; - else if (addr->ai_family == PF_INET6) - any_v6 = 1; -#endif - count++; - } - - if (tcp_listen_addr) { - tcp_t s; -#ifdef MZ_TCP_LISTEN_IPV6_ONLY_SOCKOPT - /* Try IPv6 listeners first, so we can retry and use just IPv4 if - IPv6 doesn't work right. */ - int v6_loop = (any_v6 && any_v4), skip_v6 = 0; -#endif - int first_time = 1; - int first_was_zero = 0; - unsigned short no_port = 0; + tcp_src = rktio_addrinfo_lookup_get(scheme_rktio, lookup); + if (!tcp_src) + connect_failed(pd, "address-resolution error", address, id); - errid = 0; - for (addr = tcp_listen_addr; addr; ) { -#ifdef MZ_TCP_LISTEN_IPV6_ONLY_SOCKOPT - if ((v6_loop && (addr->ai_family != PF_INET6)) - || (skip_v6 && (addr->ai_family == PF_INET6))) { - addr = addr->ai_next; - if (v6_loop && !addr) { - v6_loop = 0; - skip_v6 = 1; - addr = tcp_listen_addr; - } - continue; - } -#endif + pd->src_addr = tcp_src; + lnr = rktio_listen(rktio, tcp_src, backlog, reuse); - s = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); - -#ifdef MZ_TCP_LISTEN_IPV6_ONLY_SOCKOPT - if (s == INVALID_SOCKET) { - /* Maybe it failed because IPv6 is not available: */ - if ((addr->ai_family == PF_INET6) && (errno == EAFNOSUPPORT)) { - if (any_v4 && !pos) { - /* Maybe we can make it work with just IPv4. Try again. */ - no_ipv6 = 1; - mz_freeaddrinfo(tcp_listen_addr); - goto retry; - } - } - } - if (s != INVALID_SOCKET) { - if (any_v4 && (addr->ai_family == PF_INET6)) { - int ok; -# ifdef IPV6_V6ONLY - int on = 1; - ok = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); -# else - ok = -1; -# endif - if (ok) { - if (!pos) { - /* IPV6_V6ONLY doesn't work */ - no_ipv6 = 1; - mz_freeaddrinfo(tcp_listen_addr); - goto retry; - } else { - errid = errno; - closesocket(s); - (void)scheme_fd_to_semaphore(s, MZFD_REMOVE, 1); - errno = errid; - s = INVALID_SOCKET; - } - } - } - } -#endif - - if (s != INVALID_SOCKET) { -#ifdef USE_WINSOCK_TCP - unsigned long ioarg = 1; - ioctlsocket(s, FIONBIO, &ioarg); -#else - fcntl(s, F_SETFL, MZ_NONBLOCKING); -#endif - - if (reuse) { - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuse), sizeof(int)); - } - - if (first_was_zero) { - ((struct sockaddr_in *)addr->ai_addr)->sin_port = no_port; - } - if (!bind(s, addr->ai_addr, addr->ai_addrlen)) { - if (first_time) { - if (((struct sockaddr_in *)addr->ai_addr)->sin_port == 0) { - no_port = get_no_portno(s, &errid); - first_was_zero = 1; - if (no_port == 0) { - closesocket(s); - break; - } - } - first_time = 0; - } - - if (!listen(s, backlog)) { - if (!pos) { - l = scheme_malloc_tagged(sizeof(listener_t) + ((count - mzFLEX_DELTA) * sizeof(tcp_t))); - l->so.type = scheme_listener_type; - l->count = count; -# ifdef HAVE_POLL_SYSCALL - { - struct pollfd *pfd; - pfd = (struct pollfd *)scheme_malloc_atomic(sizeof(struct pollfd) * count); - l->pfd = pfd; - } -# endif - { - Scheme_Custodian_Reference *mref; - mref = scheme_add_managed(NULL, - (Scheme_Object *)l, - (Scheme_Close_Custodian_Client *)stop_listener, - NULL, - 1); - l->mref = mref; - } - } -# ifdef HAVE_POLL_SYSCALL - l->pfd[pos].fd = s; - l->pfd[pos].events = POLLIN; -# endif - l->s[pos++] = s; - - REGISTER_SOCKET(s); - - if (pos == count) { - mz_freeaddrinfo(tcp_listen_addr); - - return (Scheme_Object *)l; - } - } else { - errid = SOCK_ERRNO(); - closesocket(s); - break; - } - } else { - errid = SOCK_ERRNO(); - closesocket(s); - break; - } - } else { - errid = SOCK_ERRNO(); - break; - } - - addr = addr->ai_next; - -#ifdef MZ_TCP_LISTEN_IPV6_ONLY_SOCKOPT - if (!addr && v6_loop) { - v6_loop = 0; - skip_v6 = 1; - addr = tcp_listen_addr; - } -#endif - } - - for (i = 0; i < pos; i++) { - s = l->s[i]; - UNREGISTER_SOCKET(s); - closesocket(s); - } - - mz_freeaddrinfo(tcp_listen_addr); - } else { - scheme_raise_exn(MZEXN_FAIL_NETWORK, - "tcp-listen: host lookup failed\n" - " address: %s\n" - " system error: %N", - address ? address : "#f", 1, err); - return NULL; - } + pd->src_addr = NULL; + rktio_addrinfo_free(scheme_rktio, tcp_src); + + if (!lnr) { + if (scheme_last_error_is_racket(RKTIO_ERROR_TRY_AGAIN_WITH_IPV4)) { + /* try again */ + no_ipv6 = 1; + } else + break; + } else + break; } - scheme_raise_exn(MZEXN_FAIL_NETWORK, - "tcp-listen: listen failed\n" - " port number: %d\n" - " system error: %E", - (int)origid, errid); -#else - scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, - "tcp-listen: " NOT_SUPPORTED_STR); -#endif - - return NULL; -} - -#ifdef USE_TCP -static int stop_listener(Scheme_Object *o) -{ - int was_closed = 0; + if (!lnr) + listen_failed(pd, NULL, address, id); + l = MALLOC_ONE_TAGGED(listener_t); + l->so.type = scheme_listener_type; + l->lnr = lnr; { - listener_t *listener = (listener_t *)o; - int i; - tcp_t s; - s = listener->s[0]; - if (s == INVALID_SOCKET) - was_closed = 1; - else { - for (i = 0; i < listener->count; i++) { - s = listener->s[i]; - UNREGISTER_SOCKET(s); - closesocket(s); - (void)scheme_fd_to_semaphore(s, MZFD_REMOVE, 1); - listener->s[i] = INVALID_SOCKET; - } - scheme_remove_managed(((listener_t *)o)->mref, o); - } + Scheme_Custodian_Reference *mref; + mref = scheme_add_managed(NULL, + (Scheme_Object *)l, + (Scheme_Close_Custodian_Client *)stop_listener, + NULL, + 1); + l->mref = mref; } - - return was_closed; + + return (Scheme_Object *)l; } -#endif static Scheme_Object * tcp_stop(int argc, Scheme_Object *argv[]) { -#ifdef USE_TCP int was_closed; if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_listener_type)) @@ -2325,16 +1705,11 @@ tcp_stop(int argc, Scheme_Object *argv[]) } return scheme_void; -#else - scheme_wrong_contract("tcp-close", "tcp-listener?", 0, argc, argv); - return NULL; -#endif } static Scheme_Object * tcp_accept_ready(int argc, Scheme_Object *argv[]) { -#ifdef USE_TCP int ready; if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_listener_type)) @@ -2351,10 +1726,6 @@ tcp_accept_ready(int argc, Scheme_Object *argv[]) ready = tcp_check_accept(argv[0], NULL); return (ready ? scheme_true : scheme_false); -#else - scheme_wrong_contract("tcp-accept-ready?", "tcp-listener?", 0, argc, argv); - return NULL; -#endif } static Scheme_Object * @@ -2364,15 +1735,13 @@ do_tcp_accept(int argc, Scheme_Object *argv[], Scheme_Object *cust, char **_fail #ifdef USE_TCP int was_closed = 0, errid, ready_pos; Scheme_Object *listener; - tcp_t s, ls; + rktio_fd_t *s; unsigned int l; GC_CAN_IGNORE char tcp_accept_addr[MZ_SOCK_NAME_MAX_LEN]; if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_listener_type)) scheme_wrong_contract("tcp-accept", "tcp-listener?", 0, argc, argv); - TCP_INIT("tcp-accept"); - listener = argv[0]; was_closed = LISTENER_WAS_CLOSED(listener); @@ -2412,45 +1781,27 @@ do_tcp_accept(int argc, Scheme_Object *argv[], Scheme_Object *cust, char **_fail return NULL; } } - - ls = ((listener_t *)listener)->s[ready_pos-1]; - l = sizeof(tcp_accept_addr); + s = rktio_accept(scheme_rktio, ((listener_t *)listener)->lnr); - do { - s = accept(ls, (struct sockaddr *)tcp_accept_addr, &l); - } while ((s == -1) && (NOT_WINSOCK(errno) == EINTR)); - - if (s != INVALID_SOCKET) { + if (s) { Scheme_Object *v[2]; Scheme_Tcp *tcp; -# ifdef USE_UNIX_SOCKETS_TCP - mzWHEN_SET_SOCKBUF_SIZE(int size = TCP_SOCKSENDBUF_SIZE); - mzWHEN_SET_SOCKBUF_SIZE(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(int))); -# endif - tcp = make_tcp_port_data(s, 2); v[0] = make_tcp_input_port(tcp, "tcp-accepted", cust); v[1] = make_tcp_output_port(tcp, "tcp-accepted", cust); - REGISTER_SOCKET(s); - return scheme_values(2, v); } - errid = SOCK_ERRNO(); if (_fail_reason) *_fail_reason = "tcp-accept-evt: accept from listener failed"; else scheme_raise_exn(MZEXN_FAIL_NETWORK, "tcp-accept: accept from listener failed\n" - " system error: %E", - errid); -#else - scheme_wrong_contract("tcp-accept", "tcp-listener?", 0, argc, argv); -#endif + " system error: %R"); return NULL; } @@ -2485,31 +1836,6 @@ static Scheme_Object *tcp_listener_p(int argc, Scheme_Object *argv[]) : scheme_false); } -void scheme_getnameinfo(void *sa, int salen, - char *host, int hostlen, - char *serv, int servlen) -{ -#ifdef USE_TCP -# ifdef HAVE_GETADDRINFO - getnameinfo(sa, salen, host, hostlen, serv, servlen, - NI_NUMERICHOST | NI_NUMERICSERV); -# else - if (host) { - unsigned char *b; - b = (unsigned char *)&((struct sockaddr_in *)sa)->sin_addr; - sprintf(host, "%d.%d.%d.%d", b[0], b[1], b[2], b[3]); - } - if (serv) { - int id; - id = ntohs(((struct sockaddr_in *)sa)->sin_port); - sprintf(serv, "%d", id); - } -# endif -#else - scheme_signal_error("getnameinfo unsupported"); -#endif -} - static int extract_svc_value(char *svc_buf) { int id = 0, j; @@ -2525,13 +1851,12 @@ static int extract_svc_value(char *svc_buf) static Scheme_Object *tcp_addresses(int argc, Scheme_Object *argv[]) { #ifdef USE_TCP - tcp_t socket = 0; + rktio_fd_t *socket = NULL; + rktio_listener_t *lnr = NULL; Scheme_Tcp *tcp = NULL; - int closed = 0; + int closed = 0, require_peer = 0; Scheme_Object *result[4]; int with_ports = 0; - int listener = 0; - int udp = 0; if (SCHEME_OUTPUT_PORTP(argv[0])) { Scheme_Output_Port *op; @@ -2552,90 +1877,84 @@ static Scheme_Object *tcp_addresses(int argc, Scheme_Object *argv[]) if (tcp) { socket = tcp->tcp; - } - else { + if (closed) + scheme_raise_exn(MZEXN_FAIL_NETWORK, + "tcp-addresses: port is closed"); + require_peer = 1; + } else { if (SCHEME_LISTEN_PORTP(argv[0])) { listener = 1; - socket = ((listener_t *)argv[0])->s[0]; + if (LISTENER_WAS_CLOSED(argv[0])) { + scheme_raise_exn(MZEXN_FAIL_NETWORK, + "tcp-addresses: listener is closed"); + } else + lnr = ((listener_t *)argv[0])->lnr; } else if (SCHEME_UDP_PORTP(argv[0])) { udp = 1; socket = ((Scheme_UDP *)argv[0])->s; + if (!socket) + scheme_raise_exn(MZEXN_FAIL_NETWORK, + "tcp-addresses: socket is closed"); } else { - scheme_wrong_contract("tcp-addresses", "tcp-port?", 0, argc, argv); + scheme_wrong_contract("tcp-addresses", "(or/c tcp-port? listener? udp-socket?)", 0, argc, argv); } } - if (closed) - scheme_raise_exn(MZEXN_FAIL_NETWORK, - "tcp-addresses: port is closed"); + if (socket) + local_names = rktio_socket_address(socket); + else + local_names = rktio_listener_address(lnr); - { - unsigned int l; - char here[MZ_SOCK_NAME_MAX_LEN], there[MZ_SOCK_NAME_MAX_LEN]; - char host_buf[MZ_SOCK_HOST_NAME_MAX_LEN]; - char svc_buf[MZ_SOCK_SVC_NAME_MAX_LEN]; - unsigned int here_len; - unsigned int there_len = 0; - int peerrc = 0; + if (!local_names) + scheme_raise_exn(MZEXN_FAIL_NETWORK, + "tcp-addresses: could not get address\n" + " system error: %R"); - l = sizeof(here); - if (getsockname(socket, (struct sockaddr *)here, &l)) { - scheme_raise_exn(MZEXN_FAIL_NETWORK, - "tcp-addresses: could not get local address\n" - " system error: %E", - SOCK_ERRNO()); - } - here_len = l; + if (socket) + peer_names = rktio_socket_address(socket); + else + peer_names = NULL; - if (!listener) { - l = sizeof(there); - peerrc = getpeername(socket, (struct sockaddr *)there, &l); - if (peerrc && !udp) { - scheme_raise_exn(MZEXN_FAIL_NETWORK, - "tcp-addresses: could not get peer address\n" - " system error: %E", - SOCK_ERRNO()); - } - there_len = l; - } + if (!peer_names && require_peer) { + free(local_names[0]); + free(local_names[1]); + free(local_names); + scheme_raise_exn(MZEXN_FAIL_NETWORK, + "tcp-addresses: could not get peer address\n" + " system error: %R"); + } - scheme_getnameinfo((struct sockaddr *)here, here_len, - host_buf, sizeof(host_buf), - (with_ports ? svc_buf : NULL), - (with_ports ? sizeof(svc_buf) : 0)); - result[0] = scheme_make_utf8_string(host_buf); + result[0] = scheme_make_utf8_string(local_names[0]); + if (with_ports) { + l = extract_svc_value(local_names[1]); + result[1] = scheme_make_integer(l); + } + + if (!peer_names) { + result[with_ports ? 2 : 1] = scheme_make_utf8_string("0.0.0.0"); + result[3] = scheme_make_integer(0); + } else { + result[with_ports ? 2 : 1] = scheme_make_utf8_string(host_buf); if (with_ports) { l = extract_svc_value(svc_buf); - result[1] = scheme_make_integer(l); - } - - if (listener || (udp && peerrc)) { - result[with_ports ? 2 : 1] = scheme_make_utf8_string("0.0.0.0"); - result[3] = scheme_make_integer(0); - } - else { - scheme_getnameinfo((struct sockaddr *)there, there_len, - host_buf, sizeof(host_buf), - (with_ports ? svc_buf : NULL), - (with_ports ? sizeof(svc_buf) : 0)); - result[with_ports ? 2 : 1] = scheme_make_utf8_string(host_buf); - if (with_ports) { - l = extract_svc_value(svc_buf); - result[3] = scheme_make_integer(l); - } + result[3] = scheme_make_integer(l); } } + free(local_names[0]); + free(local_names[1]); + free(local_names); + if (peer_names) { + free(peer_names[0]); + free(peer_names[1]); + free(perr_names); + } + return scheme_values(with_ports ? 4 : 2, result); -#else - /* First arg can't possibly be right! */ - scheme_wrong_contract("tcp-addresses", "tcp-port?", 0, argc, argv); -#endif } static Scheme_Object *tcp_abandon_port(int argc, Scheme_Object *argv[]) { -#ifdef USE_TCP if (SCHEME_OUTPUT_PORTP(argv[0])) { Scheme_Output_Port *op; op = scheme_output_port_record(argv[0]); @@ -2659,7 +1978,6 @@ static Scheme_Object *tcp_abandon_port(int argc, Scheme_Object *argv[]) return scheme_void; } } -#endif scheme_wrong_contract("tcp-abandon-port", "tcp-port?", 0, argc, argv); @@ -2672,7 +1990,6 @@ void scheme_tcp_abandon_port(Scheme_Object *port) { static Scheme_Object *tcp_port_p(int argc, Scheme_Object *argv[]) { -#ifdef USE_TCP if (SCHEME_OUTPUT_PORTP(argv[0])) { Scheme_Output_Port *op; op = scheme_output_port_record(argv[0]); @@ -2686,7 +2003,6 @@ static Scheme_Object *tcp_port_p(int argc, Scheme_Object *argv[]) return scheme_true; } } -#endif return scheme_false; } @@ -2746,8 +2062,7 @@ static void tcp_accept_evt_needs_wakeup(Scheme_Object *ae, void *fds) int scheme_get_port_socket(Scheme_Object *p, intptr_t *_s) { -#ifdef USE_TCP - tcp_t s = 0; + rktio_fd_t *s = NULL; int s_ok = 0; if (SCHEME_OUTPUT_PORTP(p)) { @@ -2771,34 +2086,29 @@ int scheme_get_port_socket(Scheme_Object *p, intptr_t *_s) } if (s_ok) { - *_s = (intptr_t)s; + intptr_t sv; + sv = rktio_fd_system_fd(s); + *_s = sv; return 1; } else return 0; -#endif } void scheme_socket_to_ports(intptr_t s, const char *name, int takeover, Scheme_Object **_inp, Scheme_Object **_outp) { -#ifdef USE_TCP Scheme_Tcp *tcp; Scheme_Object *v; + rktio_fd_t *rfd; - tcp = make_tcp_port_data(s, takeover ? 2 : 3); + rfd = rktio_open(s, RKTIO_OPEN_READ | RKTIO_OPEN_WRITE | RKTIO_OPEN_SOCKET | RKTIO_OPEN_OWN); + + tcp = make_tcp_port_data(rfd, takeover ? 2 : 3); v = make_tcp_input_port(tcp, name, NULL); *_inp = v; v = make_tcp_output_port(tcp, name, NULL); *_outp = v; - - if (takeover) { - REGISTER_SOCKET(s); - } -#else - *_inp = NULL; - *_outp = NULL; -#endif } void scheme_socket_to_input_port(intptr_t s, Scheme_Object *name, int takeover, diff --git a/racket/src/racket/src/place.c b/racket/src/racket/src/place.c index 9089806cc5..5d6fabd636 100644 --- a/racket/src/racket/src/place.c +++ b/racket/src/racket/src/place.c @@ -1055,7 +1055,7 @@ void scheme_wait_resume() { mzrt_mutex_unlock(child_wait_lock); } - +b void scheme_starting_child() { mzrt_mutex_lock(child_wait_lock); @@ -2785,7 +2785,8 @@ static void *place_start_proc_after_stack(void *data_arg, void *stack_base) { if (!scheme_setjmp(new_error_buf)) { Scheme_Object *dynamic_require; - scheme_check_place_port_ok(); + if (!scheme_rktio) + scheme_signal_error("place: I/O manager initialization failed"); dynamic_require = scheme_builtin_value("dynamic-require"); place_main = scheme_apply(dynamic_require, 2, a); diff --git a/racket/src/racket/src/port.c b/racket/src/racket/src/port.c index 296c4ca520..21c54bc628 100644 --- a/racket/src/racket/src/port.c +++ b/racket/src/racket/src/port.c @@ -31,66 +31,6 @@ #include "schpriv.h" #include "schmach.h" -#ifdef UNISTD_INCLUDE -# include -#endif -#ifdef USE_ULIMIT -# include -#endif -#ifdef FILES_HAVE_FDS -# include -# include -# include -# include -# ifdef BSTRING_INCLUDE -# include -# endif -# ifdef SELECT_INCLUDE -# include -# endif -# ifdef HAVE_POLL_SYSCALL -# include -# endif -# ifdef HAVE_INOTIFY_SYSCALL -# include -# endif -#endif -#ifdef USE_ITIMER -# include -# include -# include -#endif -#if defined(UNIX_PROCESSES) -# include -# include -# include -#endif -#ifdef IO_INCLUDE -# include -#endif -#ifdef NO_ERRNO_GLOBAL -static int mzerrno = 0; -# define errno mzerrno -#else -# include -#endif -#ifndef DONT_IGNORE_PIPE_SIGNAL -# include -#endif -#ifdef USE_OSKIT_CONSOLE -# ifndef OSKIT_TEST -# include -# endif -extern int osk_not_console; /* set by cmd-line flag */ -#endif -#include /* for fmod , used by default_sleep */ -#if defined(__QNX__) -#include /* for subprocess vfork() */ -#endif - -#ifndef MZ_BINARY -# define MZ_BINARY 0 -#endif #define mzAssert(x) /* if (!(x)) abort() */ @@ -106,115 +46,13 @@ typedef struct { FILE *f; } Scheme_Output_File; -/******************** Windows I/O and Subprocesses ********************/ - -#if defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES) - -static void init_thread_memory(); - -# define WIN32_FD_HANDLES -# include -# include -# include -# include -# include -# include -# define OS_SEMAPHORE_TYPE HANDLE -# define OS_MUTEX_TYPE CRITICAL_SECTION -# define OS_THREAD_TYPE HANDLE -#endif - -#include "schfd.h" - -#ifdef WINDOWS_FILE_HANDLES - -# define MZ_FDS - -typedef struct Win_FD_Input_Thread { - /* This is malloced for use in a Win32 thread */ - HANDLE fd; - volatile int avail, err, checking; - int *refcount; - HANDLE eof; - unsigned char *buffer; - HANDLE checking_sema, ready_sema, you_clean_up_sema; - HANDLE thread; -} Win_FD_Input_Thread; - -typedef struct Win_FD_Output_Thread { - /* This is malloced for use in a Win32 thread */ - HANDLE fd; - int nonblocking; /* non-zero => an NT pipe where non-blocking WriteFile - works. We still use a thread to detect when the - write has ben flushed, which in turn is needed to - know whether future writes will immediately succeed. */ - volatile flushed, needflush; /* Used for non-blocking, only. The flushed - flag communicates from the flush-testing thread - to the main thread. For efficiency, we request - flush checking only when needed (instead of - after every write); needflush indicates that - a flush check is currently needed, but hasn't - been started. */ - volatile int done, err_no; - volatile unsigned int buflen, bufstart, bufend; /* used for blocking, only */ - unsigned char *buffer; /* used for blocking, only */ - int *refcount; - HANDLE lock_sema, work_sema, ready_sema, you_clean_up_sema; - /* lock_sema protects the fields, work_sema starts the flush or - flush-checking thread to work, ready_sema indicates that a flush - finished, and you_clean_up_sema is essentially a reference - count */ - HANDLE thread; -} Win_FD_Output_Thread; - -int scheme_stupid_windows_machine; - -#endif - -#if defined(WINDOWS_PROCESSES) -# include -#endif - -/******************** Unix Subprocesses ********************/ - -#if defined(UNIX_PROCESSES) && !defined(MZ_PLACES_WAITPID) -/* For process & system: */ -typedef struct System_Child { - MZTAG_IF_REQUIRED - pid_t id; - short done; - int status; - struct System_Child *next; -} System_Child; - -System_Child *scheme_system_children; -#endif +/******************** Subprocesses ********************/ typedef struct Scheme_Subprocess { Scheme_Object so; - void *handle; - int pid; - int is_group; -#if defined(MZ_PLACES_WAITPID) - short done; - int status; -#endif -#ifdef WINDOWS_GET_PROCESS_TIMES - int got_time; -#endif - Scheme_Custodian_Reference *mref; + rktio_process_t *proc; } Scheme_Subprocess; -#ifdef USE_FD_PORTS -# include -# include -# define MZ_FDS -#endif - -#ifdef CLOSE_ALL_FDS_AFTER_FORK -static void close_fds_after_fork(int skip1, int skip2, int skip3); -#endif - /******************** refcounts ********************/ #if defined(WINDOWS_FILE_HANDLES) || defined(MZ_USE_PLACES) @@ -268,35 +106,20 @@ static int adj_refcount(int *refcount, int amt) /******************** file-descriptor I/O ********************/ -/* Windows/Mac I/O is piggy-backed on Unix file-descriptor I/O. Making - Windows file HANDLEs behave as nicely as file descriptors for - non-blocking I/O requires a lot of work, and often a separate - thread. The "th" and "oth" fields of Scheme_FD point to malloced - (non-GCed) records that mediate the threads. */ - -#ifdef MZ_FDS - static int *stdin_refcount, *stdout_refcount, *stderr_refcount; -# define MZPORT_FD_BUFFSIZE 4096 -# define MZPORT_FD_DIRECT_THRESHOLD MZPORT_FD_BUFFSIZE - /* The Scheme_FD type is used for both input and output */ typedef struct Scheme_FD { MZTAG_IF_REQUIRED - intptr_t fd; /* fd is really a HANDLE in Windows */ + rktio_fd_t fd; intptr_t bufcount, buffpos; - char flushing, regfile, flush; - char textmode; /* Windows: textmode => CRLF conversion; SOME_FDS_... => select definitely works */ + char flushing, flush; unsigned char *buffer; + char *buffer; int *refcount; Scheme_Object *flush_handle; /* output port: registration with plumber */ - -# ifdef WINDOWS_FILE_HANDLES - Win_FD_Input_Thread *th; /* input mode */ - Win_FD_Output_Thread *oth; /* output mode */ - int unblocked; /* whether non-blocking mode is installed */ -# endif + /* For text mode and `port-file-position`: */ + char *bufwidths; } Scheme_FD; Scheme_Object *scheme_port_name(Scheme_Object *p) { @@ -316,29 +139,16 @@ int scheme_get_serialized_fd_flags(Scheme_Object* p, Scheme_Serialized_File_FD * fds = (Scheme_FD *) ((Scheme_Output_Port *)p)->port_data; so->name = ((Scheme_Output_Port *)p)->name; } - so->regfile = fds->regfile; + so->regfile = rktio_fd_is_regular_file(fds->fd); so->textmode = (fds->textmode ? 1 : 0); so->flush_mode = fds->flush; return 1; } - -#endif - #define MZ_FLUSH_NEVER 0 #define MZ_FLUSH_BY_LINE 1 #define MZ_FLUSH_ALWAYS 2 -#ifdef SOME_FDS_ARE_NOT_SELECTABLE -# include -#endif - -#if defined(WINDOWS_FILE_HANDLES) -# define FILENAME_EXN_E "%E" -#else -# define FILENAME_EXN_E "%e" -#endif - #if defined(DOS_FILE_SYSTEM) # if defined(__MINGW32__) # define fseeko fseek @@ -349,7 +159,6 @@ int scheme_get_serialized_fd_flags(Scheme_Object* p, Scheme_Serialized_File_FD * # endif #endif - /******************** Globals and Prototypes ********************/ /* globals */ @@ -358,15 +167,7 @@ THREAD_LOCAL_DECL(Scheme_Object *scheme_orig_stdout_port); THREAD_LOCAL_DECL(Scheme_Object *scheme_orig_stderr_port); THREAD_LOCAL_DECL(Scheme_Object *scheme_orig_stdin_port); -THREAD_LOCAL_DECL(struct mz_fd_set *scheme_fd_set); THREAD_LOCAL_DECL(struct mz_fd_set *scheme_semaphore_fd_set); -THREAD_LOCAL_DECL(Scheme_Hash_Table *scheme_semaphore_fd_mapping); -THREAD_LOCAL_DECL(void *scheme_inotify_server); - -#ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS -THREAD_LOCAL_DECL(Scheme_Hash_Table *locked_fd_process_map); -static void release_lockf(int fd); -#endif HOOK_SHARED_OK Scheme_Object *(*scheme_make_stdin)(void) = NULL; HOOK_SHARED_OK Scheme_Object *(*scheme_make_stdout)(void) = NULL; @@ -382,21 +183,14 @@ THREAD_LOCAL_DECL(static int special_is_ok); THREAD_LOCAL_DECL(static int fd_reserved); THREAD_LOCAL_DECL(static int the_fd); #endif -#ifdef MZ_FDS READ_ONLY static Scheme_Object *fd_input_port_type; -#endif -#ifdef USE_OSKIT_CONSOLE -READ_ONLY static Scheme_Object *oskit_console_input_port_type; -#endif READ_ONLY static Scheme_Object *file_input_port_type; READ_ONLY Scheme_Object *scheme_string_input_port_type; #ifdef USE_TCP READ_ONLY Scheme_Object *scheme_tcp_input_port_type; READ_ONLY Scheme_Object *scheme_tcp_output_port_type; #endif -#ifdef MZ_FDS READ_ONLY static Scheme_Object *fd_output_port_type; -#endif READ_ONLY static Scheme_Object *file_output_port_type; READ_ONLY Scheme_Object *scheme_string_output_port_type; READ_ONLY Scheme_Object *scheme_user_input_port_type; @@ -422,8 +216,8 @@ static void register_port_wait(); #ifdef MZ_FDS static intptr_t flush_fd(Scheme_Output_Port *op, - const char * volatile bufstr, volatile uintptr_t buflen, - volatile uintptr_t offset, int immediate_only, int enable_break); + const char * volatile bufstr, volatile uintptr_t buflen, + volatile uintptr_t offset, int immediate_only, int enable_break); static void flush_if_output_fds(Scheme_Object *o, Scheme_Close_Custodian_Client *f, void *data); #endif @@ -471,14 +265,8 @@ static void register_traversers(void); THREAD_LOCAL_DECL(void *scheme_break_semaphore;) #endif -#ifdef MZ_FDS -static Scheme_Object *make_fd_input_port(intptr_t fd, Scheme_Object *name, int regfile, int textmode, int *refcount, int internal); -static Scheme_Object *make_fd_output_port(intptr_t fd, Scheme_Object *name, int regfile, int textmode, int read_too, int flush_mode, - int *refcount); -#endif -#ifdef USE_OSKIT_CONSOLE -static Scheme_Object *make_oskit_console_input_port(); -#endif +static Scheme_Object *make_fd_input_port(rktio_fd_t *fd, Scheme_Object *name, int *refcount, int internal); +static Scheme_Object *make_fd_output_port(rktio_fd_t *fd, Scheme_Object *name, int read_too, int flush_mode, int *refcount); static void force_close_output_port(Scheme_Object *port); static void force_close_input_port(Scheme_Object *port); @@ -501,8 +289,7 @@ THREAD_LOCAL_DECL(static char *read_string_byte_buffer); typedef struct Scheme_Filesystem_Change_Evt { Scheme_Object so; - intptr_t fd; - Scheme_Object *sema; + rktio_fs_change_t *rfc; Scheme_Custodian_Reference *mref; } Scheme_Filesystem_Change_Evt; @@ -553,13 +340,8 @@ scheme_init_port (Scheme_Env *env) exact_symbol = scheme_intern_symbol("exact"); -#ifdef MZ_FDS REGISTER_SO(fd_input_port_type); REGISTER_SO(fd_output_port_type); -#endif -#ifdef USE_OSKIT_CONSOLE - REGISTER_SO(oskit_console_input_port_type); -#endif REGISTER_SO(file_input_port_type); REGISTER_SO(scheme_string_input_port_type); #ifdef USE_TCP @@ -593,13 +375,8 @@ scheme_init_port (Scheme_Env *env) scheme_string_input_port_type = scheme_make_port_type(""); scheme_string_output_port_type = scheme_make_port_type(""); -#ifdef MZ_FDS fd_input_port_type = scheme_make_port_type(""); fd_output_port_type = scheme_make_port_type(""); -#endif -#ifdef USE_OSKIT_CONSOLE - oskit_console_input_port_type = scheme_make_port_type(""); -#endif file_input_port_type = scheme_make_port_type(""); file_output_port_type = scheme_make_port_type(""); @@ -618,19 +395,6 @@ scheme_init_port (Scheme_Env *env) scheme_null_output_port_type = scheme_make_port_type(""); scheme_redirect_output_port_type = scheme_make_port_type(""); -#ifdef WIN32_FD_HANDLES - /* We'll need to know whether this is Win95 or WinNT: */ - { - OSVERSIONINFO info; - info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&info); - if (info.dwPlatformId == VER_PLATFORM_WIN32_NT) - scheme_stupid_windows_machine = -1; /* not as stupid */ - else - scheme_stupid_windows_machine = 1; - } -#endif - scheme_add_global_constant("subprocess", scheme_make_prim_w_arity2(subprocess, "subprocess", 4, -1, 4, 4), env); scheme_add_global_constant("subprocess-status", scheme_make_prim_w_arity(subprocess_status, "subprocess-status", 1, 1), env); scheme_add_global_constant("subprocess-kill", scheme_make_prim_w_arity(subprocess_kill, "subprocess-kill", 2, 2), env); @@ -682,55 +446,18 @@ void scheme_init_port_places(void) REGISTER_SO(scheme_orig_stdin_port); scheme_orig_stdin_port = (scheme_make_stdin ? scheme_make_stdin() -#ifdef USE_OSKIT_CONSOLE - : (osk_not_console - ? scheme_make_named_file_input_port(stdin, scheme_intern_symbol("stdin")) - : make_oskit_console_input_port()) -#else -# ifdef MZ_FDS -# ifdef WINDOWS_FILE_HANDLES - : make_fd_input_port((intptr_t)GetStdHandle(STD_INPUT_HANDLE), scheme_intern_symbol("stdin"), 0, 0, - stdin_refcount, 0) -# else - : make_fd_input_port(0, scheme_intern_symbol("stdin"), 0, 0, stdin_refcount, 0) -# endif -# else - : scheme_make_named_file_input_port(stdin, scheme_intern_symbol("stdin")) -# endif -#endif - ); + : make_fd_input_port(rktio_std_fd(RKTIO_STDIN), scheme_intern_symbol("stdin"), 0, + stdin_refcount, 0)); scheme_orig_stdout_port = (scheme_make_stdout ? scheme_make_stdout() -#ifdef MZ_FDS -# ifdef WINDOWS_FILE_HANDLES - : make_fd_output_port((intptr_t)GetStdHandle(STD_OUTPUT_HANDLE), - scheme_intern_symbol("stdout"), 0, 0, 0, - -1, stdout_refcount) -# else - : make_fd_output_port(1, scheme_intern_symbol("stdout"), 0, 0, 0, -1, - stdout_refcount) -# endif -#else - : scheme_make_file_output_port(stdout) -#endif - ); + : make_fd_output_port(rktio_std_fd(RKTIO_STDOUT), scheme_intern_symbol("stdout"), 0, 0, + -1, stdout_refcount)); scheme_orig_stderr_port = (scheme_make_stderr ? scheme_make_stderr() -#ifdef MZ_FDS -# ifdef WINDOWS_FILE_HANDLES - : make_fd_output_port((intptr_t)GetStdHandle(STD_ERROR_HANDLE), - scheme_intern_symbol("stderr"), 0, 0, 0, - MZ_FLUSH_ALWAYS, stderr_refcount) -# else - : make_fd_output_port(2, scheme_intern_symbol("stderr"), 0, 0, 0, - MZ_FLUSH_ALWAYS, stderr_refcount) -# endif -#else - : scheme_make_file_output_port(stderr) -#endif - ); + : make_fd_output_port(rktio_std_fd(RKTIO_STDERR), scheme_intern_symbol("stderr"), 0, 0, + MZ_FLUSH_ALWAYS, stderr_refcount)); #ifdef MZ_FDS if (!scheme_current_place_id) { @@ -740,32 +467,6 @@ void scheme_init_port_places(void) } #endif -#if defined(FILES_HAVE_FDS) -# ifndef USE_OSKIT_CONSOLE - /* Set up a pipe for signaling external events: */ - { - int fds[2]; - if (!pipe(fds)) { - external_event_fd = fds[0]; - put_external_event_fd = fds[1]; - fcntl(external_event_fd, F_SETFL, MZ_NONBLOCKING); - fcntl(put_external_event_fd, F_SETFL, MZ_NONBLOCKING); - } else { - if (!scheme_current_place_id) { - scheme_log_abort("creation of scheduler pipe failed"); - abort(); - } else { - /* place will call scheme_check_place_port_ok() to discover failure */ - } - } - } -# endif -#endif - -#ifdef WIN32_FD_HANDLES - scheme_break_semaphore = (void*)CreateSemaphore(NULL, 0, 1, NULL); -#endif - flush_out = SCHEME_TRUEP(scheme_terminal_port_p(1, &scheme_orig_stdout_port)); flush_err = SCHEME_TRUEP(scheme_terminal_port_p(1, &scheme_orig_stderr_port)); } @@ -795,844 +496,37 @@ void scheme_set_stdio_makers(Scheme_Stdio_Maker_Proc in, scheme_make_stderr = err; } -#ifdef MZ_USE_PLACES -void scheme_check_place_port_ok() -{ -# if defined(FILES_HAVE_FDS) -# ifndef USE_OSKIT_CONSOLE - if (!external_event_fd && !put_external_event_fd) { - scheme_signal_error("place: scheduler pipe failed"); - } -# endif -# endif -} -#endif - /*========================================================================*/ /* fd arrays */ /*========================================================================*/ -/* Implement fd arrays (FD_SET, etc) with a runtime-determined size. - Also implement special hooks for Windows "descriptors", like - even queues and semaphores. */ - void scheme_alloc_global_fdset() { -#ifdef USE_FAR_MZ_FDCALLS - REGISTER_SO(scheme_fd_set); - scheme_fd_set = (struct mz_fd_set *)scheme_alloc_fdset_array(3, 0); -#endif - - REGISTER_SO(scheme_semaphore_fd_set); -#ifdef USE_FAR_MZ_FDCALLS - scheme_semaphore_fd_set = (struct mz_fd_set *)scheme_alloc_fdset_array(3, 0); -#else - scheme_semaphore_fd_set = (struct mz_fd_set *)scheme_malloc_atomic(3 * sizeof(fd_set)); -#endif - scheme_fdzero(MZ_GET_FDSET(scheme_semaphore_fd_set, 0)); - scheme_fdzero(MZ_GET_FDSET(scheme_semaphore_fd_set, 1)); - scheme_fdzero(MZ_GET_FDSET(scheme_semaphore_fd_set, 2)); - - REGISTER_SO(scheme_semaphore_fd_mapping); - scheme_semaphore_fd_mapping = scheme_make_hash_table_eqv(); + scheme_semaphore_fd_set = rktio_ltps_open(scheme_rktio); } -#ifdef HAVE_POLL_SYSCALL - -# define PFD_EXTRA_SPACE 1 - -void *scheme_alloc_fdset_array(int count, int permanent) -{ - struct mz_fd_set_data *data; - struct mz_fd_set *r, *w, *e; - struct pollfd *pfd; - - data = (struct mz_fd_set_data *)scheme_malloc(sizeof(struct mz_fd_set_data)); - r = (struct mz_fd_set *)scheme_malloc(sizeof(struct mz_fd_set)); - w = (struct mz_fd_set *)scheme_malloc(sizeof(struct mz_fd_set)); - e = (struct mz_fd_set *)scheme_malloc(sizeof(struct mz_fd_set)); - - r->w = w; - r->e = e; - r->data = data; - w->data = data; - e->data = data; - - r->flags = scheme_make_integer(POLLIN); - w->flags = scheme_make_integer(POLLOUT); - e->flags = scheme_make_integer(0); - - data->size = scheme_make_integer(32); - data->count = scheme_make_integer(0); - - pfd = (struct pollfd *)scheme_malloc_atomic(sizeof(struct pollfd) * (32 + PFD_EXTRA_SPACE)); - data->pfd = pfd; - - if (permanent) - scheme_dont_gc_ptr(r); - - return r; +void scheme_free_global_fdset(void) { + rktio_ltps_close(scheme_rktio, scheme_semaphore_fd_set); } -void *scheme_init_fdset_array(void *fdarray, int count) -{ - ((struct mz_fd_set *)fdarray)->data->count = scheme_make_integer(0); - return fdarray; -} - -void *scheme_get_fdset(void *fdarray, int pos) -{ - switch (pos) { - case 0: - return fdarray; - case 1: - return ((struct mz_fd_set *)fdarray)->w; - case 2: - default: - return ((struct mz_fd_set *)fdarray)->e; - } -} - -void scheme_fdzero(void *fd) -{ - ((struct mz_fd_set *)fd)->data->count = scheme_make_integer(0); -} - -static int find_fd_pos(struct mz_fd_set_data *data, int n) -{ - intptr_t count = SCHEME_INT_VAL(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 scheme_fdclr(void *fd, int n) -{ - struct mz_fd_set_data *data = ((struct mz_fd_set *)fd)->data; - intptr_t flag = SCHEME_INT_VAL(((struct mz_fd_set *)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 scheme_fdset(void *fd, int n) -{ - struct mz_fd_set_data *data = ((struct mz_fd_set *)fd)->data; - intptr_t flag = SCHEME_INT_VAL(((struct mz_fd_set *)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 = SCHEME_INT_VAL(data->count); - size = SCHEME_INT_VAL(data->size); - if (count >= size) { - size = size * 2; - pfd = scheme_malloc_atomic(sizeof(struct pollfd) * (size + PFD_EXTRA_SPACE)); - memcpy(pfd, data->pfd, sizeof(struct pollfd) * count); - data->pfd = pfd; - data->size = scheme_make_integer(size); - } - - data->pfd[count].fd = n; - data->pfd[count].events = flag; - count++; - data->count = scheme_make_integer(count); -} - -int scheme_fdisset(void *fd, int n) -{ - struct mz_fd_set_data *data = ((struct mz_fd_set *)fd)->data; - intptr_t flag = SCHEME_INT_VAL(((struct mz_fd_set *)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; -} - -void *scheme_merge_fd_sets(void *fds, void *src_fds) -{ - struct mz_fd_set_data *data = ((struct mz_fd_set *)fds)->data; - struct mz_fd_set_data *src_data = ((struct mz_fd_set *)src_fds)->data; - int i, si, c, sc, j, nc; - struct pollfd *pfds; - - scheme_clean_fd_set(fds); - scheme_clean_fd_set(src_fds); - - c = SCHEME_INT_VAL(data->count); - sc = SCHEME_INT_VAL(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 *)scheme_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 > SCHEME_INT_VAL(data->size)) { - data->pfd = pfds; - data->size = scheme_make_integer(nc); - } else - memcpy(data->pfd, pfds, j * sizeof(struct pollfd)); - data->count = scheme_make_integer(j); - - return fds; -} - -void scheme_clean_fd_set(void *fds) -{ - struct mz_fd_set_data *data = ((struct mz_fd_set *)fds)->data; - intptr_t count = SCHEME_INT_VAL(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 = scheme_make_integer(count); -} - -int scheme_get_fd_limit(void *fds) -{ - return 0; -} - -#else - -# if defined(USE_DYNAMIC_FDSET_SIZE) -/* initialized early via scheme_alloc_global_fdset */ -SHARED_OK static int dynamic_fd_size; - -# define STORED_ACTUAL_FDSET_LIMIT -# define FDSET_LIMIT(fd) (*(int *)((char *)fd XFORM_OK_PLUS dynamic_fd_size)) - -void *scheme_alloc_fdset_array(int count, int permanent) - XFORM_SKIP_PROC -{ - /* Note: alloc only at the end, because this function - isn't annotated. We skip annotation so that it's - ok with OS X use from default_sleep() */ - - 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*)); - } - - if (permanent) - return scheme_malloc_eternal(count * (dynamic_fd_size + sizeof(intptr_t))); - else - return scheme_malloc_atomic_allow_interior(count * (dynamic_fd_size + sizeof(intptr_t))); -} - -void *scheme_init_fdset_array(void *fdarray, int count) -{ - return fdarray; -} - -void *scheme_get_fdset(void *fdarray, int pos) -{ - return ((char *)fdarray) + (pos * (dynamic_fd_size + sizeof(intptr_t))); -} - -void scheme_fdzero(void *fd) -{ - memset(fd, 0, dynamic_fd_size + sizeof(intptr_t)); -} - -# else - -# if defined(WIN32_FD_HANDLES) -# define fdset_type win_extended_fd_set -# else -# define fdset_type fd_set -# endif - -void *scheme_alloc_fdset_array(int count, int permanent) -{ -# if defined(FILES_HAVE_FDS) || defined(USE_TCP) || defined(WIN32_FD_HANDLES) - void *fdarray; -# if defined(WIN32_FD_HANDLES) - if (count) { - fdarray = scheme_malloc_allow_interior(count * sizeof(fdset_type)); - if (permanent) - scheme_dont_gc_ptr(fdarray); - - scheme_init_fdset_array(fdarray, count); - } else - fdarray = NULL; -# else - if (permanent) - fdarray = scheme_malloc_eternal(count * sizeof(fdset_type)); - else - fdarray = scheme_malloc_atomic(count * sizeof(fdset_type)); -# endif - return fdarray; -# else - return NULL; -# endif -} - -# if defined(WIN32_FD_HANDLES) -static void reset_wait_array(win_extended_fd_set *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 * (SCHEME_INT_VAL(efd->alloc) + SCHEME_INT_VAL(efd->alloc_handles))) + 2; - HANDLE *wa; - wa = MALLOC_N_ATOMIC(HANDLE, sz); - efd->wait_array = wa; -} -# endif - -void *scheme_init_fdset_array(void *fdarray, int count) -{ -# if defined(WIN32_FD_HANDLES) - if (count) { - int i; - win_extended_fd_set *fd; - for (i = 0; i < count; i++) { - int reset = 0; - fd = (win_extended_fd_set *)scheme_get_fdset(fdarray, i); - fd->added = scheme_make_integer(0); - if (SCHEME_INT_VAL(fd->alloc) > (2 * SCHEME_INT_VAL(fd->last_alloc))) { - fd->alloc = scheme_make_integer(0); - fd->sockets = NULL; - reset = 1; - } - fd->last_alloc = scheme_make_integer(0); - fd->num_handles = scheme_make_integer(0); - if (SCHEME_INT_VAL(fd->alloc_handles) > (2 * SCHEME_INT_VAL(fd->last_alloc_handles))) { - fd->alloc_handles = scheme_make_integer(0); - fd->handles = NULL; - fd->repost_sema = NULL; - reset = 1; - } - fd->last_alloc_handles = scheme_make_integer(0); - fd->no_sleep = NULL; - fd->wait_event_mask = scheme_make_integer(0); - if (reset) - reset_wait_array(fdarray); - } - } -# endif - return fdarray; -} - -void *scheme_get_fdset(void *fdarray, int pos) -{ -# if defined(FILES_HAVE_FDS) || defined(USE_TCP) || defined(WIN32_FD_HANDLES) - return ((fdset_type *)fdarray) + pos; -# else - return NULL; -# endif -} - -void scheme_fdzero(void *fd) -{ -# if defined(WIN32_FD_HANDLES) - scheme_init_fdset_array(fd, 1); -# else -# if defined(FILES_HAVE_FDS) || defined(USE_TCP) - XFORM_HIDE_EXPR(FD_ZERO((fd_set *)fd)); -# endif -# endif -} - -# endif - -void scheme_fdclr(void *fd, int n) -{ -#if defined(WIN32_FD_HANDLES) - win_extended_fd_set *efd = (win_extended_fd_set *)fd; - int i; - for (i = SCHEME_INT_VAL(efd->added); i--; ) { - if (efd->sockets[i] == n) - efd->sockets[i] = INVALID_SOCKET; - } -#else -# if defined(FILES_HAVE_FDS) || defined(USE_TCP) - FD_CLR((unsigned)n, ((fd_set *)fd)); -# endif -#endif -} - -#if defined(WIN32_FD_HANDLES) -static int next_size(int v) { return (v ? (2 * v) : 10); } -#endif - -void scheme_fdset(void *fd, int n) -{ -#if defined(WIN32_FD_HANDLES) - win_extended_fd_set *efd = (win_extended_fd_set *)fd; - if (SCHEME_INT_VAL(efd->added) >= SCHEME_INT_VAL(efd->last_alloc)) { - int na; - na = next_size(SCHEME_INT_VAL(efd->last_alloc)); - efd->last_alloc = scheme_make_integer(na); - } - if (SCHEME_INT_VAL(efd->added) >= SCHEME_INT_VAL(efd->alloc)) { - SOCKET *naya; - int na; - na = next_size(SCHEME_INT_VAL(efd->alloc)); - naya = (SOCKET *)scheme_malloc_atomic(na * sizeof(SOCKET)); - memcpy(naya, efd->sockets, SCHEME_INT_VAL(efd->alloc) * sizeof(SOCKET)); - efd->sockets = naya; - efd->alloc = scheme_make_integer(na); - reset_wait_array(efd); - } - efd->sockets[SCHEME_INT_VAL(efd->added)] = n; - efd->added = scheme_make_integer(1 + SCHEME_INT_VAL(efd->added)); -#else -# if defined(FILES_HAVE_FDS) || defined(USE_TCP) -# ifdef STORED_ACTUAL_FDSET_LIMIT - int mx; - mx = FDSET_LIMIT(fd); - if (n > mx) - FDSET_LIMIT(fd) = n; -# endif - FD_SET(n, ((fd_set *)fd)); -# endif -#endif -} - -int scheme_fdisset(void *fd, int n) -{ -#if defined(WIN32_FD_HANDLES) - win_extended_fd_set *efd = (win_extended_fd_set *)fd; - int i; - for (i = SCHEME_INT_VAL(efd->added); i--; ) { - if (efd->sockets[i] == n) - return 1; - } - return 0; -#else -# if defined(FILES_HAVE_FDS) || defined(USE_TCP) - return FD_ISSET(n, ((fd_set *)fd)); -# else - return 0; -# endif -#endif -} - -void *scheme_merge_fd_sets(void *fds, void *src_fds) -{ -#if defined(WIN32_FD_HANDLES) - win_extended_fd_set *efd = (win_extended_fd_set *)src_fds; - int i; - for (i = SCHEME_INT_VAL(efd->added); i--; ) { - if (efd->sockets[i] != INVALID_SOCKET) - scheme_fdset(fds, efd->sockets[i]); - } - return fds; -#else - int i, j; - GC_CAN_IGNORE unsigned char *p, *sp; - for (j = 0; j < 3; j++) { - p = scheme_get_fdset(fds, j); - sp = scheme_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; -#endif -} - -void scheme_clean_fd_set(void *fds) -{ -} - -int scheme_get_fd_limit(void *fds) - XFORM_SKIP_PROC -/* This function must not allocate or call GC-cooperating functions. - It's constrained because it's used by default_sleep, which - must not allocate on Mac OS X. */ -{ - int actual_limit; - fd_set *rd, *wr, *ex; - - rd = (fd_set *)fds; - wr = (fd_set *)MZ_GET_FDSET(fds, 1); - ex = (fd_set *)MZ_GET_FDSET(fds, 2); -# 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++; -# else - { - int limit; -# ifdef USE_WINSOCK_TCP - limit = 0; -# else -# ifdef USE_ULIMIT - limit = ulimit(4, 0); -# else -# ifdef FIXED_FD_LIMIT - limit = FIXED_FD_LIMIT; -# else - limit = getdtablesize(); -# endif -# endif -# endif - - actual_limit = limit; - } -# endif - - return actual_limit; -} - -#endif - void scheme_add_fd_handle(void *h, void *fds, int repost) { #if defined(WIN32_FD_HANDLES) - win_extended_fd_set *efd = (win_extended_fd_set *)fds; - OS_SEMAPHORE_TYPE *hs; - int i, new_i, *rps; - - if (SCHEME_INT_VAL(efd->num_handles) == SCHEME_INT_VAL(efd->last_alloc_handles)) { - i = next_size(SCHEME_INT_VAL(efd->last_alloc_handles)); - efd->last_alloc_handles = scheme_make_integer(1); - } - if (SCHEME_INT_VAL(efd->num_handles) == SCHEME_INT_VAL(efd->alloc_handles)) { - i = SCHEME_INT_VAL(efd->alloc_handles); - new_i = next_size(i); - hs = MALLOC_N_ATOMIC(OS_SEMAPHORE_TYPE, new_i); - rps = MALLOC_N_ATOMIC(int, new_i); - memcpy(hs, efd->handles, sizeof(OS_SEMAPHORE_TYPE)*i); - memcpy(rps, efd->repost_sema, sizeof(int)*i); - efd->handles = hs; - efd->repost_sema = rps; - efd->alloc_handles = scheme_make_integer(new_i); - reset_wait_array(efd); - } - i = SCHEME_INT_VAL(efd->num_handles); - efd->handles[i] = (OS_SEMAPHORE_TYPE)h; - efd->repost_sema[i] = repost; - efd->num_handles = scheme_make_integer(1 + SCHEME_INT_VAL(efd->num_handles)); -#else - /* Do nothing. */ + rktio_poll_set_add_handle(scheme_rktio, (intptr_t)h, fds, repost); #endif } void scheme_add_fd_nosleep(void *fds) { -#if defined(WIN32_FD_HANDLES) - win_extended_fd_set *efd = (win_extended_fd_set *)fds; - efd->no_sleep = scheme_true; -#else -#endif + rktio_poll_set_nosleep(scheme_rktio, fds); } void scheme_add_fd_eventmask(void *fds, int mask) { #if defined(WIN32_FD_HANDLES) - win_extended_fd_set *efd = (win_extended_fd_set *)fds; - efd->wait_event_mask = scheme_make_integer(mask | SCHEME_INT_VAL(efd->wait_event_mask)); + rktio_poll_set_add_eventmask(scheme_rktio, mask, fds); #endif } -#if defined(WIN32_FD_HANDLES) -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); - } -} -#endif - -void scheme_collapse_win_fd(void *fds) -{ -#if defined(WIN32_FD_HANDLES) - win_extended_fd_set *rfd, *wfd, *efd; - HANDLE *wa, e; - int i, p = 0, mask, j; - SOCKET s; - - rfd = (win_extended_fd_set *)fds; - wfd = (win_extended_fd_set *)scheme_get_fdset(fds, 1); - efd = (win_extended_fd_set *)scheme_get_fdset(fds, 2); - - if (rfd->combined_wait_array) { - /* clean up */ - for (i = SCHEME_INT_VAL(rfd->added); i--; ) { - if (rfd->sockets[i] != INVALID_SOCKET) - WSAEventSelect(rfd->sockets[i], NULL, 0); - } - for (i = SCHEME_INT_VAL(wfd->added); i--; ) { - if (wfd->sockets[i] != INVALID_SOCKET) - WSAEventSelect(wfd->sockets[i], NULL, 0); - } - for (i = SCHEME_INT_VAL(efd->added); i--; ) { - if (efd->sockets[i] != INVALID_SOCKET) - WSAEventSelect(efd->sockets[i], NULL, 0); - } - p = SCHEME_INT_VAL(rfd->num_handles); - for (i = SCHEME_INT_VAL(rfd->combined_len); i-- > p; ) { - WSACloseEvent(rfd->combined_wait_array[i]); - } - rfd->combined_wait_array = NULL; - } else { - /* merge */ - if (SCHEME_INT_VAL(rfd->alloc) < SCHEME_INT_VAL(wfd->alloc)) { - if (SCHEME_INT_VAL(wfd->alloc) < SCHEME_INT_VAL(efd->alloc)) - wa = efd->wait_array; - else - wa = wfd->wait_array; - } else { - if (SCHEME_INT_VAL(rfd->alloc) < SCHEME_INT_VAL(efd->alloc)) - wa = efd->wait_array; - else - wa = rfd->wait_array; - } - - rfd->combined_wait_array = wa; - - p = SCHEME_INT_VAL(rfd->num_handles); - for (i = 0; i < p; i++) { - wa[i] = rfd->handles[i]; - } - - for (i = SCHEME_INT_VAL(rfd->added); i--; ) { - s = rfd->sockets[i]; - if (s != INVALID_SOCKET) { - mask = FD_READ | FD_ACCEPT | FD_CLOSE; - - for (j = SCHEME_INT_VAL(wfd->added); j--; ) { - if (wfd->sockets[j] == s) { - mask |= FD_WRITE; - break; - } - } - - for (j = SCHEME_INT_VAL(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 = SCHEME_INT_VAL(wfd->added); i--; ) { - s = wfd->sockets[i]; - if (s != INVALID_SOCKET) { - mask = FD_WRITE | FD_CONNECT | FD_CLOSE; - - for (j = SCHEME_INT_VAL(rfd->added); j--; ) { - if (rfd->sockets[j] == s) { - mask = 0; - break; - } - } - - if (mask) { - for (j = SCHEME_INT_VAL(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 = SCHEME_INT_VAL(efd->added); i--; ) { - s = efd->sockets[i]; - if (s != INVALID_SOCKET) { - mask = FD_OOB | FD_CLOSE; - - for (j = SCHEME_INT_VAL(rfd->added); j--; ) { - if (rfd->sockets[j] == s) { - mask = 0; - break; - } - } - - if (mask) { - for (j = SCHEME_INT_VAL(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 = scheme_make_integer(p); - } -#endif -} - -intptr_t scheme_dup_file(intptr_t fd) { -#ifdef WINDOWS_FILE_HANDLES - HANDLE newhandle; - BOOL rc; - - rc = DuplicateHandle(GetCurrentProcess(), (HANDLE) fd, - GetCurrentProcess(), &newhandle, - 0, FALSE, DUPLICATE_SAME_ACCESS); - - if (rc == FALSE) { - return -1; - } - else { - return (intptr_t) newhandle; - } -#else - intptr_t nfd; - do { - nfd = dup(fd); - } while (nfd == -1 && errno == EINTR); - return nfd; -#endif -} - -void scheme_close_file_fd(intptr_t fd) { -#ifdef WINDOWS_FILE_HANDLES - CloseHandle((HANDLE)fd); -#else - { - intptr_t rc; - do { - rc = close(fd); - } while (rc == -1 && errno == EINTR); - } -#endif -} - - /*========================================================================*/ /* Windows thread suspension */ /*========================================================================*/ @@ -1792,7 +686,6 @@ void scheme_resume_remembered_threads(void) { } /* Generic port support */ /*========================================================================*/ - Scheme_Object *scheme_make_port_type(const char *name) { return scheme_make_symbol(name); @@ -4431,13 +3324,10 @@ int scheme_get_port_file_descriptor(Scheme_Object *p, intptr_t *_fd) if (SAME_OBJ(ip->sub_type, file_input_port_type)) { fd = MSC_IZE(fileno)((FILE *)((Scheme_Input_File *)ip->port_data)->f); fd_ok = 1; - } -#ifdef MZ_FDS - else if (SAME_OBJ(ip->sub_type, fd_input_port_type)) { - fd = ((Scheme_FD *)ip->port_data)->fd; + } else if (SAME_OBJ(ip->sub_type, fd_input_port_type)) { + fd = rktio_fd_system_fd(scheme_rktio, ((Scheme_FD *)ip->port_data)->fd); fd_ok = 1; } -#endif } } else if (SCHEME_OUTPUT_PORTP(p)) { Scheme_Output_Port *op; @@ -4448,13 +3338,10 @@ int scheme_get_port_file_descriptor(Scheme_Object *p, intptr_t *_fd) if (SAME_OBJ(op->sub_type, file_output_port_type)) { fd = MSC_IZE (fileno)((FILE *)((Scheme_Output_File *)op->port_data)->f); fd_ok = 1; - } -#ifdef MZ_FDS - else if (SAME_OBJ(op->sub_type, fd_output_port_type)) { - fd = ((Scheme_FD *)op->port_data)->fd; + } else if (SAME_OBJ(op->sub_type, fd_output_port_type)) { + fd = rktio_fd_system_fd(scheme_rktio, ((Scheme_FD *)op->port_data)->fd); fd_ok = 1; } -#endif } } @@ -4465,6 +3352,35 @@ int scheme_get_port_file_descriptor(Scheme_Object *p, intptr_t *_fd) return 1; } +int scheme_get_port_rktio_file_descriptor(Scheme_Object *p, rktio_fd_t *_fd) +{ + if (SCHEME_INPUT_PORTP(p)) { + Scheme_Input_Port *ip; + + ip = scheme_input_port_record(p); + + if (!ip->closed) { + if (SAME_OBJ(ip->sub_type, fd_input_port_type)) { + *_fd = ((Scheme_FD *)ip->port_data)->fd; + return 1; + } + } + } else if (SCHEME_OUTPUT_PORTP(p)) { + Scheme_Output_Port *op; + + op = scheme_output_port_record(p); + + if (!op->closed) { + if (SAME_OBJ(op->sub_type, fd_output_port_type)) { + *_fd = ((Scheme_FD *)op->port_data)->fd; + return 1; + } + } + } + + return 0; +} + intptr_t scheme_get_port_fd(Scheme_Object *p) { intptr_t fd; @@ -4511,18 +3427,14 @@ Scheme_Object *scheme_file_identity(int argc, Scheme_Object *argv[]) static int is_fd_terminal(intptr_t fd) { -#if defined(WIN32_FD_HANDLES) - if (GetFileType((HANDLE)fd) == FILE_TYPE_CHAR) { - DWORD mode; - if (GetConsoleMode((HANDLE)fd, &mode)) - return 1; - else - return 0; - } else - return 0; -#else - return isatty(fd); -#endif + rktio_fd_t *rfd; + int is_term; + + rfd = rktio_system_fd(fd, RKTIO_OPEN_NOT_REGFILE); + is_term = rktio_fd_is_terminal(scheme_rktio, rfd); + rktio_fd_forget(rfd); + + return is_term; } Scheme_Object *scheme_terminal_port_p(int argc, Scheme_Object *argv[]) @@ -4547,7 +3459,7 @@ Scheme_Object *scheme_terminal_port_p(int argc, Scheme_Object *argv[]) } #ifdef MZ_FDS else if (SAME_OBJ(ip->sub_type, fd_input_port_type)) { - fd = ((Scheme_FD *)ip->port_data)->fd; + fd = rktio_fd_to_system_fd(((Scheme_FD *)ip->port_data)->fd); fd_ok = 1; } #endif @@ -4565,7 +3477,7 @@ Scheme_Object *scheme_terminal_port_p(int argc, Scheme_Object *argv[]) } #ifdef MZ_FDS else if (SAME_OBJ(op->sub_type, fd_output_port_type)) { - fd = ((Scheme_FD *)op->port_data)->fd; + fd = rktio_fd_to_system_fd(((Scheme_FD *)op->port_data)->fd); fd_ok = 1; } #endif @@ -4577,7 +3489,7 @@ Scheme_Object *scheme_terminal_port_p(int argc, Scheme_Object *argv[]) return is_fd_terminal(fd) ? scheme_true : scheme_false; } -static void filename_exn(char *name, char *msg, char *filename, int err, int maybe_module_errno) +static void filename_exn(char *name, char *msg, char *filename, int maybe_module_errno) { char *dir, *drive; int len; @@ -4615,24 +3527,22 @@ static void filename_exn(char *name, char *msg, char *filename, int err, int may "%t%s: %s\n" " module path: %W\n" " path: %q%s%q%s\n" - " system error: " FILENAME_EXN_E, + " system error: %R", srcloc, srcloc_len, srcloc_len ? "" : name, "cannot open module file", mp, filename, - pre, rel, post, - err); + pre, rel, post); } else { scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_MISSING_MODULE, mod_path, "%s: %s\n" " module path: %W\n" " path: %q%s%q%s\n" - " system error: " FILENAME_EXN_E, + " system error: %R", name, "cannot open module file", mod_path, filename, - pre, rel, post, - err); + pre, rel, post); } return; } @@ -4641,31 +3551,19 @@ static void filename_exn(char *name, char *msg, char *filename, int err, int may scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, "%s: %s\n" " path: %q%s%q%s\n" - " system error: " FILENAME_EXN_E, + " system error: %R", name, msg, filename, - pre, rel, post, - err); + pre, rel, post); } Scheme_Object * -scheme_do_open_input_file(char *name, int offset, int argc, Scheme_Object *argv[], - int internal, char **err, int *eerrno, int for_module) +scheme_do_open_input_file(char *name, int offset, int argc, Scheme_Object *argv[], + int internal, int for_module) { -#ifdef USE_FD_PORTS - int fd; - struct stat buf; -#else - char *mode = "rb"; -# ifdef WINDOWS_FILE_HANDLES - HANDLE fd; -# else - FILE *fp; -# endif -#endif char *filename; int regfile, i; - int m_set = 0, mm_set = 0; - Scheme_Object *result; + int m_set = 0, mm_set = 0, text_mode = 0; + rktio_fd_t *fd; if (!SCHEME_PATH_STRINGP(argv[0])) scheme_wrong_contract(name, "path-string?", 0, argc, argv); @@ -4675,9 +3573,7 @@ scheme_do_open_input_file(char *name, int offset, int argc, Scheme_Object *argv[ scheme_wrong_contract(name, "symbol?", i, argc, argv); if (SAME_OBJ(argv[i], text_symbol)) { -#ifndef USE_FD_PORTS - mode = "rt"; -#endif + text_mode = 1; m_set++; } else if (SAME_OBJ(argv[i], binary_symbol)) { /* This is the default */ @@ -4720,118 +3616,21 @@ scheme_do_open_input_file(char *name, int offset, int argc, Scheme_Object *argv[ if (!internal) scheme_custodian_check_available(NULL, name, "file-stream"); -#ifdef USE_FD_PORTS - /* Note: assuming there's no difference between text and binary mode */ - do { - fd = open(filename, O_RDONLY | MZ_NONBLOCKING | MZ_BINARY); - } while ((fd == -1) && (errno == EINTR)); + fd = rktio_open(filename, (RKTIO_OPEN_READ + | (text_mode ? RKTIO_OPEN_TEXT : 0))); - if (fd == -1) { - if (err) { - *err = "cannot open source file"; - *eerrno = errno; - } else - filename_exn(name, "cannot open input file", filename, errno, (for_module ? ENOENT : 0)); - return NULL; - } else { - int ok; - - do { - ok = fstat(fd, &buf); - } while ((ok == -1) && (errno == EINTR)); - - if (S_ISDIR(buf.st_mode)) { - int cr; - do { - cr = close(fd); - } while ((cr == -1) && (errno == EINTR)); - if (err) { - *err = "source is a directory"; - *eerrno = 0; - } else - filename_exn(name, "cannot open directory as a file", filename, 0, 0); - return NULL; - } else { - regfile = S_ISREG(buf.st_mode); - result = make_fd_input_port(fd, scheme_make_path(filename), regfile, 0, NULL, internal); - } - } -#else -# ifdef WINDOWS_FILE_HANDLES - fd = CreateFileW(WIDE_PATH(filename), - GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - 0, - NULL); - - if (fd == INVALID_HANDLE_VALUE) { - if (err) { - int errv; - errv = GetLastError(); - *err = "cannot open source file"; - *eerrno = errv; - } else - filename_exn(name, "cannot open input file", filename, GetLastError(), (for_module ? ERROR_FILE_NOT_FOUND : 0)); - return NULL; - } else - regfile = (GetFileType(fd) == FILE_TYPE_DISK); - - if ((mode[1] == 't') && !regfile) { - CloseHandle(fd); - filename_exn(name, "cannot use text-mode on a non-file device", filename, 0, 0); + if (!fd) { + filename_exn(name, "cannot open input file", filename, RKTIO_ERROR_DOES_NOT_EXIST); return NULL; } - - result = make_fd_input_port((intptr_t)fd, scheme_make_path(filename), regfile, mode[1] == 't', NULL, internal); -# else - if (scheme_directory_exists(filename)) { - if (err) { - *err = "source is a directory"; - *eerrno = 0; - } else - filename_exn(name, err, filename, 0, 0); - return NULL; - } - - regfile = scheme_is_regular_file(filename); - - fp = fopen(filename, mode); - if (!fp) { - if (err) { - *err = "cannot open source file"; - *eerrno = errno; - } else - filename_exn(name, "cannot open input file", filename, errno, (for_module ? ENOENT : 0)); - return NULL; - } - - result = scheme_make_named_file_input_port(fp, scheme_make_path(filename)); -# endif -#endif - - return result; + + return make_fd_input_port(fd, scheme_make_path(filename), NULL, internal); } Scheme_Object * scheme_do_open_output_file(char *name, int offset, int argc, Scheme_Object *argv[], int and_read, - int internal, char **err, int *eerrno) + int internal) { -#ifdef USE_FD_PORTS - int fd; - int flags, regfile; - struct stat buf; - int ok; -#else -# ifdef WINDOWS_FILE_HANDLES - HANDLE fd; - int hmode, regfile; - BY_HANDLE_FILE_INFORMATION info; -# else - FILE *fp; -# endif -#endif int e_set = 0, m_set = 0, i; int existsok = 0, must_exist = 0; char *filename; @@ -4939,267 +3738,36 @@ scheme_do_open_output_file(char *name, int offset, int argc, Scheme_Object *argv scheme_custodian_check_available(NULL, name, "file-stream"); -#ifdef USE_FD_PORTS - /* Note: assuming there's no difference between text and binary mode */ + fd = rktio_open(filename, (RKTIO_OPEN_WRITE + | (and_read ? RKTIO_OPEN_READ : 0) + | ((mode[1] == 't') ? RKTIO_OPEN_TEXT : 0))); - flags = (and_read ? O_RDWR : O_WRONLY) | (must_exist ? 0 : O_CREAT); - - if (mode[0] == 'a') - flags |= O_APPEND; - else if (existsok < 0) - flags |= O_TRUNC; - - if ((existsok <= 1) && (existsok > -1)) - flags |= O_EXCL; - - do { - fd = open(filename, flags | MZ_NONBLOCKING | MZ_BINARY, 0666); - } while ((fd == -1) && (errno == EINTR)); - - if (errno == ENXIO) { - /* FIFO with no reader? Try opening in RW mode: */ - flags -= O_WRONLY; - flags |= O_RDWR; - do { - fd = open(filename, flags | MZ_NONBLOCKING | MZ_BINARY, 0666); - } while ((fd == -1) && (errno == EINTR)); - } - - if (fd == -1) { - if (errno == EISDIR) { - if (err) { - *err = "destination is a directory path"; - *eerrno = errno; - return NULL; - } else - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_EXISTS, - "%s: path is a directory\n" - " path: %q", - name, filename); - } else if (errno == EEXIST) { - if (!existsok) { - if (err) { - *err = "destination already exists"; - *eerrno = errno; - return NULL; - } else - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_EXISTS, - "%s: file exists\n" - " path: %q", name, filename); - } else { - do { - ok = unlink(filename); - } while ((ok == -1) && (errno == EINTR)); - - if (ok) - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - "%s: error deleting file\n" - " path: %q", - name, filename); - do { - fd = open(filename, flags | MZ_BINARY, 0666); - } while ((fd == -1) && (errno == EINTR)); - } - } - - if (fd == -1) { - if (err) { - *err = "cannot open destination file"; - *eerrno = errno; - } else - filename_exn(name, "cannot open output file", filename, errno, 0); - return NULL; - } - } - - do { - ok = fstat(fd, &buf); - } while ((ok == -1) && (errno == EINTR)); - - regfile = S_ISREG(buf.st_mode); - return make_fd_output_port(fd, scheme_make_path(filename), regfile, 0, and_read, - -1, NULL); -#else -# ifdef WINDOWS_FILE_HANDLES - if (!existsok) - hmode = CREATE_NEW; - else if (existsok < 0) { - if (must_exist) - hmode = TRUNCATE_EXISTING; - else - hmode = OPEN_ALWAYS; - } else if (existsok == 1) { - /* assert: !must_exist */ - hmode = CREATE_ALWAYS; - } else if (existsok == 2) { - hmode = OPEN_EXISTING; - } else if (existsok == 3) { - hmode = OPEN_ALWAYS; - } - - fd = CreateFileW(WIDE_PATH(filename), - GENERIC_WRITE | (and_read ? GENERIC_READ : 0), - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - hmode, - FILE_FLAG_BACKUP_SEMANTICS, /* lets us detect directories in NT */ - NULL); - - if (fd == INVALID_HANDLE_VALUE) { - int errv; - errv = GetLastError(); - if ((errv == ERROR_ACCESS_DENIED) && (existsok < -1)) { - /* Delete and try again... */ - if (DeleteFileW(WIDE_PATH(filename))) { - fd = CreateFileW(WIDE_PATH(filename), - GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - hmode, - 0, - NULL); - if (fd == INVALID_HANDLE_VALUE) - errv = GetLastError(); - } else { - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, + if (!fd) { + if (scheme_last_error_is_racket(RKTIO_ERROR_EXISTS)) { + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_EXISTS, + "%s: file exists\n" + " path: %q", name, filename); + } else if (scheme_last_error_is_racket(RKTIO_ERROR_IS_A_DIRECTORY)) { + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_EXISTS, + "%s: path is a directory\n" + " path: %q", + name, filename); + } else { +#if 0 + /* Add a way to get this information from rktio_open()? */ + if (???) + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, "%s: error deleting file\n" " path: %q\n" - " system error: %E", - name, filename, GetLastError()); - return NULL; - } - } else if (errv == ERROR_FILE_EXISTS) { - if (err) { - *err = "destination already exists"; - *eerrno = errv; - } else - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_EXISTS, - "%s: file exists\n" - " path: %q", name, filename); - return NULL; - } + " system error: %R", + name, filename); - if (fd == INVALID_HANDLE_VALUE) { - if (err) { - *err = "cannot open destination"; - *eerrno = errv; - } else - filename_exn(name, "cannot open output file", filename, errv, 0); - return NULL; - } - } - - if (GetFileInformationByHandle(fd, &info)) { - if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - CloseHandle(fd); - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_EXISTS, - "%s: path is a directory\n" - " path: %q", - name, filename); - return NULL; - } - } - - regfile = (GetFileType(fd) == FILE_TYPE_DISK); - - if ((mode[1] == 't') && !regfile) { - CloseHandle(fd); - filename_exn(name, "cannot use text-mode on a non-file device", filename, 0, 0); - return NULL; - } - - if (regfile && (existsok < 0)) { - if (mode[0] == 'a') - SetFilePointer(fd, 0, NULL, FILE_END); - else - SetEndOfFile(fd); - } - - return make_fd_output_port((intptr_t)fd, scheme_make_path(filename), regfile, mode[1] == 't', and_read, - -1, NULL); -# else - if (scheme_directory_exists(filename)) { - if (err) { - *err = "destination is a directory path"; - *eerrno = 0; - } else if (!existsok) - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_EXISTS, - "%s: path is a directory\n" - " path: %q", - name, filename); - else - filename_exn(name, "cannot open directory as a file", filename, errno, 0); - return NULL; - } - - - if (and_read) { - scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, - "%s: " NOT_SUPPORTED_STR, - name); - return NULL; - } - - if (scheme_file_exists(filename)) { - int uok; - - if (!existsok) { - if (err) { - *err = "destination exists already"; - *eerrno = 0; - } else - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_EXISTS, - "%s: file exists\n" - " path: %q", name, filename); - return NULL; - } - - do { - uok = MSC_IZE(unlink)(filename); - } while ((uok == -1) && (errno == EINTR)); - - if (uok) - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_EXISTS, - "%s: error deleting file\n" - " path: %q\n" - " system error: %e", - name, filename, errno); - } - - fp = fopen(filename, mode); - if (!fp) { - if (existsok < -1) { - /* Can't truncate; try to replace */ - if (scheme_file_exists(filename)) { - int uok; - - do { - uok = MSC_IZE(unlink)(filename); - } while ((uok == -1) && (errno == EINTR)); - - if (uok) - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM_EXISTS, - "%s: error deleting file\n" - " path: %q", - name, filename); - else { - fp = fopen(filename, mode); - } - } - } - if (!fp) { - if (err) { - *err = "cannot open destination"; - *eerrno = errno; - } else - filename_exn(name, "cannot open output file", filename, errno); - return NULL; - } - } - - return scheme_make_file_output_port(fp); -# endif #endif + filename_exn(name, "cannot open output file", filename, 0); + } + } + + return make_fd_output_port(fd, scheme_make_path(filename), and_read, -1, NULL); } Scheme_Object *scheme_open_input_file(const char *name, const char *who) @@ -5207,7 +3775,7 @@ Scheme_Object *scheme_open_input_file(const char *name, const char *who) Scheme_Object *a[1]; a[0]= scheme_make_path(name); - return scheme_do_open_input_file((char *)who, 0, 1, a, 0, NULL, NULL, 0); + return scheme_do_open_input_file((char *)who, 0, 1, a, 0, 0); } Scheme_Object *scheme_open_output_file(const char *name, const char *who) @@ -5216,7 +3784,7 @@ Scheme_Object *scheme_open_output_file(const char *name, const char *who) a[0]= scheme_make_path(name); a[1] = truncate_replace_symbol; - return scheme_do_open_output_file((char *)who, 0, 2, a, 0, 0, NULL, NULL); + return scheme_do_open_output_file((char *)who, 0, 2, a, 0, 0); } Scheme_Object *scheme_open_input_output_file(const char *name, const char *who, Scheme_Object **oport) @@ -5225,7 +3793,7 @@ Scheme_Object *scheme_open_input_output_file(const char *name, const char *who, a[0]= scheme_make_path(name); a[1] = truncate_replace_symbol; - scheme_do_open_output_file((char *)who, 0, 2, a, 1, 0, NULL, NULL); + scheme_do_open_output_file((char *)who, 0, 2, a, 1, 0); *oport = scheme_multiple_array[1]; return scheme_multiple_array[0]; } @@ -5237,7 +3805,7 @@ Scheme_Object *scheme_open_output_file_with_mode(const char *name, const char *w a[0]= scheme_make_path(name); a[1] = truncate_replace_symbol; a[2] = (text ? text_symbol : binary_symbol); - return scheme_do_open_output_file((char *)who, 0, 3, a, 0, 0, NULL, NULL); + return scheme_do_open_output_file((char *)who, 0, 3, a, 0, 0); } #ifdef WINDOWS_FILE_HANDLES @@ -5255,10 +3823,7 @@ do_file_position(const char *who, int argc, Scheme_Object *argv[], int can_false { FILE *f; Scheme_Indexed_String *is; - intptr_t fd; -#ifdef MZ_FDS - int had_fd; -#endif + rktio_fd_t *fd; int wis; if (!SCHEME_OUTPUT_PORTP(argv[0]) && !SCHEME_INPUT_PORTP(argv[0])) @@ -5283,10 +3848,7 @@ do_file_position(const char *who, int argc, Scheme_Object *argv[], int can_false f = NULL; is = NULL; wis = 0; - fd = 0; -#ifdef MZ_FDS - had_fd = 0; -#endif + fd = NULL; if (!SCHEME_INPUT_PORTP(argv[0])) { Scheme_Output_Port *op; @@ -5295,11 +3857,8 @@ do_file_position(const char *who, int argc, Scheme_Object *argv[], int can_false if (SAME_OBJ(op->sub_type, file_output_port_type)) { f = ((Scheme_Output_File *)op->port_data)->f; -#ifdef MZ_FDS } else if (SAME_OBJ(op->sub_type, fd_output_port_type)) { fd = ((Scheme_FD *)op->port_data)->fd; - had_fd = 1; -#endif } else if (SAME_OBJ(op->sub_type, scheme_string_output_port_type)) { is = (Scheme_Indexed_String *)op->port_data; wis = 1; @@ -5325,11 +3884,8 @@ do_file_position(const char *who, int argc, Scheme_Object *argv[], int can_false if (SAME_OBJ(ip->sub_type, file_input_port_type)) { f = ((Scheme_Input_File *)ip->port_data)->f; -#ifdef MZ_FDS } else if (SAME_OBJ(ip->sub_type, fd_input_port_type)) { fd = ((Scheme_FD *)ip->port_data)->fd; - had_fd = 1; -#endif } else if (SAME_OBJ(ip->sub_type, scheme_string_input_port_type)) is = (Scheme_Indexed_String *)ip->port_data; else if (argc < 2) { @@ -5346,11 +3902,7 @@ do_file_position(const char *who, int argc, Scheme_Object *argv[], int can_false } } - if (!f -#ifdef MZ_FDS - && !had_fd -#endif - && !is) + if (!f && !fd && !is) scheme_contract_error(who, "setting position allowed for file-stream and string ports only", "port", 1, argv[0], @@ -5390,43 +3942,22 @@ do_file_position(const char *who, int argc, Scheme_Object *argv[], int can_false " system error: %e", errno); } -#ifdef MZ_FDS - } else if (had_fd) { + } else if (fd) { intptr_t lv; int errid = 0; if (!SCHEME_INPUT_PORTP(argv[0])) { flush_fd(scheme_output_port_record(argv[0]), NULL, 0, 0, 0, 0); } - -# ifdef WINDOWS_FILE_HANDLES - if (win_seekable(fd)) { - DWORD r; - LONG lo_w, hi_w; - lo_w = (LONG)(nll & 0xFFFFFFFF); - hi_w = (LONG)(nll >> 32); - r = SetFilePointer((HANDLE)fd, lo_w, &hi_w, - ((whence == SEEK_SET) ? FILE_BEGIN : FILE_END)); - if ((r == INVALID_SET_FILE_POINTER) - && GetLastError() != NO_ERROR) { - errid = GetLastError(); - lv = -1; - } else - lv = 0; - } else { - lv = -1; - errid = ERROR_UNSUPPORTED_TYPE; - } -# else - lv = BIG_OFF_T_IZE(lseek)(fd, nll, whence); - if (lv < 0) errid = errno; -# endif - if (lv < 0) { + if (!rktio_set_file_position(scheme_rktio, fd, nll, + ((whence == SEEK_SET) + ? RKTIO_POSITION_FROM_START + : RKTIO_POSITION_FROM__END))) { scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, "file-position: position change failed on stream\n" - " system error: " FILENAME_EXN_E, - errid); + " system error: %R"); + return NULL; } if (SCHEME_INPUT_PORTP(argv[0])) { @@ -5440,7 +3971,6 @@ do_file_position(const char *who, int argc, Scheme_Object *argv[], int can_false /* 1 means no pending eof, but can set: */ ip->pending_eof = 1; } -#endif } else { intptr_t n; @@ -5505,32 +4035,22 @@ do_file_position(const char *who, int argc, Scheme_Object *argv[], int can_false mzlonglong pll; if (f) { pll = BIG_OFF_T_IZE(ftello)(f); -#ifdef MZ_FDS - } else if (had_fd) { -# ifdef WINDOWS_FILE_HANDLES - if (win_seekable(fd)) { - DWORD lo_w, hi_w; - hi_w = 0; - lo_w = SetFilePointer((HANDLE)fd, 0, &hi_w, FILE_CURRENT); - if ((lo_w == INVALID_SET_FILE_POINTER) - && GetLastError() != NO_ERROR) - pll = -1; - else - pll = ((mzlonglong)hi_w << 32) | lo_w; - } else - pll = -1; -# else - pll = BIG_OFF_T_IZE(lseek)(fd, 0, 1); -# endif - if (pll < 0) { + } else if (fd) { + rktio_filesize_t *sz; + + sz = rktio_get_file_position(scheme_rktio, fd); + if (!sz) { pll = do_tell(argv[0], 0); } else { + pll = *sz; + free(sz); + if (SCHEME_INPUT_PORTP(argv[0])) { Scheme_Input_Port *ip; ip = scheme_input_port_record(argv[0]); pll -= ((Scheme_FD *)ip->port_data)->bufcount; -# ifdef WINDOWS_FILE_HANDLES - if (((Scheme_FD *)ip->port_data)->textmode) { + if (rktio_fd_is_text_converted(fd)) { + /* Correct for CRLF->LF conversion of buffer content */ int bp, bd; bd = ((Scheme_FD *)ip->port_data)->buffpos; for (bp = ((Scheme_FD *)ip->port_data)->bufcount; bp--; ) { @@ -5539,19 +4059,14 @@ do_file_position(const char *who, int argc, Scheme_Object *argv[], int can_false pll--; } } - if (((Scheme_FD *)ip->port_data)->textmode > 1) { - /* one more for leftover CR */ - pll--; - } + pll -= rktio_buffered_byte_count(scheme_rktio, ((Scheme_FD *)ip->port_data)->fd); } -# endif } else { Scheme_Output_Port *op; op = scheme_output_port_record(argv[0]); pll += ((Scheme_FD *)op->port_data)->bufcount; } } -#endif } else if (wis) pll = is->index; else { @@ -5590,7 +4105,7 @@ Scheme_Object *scheme_file_truncate(int argc, Scheme_Object *argv[]) { mzlonglong nll; Scheme_Output_Port *op; - intptr_t fd; + rktio_fd_t *fd; int errid; if (!SCHEME_OUTPUT_PORTP(argv[0]) @@ -5611,55 +4126,19 @@ Scheme_Object *scheme_file_truncate(int argc, Scheme_Object *argv[]) if (SAME_OBJ(op->sub_type, file_output_port_type)) { fd = MSC_IZE (fileno)((FILE *)((Scheme_Output_File *)op->port_data)->f); -#ifdef MZ_FDS } else if (SAME_OBJ(op->sub_type, fd_output_port_type)) { fd = ((Scheme_FD *)op->port_data)->fd; -#endif } else return scheme_void; errid = -1; -#ifdef WINDOWS_FILE_HANDLES flush_fd(scheme_output_port_record(argv[0]), NULL, 0, 0, 0, 0); - if (win_seekable(fd)) { - DWORD r; - LONG lo_w, hi_w, old_lo_w, old_hi_w; - old_hi_w = 0; - old_lo_w = SetFilePointer((HANDLE)fd, 0, &old_hi_w, FILE_CURRENT); - if ((old_lo_w == INVALID_SET_FILE_POINTER) - && GetLastError() != NO_ERROR) { - errid = GetLastError(); - } else { - lo_w = (LONG)(nll & 0xFFFFFFFF); - hi_w = (LONG)(nll >> 32); - r = SetFilePointer((HANDLE)fd, lo_w, &hi_w, FILE_BEGIN); - if ((r == INVALID_SET_FILE_POINTER) - && GetLastError() != NO_ERROR) { - errid = GetLastError(); - } else { - if (SetEndOfFile((HANDLE)fd)) { - /* we assume that this works: */ - (void)SetFilePointer((HANDLE)fd, lo_w, &hi_w, FILE_BEGIN); - return scheme_void; - } - errid = GetLastError(); - } - } - } else { - errid = ERROR_UNSUPPORTED_TYPE; + + if (!rktio_set_file_size(scheme_rktio, fd, nll)) { + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, + "file-truncate: size change failed\n" + " system error: %R"); } -#else -# ifdef MZ_FDS - if (!BIG_OFF_T_IZE(ftruncate)(fd, nll)) - return scheme_void; - errid = errno; -# endif -#endif - - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - "file-truncate: size change failed\n" - " system error: " FILENAME_EXN_E, - errid); return NULL; } @@ -5743,194 +4222,6 @@ scheme_file_buffer(int argc, Scheme_Object *argv[]) } } -static int try_lock(intptr_t fd, int writer, int *_errid) -{ -#ifdef UNIX_FILE_SYSTEM -# ifdef USE_FLOCK_FOR_FILE_LOCKS - { - int ok; - - do { - ok = flock(fd, (writer ? LOCK_EX : LOCK_SH) | LOCK_NB); - } while ((ok == -1) && (errno == EINTR)); - - if (ok == 0) - return 1; - - if (errno == EWOULDBLOCK) { - *_errid = 0; - return 0; - } - - *_errid = errno; - return 0; - } -# 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(). */ - { - int ifds[2], ofds[2], cr; - - if (locked_fd_process_map) - if (scheme_hash_get(locked_fd_process_map, scheme_make_integer(fd))) - /* already have a lock */ - return 1; - - 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; - - do { - cr = close(ifds[1]); - } while ((cr == -1) && (errno == EINTR)); - do { - cr = close(ofds[0]); - } while ((cr == -1) && (errno == EINTR)); - - do{ - cr = read(ifds[0], &errid, sizeof(int)); - } while ((cr == -1) && (errno == EINTR)); - if (cr == -1) - errid = errno; - - do { - cr = close(ifds[0]); - } while ((cr == -1) && (errno == EINTR)); - - if (errid) { - do { - cr = close(ofds[1]); - } while ((cr == -1) && (errno == EINTR)); - - if (errid == EAGAIN) - *_errid = 0; - else - *_errid = errid; - - return 0; - } else { - /* got lock; record fd -> pipe mapping */ - if (!locked_fd_process_map) { - REGISTER_SO(locked_fd_process_map); - locked_fd_process_map = scheme_make_hash_table(SCHEME_hash_ptr); - } - scheme_hash_set(locked_fd_process_map, - scheme_make_integer(fd), - scheme_make_pair(scheme_make_integer(ofds[1]), - scheme_make_integer(pid))); - return 1; - } - } else if (!pid) { - /* Child process */ - int ok = 0; - struct flock fl; - - do { - cr = close(ifds[0]); - } while ((cr == -1) && (errno == EINTR)); - do { - cr = close(ofds[1]); - } while ((cr == -1) && (errno == EINTR)); -#ifdef CLOSE_ALL_FDS_AFTER_FORK - close_fds_after_fork(ifds[1], ofds[0], fd); -#endif - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = (writer ? 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 { - int i; - *_errid = errno; - for (i = 0; i < 2; i++) { - do { - cr = close(ifds[i]); - } while ((cr == -1) && (errno == EINTR)); - do { - cr = close(ofds[i]); - } while ((cr == -1) && (errno == EINTR)); - } - return 0; - } - } else { - int i; - *_errid = errno; - for (i = 0; i < 2; i++) { - do { - cr = close(ifds[i]); - } while ((cr == -1) && (errno == EINTR)); - } - return 0; - } - } else { - *_errid = errno; - return 0; - } - } -# else - *_errid = ENOTSUP; - return 0; -# endif -#endif -#ifdef WINDOWS_FILE_HANDLES - { - OVERLAPPED o; - int errid; - -# define LOCK_ALL_FILE_LO 0 -# define LOCK_ALL_FILE_HI 0x10000 - - memset(&o, 0, sizeof(OVERLAPPED)); - if (LockFileEx((HANDLE)fd, - (LOCKFILE_FAIL_IMMEDIATELY - | (writer ? LOCKFILE_EXCLUSIVE_LOCK : 0)), - 0, - LOCK_ALL_FILE_LO, LOCK_ALL_FILE_HI, - &o)) - return 1; - - errid = GetLastError(); - if (errid == ERROR_LOCK_VIOLATION) - *_errid = 0; - else - *_errid = errid; - - return 0; - } -#endif -} - static void check_already_closed(const char *name, Scheme_Object *p) { int is_closed; @@ -5949,10 +4240,12 @@ static void check_already_closed(const char *name, Scheme_Object *p) Scheme_Object *scheme_file_try_lock(int argc, Scheme_Object **argv) { + rktio_fd_t *rfd = NULL; intptr_t fd; - int writer = 0, errid; + int writer = 0, r; - if (!scheme_get_port_file_descriptor(argv[0], &fd)) + if (!scheme_get_port_rktio_file_descriptor(argv[0], &rfd) + && !scheme_get_port_file_descriptor(argv[0], &fd)) scheme_wrong_contract("port-try-file-lock?", "file-stream-port?", 0, argc, argv); if (SCHEME_SYMBOLP(argv[1]) && !SCHEME_SYM_WEIRDP(argv[1])) { @@ -5981,83 +4274,49 @@ Scheme_Object *scheme_file_try_lock(int argc, Scheme_Object **argv) check_already_closed("port-try-file-lock?", argv[0]); - if (try_lock(fd, writer, &errid)) + if (!rfd) { + rfd = scheme_system_fd(scheme_rktio, fd, RKTIO_OPEN_READ | RKTIO_OPEN_WRITE); + r = rktio_file_lock_try(scheme_rktio, rfd, write); + rktio_forget(scheme_rktio, rfd); + } else + r = rktio_file_lock_try(scheme_rktio, rfd, write); + + if (r == RKTIO_LOCK_ACQUIRED) return scheme_true; - if (errid) { + if (r == RKTIO_LOCK_ERROR) { scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, "port-try-file-lock?: error getting file %s lock\n" - " system error: %E", - (writer ? "exclusive" : "shared"), - errid); + " system error: %R", + (writer ? "exclusive" : "shared")); } return scheme_false; } -#ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS -static void release_lockf(int fd) -{ - if (locked_fd_process_map) { - Scheme_Object *v; - v = scheme_hash_get(locked_fd_process_map, scheme_make_integer(fd)); - if (v) { - int fd2, cr, pid, status; - - fd2 = SCHEME_INT_VAL(SCHEME_CAR(v)); - pid = SCHEME_INT_VAL(SCHEME_CDR(v)); - scheme_hash_set(locked_fd_process_map, scheme_make_integer(fd), NULL); - - scheme_block_child_signals(1); - do { - cr = close(fd2); /* makes the fork()ed process exit */ - } while ((cr == -1) && (errno == EINTR)); - waitpid(pid, &status, 0); - scheme_block_child_signals(0); - } - } -} -#endif - Scheme_Object *scheme_file_unlock(int argc, Scheme_Object **argv) { - int ok, errid; intptr_t fd; + rktio_fd_t *rfd = NULL; + int r; - if (!scheme_get_port_file_descriptor(argv[0], &fd)) + if (!scheme_get_port_rktio_file_descriptor(argv[0], &rfd) + && !scheme_get_port_file_descriptor(argv[0], &fd)) scheme_wrong_contract("port-file-unlock", "file-stream-port?", 0, argc, argv); check_already_closed("port-file-unlock", argv[0]); -#ifdef UNIX_FILE_SYSTEM -# ifdef USE_FLOCK_FOR_FILE_LOCKS - do { - ok = flock(fd, LOCK_UN); - } while ((ok == -1) && (errno == EINTR)); - ok = !ok; - errid = errno; -# elif defined(USE_FCNTL_AND_FORK_FOR_FILE_LOCKS) - release_lockf(fd); - ok = 1; - errid = 0; -# else - ok = 0; - errid = ENOTSUP; -# endif -#endif -#ifdef WINDOWS_FILE_HANDLES - ok = UnlockFile((HANDLE)fd, 0, 0, LOCK_ALL_FILE_LO, LOCK_ALL_FILE_HI); - if (!ok) - errid = GetLastError(); - else - errid = 0; -#endif + if (!rfd) { + rfd = scheme_system_fd(scheme_rktio, fd, RKTIO_OPEN_READ | RKTIO_OPEN_WRITE); + r = rktio_file_unlock(scheme_rktio, rfd, write); + rktio_forget(scheme_rktio, rfd); + } else + r = rktio_file_unlock(rktio, fd); - if (!ok) { + if (!r) { scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, "port-file-unlock: error unlocking file\n" - " system error: %E", - errid); + " system error: %R"); } return scheme_void; @@ -6067,34 +4326,11 @@ Scheme_Object *scheme_file_unlock(int argc, Scheme_Object **argv) /* filesystem change events */ /*========================================================================*/ -#if defined(HAVE_KQUEUE_SYSCALL) \ - || defined(DOS_FILE_SYSTEM) \ - || defined(HAVE_INOTIFY_SYSCALL) \ - || defined(FILESYSTEM_NEVER_CHANGES) -# define HAVE_FILESYSTEM_CHANGE_EVTS -#else -# define NO_FILESYSTEM_CHANGE_EVTS -#endif - -#if defined(HAVE_INOTIFY_SYSCALL) -# include "inotify.inc" -#endif - -#if !defined(NO_FILESYSTEM_CHANGE_EVTS) && !defined(FILESYSTEM_NEVER_CHANGES) -static void filesystem_change_evt_fnl(void *fc, void *data) -{ - scheme_filesystem_change_evt_cancel((Scheme_Object *)fc, NULL); -} -#endif - Scheme_Object *scheme_filesystem_change_evt(Scheme_Object *path, int flags, int signal_errs) { char *filename; int ok = 0; -#ifndef NO_FILESYSTEM_CHANGE_EVTS - int errid = 0; -#endif - intptr_t fd; + rktio_fs_change_t *rfc; filename = scheme_expand_string_filename(path, "filesystem-change-evt", @@ -6102,308 +4338,78 @@ Scheme_Object *scheme_filesystem_change_evt(Scheme_Object *path, int flags, int SCHEME_GUARD_FILE_EXISTS); fd = 0; -#if defined(NO_FILESYSTEM_CHANGE_EVTS) - ok = 0; -#elif defined(FILESYSTEM_NEVER_CHANGES) - ok = 1; -#elif defined(HAVE_KQUEUE_SYSCALL) - do { - fd = open(filename, flags | MZ_BINARY, 0666); - } while ((fd == -1) && (errno == EINTR)); - if (fd == -1) - errid = errno; - else - ok = 1; -#elif defined(HAVE_INOTIFY_SYSCALL) - /* see "inotify.inc" */ - mz_inotify_init(); - if (!mz_inotify_ready()) - errid = mz_inotify_errid(); - else { - fd = mz_inotify_add(filename); - if (fd == -1) - errid = errno; - else - ok = 1; - } -#elif defined(DOS_FILE_SYSTEM) - { - HANDLE h; - char *try_filename = filename; - - while (1) { - h = FindFirstChangeNotificationW(WIDE_PATH(try_filename), FALSE, - (FILE_NOTIFY_CHANGE_FILE_NAME - | FILE_NOTIFY_CHANGE_DIR_NAME - | FILE_NOTIFY_CHANGE_SIZE - | FILE_NOTIFY_CHANGE_LAST_WRITE - | FILE_NOTIFY_CHANGE_ATTRIBUTES)); - if (h == INVALID_HANDLE_VALUE) { - /* If `filename' refers to a file, then monitor its enclosing directory. */ - errid = GetLastError(); - if ((try_filename == filename) && scheme_file_exists(filename)) { - Scheme_Object *base, *name; - int is_dir; - name = scheme_split_path(filename, strlen(filename), &base, &is_dir, SCHEME_PLATFORM_PATH_KIND); - try_filename = scheme_expand_string_filename(base, - "filesystem-change-evt", - NULL, - SCHEME_GUARD_FILE_EXISTS); - } else - break; - } else { - fd = (intptr_t)h; - ok = 1; - break; - } - } - } -#endif - - if (!ok) { - if (signal_errs) { -#ifdef NO_FILESYSTEM_CHANGE_EVTS + rfc = rktio_fs_change(scheme_rktio, filename); + + if (!rfc) { + if (scheme_last_error_is_racket(RKTIO_ERROR_UNSUPPORTED)) { scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, "filesystem-change-evt: " NOT_SUPPORTED_STR "\n" " path: %q\n", filename); -#else + } else { scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, "filesystem-change-evt: error generating event\n" " path: %q\n" - " system error: %E", - filename, - errid); -#endif + " system error: %R", + filename); } return NULL; } -#if defined(NO_FILESYSTEM_CHANGE_EVTS) - return NULL; -#elif defined(FILESYSTEM_NEVER_CHANGES) - { - Scheme_Filesystem_Change_Evt *fc; - - fc = MALLOC_ONE_TAGGED(Scheme_Filesystem_Change_Evt); - fc->so.type = scheme_filesystem_change_evt_type; - - return (Scheme_Object *)fc; - } -#elif defined(DOS_FILE_SYSTEM) || defined(HAVE_INOTIFY_SYSCALL) { Scheme_Filesystem_Change_Evt *fc; Scheme_Custodian_Reference *mref; fc = MALLOC_ONE_TAGGED(Scheme_Filesystem_Change_Evt); fc->so.type = scheme_filesystem_change_evt_type; - fc->fd = fd; - - mref = scheme_add_managed(NULL, (Scheme_Object *)fc, scheme_filesystem_change_evt_cancel, NULL, 1); - fc->mref = mref; - scheme_add_finalizer(fc, filesystem_change_evt_fnl, NULL); - - return (Scheme_Object *)fc; - } -#else - { - Scheme_Filesystem_Change_Evt *fc; - Scheme_Object *sema; - Scheme_Custodian_Reference *mref; - - sema = scheme_fd_to_semaphore(fd, MZFD_CREATE_VNODE, 0); - if (!sema) { - const char *reason = ""; - -#if defined(HAVE_KQUEUE_SYSCALL) - if (!scheme_fd_regular_file(fd, 1)) - reason = ";\n not a regular file or directory"; -#endif - - scheme_close_file_fd(fd); - - if (signal_errs) { - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - "filesystem-change-evt: cannot generate event%s\n" - " path: %q", - reason, - filename); - } - return NULL; - } - - fc = MALLOC_ONE_TAGGED(Scheme_Filesystem_Change_Evt); - fc->so.type = scheme_filesystem_change_evt_type; - fc->fd = fd; - fc->sema = sema; + fc->rfc = rfc; mref = scheme_add_managed(NULL, (Scheme_Object *)fc, scheme_filesystem_change_evt_cancel, NULL, 1); fc->mref = mref; - scheme_add_finalizer(fc, filesystem_change_evt_fnl, NULL); - return (Scheme_Object *)fc; } -#endif } void scheme_filesystem_change_evt_cancel(Scheme_Object *evt, void *ignored_data) { -#ifndef NO_FILESYSTEM_CHANGE_EVTS Scheme_Filesystem_Change_Evt *fc = (Scheme_Filesystem_Change_Evt *)evt; - if (fc->mref) { -# if defined(FILESYSTEM_NEVER_CHANGES) - fc->mref = NULL; -# else -# if defined(DOS_FILE_SYSTEM) - if (fc->fd) { - FindCloseChangeNotification((HANDLE)fc->fd); - fc->fd = 0; - } -# elif defined(HAVE_INOTIFY_SYSCALL) - if (fc->fd) { - mz_inotify_remove(fc->fd); - fc->fd = 0; - } -# else - (void)scheme_fd_to_semaphore(fc->fd, MZFD_REMOVE_VNODE, 0); - scheme_close_file_fd(fc->fd); - scheme_post_sema_all(fc->sema); -# endif - scheme_remove_managed(fc->mref, (Scheme_Object *)fc); - fc->mref = NULL; -# endif - } -#endif + rktio_fs_change_forget(scheme_rktio, fc->rfc); + fc->rfc = NULL; } static int filesystem_change_evt_ready(Scheme_Object *evt, Scheme_Schedule_Info *sinfo) { -#ifndef NO_FILESYSTEM_CHANGE_EVTS Scheme_Filesystem_Change_Evt *fc = (Scheme_Filesystem_Change_Evt *)evt; -# if defined(DOS_FILE_SYSTEM) - if (fc->fd) { - if (WaitForSingleObject((HANDLE)fc->fd, 0) == WAIT_OBJECT_0) - scheme_filesystem_change_evt_cancel((Scheme_Object *)fc, NULL); - } - - return !fc->fd; -# elif defined(HAVE_INOTIFY_SYSCALL) - if (fc->fd) { - if (mz_inotify_poll(fc->fd)) - scheme_filesystem_change_evt_cancel((Scheme_Object *)fc, NULL); - } - - return !fc->fd; -# elif defined(FILESYSTEM_NEVER_CHANGES) - return fc->fd; /* = 0 */ -# else - if (scheme_try_plain_sema(fc->sema)) - scheme_filesystem_change_evt_cancel((Scheme_Object *)fc, NULL); - else - scheme_check_fd_semaphores(); - scheme_set_sync_target(sinfo, fc->sema, evt, NULL, 0, 1, NULL); -# endif - -#endif + if (!fc->rfd) + return 1; + if (rktio_poll_fs_change_ready(scheme_rktio, fc->rfc)) + return 1; + return 0; } -#if defined(DOS_FILE_SYSTEM) || defined(HAVE_INOTIFY_SYSCALL) static void filesystem_change_evt_need_wakeup (Scheme_Object *evt, void *fds) { Scheme_Filesystem_Change_Evt *fc = (Scheme_Filesystem_Change_Evt *)evt; - if (fc->fd) { -#ifdef DOS_FILE_SYSTEM - scheme_add_fd_handle((void *)fc->fd, fds, 0); -#else - int fd; - fd = mz_inotify_fd(); - if (fd >= 0) { - void *fds2; - fds2 = MZ_GET_FDSET(fds, 0); - MZ_FD_SET(fd, (fd_set *)fds2); - fds2 = MZ_GET_FDSET(fds, 2); - MZ_FD_SET(fd, (fd_set *)fds2); - } else if (fd == -2) { - scheme_cancel_sleep(); - } -#endif - } -} -#endif - -int scheme_fd_regular_file(intptr_t fd, int or_other) -/* or_other == 1 => directory - or_other == 2 => directory or fifo */ -{ -#if defined(USE_FD_PORTS) && !defined(DOS_FILE_SYSTEM) - int ok; - struct stat buf; - - do { - ok = fstat(fd, &buf); - } while ((ok == -1) && (errno == EINTR)); - - if (ok == -1) { - scheme_log(NULL, SCHEME_LOG_ERROR, 0, - "error while checking whether a file descriptor is a regular file: %d", - errno); - return 0; - } - - if (S_ISREG(buf.st_mode)) - return 1; - - if ((or_other >= 1) && S_ISDIR(buf.st_mode)) - return 1; - - if ((or_other >= 2) && S_ISFIFO(buf.st_mode)) - return 1; - - return 0; -#else - return 0; -#endif -} - -void scheme_release_inotify() -{ -#ifdef HAVE_INOTIFY_SYSCALL - mz_inotify_stop(); -#endif + if (fc->rfc) + rktio_poll_add_fs_change(scheme_rktio, fc->rfc, fds); } void scheme_fs_change_properties(int *_supported, int *_scalable, int *_low_latency, int *_file_level) { -#ifdef NO_FILESYSTEM_CHANGE_EVTS - *_supported = 0; - *_scalable = 0; - *_low_latency = 0; - *_file_level = 0; -#else - *_supported = 1; -# if defined(HAVE_KQUEUE_SYSCALL) - *_scalable = 0; -# else - *_scalable = 1; -# endif -# if defined(HAVE_INOTIFY_SYSCALL) - *_low_latency = 0; -# else - *_low_latency = 1; -# endif -# if defined(DOS_FILE_SYSTEM) - *_file_level = 0; -# else - *_file_level = 1; -# endif -#endif + int props; + + props = rktio_fs_change_properties(scheme_rktio); + *_supported = ((props & RKTIO_FS_CHANGE_SUPPORTED) ? 1 : 0); + *_scalable = ((props & RKTIO_FS_CHANGE_SCALABLE) ? 1 : 0); + *_low_latency = ((props & RKTIO_FS_CHANGE_LOW_LATENCY) ? 1 : 0); + *_file_level = ((props & RKTIO_FS_CHANGE_FILE_LEVEL) ? 1 : 0); } /*========================================================================*/ @@ -6547,71 +4553,10 @@ scheme_make_file_input_port(FILE *fp) /* fd input ports */ /*========================================================================*/ -#ifdef MZ_FDS - -# ifdef WINDOWS_FILE_HANDLES -static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th); -static void WindowsFDICleanup(Win_FD_Input_Thread *th); -typedef BOOL (WINAPI* CSI_proc)(HANDLE); - -static CSI_proc get_csi(void) -{ - static int tried_csi = 0; - static CSI_proc csi; - - START_XFORM_SKIP; - if (!tried_csi) { - HMODULE hm; - hm = LoadLibrary("kernel32.dll"); - if (hm) - csi = (CSI_proc)GetProcAddress(hm, "CancelSynchronousIo"); - else - csi = NULL; - tried_csi = 1; - } - END_XFORM_SKIP; - return csi; -} - -# endif - -/* forward decl: */ -static void fd_need_wakeup(Scheme_Input_Port *port, void *fds); - -#ifdef SOME_FDS_ARE_NOT_SELECTABLE -static int try_get_fd_char(int fd, int *ready) -{ - int old_flags, c; - unsigned char buf[1]; - - old_flags = fcntl(fd, F_GETFL, 0); - if (!(old_flags & MZ_NONBLOCKING)) - fcntl(fd, F_SETFL, old_flags | MZ_NONBLOCKING); - do { - c = read(fd, buf, 1); - } while ((c == -1) && errno == EINTR); - if (!(old_flags & MZ_NONBLOCKING)) - fcntl(fd, F_SETFL, old_flags); - - if (c < 0) { - *ready = 0; - return 0; - } else { - *ready = 1; - if (!c) - return EOF; - else - return buf[0]; - } -} -#endif - static int fd_byte_ready (Scheme_Input_Port *port) { - Scheme_FD *fip; - - fip = (Scheme_FD *)port->port_data; + Scheme_FD *fip = (Scheme_FD *)port->port_data; if (fip->regfile || port->closed) return 1; @@ -6619,83 +4564,21 @@ fd_byte_ready (Scheme_Input_Port *port) if (fip->bufcount) return 1; else { -#ifdef WINDOWS_FILE_HANDLES - if (!fip->th) { - /* No thread -- so wait works. This case isn't actually used - right now, because wait doesn't seem to work reliably for - anything that we can recognize other than regfiles, which are - handled above. */ - if (WaitForSingleObject((HANDLE)fip->fd, 0) == WAIT_OBJECT_0) - return 1; - } else { - /* Has the reader thread pulled in data? */ - if (fip->th->checking) { - /* The thread is still trying, last we knew. Check the - data-is-ready sema: */ - if (WaitForSingleObject(fip->th->ready_sema, 0) == WAIT_OBJECT_0) { - fip->th->checking = 0; - return 1; - } - } else if (fip->th->avail || fip->th->err || fip->th->eof) - return 1; /* other thread found data */ - else { - /* Doesn't have anything, and it's not even looking. Tell it - to look: */ - fip->th->checking = 1; - ReleaseSemaphore(fip->th->checking_sema, 1, NULL); - } - } - - return 0; -#else - int r; -# ifdef HAVE_POLL_SYSCALL - GC_CAN_IGNORE struct pollfd pfd[1]; - pfd[0].fd = fip->fd; - pfd[0].events = POLLIN; - do { - r = poll(pfd, 1, 0); - } while ((r == -1) && (errno == EINTR)); -# else - DECL_FDSET(readfds, 1); - DECL_FDSET(exnfds, 1); - struct timeval time = {0, 0}; - - INIT_DECL_RD_FDSET(readfds); - INIT_DECL_ER_FDSET(exnfds); - - MZ_FD_ZERO(readfds); - MZ_FD_ZERO(exnfds); - MZ_FD_SET(fip->fd, readfds); - MZ_FD_SET(fip->fd, exnfds); - - do { - r = select(fip->fd + 1, readfds, NULL, exnfds, &time); - } while ((r == -1) && (errno == EINTR)); -# endif - -# ifdef SOME_FDS_ARE_NOT_SELECTABLE - /* Try a non-blocking read: */ - if (!r && !fip->textmode) { - int c, ready; - - c = try_get_fd_char(fip->fd, &ready); - if (ready) { - if (c != EOF) { - fip->buffpos = 0; - fip->buffer[0] = (unsigned char)c; - fip->bufcount = 1; - } - r = 1; - } - } -# endif - - return r; -#endif + if (rktio_poll_read_ready(scheme_rktio, fip->fd)) + return 1; + else + return 0; } } +static void +fd_need_wakeup(Scheme_Input_Port *port, void *fds) +{ + Scheme_FD *fip = (Scheme_FD *)port->port_data; + + rktio_poll_add(scheme_rktio, fip->fd, fds, RKTIO_POLL_READ); +} + MZ_DO_NOT_INLINE(static intptr_t fd_get_string_slow(Scheme_Input_Port *port, char *buffer, intptr_t offset, intptr_t size, int nonblock, @@ -6723,11 +4606,8 @@ static intptr_t fd_get_string_slow(Scheme_Input_Port *port, if (nonblock > 0) return 0; -#ifdef WINDOWS_FILE_HANDLES - sema = NULL; -#else sema = scheme_fd_to_semaphore(fip->fd, MZFD_CREATE_READ, 0); -#endif + if (sema) scheme_wait_sema(sema, nonblock ? -1 : 0); else @@ -6749,21 +4629,6 @@ static intptr_t fd_get_string_slow(Scheme_Input_Port *port, scheme_get_byte((Scheme_Object *)port); } - /* Another thread might have filled the buffer, or - if SOME_FDS_ARE_NOT_SELECTABLE is set, - fd_byte_ready might have read one character. */ - if (fip->bufcount) { - bc = ((size <= fip->bufcount) - ? size - : fip->bufcount); - - memcpy(buffer + offset, fip->buffer + fip->buffpos, bc); - fip->buffpos += bc; - fip->bufcount -= bc; - - return bc; - } - if ((size >= MZPORT_FD_DIRECT_THRESHOLD) && (fip->flush != MZ_FLUSH_ALWAYS)) { ext_target = 1; target = buffer; @@ -6779,132 +4644,29 @@ static intptr_t fd_get_string_slow(Scheme_Input_Port *port, target_size = MZPORT_FD_BUFFSIZE; } -#ifdef WINDOWS_FILE_HANDLES - if (!fip->th) { - /* We can read directly. This must be a regular file, where - reading never blocks. */ - DWORD rgot, delta; - - if (fip->textmode) { - ext_target = 0; - target = fip->buffer; - target_offset = 0; - if (fip->flush == MZ_FLUSH_ALWAYS) - target_size = 1; - else - target_size = MZPORT_FD_BUFFSIZE; - } - - rgot = target_size; - - /* Pending CR in text mode? */ - if (fip->textmode > 1) { - delta = 1; - if (rgot > 1) - rgot--; - fip->buffer[0] = '\r'; - } else - delta = 0; - - if (ReadFile((HANDLE)fip->fd, target XFORM_OK_PLUS target_offset + delta, rgot, &rgot, NULL)) { - bc = rgot; - } else { - int errid; - bc = -1; - errid = GetLastError(); - errno = errid; - } - - /* bc == 0 and no err => EOF */ - - /* Finish text-mode handling: */ - if (fip->textmode && (bc >= 0)) { - int i, j; - unsigned char *buf; - - if (fip->textmode > 1) { - /* we had added a CR */ - bc++; - fip->textmode = 1; - } - - /* If bc is only 1 in buffer mode, then we've reached the end, and - any leftover CR there should stay. */ - if ((bc > 1) || (bc && (target_size == 1))) { - /* Collapse CR-LF: */ - char *bufwidths = port->bufwidths; /* for file-position */ - buf = fip->buffer; - for (i = 0, j = 0; i < bc - 1; i++) { - if ((buf[i] == '\r') - && (buf[i+1] == '\n')) { - bufwidths[j] = 1; - buf[j++] = '\n'; - i++; - } else { - bufwidths[j] = 0; - buf[j++] = buf[i]; - } - } - if (i < bc) { /* common case: didn't end with CRLF */ - bufwidths[j] = 0; - buf[j++] = buf[i]; - } - bc = j; - /* Check for CR at end; if there, save it to maybe get a - LF on the next read: */ - if (buf[bc - 1] == '\r') { - bc--; - fip->textmode = 2; /* 2 indicates a leftover CR */ - } - } - } - - } else { + if (rktio_fd_is_text_converted(scheme_rktio, fip->fd)) { + /* Always read into the port buffer so that `bufwidths` can be + filled in parallel to the buffer. */ ext_target = 0; + target = fip->buffer; + target_offset = 0; + if (fip->flush == MZ_FLUSH_ALWAYS) + target_size = 1; + else + target_size = MZPORT_FD_BUFFSIZE; - /* If we get this far, there's definitely data available. - Extract data made available by the reader thread. */ - if (fip->th->eof) { - bc = 0; - if (fip->th->eof != INVALID_HANDLE_VALUE) { - ReleaseSemaphore(fip->th->eof, 1, NULL); - fip->th->eof = NULL; - } - } else if (fip->th->err) { - bc = -1; - errno = fip->th->err; - } else { - bc = fip->th->avail; - fip->th->avail = 0; - } - } -#else - if (fip->regfile) { - do { - bc = read(fip->fd, target + target_offset, target_size); - } while ((bc == -1) && (errno == EINTR)); + bc = rktio_read_converted(scheme_rktio, fip->fd, fip->buffer, target_size, fip->bufwidths); } else { - /* We use a non-blocking read here, even though we've waited - for input above, because an external process might have - gobbled the characters that we expected to get. */ - int old_flags; - - old_flags = fcntl(fip->fd, F_GETFL, 0); - if (!(old_flags & MZ_NONBLOCKING)) - fcntl(fip->fd, F_SETFL, old_flags | MZ_NONBLOCKING); - do { - bc = read(fip->fd, target + target_offset, target_size); - } while ((bc == -1) && errno == EINTR); - if (!(old_flags & MZ_NONBLOCKING)) - fcntl(fip->fd, F_SETFL, old_flags); - - if ((bc == -1) && (errno == EAGAIN)) { - none_avail = 1; - bc = 0; - } + bc = rktio_read(scheme_rktio, fip->fd, target + target_offset, target_size); } -#endif - + + if (bc == 0) + none_avail = 1; + else if (bc == RKTIO_READ_EOF) + bc = 0; /* EOF */ + else + bc = -1; /* error */ + if (!none_avail) { if (ext_target && (bc > 0)) { return bc; @@ -6918,14 +4680,14 @@ static intptr_t fd_get_string_slow(Scheme_Input_Port *port, scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, "error reading from stream port\n" " port: %V\n" - " system error: " FILENAME_EXN_E, - port->name, errno); + " system error: %R", + port->name); return 0; } if (!fip->bufcount) { - if (fip->textmode > 1) { - /* have a CR pending, so maybe keep trying */ + if (rktio_buffered_byte_count(scheme_rktio, fip->fd)) { + /* maybe have a CR pending for text conversion, so maybe keep trying */ if (nonblock > 0) return 0; } else { @@ -6994,59 +4756,16 @@ static void fd_close_input(Scheme_Input_Port *port) { Scheme_FD *fip; + int rc; fip = (Scheme_FD *)port->port_data; -#ifdef WINDOWS_FILE_HANDLES - if (fip->th) { - CSI_proc csi; - - /* -1 for checking means "shut down" */ - fip->th->checking = -1; - ReleaseSemaphore(fip->th->checking_sema, 1, NULL); - - if (fip->th->eof && (fip->th->eof != INVALID_HANDLE_VALUE)) { - ReleaseSemaphore(fip->th->eof, 1, NULL); - fip->th->eof = NULL; - } - - csi = get_csi(); - if (csi) { - /* Helps thread wake up. Otherwise, it's possible for the - thread to stay stuck trying to read, in which case the - file handle (probably a pipe) doesn't get closed. */ - csi(fip->th->thread); - } - - /* Try to get out of cleaning up the records (since they can't be - cleaned until the thread is also done: */ - if (WaitForSingleObject(fip->th->you_clean_up_sema, 0) != WAIT_OBJECT_0) { - /* The other thread exited and left us with clean-up: */ - WindowsFDICleanup(fip->th); - } /* otherwise, thread is responsible for clean-up */ + rc = adj_refcount(fip->refcount, -1); + if (!rc) { + rktio_close(fip->fd); } else { - int rc; - rc = adj_refcount(fip->refcount, -1); - if (!rc) { - CloseHandle((HANDLE)fip->fd); - } + rktio_forget(fip->fd); } -#else - { - int rc; - rc = adj_refcount(fip->refcount, -1); - if (!rc) { - int cr; - (void)scheme_fd_to_semaphore(fip->fd, MZFD_REMOVE, 0); - do { - cr = close(fip->fd); - } while ((cr == -1) && (errno == EINTR)); -# ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS - release_lockf(fip->fd); -# endif - } - } -#endif } static void @@ -7055,49 +4774,6 @@ fd_init_close_input(Scheme_Input_Port *port) /* never actually opened! */ } -static void -fd_need_wakeup(Scheme_Input_Port *port, void *fds) -{ - Scheme_FD *fip; - -#ifdef WINDOWS_FILE_HANDLES -#else - void *fds2; - int n; -#endif - - fip = (Scheme_FD *)port->port_data; - -#ifdef WINDOWS_FILE_HANDLES - if (fip->th) { - /* See fd_byte_ready */ - if (!fip->th->checking) { - if (fip->th->avail || fip->th->err || fip->th->eof) { - /* Data is ready. We shouldn't be trying to sleep, so force an - immediate wake-up: */ - scheme_add_fd_nosleep(fds); - } else { - fip->th->checking = 1; - ReleaseSemaphore(fip->th->checking_sema, 1, NULL); - scheme_add_fd_handle((void *)fip->th->ready_sema, fds, 1); - } - } else - scheme_add_fd_handle((void *)fip->th->ready_sema, fds, 1); - } else if (fip->regfile) { - /* regular files never block */ - scheme_add_fd_nosleep(fds); - } else { - /* This case is not currently used. See fd_byte_ready. */ - scheme_add_fd_handle((void *)fip->fd, fds, 0); - } -#else - n = fip->fd; - MZ_FD_SET(n, (fd_set *)fds); - fds2 = MZ_GET_FDSET(fds, 2); - MZ_FD_SET(n, (fd_set *)fds2); -#endif -} - static int fd_input_buffer_mode(Scheme_Port *p, int mode) { Scheme_FD *fd; @@ -7114,7 +4790,7 @@ static int fd_input_buffer_mode(Scheme_Port *p, int mode) } static Scheme_Object * -make_fd_input_port(intptr_t fd, Scheme_Object *name, int regfile, int win_textmode, int *refcount, int internal) +make_fd_input_port(rktio_fd_t *fd, Scheme_Object *name, int *refcount, int internal) { Scheme_Input_Port *ip; Scheme_FD *fip; @@ -7128,23 +4804,22 @@ make_fd_input_port(intptr_t fd, Scheme_Object *name, int regfile, int win_textmo bfr = (unsigned char *)scheme_malloc_atomic(MZPORT_FD_BUFFSIZE); fip->buffer = bfr; + if (rktio_fd_is_text_converted(scheme_rktio, fd)) { + char *bws; + bws = scheme_malloc_atomic(MZPORT_FD_BUFFSIZE); + fip->bufwidths = bws; + } fip->fd = fd; fip->bufcount = 0; - fip->regfile = regfile; -#ifdef SOME_FDS_ARE_NOT_SELECTABLE - if (regfile || isatty(fd)) - fip->textmode = 1; -#else - fip->textmode = (win_textmode ? 1 : 0); -#endif - if (refcount) { fip->refcount = refcount; if (!adj_refcount(refcount, 1)) { /* fd is already closed! */ start_closed = 1; + rktio_fd_forget(fd); + fip->fd = NULL; } } @@ -7167,354 +4842,28 @@ make_fd_input_port(intptr_t fd, Scheme_Object *name, int regfile, int win_textmo ip->pending_eof = 1; /* means that pending EOFs should be tracked */ -#ifdef WINDOWS_FILE_HANDLES - if (fip->textmode) { - char *bw; - bw = (char *)scheme_malloc_atomic(MZPORT_FD_BUFFSIZE); - ip->bufwidths = bw; - } -#endif - -#ifdef WINDOWS_FILE_HANDLES - if (!regfile && !start_closed) { - /* To get non-blocking I/O for anything that can block, we create - a separate reader thread. - - Yes, Windows NT pipes support non-blocking reads, but there - doesn't seem to be any way to use WaitForSingleObject to sleep - until characters are ready. PeekNamedPipe can be used for - polling, but not sleeping. */ - - Win_FD_Input_Thread *th; - DWORD id; - HANDLE h; - OS_SEMAPHORE_TYPE sm; - - th = (Win_FD_Input_Thread *)malloc(sizeof(Win_FD_Input_Thread)); - fip->th = th; - - /* Replace buffer with a malloced one: */ - bfr = (unsigned char *)malloc(MZPORT_FD_BUFFSIZE); - fip->buffer = bfr; - th->buffer = bfr; - - th->fd = (HANDLE)fd; - th->avail = 0; - th->err = 0; - th->eof = NULL; - th->checking = 0; - - sm = CreateSemaphore(NULL, 0, 1, NULL); - th->checking_sema = sm; - sm = CreateSemaphore(NULL, 0, 1, NULL); - th->ready_sema = sm; - sm = CreateSemaphore(NULL, 1, 1, NULL); - th->you_clean_up_sema = sm; - th->refcount = refcount; - - h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDReader, th, 0, &id); - - th->thread = h; - - scheme_remember_thread(h, 1); - } -#endif - if (start_closed) scheme_close_input_port((Scheme_Object *)ip); return (Scheme_Object *)ip; } -# ifdef WINDOWS_FILE_HANDLES - -static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th) - XFORM_SKIP_PROC -{ - DWORD toget, got; - int perma_eof = 0; - HANDLE eof_wait = NULL; - - if (GetFileType((HANDLE)th->fd) == FILE_TYPE_PIPE) { - /* Reading from a pipe will return early when data is available. */ - toget = MZPORT_FD_BUFFSIZE; - } else { - /* Non-pipe: get one char at a time: */ - toget = 1; - } - - while (!perma_eof && !th->err) { - /* Wait until we're supposed to look for input: */ - WaitForSingleObject(th->checking_sema, INFINITE); - - if (th->checking < 0) - break; - - if (ReadFile(th->fd, th->buffer, toget, &got, NULL)) { - th->avail = got; - if (!got) { - /* We interpret a send of 0 bytes as a mid-stream EOF. */ - eof_wait = CreateSemaphore(NULL, 0, 1, NULL); - th->eof = eof_wait; - } - } else { - int err; - err = GetLastError(); - if (err == ERROR_BROKEN_PIPE) { - th->eof = INVALID_HANDLE_VALUE; - perma_eof = 1; - } else - th->err = err; - } - - /* Notify main program that we found something: */ - ReleaseSemaphore(th->ready_sema, 1, NULL); - - if (eof_wait) { - WaitForSingleObject(eof_wait, INFINITE); - eof_wait = NULL; - } - } - - /* We have to clean up if the main program has abandoned us: */ - if (WaitForSingleObject(th->you_clean_up_sema, 0) != WAIT_OBJECT_0) { - WindowsFDICleanup(th); - } /* otherwise, main program is responsible for clean-up */ - - return 0; -} - -static void WindowsFDICleanup(Win_FD_Input_Thread *th) - XFORM_SKIP_PROC -{ - int rc; - - CloseHandle(th->checking_sema); - CloseHandle(th->ready_sema); - CloseHandle(th->you_clean_up_sema); - - rc = adj_refcount(th->refcount, -1); - if (!rc) CloseHandle(th->fd); - - free(th->buffer); - free(th); -} - -# endif - -#endif - Scheme_Object * scheme_make_fd_input_port(int fd, Scheme_Object *name, int regfile, int textmode) { -#ifdef MZ_FDS - return make_fd_input_port(fd, name, regfile, textmode, NULL, 0); -#else - return NULL; -#endif + rktio_fd_t *rfd; + + rfd = rktio_system_fd(scheme_rktio, + fd, + (RKTIO_OPEN_READ + | (regfile + ? RKTIO_OPEN_REGFILE + : RKTIO_OPEN_NOT_REGFILE) + | (textmode ? RKTIO_OPEN_TEXT))); + + return make_fd_input_port(rfd, name, NULL, 0); } -/*========================================================================*/ -/* OSKit console input ports */ -/*========================================================================*/ - -#ifdef USE_OSKIT_CONSOLE - -# ifdef OSKIT_TEST -static Scheme_Object *normal_stdin; -static int direct_cons_trygetchar() { return scheme_byte_ready(normal_stdin) ? scheme_get_byte(normal_stdin) : -1; } -static void direct_cons_putchar(int c) { } -# define convert_scan_code(x) x -# else -# include "pc_keys.inc" -# endif - -typedef struct osk_console_input { - MZTAG_IF_REQUIRED - int count, size, ready; - unsigned char *buffer; - struct osk_console_input *next; /* typeahead */ -} osk_console_input; - -static int -osk_byte_ready (Scheme_Input_Port *port) -{ - osk_console_input *osk, *orig; - int k; - - if (port->closed) - return 1; - - osk = orig = (osk_console_input *)port->port_data; - - while (osk->ready) { - if (osk->next) - osk = osk->next; - else { - osk->next = MALLOC_ONE_RT(osk_console_input); -#ifdef MZTAG_REQUIRED - osk->type = scheme_rt_oskit_console_input; -#endif - osk = osk->next; - osk->count = osk->size = osk->ready = 0; - osk->buffer = NULL; - osk->next = NULL; - } - } - - k = direct_cons_trygetchar(); - k = convert_scan_code(k); /* defined in pc_keys.inc; handles ctl-alt-del */ - if (k > 0) { - if (k == 3) { /* Ctl-C */ - scheme_break_thread(NULL); - } else if (k == 4) { /* Ctl-D */ - if (!osk->count) - /* ready with !count => EOF */ - osk->ready = 1; - } else if (k == 8) { /* Backspace */ - if (osk->count) { - direct_cons_putchar(8); - direct_cons_putchar(' '); /* space erases old letter */ - direct_cons_putchar(8); - --osk->count; - } - } else { - if (osk->count == osk->size) { - char *naya; - osk->size = osk->size ? 2 * osk->size : 256; - naya = scheme_malloc_atomic(osk->size); - memcpy(naya, osk->buffer, osk->count); - osk->buffer = naya; - } - osk->buffer[osk->count++] = k; - if (k == 13 || k == 10) { /* Return/newline */ - direct_cons_putchar(13); - direct_cons_putchar(10); - osk->ready = 1; - } else - direct_cons_putchar(k); - } - } - - if (orig->ready) - return 1; - else - return 0; -} - -static int osk_get_string(Scheme_Input_Port *port, - char *buffer, int offset, int size, - int nonblock, Scheme_Object *unless) -{ - int c; - osk_console_input *osk; - - while (!osk_byte_ready(port)) { - if (nonblock > 0) { - return 0; - } - - scheme_block_until_unless(osk_byte_ready, NULL, (Scheme_Object *)port, 0.0, - unless, - nonblock); - - scheme_wait_input_allowed(port, nonblock); - - if (scheme_unless_ready(unless)) - return SCHEME_UNLESS_READY; - } - - if (port->closed) { - /* Another thread closed the input port while we were waiting. */ - /* Call scheme_getc to signal the error */ - scheme_getc((Scheme_Object *)port); - } - - osk = (osk_console_input *)port->port_data; - - if (!osk->count) { - /* EOF */ - osk->ready = 0; - return EOF; - } - - c = osk->buffer[osk->ready - 1]; - osk->ready++; - if (osk->ready > osk->count) { - if (osk->next) { - /* Copy typeahead to here */ - osk_console_input *next = osk->next; - memcpy(osk, next, sizeof(osk_console_input)); - } else - osk->ready = osk->count = 0; - } - - buffer[offset] = c; - return 1; -} - -static void -osk_close_input(Scheme_Input_Port *port) -{ -} - -static void -osk_need_wakeup(Scheme_Input_Port *port, void *fds) -{ -# ifdef OSKIT_TEST - /* for testing, write to stdout is almost certainly ready: */ - void *fdw; - fdw = MZ_GET_FDSET(fds, 1); - MZ_FD_SET(1, (fd_set *)fdw); -# endif - - /* In OSKit, makes select() return immediately */ - MZ_FD_SET(0, (fd_set *)fds); -} - -static Scheme_Object * -make_oskit_console_input_port() -{ - Scheme_Input_Port *ip; - osk_console_input *osk; - - osk = MALLOC_ONE_RT(osk_console_input); -#ifdef MZTAG_REQUIRED - osk->type = scheme_rt_oskit_console_input; -#endif - - osk->count = osk->size = osk->ready = 0; - osk->buffer = NULL; - osk->next = NULL; - -# ifdef OSKIT_TEST - REGISTER_SO(normal_stdin); - normal_stdin = scheme_make_named_file_input_port(stdin, scheme_intern_symbol("stdin")); -# endif - - ip = scheme_make_input_port(oskit_console_input_port_type, - osk, - scheme_intern_symbol("stdin"), - osk_get_string, - NULL, - scheme_progress_evt_via_get, - scheme_get_string_unless_via_get, - osk_byte_ready, - osk_close_input, - osk_need_wakeup, - 1); - - return (Scheme_Object *)ip; -} - -void scheme_check_keyboard_input(void) -{ - if (!osk_not_console) - osk_byte_ready((Scheme_Input_Port *)scheme_orig_stdin_port); -} - -#endif - /*========================================================================*/ /* FILE output ports */ /*========================================================================*/ @@ -7617,13 +4966,6 @@ scheme_make_file_output_port(FILE *fp) /* fd output ports */ /*========================================================================*/ -#ifdef MZ_FDS - -#ifdef WINDOWS_FILE_HANDLES -static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth); -static void WindowsFDOCleanup(Win_FD_Output_Thread *oth); -#endif - static int fd_flush_done(Scheme_Object *port) { @@ -7643,46 +4985,6 @@ static void wait_until_fd_flushed(Scheme_Output_Port *op, int enable_break) 0.0, enable_break); } -#ifdef WINDOWS_FILE_HANDLES -static int win_fd_flush_done(Scheme_Object *_oth) -{ - /* For checking whether the output thread has finished a flush. */ - - Win_FD_Output_Thread *oth = (Win_FD_Output_Thread *)_oth; - int done; - - WaitForSingleObject(oth->lock_sema, INFINITE); - if (oth->nonblocking) { - if (oth->needflush) { - oth->needflush = 0; - oth->flushed = 0; - ReleaseSemaphore(oth->work_sema, 1, NULL); /* start trying to flush */ - done = 0; - } else - done = oth->flushed; - } else - done = (oth->err_no || !oth->buflen); - ReleaseSemaphore(oth->lock_sema, 1, NULL); - - return done; -} - -static void win_fd_flush_needs_wakeup(Scheme_Object *_oth, void *fds) -{ - /* For sleping until the output thread has finished a flush. */ - - /* Double-check that we're not already done: */ - if (win_fd_flush_done(_oth)) - scheme_add_fd_nosleep(fds); - else { - /* Not done. Thread will notify us through ready_sema: */ - Win_FD_Output_Thread *oth = (Win_FD_Output_Thread *)_oth; - - scheme_add_fd_handle(oth->ready_sema, fds, 1); - } -} -#endif - static int fd_write_ready (Scheme_Object *port) { @@ -7695,98 +4997,19 @@ fd_write_ready (Scheme_Object *port) op = scheme_output_port_record(port); fop = (Scheme_FD *)op->port_data; - if (fop->regfile || op->closed) + if (op->closed) return 1; -#ifdef WINDOWS_FILE_HANDLES - if (fop->oth) { - /* Pipe output that can block... */ - int retval; - Win_FD_Output_Thread *oth = fop->oth; - - WaitForSingleObject(oth->lock_sema, INFINITE); - if (oth->nonblocking) { - if (oth->needflush) { - oth->needflush = 0; - oth->flushed = 0; - ReleaseSemaphore(oth->work_sema, 1, NULL); /* start trying to flush */ - retval = 0; - } else - retval = oth->flushed; - } else - retval = (oth->err_no || (oth->buflen < MZPORT_FD_BUFFSIZE)); - if (!retval) - WaitForSingleObject(oth->ready_sema, 0); /* clear any leftover state */ - ReleaseSemaphore(oth->lock_sema, 1, NULL); - - return retval; - } else - return 1; /* non-blocking output, such as a console, or haven't written yet */ -#else - { - int sr; -# ifdef HAVE_POLL_SYSCALL - GC_CAN_IGNORE struct pollfd pfd[1]; - pfd[0].fd = fop->fd; - pfd[0].events = POLLOUT; - do { - sr = poll(pfd, 1, 0); - } while ((sr == -1) && (errno == EINTR)); -# else - DECL_FDSET(writefds, 1); - DECL_FDSET(exnfds, 1); - struct timeval time = {0, 0}; - - INIT_DECL_WR_FDSET(writefds); - INIT_DECL_ER_FDSET(exnfds); - - MZ_FD_ZERO(writefds); - MZ_FD_ZERO(exnfds); - MZ_FD_SET(fop->fd, writefds); - MZ_FD_SET(fop->fd, exnfds); - - do { - /* Mac OS X 10.8 and 10.9: select() seems to claim that a pipe - is always ready for output. To work around that problem, - kqueue() support is enabled for pipes, so we shouldn't get - here much for pipes. */ - sr = select(fop->fd + 1, NULL, writefds, exnfds, &time); - } while ((sr == -1) && (errno == EINTR)); -#endif - - return sr; - } -#endif + if (rktio_poll_write_ready(scheme_rktio, fop->fd); } - static void fd_write_need_wakeup(Scheme_Object *port, void *fds) { Scheme_Output_Port *op; Scheme_FD *fop; -#ifdef WINDOWS_FILE_HANDLES -#else - void *fds2; - int n; -#endif - - op = scheme_output_port_record(port); - fop = (Scheme_FD *)op->port_data; - -#ifdef WINDOWS_FILE_HANDLES - if (fop->oth && !fd_write_ready(port)) - scheme_add_fd_handle(fop->oth->ready_sema, fds, 1); - else - scheme_add_fd_nosleep(fds); -#else - n = fop->fd; - fds2 = MZ_GET_FDSET(fds, 1); - MZ_FD_SET(n, (fd_set *)fds2); - fds2 = MZ_GET_FDSET(fds, 2); - MZ_FD_SET(n, (fd_set *)fds2); -#endif + rktio_poll_add(scheme_rktio, fds, fop->fd, RKTIO_POLL_WRITE); } static void release_flushing_lock(void *_fop) @@ -7799,10 +5022,10 @@ static void release_flushing_lock(void *_fop) } static intptr_t flush_fd(Scheme_Output_Port *op, - const char * volatile bufstr, volatile uintptr_t buflen, volatile uintptr_t offset, - int immediate_only, int enable_break) - /* immediate_only == 1 => write at least one character, then give up; - immediate_only == 2 => never block */ + const char * volatile bufstr, volatile uintptr_t buflen, volatile uintptr_t offset, + int immediate_only, int enable_break) +/* immediate_only == 1 => write at least one character, then give up; + immediate_only == 2 => never block */ { Scheme_FD * volatile fop = (Scheme_FD *)op->port_data; volatile intptr_t wrote = 0; @@ -7839,387 +5062,40 @@ static intptr_t flush_fd(Scheme_Output_Port *op, intptr_t len; int errsaved, full_write_buffer; -#ifdef WINDOWS_FILE_HANDLES - DWORD winwrote; + len = rktio_write(scheme_rktio, fop->fd, bufstr + offset, amt); - full_write_buffer = 0; + if (!len) { + /* Need to block; remember that we're holding a lock. */ + Scheme_Object *sema; - if (fop->regfile) { - /* Regular files never block, so this code looks like the Unix - code. We've cheated in the make_fd proc and called - consoles regular files, because they cannot block, either. */ - int orig_len; + if (immediate_only == 2) { + fop->flushing = 0; + return wrote; + } - if (fop->textmode) { - /* Convert LF to CRLF. We're relying on the fact that WriteFile - will write everything. */ - int c = 0; - unsigned int i; + sema = scheme_fd_to_semaphore(fop->fd, MZFD_CREATE_WRITE, 0); - for (i = offset; i < buflen; i++) { - if (bufstr[i] == '\n') - c++; - } - - orig_len = buflen - offset; - - if (c) { - char *naya; - int j; - - naya = scheme_malloc_atomic(orig_len + c); - - for (i = offset, j = 0; i < buflen; i++) { - if (bufstr[i] == '\n') { - naya[j++] = '\r'; - naya[j++] = '\n'; - } else - naya[j++] = bufstr[i]; - } - - bufstr = naya; - offset = 0; - buflen = orig_len + c; - } - } else - orig_len = 0; /* not used */ - - /* Write bytes. If we try to write too much at once, the result - is ERROR_NOT_ENOUGH_MEMORY (as opposed to a partial write). */ - { - int ok; - intptr_t towrite = buflen - offset; - - while (1) { - ok = WriteFile((HANDLE)fop->fd, bufstr XFORM_OK_PLUS offset, towrite, &winwrote, NULL); - if (!ok) - errsaved = GetLastError(); - - if (!ok && (errsaved == ERROR_NOT_ENOUGH_MEMORY)) { - towrite = towrite >> 1; - if (!towrite) - break; - } else - break; - } - - if (ok) { - if (fop->textmode) { - if (winwrote != buflen) { - /* Trouble! This shouldn't happen. We pick an random error msg. */ - errsaved = ERROR_NEGATIVE_SEEK; - len = -1; - } else { - len = orig_len; - buflen = orig_len; /* so we don't loop! */ - } - } else - len = winwrote; - } else { - len = -1; - } - } - } else { - errsaved = 0; - len = -1; - - /* If we don't have a thread yet, we'll need to start it. If - we have a non-blocking pipe, we can try the write (and - we'll still need the thread to determine when the data is - flushed). */ - if (!fop->oth || fop->oth->nonblocking) { - int nonblocking; - - /* If we don't have a thread, this is our first write attempt. - Determine whether this is a non-blocking pipe: */ - if (!fop->oth) { - /* The FILE_TYPE_PIPE test is currently redundant, I think, - but better safe than sorry. */ - nonblocking = ((scheme_stupid_windows_machine < 0) - && (GetFileType((HANDLE)fop->fd) == FILE_TYPE_PIPE)); - } else - nonblocking = 1; /* must be, or we would not have gotten here */ - - if (nonblocking) { - /* Unless we're still trying to flush old data, write to the - pipe and have the other thread start flushing it. */ - DWORD nonblock = PIPE_NOWAIT; - int ok, flushed; - - if (fop->oth) { - if (fop->oth->needflush) { - /* Not flushed, but we haven't promised not to block: */ - flushed = 1; - } else { - WaitForSingleObject(fop->oth->lock_sema, INFINITE); - flushed = fop->oth->flushed; - ReleaseSemaphore(fop->oth->lock_sema, 1, NULL); - } - } else - flushed = 1; /* haven't written anything before */ - - if (flushed) { - /* Put the pipe in non-blocking mode and write. */ - - int towrite; - - towrite = buflen - offset; - - /* Apparently, the semantics of non-blocking pipe writes - is not partial writes, but giving up entirely when - the other end isn't being read. In other words, if we - try to write too much and nothing is being pulled - from the pipe, winwrote will be set to 0. Also, if - we try to write too much at once, the result is a - ERROR_NOT_ENOUGH_MEMORY error. Account for these - behaviors by trying to write less each iteration when the - write fails. (Yuck.) */ - while (1) { - if (!fop->unblocked) { - ok = SetNamedPipeHandleState((HANDLE)fop->fd, &nonblock, NULL, NULL); - if (ok) - fop->unblocked = 1; - else - errsaved = GetLastError(); - } else - ok = 1; - if (ok) { - ok = WriteFile((HANDLE)fop->fd, bufstr XFORM_OK_PLUS offset, towrite, &winwrote, NULL); - if (!ok) - errsaved = GetLastError(); - } - - if ((ok && !winwrote) - || (!ok && (errsaved == ERROR_NOT_ENOUGH_MEMORY))) { - towrite = towrite >> 1; - if (!towrite) { - break; - } - } else - break; - } - } else { - /* Don't try to write while flushing. */ - ok = 1; - winwrote = 0; - } - - if (ok) { - if (!winwrote) { - full_write_buffer = 1; - } else { - len = winwrote; - } - } - } else - full_write_buffer = 0; /* and create the writer thread... */ - - if (!fop->oth) { - /* We create a thread even for pipes that can be put in - non-blocking mode, because that seems to be the only - way to get evt behavior. */ - Win_FD_Output_Thread *oth; - HANDLE h; - DWORD id; - unsigned char *bfr; - OS_SEMAPHORE_TYPE sm; - - oth = malloc(sizeof(Win_FD_Output_Thread)); - fop->oth = oth; - - oth->nonblocking = nonblocking; - - if (!nonblocking) { - bfr = (unsigned char *)malloc(MZPORT_FD_BUFFSIZE); - oth->buffer = bfr; - oth->flushed = 0; - oth->needflush = 0; - } else { - oth->buffer = NULL; - oth->flushed = (len <= 0); - oth->needflush = 1; - } - - oth->buflen = 0; - oth->bufstart = 0; - oth->bufend = 0; - - oth->fd = (HANDLE)fop->fd; - oth->err_no = 0; - oth->done = 0; - sm = CreateSemaphore(NULL, 1, 1, NULL); - oth->lock_sema = sm; - sm = CreateSemaphore(NULL, 0, 1, NULL); - oth->work_sema = sm; - sm = CreateSemaphore(NULL, 1, 1, NULL); - oth->ready_sema = sm; - sm = CreateSemaphore(NULL, 1, 1, NULL); - oth->you_clean_up_sema = sm; - oth->refcount = fop->refcount; - - h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDWriter, oth, 0, &id); - - scheme_remember_thread(h, 1); - - /* scheme_remember_thread() is in charge of releasing h, so - duplicate it for use in closing: */ - DuplicateHandle(GetCurrentProcess(), - h, - GetCurrentProcess(), - &h, - 0, - FALSE, - DUPLICATE_SAME_ACCESS); - - oth->thread = h; - - } - } - - /* We have a thread, if only to watch when the flush is - done... */ - - if (!fop->oth->nonblocking) { - /* This case is for Win 95/98/Me anonymous pipes and - character devices. We haven't written anything yet! We - write to a buffer read by the other thread, and return -- - the other thread takes care of writing. Thus, as long as - there's room in the buffer, we don't block, and we can - tell whether there's room. Technical problem: if multiple - ports are attched to the same underlying pipe (different - handle, same "device"), the port writes can get out of - order. We try to avoid the problem by sleeping. */ - - Win_FD_Output_Thread *oth = fop->oth; - - WaitForSingleObject(oth->lock_sema, INFINITE); - if (oth->err_no) - errsaved = oth->err_no; - else if (oth->buflen == MZPORT_FD_BUFFSIZE) { - full_write_buffer = 1; - WaitForSingleObject(oth->ready_sema, 0); /* clear any leftover state */ - } else { - intptr_t topp; - int was_pre; - - if (!oth->buflen) { - /* Avoid fragmenting in circular buffer: */ - oth->bufstart = 0; - oth->bufend = 0; - } - - /* Write to top part of circular buffer, then bottom part - if anything's left. */ - - if (oth->bufstart <= oth->bufend) { - was_pre = 1; - topp = MZPORT_FD_BUFFSIZE; - } else { - was_pre = 0; - topp = oth->bufstart; - } - - winwrote = topp - oth->bufend; - if (winwrote > buflen - offset) - winwrote = buflen - offset; - - memcpy(oth->buffer + oth->bufend, bufstr + offset, winwrote); - oth->buflen += winwrote; - len = winwrote; - - oth->bufend += winwrote; - if (oth->bufend == MZPORT_FD_BUFFSIZE) - oth->bufend = 0; - - if (was_pre) { - if (winwrote < buflen - offset) { - /* Try continuing with a wrap-around: */ - winwrote = oth->bufstart - oth->bufend; - if (winwrote > buflen - offset - len) - winwrote = buflen - offset - len; - - memcpy(oth->buffer + oth->bufend, bufstr + offset + len, winwrote); - oth->buflen += winwrote; - oth->bufend += winwrote; - len += winwrote; - } - } - /* Let the other thread know that it should start trying - to write, if it isn't already: */ - ReleaseSemaphore(oth->work_sema, 1, NULL); - Sleep(0); /* to decrease the chance of re-ordering flushes */ - } - ReleaseSemaphore(oth->lock_sema, 1, NULL); - } else if (len > 0) { - /* We've already written, which implies that no flush is - in progress. We'll need a flush check in the future. */ - fop->oth->needflush = 1; - } - } -#else - int flags; - intptr_t amt; - - flags = fcntl(fop->fd, F_GETFL, 0); - if (!(flags & MZ_NONBLOCKING)) - fcntl(fop->fd, F_SETFL, flags | MZ_NONBLOCKING); - - amt = buflen - offset; - - do { - do { - len = write(fop->fd, bufstr + offset, amt); - } while ((len == -1) && (errno == EINTR)); - - /* If there was no room to write `amt` bytes, then it's - possible that writing fewer bytes will succeed. That seems - to be the case with FIFOs on Mac OS X, for example. */ - amt = amt >> 1; - } while ((len == -1) && (errno == EAGAIN) && (amt > 0)); - - errsaved = errno; - if (!(flags & MZ_NONBLOCKING)) - fcntl(fop->fd, F_SETFL, flags); - - full_write_buffer = (errsaved == EAGAIN); -#endif - - if (len < 0) { + BEGIN_ESCAPEABLE(release_flushing_lock, fop); + if (sema) + scheme_wait_sema(sema, enable_break ? -1 : 0); + else + scheme_block_until_enable_break(fd_write_ready, + fd_write_need_wakeup, + (Scheme_Object *)op, 0.0, + enable_break); + END_ESCAPEABLE(); + } else if (len == RKTIO_WRITE_ERROR) { if (scheme_force_port_closed) { /* Don't signal exn or wait. Just give up. */ return wrote; - } else if (full_write_buffer) { - /* Need to block; remember that we're holding a lock. */ - Scheme_Object *sema; - - if (immediate_only == 2) { - fop->flushing = 0; - return wrote; - } - -#ifdef WINDOWS_FILE_HANDLES - sema = NULL; -#else - sema = scheme_fd_to_semaphore(fop->fd, MZFD_CREATE_WRITE, 0); -#endif - - BEGIN_ESCAPEABLE(release_flushing_lock, fop); - if (sema) - scheme_wait_sema(sema, enable_break ? -1 : 0); - else - scheme_block_until_enable_break(fd_write_ready, - fd_write_need_wakeup, - (Scheme_Object *)op, 0.0, - enable_break); - END_ESCAPEABLE(); - } else { + } else else { fop->flushing = 0; scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, "error writing to stream port\n" - " system error: " FILENAME_EXN_E, + " system error: %R", errsaved); return 0; /* doesn't get here */ - } + } } else if ((len + offset == buflen) || immediate_only) { fop->flushing = 0; return wrote + len; @@ -8332,10 +5208,21 @@ fd_write_string(Scheme_Output_Port *port, return fd_write_string_slow(port, str, d, len, rarely_block, enable_break); } +static int end_fd_flush_done(Scheme_Object *fop) +{ + return rktio_poll_write_flushed(scheme_rktio, ((Scheme_FD *)fop)->fd); +} + +static void end_fd_flush_needs_wakeup(Scheme_Object *fop, void *fds) +{ + rktio_poll_add(scheme_rktio, fds, ((Scheme_FD *)fop)->fd, RKTIO_POLL_FLUSH); +} + static void fd_close_output(Scheme_Output_Port *port) { Scheme_FD *fop = (Scheme_FD *)port->port_data; + int rc; if (fop->bufcount) flush_fd(port, NULL, 0, 0, 0, 0); @@ -8343,15 +5230,13 @@ fd_close_output(Scheme_Output_Port *port) if (fop->flushing && !scheme_force_port_closed) wait_until_fd_flushed(port, 0); -#ifdef WINDOWS_FILE_HANDLES - if (fop->oth) { - if (!scheme_force_port_closed) { - /* If there's a work thread, wait until the port - is *really* flushed! */ - scheme_block_until(win_fd_flush_done, win_fd_flush_needs_wakeup, (Scheme_Object *)fop->oth, 0.0); + if (!scheme_force_port_closed && fop->fd) { + /* Check for flushing at the rktio level (not to be confused + with pulmber flushes): */ + while (!rktio_poll_write_flushed(scheme_rktio, fop->fd)) { + scheme_block_until(end_fd_flush_done, end_fd_flush_needs_wakeup, (Scheme_Object *)fop, 0.0); } } -#endif scheme_remove_flush(fop->flush_handle); @@ -8359,50 +5244,13 @@ fd_close_output(Scheme_Output_Port *port) if (port->closed) return; -#ifdef WINDOWS_FILE_HANDLES - if (fop->oth) { - CSI_proc csi; - - csi = get_csi(); - - if (csi) { - /* See also call to csi in fd_close_input */ - csi(fop->oth->thread); - } - CloseHandle(fop->oth->thread); - fop->oth->done = 1; - ReleaseSemaphore(fop->oth->work_sema, 1, NULL); - - /* Try to leave clean-up to the other thread: */ - if (WaitForSingleObject(fop->oth->you_clean_up_sema, 0) != WAIT_OBJECT_0) { - /* Other thread is already done, so we're stuck with clean-up: */ - WindowsFDOCleanup(fop->oth); - } /* otherwise, thread is responsible for clean-up */ - fop->oth = NULL; - } else { - int rc; - rc = adj_refcount(fop->refcount, -1); - if (!rc) { - CloseHandle((HANDLE)fop->fd); - } + rc = adj_refcount(fop->refcount, -1); + if (fop->fd) { + if (!rc) + rktio_close(scheme_rktio, (HANDLE)fop->fd); + else + rktio_fd_forget(scheme_rktio, (HANDLE)fop->fd); } -#else - { - int rc; - rc = adj_refcount(fop->refcount, -1); - - if (!rc) { - int cr; - (void)scheme_fd_to_semaphore(fop->fd, MZFD_REMOVE, 0); - do { - cr = close(fop->fd); - } while ((cr == -1) && (errno == EINTR)); -# ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS - release_lockf(fop->fd); -# endif - } - } -#endif } static void @@ -8431,8 +5279,7 @@ static int fd_output_buffer_mode(Scheme_Port *p, int mode) } static Scheme_Object * -make_fd_output_port(intptr_t fd, Scheme_Object *name, int regfile, int win_textmode, int and_read, - int flush_mode, int *refcount) +make_fd_output_port(rktio_fd_t *fd, Scheme_Object *name, int and_read, int flush_mode, int *refcount) { Scheme_FD *fop; unsigned char *bfr; @@ -8450,19 +5297,6 @@ make_fd_output_port(intptr_t fd, Scheme_Object *name, int regfile, int win_textm fop->fd = fd; fop->bufcount = 0; -#ifdef WINDOWS_FILE_HANDLES - /* Character devices can't block output, right? */ - if (!regfile && is_fd_terminal(fop->fd)) - regfile = 1; - /* It's important to not use pipe code for flushing to file handles: */ - if (!regfile && (GetFileType((HANDLE)fop->fd) == FILE_TYPE_DISK)) - regfile = 1; - /* The work thread is created on demand in fd_flush. */ -#endif - - fop->regfile = regfile; - fop->textmode = win_textmode; - if (flush_mode > -1) { fop->flush = flush_mode; } else if (is_fd_terminal(fd)) { @@ -8529,337 +5363,21 @@ void scheme_flush_if_output_fds(Scheme_Object *o) scheme_flush_output(o); } -#ifdef WINDOWS_FILE_HANDLES - -static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth) - XFORM_SKIP_PROC -{ - DWORD towrite, wrote, start; - int ok, more_work = 0, err_no; - - if (oth->nonblocking) { - /* Non-blocking mode (Win NT pipes). Just flush. */ - while (!oth->done) { - WaitForSingleObject(oth->work_sema, INFINITE); - - FlushFileBuffers(oth->fd); - - WaitForSingleObject(oth->lock_sema, INFINITE); - oth->flushed = 1; - ReleaseSemaphore(oth->ready_sema, 1, NULL); - ReleaseSemaphore(oth->lock_sema, 1, NULL); - } - } else { - /* Blocking mode. We do the writing work. This case is for - Win 95/98/Me anonymous pipes and character devices (such - as LPT1). */ - while (!oth->err_no) { - if (!more_work) - WaitForSingleObject(oth->work_sema, INFINITE); - - if (oth->done) - break; - - WaitForSingleObject(oth->lock_sema, INFINITE); - towrite = oth->buflen; - if (towrite > (MZPORT_FD_BUFFSIZE - oth->bufstart)) - towrite = MZPORT_FD_BUFFSIZE - oth->bufstart; - start = oth->bufstart; - ReleaseSemaphore(oth->lock_sema, 1, NULL); - - ok = WriteFile(oth->fd, oth->buffer + start, towrite, &wrote, NULL); - if (!ok) - err_no = GetLastError(); - else - err_no = 0; - - WaitForSingleObject(oth->lock_sema, INFINITE); - if (!ok) - oth->err_no = err_no; - else { - oth->bufstart += wrote; - oth->buflen -= wrote; - if (oth->bufstart == MZPORT_FD_BUFFSIZE) - oth->bufstart = 0; - more_work = oth->buflen > 0; - } - if ((oth->buflen < MZPORT_FD_BUFFSIZE) || oth->err_no) - ReleaseSemaphore(oth->ready_sema, 1, NULL); - ReleaseSemaphore(oth->lock_sema, 1, NULL); - } - } - if (WaitForSingleObject(oth->you_clean_up_sema, 0) != WAIT_OBJECT_0) { - WindowsFDOCleanup(oth); - } /* otherwise, main thread is responsible for clean-up */ - - return 0; -} - -static void WindowsFDOCleanup(Win_FD_Output_Thread *oth) - XFORM_SKIP_PROC -{ - int rc; - - CloseHandle(oth->lock_sema); - CloseHandle(oth->work_sema); - CloseHandle(oth->you_clean_up_sema); - - rc = adj_refcount(oth->refcount, -1); - if (!rc) CloseHandle(oth->fd); - - if (oth->buffer) - free(oth->buffer); - free(oth); -} - -#endif - -#endif - Scheme_Object * scheme_make_fd_output_port(int fd, Scheme_Object *name, int regfile, int textmode, int read_too) { -#ifdef MZ_FDS - return make_fd_output_port(fd, name, regfile, textmode, read_too, -1, NULL); -#else - return NULL; -#endif + rktio_fd_t *rfd; + + rfd = rktio_system_fd(scheme_rktio, + fd, + (RKTIO_OPEN_WRITE + | (regefile ? RKTIO_OPEN_REGFILE : RKTIO_OPEN_NOT_REGFILE) + | (read_too ? RKTIO_OPEN_READ : 0) + | (textmode ? RKTIO_OPEN_TEXT : 0))); + + return make_fd_output_port(rfd, name, read_too, -1, NULL); } -/*========================================================================*/ -/* system/process/execute */ -/*========================================================================*/ - -/* Unix, and Windows support --- all mixed together */ - -#define MZ_FAILURE_STATUS -1 - -#if defined(PROCESS_FUNCTION) || defined(MZ_USE_PLACES) - -# define USE_CREATE_PIPE - -#ifdef WINDOWS_PROCESSES -# ifdef USE_CREATE_PIPE -# define _EXTRA_PIPE_ARGS -static int MyPipe(intptr_t *ph, int near_index) { - HANDLE r, w; - SECURITY_ATTRIBUTES saAttr; - - /* Set the bInheritHandle flag so pipe handles are inherited. */ - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - if (CreatePipe(&r, &w, &saAttr, 0)) { - HANDLE a[2], naya; - - a[0] = r; - a[1] = w; - - if (near_index != -1) { - /* Change the near end to make it non-inheritable, then - close the inheritable one: */ - if (!DuplicateHandle(GetCurrentProcess(), a[near_index], - GetCurrentProcess(), &naya, 0, - 0, /* not inherited */ - DUPLICATE_SAME_ACCESS)) { - CloseHandle(a[0]); - CloseHandle(a[1]); - return 1; - } else { - CloseHandle(a[near_index]); - a[near_index] = naya; - } - } - - ph[0] = (intptr_t)a[0]; - ph[1] = (intptr_t)a[1]; - - return 0; - } else - return 1; -} -# define PIPE_FUNC MyPipe -# define PIPE_HANDLE_t intptr_t -# else -# include -# include -# define PIPE_FUNC(pa, nearh) MSC_IZE(pipe)(pa) -# define PIPE_HANDLE_t int -# define _EXTRA_PIPE_ARGS , 256, _O_BINARY -# endif -#else -# define _EXTRA_PIPE_ARGS -# define PIPE_FUNC(pa, nearh) MSC_IZE(pipe)(pa) -# define PIPE_HANDLE_t int -#endif - -int scheme_os_pipe(intptr_t *a, int nearh) -/* If nearh != -1, then the handle at the index - other than nearh is made inheritable so that - a subprocess can use it. */ -{ - PIPE_HANDLE_t la[2]; - - if (PIPE_FUNC(la, nearh _EXTRA_PIPE_ARGS)) - return 1; - a[0] = la[0]; - a[1] = la[1]; - return 0; -} - -#endif - -/**************** Unix: signal stuff ******************/ - -#if defined(UNIX_PROCESSES) - -void scheme_block_child_signals(int block) - XFORM_SKIP_PROC -{ -#if defined(MZ_PLACES_WAITPID) - if (block) - scheme_wait_suspend(); - else - scheme_wait_resume(); -#else - sigset_t sigs; - - sigemptyset(&sigs); - sigaddset(&sigs, SIGCHLD); -# ifdef USE_ITIMER - sigaddset(&sigs, SIGPROF); -# endif - sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sigs, NULL); -#endif -} - -#endif - -#if defined(UNIX_PROCESSES) && !defined(MZ_PLACES_WAITPID) - -#ifndef MZ_PRECISE_GC -# define GC_write_barrier(x) /* empty */ -#endif - -/* See `unused_pid_statuses' in "places.c" for - a reminder of why this is needed (in both - implementations): */ -SHARED_OK static void *unused_pids; - -static int need_to_check_children; - -static void child_done(int ingored) - XFORM_SKIP_PROC -{ - need_to_check_children = 1; - scheme_signal_received(); - -# ifdef SIGSET_NEEDS_REINSTALL - MZ_SIGSET(SIGCHLD, child_done); -# endif -} - -static int sigchld_installed = 0; - -static void init_sigchld(void) -{ -#if !defined(MZ_PLACES_WAITPID) - if (!sigchld_installed) { - /* Catch child-done signals */ - START_XFORM_SKIP; - MZ_SIGSET(SIGCHLD, child_done); - END_XFORM_SKIP; - - sigchld_installed = 1; - } -#endif -} - -static void check_child_done(pid_t pid) -{ - pid_t result, check_pid; - int status, is_unused; - System_Child *sc, *prev; - void **unused = (void **)unused_pids, **unused_prev = NULL; - - if (scheme_system_children) { - do { - if (!pid && unused) { - check_pid = (pid_t)(intptr_t)unused[0]; - is_unused = 1; - } else { - check_pid = pid; - is_unused = 0; - } - - do { - START_XFORM_SKIP; - result = waitpid(check_pid, &status, WNOHANG); - END_XFORM_SKIP; - } while ((result == -1) && (errno == EINTR)); - - if (result > 0) { - if (is_unused) { - /* done with an inaccessible group id */ - void *next; - next = (void **)unused[1]; - if (unused_prev) - unused_prev[1] = unused[1]; - else - unused_pids = unused[1]; - free(unused); - unused = (void **)next; - } - - status = scheme_extract_child_status(status); - - prev = NULL; - for (sc = scheme_system_children; sc; prev = sc, sc = sc->next) { - if (sc->id == result) { - sc->done = 1; - sc->status = status; - - if (prev) { - prev->next = sc->next; - } else - scheme_system_children = sc->next; - } - } - } else { - if (is_unused) { - unused_prev = unused; - unused = unused[1]; - } - } - } while ((result > 0) || is_unused); - } -} - -void scheme_check_child_done(void) -{ - if (need_to_check_children) { - need_to_check_children = 0; - check_child_done(0); - } -} - -#endif - -#if defined(UNIX_PROCESSES) -int scheme_extract_child_status(int status) XFORM_SKIP_PROC -{ - if (WIFEXITED(status)) - status = WEXITSTATUS(status); - else if (WIFSIGNALED(status)) - status = WTERMSIG(status) + 128; - else - status = MZ_FAILURE_STATUS; - - return status; -} -#endif - /*========================================================================*/ /* null output ports */ /*========================================================================*/ @@ -9183,41 +5701,19 @@ static Scheme_Object *redirect_get_or_peek_bytes_k(void) return scheme_make_integer(n); } -/*********** Unix/Windows: process status stuff *************/ +/*========================================================================*/ +/* subprocess */ +/*========================================================================*/ -#if defined(UNIX_PROCESSES) || defined(WINDOWS_PROCESSES) - -#if defined(WINDOWS_PROCESSES) -static void collect_process_time(DWORD w, Scheme_Subprocess *sp) +static void close_subprocess_handle(void *so, void *ignored) { - if ((w != STILL_ACTIVE) && !sp->got_time) { - FILETIME cr, ex, kr, us; - if (GetProcessTimes(sp->handle, &cr, &ex, &kr, &us)) { - mzlonglong v; - uintptr_t msecs; - v = ((((mzlonglong)kr.dwHighDateTime << 32) + kr.dwLowDateTime) - + (((mzlonglong)us.dwHighDateTime << 32) + us.dwLowDateTime)); - msecs = (uintptr_t)(v / 10000); + Scheme_Subprocess *sp = (Scheme_Subprocess *)so; - /* Will get replaced... */ -#if 0 -#if defined(MZ_USE_PLACES) - { - int set = 0; - while (!set) { - uintptr_t old_val = scheme_process_children_msecs; - set = mzrt_cas(&scheme_process_children_msecs, old_val, old_val + msecs); - } - } -#else - scheme_process_children_msecs += msecs; -#endif -#endif - } - sp->got_time = 1; + if (sp->proc) { + rktio_process_forget(scheme_rktio, sp->proc); + sp->proc = NULL; } } -#endif static void child_mref_done(Scheme_Subprocess *sp) { @@ -9229,134 +5725,53 @@ static void child_mref_done(Scheme_Subprocess *sp) static int subp_done(Scheme_Object *so) { - Scheme_Subprocess *sp; - sp = (Scheme_Subprocess*) so; + Scheme_Subprocess *sp = (Scheme_Subprocess*)so; -#if defined(UNIX_PROCESSES) -# if defined(MZ_PLACES_WAITPID) - { - int status; - if (!sp->done) { - if (scheme_get_child_status(sp->pid, sp->is_group, 1, &status)) { - sp->done = 1; - sp->status = status; - child_mref_done(sp); - scheme_ended_child(); - return 1; - } - return 0; - } - else - return 1; - } -# else - { - System_Child *sc; - sc = (System_Child *)sp->handle; - /* Check specific pid, in case the child has its own group - (either given by Racket or given to itself): */ - check_child_done(sp->pid); - if (sc->done) - child_mref_done(sp); - return sc->done; - } -# endif -#endif -#ifdef WINDOWS_PROCESSES - { - HANDLE sci = (HANDLE) ((Scheme_Subprocess *)sp)->handle; - DWORD w; - if (sci) { - if (GetExitCodeProcess(sci, &w)) { - collect_process_time(w, (Scheme_Subprocess *)sp); - return (w != STILL_ACTIVE); - } else - return 1; - } else - return 1; - } -#endif + if (!sp->proc) return 1; + + return rktio_poll_process_done(scheme_rktio, sp->proc); } -static void subp_needs_wakeup(Scheme_Object *sp, void *fds) +static void subp_needs_wakeup(Scheme_Object *so, void *fds) { -#ifdef WINDOWS_PROCESSES - void *sci = ((Scheme_Subprocess *)sp)->handle; - scheme_add_fd_handle((void *)(HANDLE)sci, fds, 0); -#endif -} + Scheme_Subprocess *sp = (Scheme_Subprocess*)so; -#endif + if (sp->proc) + rktio_poll_add_process(rktio_t *rktio, sp->proc, fds); +} static Scheme_Object *subprocess_status(int argc, Scheme_Object **argv) { Scheme_Subprocess *sp = (Scheme_Subprocess *)argv[0]; - + rktio_status_t *st; + if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_subprocess_type)) scheme_wrong_contract("subprocess-status", "subprocess?", 0, argc, argv); - -#if defined(PROCESS_FUNCTION) && !defined(MAC_CLASSIC_PROCESS_CONTROL) - { - int going = 0, status = MZ_FAILURE_STATUS; - -#if defined(UNIX_PROCESSES) -# if defined(MZ_PLACES_WAITPID) - if (sp->done) - status = sp->status; - else { - if (!scheme_get_child_status(sp->pid, sp->is_group, 1, &status)) { - going = 1; - } else { - child_mref_done(sp); - sp->done = 1; - sp->status = status; - scheme_ended_child(); - } + + st = rktio_process_status(scheme_rktio, sp->proc); + + if (!st) { + scheme_raise_exn(MZEXN_FAIL, + "subprocess-status: error getting status\n" + " system error: %R"); } -# else - System_Child *sc = (System_Child *)sp->handle; - check_child_done(sp->pid); - if (sc->done) { + if (st->running) { + free(st); + return scheme_intern_symbol("running"); + } else { + int status = st->status; + free(st); child_mref_done(sp); - status = sc->status; - } else - going = 1; -# endif -#else -# ifdef WINDOWS_PROCESSES - DWORD w; - if (sp->handle) { - if (GetExitCodeProcess((HANDLE)sp->handle, &w)) { - collect_process_time(w, sp); - if (w == STILL_ACTIVE) - going = 1; - else - status = w; - } - } -# endif -#endif - - if (going) - return scheme_intern_symbol("running"); - else - return scheme_make_integer_value(status); + return scheme_make_integer_value(status); } -#else - scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, - "%s: " NOT_SUPPORTED_STR, - "subprocess-status"); -#endif } static void register_subprocess_wait() { -#if defined(UNIX_PROCESSES) || defined(WINDOWS_PROCESSES) scheme_add_evt(scheme_subprocess_type, subp_done, - subp_needs_wakeup, NULL, 0); -#endif + subp_needs_wakeup, NULL, 0); } static Scheme_Object *subprocess_wait(int argc, Scheme_Object **argv) @@ -9364,7 +5779,6 @@ static Scheme_Object *subprocess_wait(int argc, Scheme_Object **argv) if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_subprocess_type)) scheme_wrong_contract("subprocess-wait", "subprocess?", 0, argc, argv); -#if defined(UNIX_PROCESSES) || defined(WINDOWS_PROCESSES) { Scheme_Subprocess *sp = (Scheme_Subprocess *)argv[0]; @@ -9372,119 +5786,29 @@ static Scheme_Object *subprocess_wait(int argc, Scheme_Object **argv) return scheme_void; } -#else - scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, - "%s: " NOT_SUPPORTED_STR, - "subprocess-wait"); -#endif } -#if defined(UNIX_PROCESSES) || defined(WINDOWS_PROCESSES) static Scheme_Object *do_subprocess_kill(Scheme_Object *_sp, Scheme_Object *killp, int can_error) { Scheme_Subprocess *sp = (Scheme_Subprocess *)_sp; -#if defined(UNIX_PROCESSES) -# if defined(MZ_PLACES_WAITPID) - { - int status; - - if (sp->done) - return scheme_void; - - scheme_wait_suspend(); - - /* Don't allow group checking, because we don't want to wait - on a group if we haven't already: */ - if (scheme_get_child_status(sp->pid, 0, 0, &status)) { - sp->status = status; - sp->done = 1; - child_mref_done(sp); - scheme_wait_resume(); - scheme_ended_child(); - return scheme_void; - } - } -# else - { - System_Child *sc = (System_Child *)sp->handle; - - /* Don't pass sp->pid, because we don't want to wait - on a group if we haven't already: */ - check_child_done(0); - if (sc->done) { - child_mref_done(sp); - return scheme_void; - } - } -# define scheme_wait_resume() /* empty */ -# endif - - while (1) { - - if (sp->is_group) { - if (!killpg(sp->pid, SCHEME_TRUEP(killp) ? SIGKILL : SIGINT)) { - scheme_wait_resume(); - return scheme_void; - } - } else { - if (!kill(sp->pid, SCHEME_TRUEP(killp) ? SIGKILL : SIGINT)) { - scheme_wait_resume(); - return scheme_void; - } - } - - if (errno != EINTR) - break; - /* Otherwise we were interrupted. Try `kill' again. */ - } - - scheme_wait_resume(); - -#else - if (SCHEME_TRUEP(killp) || sp->is_group) { - DWORD w; - int errid; - - if (!sp->handle) - return scheme_void; - - if (SCHEME_FALSEP(killp)) { - /* must be for a group; we don't care whether the - original process is still running */ - if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, sp->pid)) - return scheme_void; - } else if (GetExitCodeProcess((HANDLE)sp->handle, &w)) { - collect_process_time(w, sp); - if (w != STILL_ACTIVE) - return scheme_void; - if (TerminateProcess((HANDLE)sp->handle, 1)) - return scheme_void; - } - errid = GetLastError(); - errno = errid; - } else + if (!sp->proc) return scheme_void; -#endif - if (can_error) - scheme_raise_exn(MZEXN_FAIL, - "subprocess-kill: operation failed\n" - " system error: %E", errno); + if (SCHEME_TRUEP(killp)) + ok = rktio_process_kill(scheme_rktio, sp->proc); + else + ok = rktio_process_interrupt(scheme_rktio, sp->proc); - return NULL; -} - -#ifdef WINDOWS_PROCESSES -void scheme_release_process_job_object(void) -{ - if (process_job_object) { - TerminateJobObject((HANDLE)process_job_object, 1); - CloseHandle((HANDLE)process_job_object); - process_job_object = NULL; + if (!ok) { + if (can_error) + scheme_raise_exn(MZEXN_FAIL, + "subprocess-kill: operation failed\n" + " system error: %R"); } + + return scheme_void; } -#endif static void kill_subproc(Scheme_Object *o, void *data) { @@ -9495,21 +5819,13 @@ static void interrupt_subproc(Scheme_Object *o, void *data) { (void)do_subprocess_kill(o, scheme_false, 0); } -#endif static Scheme_Object *subprocess_kill(int argc, Scheme_Object **argv) { if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_subprocess_type)) scheme_wrong_contract("subprocess-kill", "subprocess?", 0, argc, argv); -#if defined(UNIX_PROCESSES) || defined(WINDOWS_PROCESSES) return do_subprocess_kill(argv[0], argv[1], 1); -#else - scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, - "%s: " NOT_SUPPORTED_STR, - "subprocess-wait"); - return NULL; -#endif } static Scheme_Object *subprocess_pid(int argc, Scheme_Object **argv) @@ -9517,7 +5833,9 @@ static Scheme_Object *subprocess_pid(int argc, Scheme_Object **argv) if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_subprocess_type)) scheme_wrong_contract("subprocess-pid", "subprocess?", 0, argc, argv); - return scheme_make_integer_value(((Scheme_Subprocess *)argv[0])->pid); + pid = rktio_process_pid(scheme_rktio, ((Scheme_Subprocess *)argv[0])->proc); + + return scheme_make_integer_value(pid); } static Scheme_Object *subprocess_p(int argc, Scheme_Object **argv) @@ -9554,260 +5872,23 @@ static Scheme_Object *subproc_group_on (int argc, Scheme_Object *argv[]) -1, NULL, NULL, 1); } -#ifdef UNIX_PROCESSES -static void unused_process_record(void *_sp, void *ignored) -{ - Scheme_Subprocess *sp = (Scheme_Subprocess *)_sp; - -# if defined(MZ_PLACES_WAITPID) - if (!sp->done) { - scheme_done_with_process_id(sp->pid, sp->is_group); - scheme_ended_child(); - } -# else - if (!((System_Child *)sp->handle)->done) { - void **unused_pid; - unused_pid = malloc(sizeof(void *) * 2); - unused_pid[0] = (void *)(intptr_t)sp->pid; - unused_pid[1] = unused_pids; - need_to_check_children = 1; - } -# endif -} -#endif - -/*********** Windows: command-line construction *************/ - -#ifdef WINDOWS_PROCESSES -static char *cmdline_protect(char *s) -{ - char *naya; - int ds; - int has_space = 0, has_quote = 0, was_slash = 0; - - if (!*s) return "\"\""; /* quote an empty argument */ - - for (ds = 0; s[ds]; ds++) { - if (isspace(s[ds]) || (s[ds] == '\'')) { - has_space = 1; - was_slash = 0; - } else if (s[ds] == '"') { - has_quote += 1 + (2 * was_slash); - was_slash = 0; - } else if (s[ds] == '\\') { - was_slash++; - } else - was_slash = 0; - } - - if (has_space || has_quote) { - char *p; - int wrote_slash = 0; - - naya = scheme_malloc_atomic(strlen(s) + 3 + 3*has_quote + was_slash); - naya[0] = '"'; - for (p = naya + 1; *s; s++) { - if (*s == '"') { - while (wrote_slash--) { - *(p++) = '\\'; - } - *(p++) = '"'; /* endquote */ - *(p++) = '\\'; - *(p++) = '"'; /* protected */ - *(p++) = '"'; /* start quote again */ - wrote_slash = 0; - } else if (*s == '\\') { - *(p++) = '\\'; - wrote_slash++; - } else { - *(p++) = *s; - wrote_slash = 0; - } - } - while (wrote_slash--) { - *(p++) = '\\'; - } - *(p++) = '"'; - *p = 0; - - return naya; - } - - return s; -} - -static intptr_t mz_spawnv(char *command, const char * const *argv, - int exact_cmdline, intptr_t sin, intptr_t sout, intptr_t serr, int *pid, - int new_process_group, Scheme_Object *cust_mode, - void *env, char *wd) -{ - int i, l, len = 0, use_jo; - intptr_t cr_flag; - char *cmdline; - STARTUPINFOW startup; - PROCESS_INFORMATION info; - - if (exact_cmdline) { - cmdline = (char *)argv[1]; - } else { - for (i = 0; argv[i]; i++) { - len += strlen(argv[i]) + 1; - } - - cmdline = (char *)scheme_malloc_atomic(len); - - len = 0; - for (i = 0; argv[i]; i++) { - l = strlen(argv[i]); - memcpy(cmdline + len, argv[i], l); - cmdline[len + l] = ' '; - len += l + 1; - } - --len; - cmdline[len] = 0; - } - - memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESTDHANDLES; - startup.hStdInput = (HANDLE)sin; - startup.hStdOutput = (HANDLE)sout; - startup.hStdError = (HANDLE)serr; - - /* If none of the stdio handles are consoles, specifically - create the subprocess without a console: */ - if (!is_fd_terminal((intptr_t)startup.hStdInput) - && !is_fd_terminal((intptr_t)startup.hStdOutput) - && !is_fd_terminal((intptr_t)startup.hStdError)) - cr_flag = CREATE_NO_WINDOW; - else - cr_flag = 0; - if (new_process_group) - cr_flag |= CREATE_NEW_PROCESS_GROUP; - cr_flag |= CREATE_UNICODE_ENVIRONMENT; - - use_jo = SCHEME_SYMBOLP(cust_mode) && !strcmp(SCHEME_SYM_VAL(cust_mode), "kill"); - if (use_jo) { - /* Use a job object to ensure that the new process will be terminated - if this process ends for any reason (including a crash) */ - if (!process_job_object) { - GC_CAN_IGNORE JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; - - process_job_object = (void*)CreateJobObject(NULL, NULL); - - memset(&jeli, 0, sizeof(jeli)); - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - SetInformationJobObject((HANDLE)process_job_object, - JobObjectExtendedLimitInformation, - &jeli, - sizeof(jeli)); - } - } - - if (CreateProcessW(WIDE_PATH_COPY(command), WIDE_PATH_COPY(cmdline), - NULL, NULL, 1 /*inherit*/, - cr_flag, env, WIDE_PATH_COPY(wd), - &startup, &info)) { - if (use_jo) - AssignProcessToJobObject((HANDLE)process_job_object, info.hProcess); - CloseHandle(info.hThread); - *pid = info.dwProcessId; - return (intptr_t)info.hProcess; - } else - return -1; -} - -static void close_subprocess_handle(void *sp, void *ignored) -{ - Scheme_Subprocess *subproc = (Scheme_Subprocess *)sp; - - CloseHandle(subproc->handle); -} - -static void CopyFileHandleForSubprocess(intptr_t *hs, int pos) -{ - HANDLE h2; - int alt_pos = (pos ? 0 : 1); - - if (DuplicateHandle(GetCurrentProcess(), - (HANDLE)hs[pos], - GetCurrentProcess(), - &h2, - 0, - TRUE, - DUPLICATE_SAME_ACCESS)) { - hs[pos] = (intptr_t)h2; - hs[alt_pos] = 1; - } else { - hs[alt_pos] = 0; - } -} - -static void CloseFileHandleForSubprocess(intptr_t *hs, int pos) -{ - int alt_pos = (pos ? 0 : 1); - if (hs[alt_pos]) { - CloseHandle((HANDLE)hs[pos]); - } -} - -#define mzCOPY_FILE_HANDLE(array, pos) CopyFileHandleForSubprocess(array, pos) -#define mzCLOSE_FILE_HANDLE(array, pos) CloseFileHandleForSubprocess(array, pos) - -#endif /* WINDOWS_PROCESSES */ - -#ifndef mzCOPY_FILE_HANDLE -# define mzCOPY_FILE_HANDLE(array, pos) /* empty */ -# define mzCLOSE_FILE_HANDLE(array, pos) /* empty */ -#endif - -/*********** All: The main system/process/execute function *************/ - static Scheme_Object *subprocess(int c, Scheme_Object *args[]) /* subprocess(out, in, err, exe, arg ...) */ { const char *name = "subprocess"; -#if defined(PROCESS_FUNCTION) && !defined(MAC_CLASSIC_PROCESS_CONTROL) - char *command; - intptr_t to_subprocess[2], from_subprocess[2], err_subprocess[2]; - int i, pid, errid; - char **argv; - Scheme_Object *in, *out, *err; -#if defined(UNIX_PROCESSES) -# if !defined(MZ_PLACES_WAITPID) - System_Child *sc; -# endif - int fork_errno = 0; - char *env; - int need_free; - Scheme_Object *current_dir; -#else - void *sc = 0; -#endif Scheme_Object *inport; Scheme_Object *outport; Scheme_Object *errport; - int stderr_is_stdout = 0; Scheme_Object *a[4]; Scheme_Subprocess *subproc; Scheme_Object *cust_mode; - int new_process_group; -#if defined(WINDOWS_PROCESSES) - int exact_cmdline = 0; -#endif -#if defined(WINDOWS_PROCESSES) - intptr_t spawn_status; -#endif - -#if defined(PROCESS_FUNCTION) && !defined(MAC_CLASSIC_PROCESS_CONTROL) - /* avoid compiler warnings: */ - to_subprocess[0] = -1; - to_subprocess[1] = -1; - from_subprocess[0] = -1; - from_subprocess[1] = -1; - err_subprocess[0] = -1; - err_subprocess[1] = -1; -#endif + int flags = 0; + rktio_fd_t *stdout_fd = NULL; + rktio_fd_t *stdin_fd = NULL; + rktio_fd_t *stderr_fd = NULL; + int need_forget_out = 0, need_forget_in = 0, need_forget_err = 0; + rktio_envvars_t *envvars; + rktio_process_result_t *result; /*--------------------------------------------*/ /* Sort out ports (create later if necessary) */ @@ -9816,7 +5897,6 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) if (SCHEME_TRUEP(args[0])) { outport = args[0]; if (SCHEME_OUTPUT_PORTP(outport) && SCHEME_TRUEP(scheme_file_stream_port_p(1, &outport))) { -#ifdef PROCESS_FUNCTION Scheme_Output_Port *op; op = scheme_output_port_record(outport); @@ -9824,23 +5904,17 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) if (SAME_OBJ(op->sub_type, file_output_port_type)) { int tmp; tmp = MSC_IZE(fileno)(((Scheme_Output_File *)op->port_data)->f); - from_subprocess[1] = tmp; - } -# ifdef MZ_FDS - else if (SAME_OBJ(op->sub_type, fd_output_port_type)) - from_subprocess[1] = ((Scheme_FD *)op->port_data)->fd; -# endif - mzCOPY_FILE_HANDLE(from_subprocess, 1); -#endif + stdout_fd = rktio_system_fd(tmp, RKTIO_OPEN_WRITE | RKTIO_NOT_REGFILE); + need_forget_out = 1; + } else if (SAME_OBJ(op->sub_type, fd_output_port_type)) + stdout_fd = ((Scheme_FD *)op->port_data)->fd; } else scheme_wrong_contract(name, "(or/c (and/c file-stream-port? output-port?) #f)", 0, c, args); - } else - outport = NULL; + } if (SCHEME_TRUEP(args[1])) { inport = args[1]; if (SCHEME_INPUT_PORTP(inport) && SCHEME_TRUEP(scheme_file_stream_port_p(1, &inport))) { -#ifdef PROCESS_FUNCTION Scheme_Input_Port *ip; ip = scheme_input_port_record(inport); @@ -9848,27 +5922,20 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) if (SAME_OBJ(ip->sub_type, file_input_port_type)) { int tmp; tmp = MSC_IZE(fileno)(((Scheme_Input_File *)ip->port_data)->f); - to_subprocess[0] = tmp; - } -# ifdef MZ_FDS - else if (SAME_OBJ(ip->sub_type, fd_input_port_type)) - to_subprocess[0] = ((Scheme_FD *)ip->port_data)->fd; -# endif - mzCOPY_FILE_HANDLE(to_subprocess, 0); -#endif + stdin_fd = rktio_system_fd(tmp, RKTIO_OPEN_READ | RKTIO_NOT_REGFILE); + need_forget_in = 1; + } else if (SAME_OBJ(ip->sub_type, fd_input_port_type)) + stdin_fd = ((Scheme_FD *)ip->port_data)->fd; } else scheme_wrong_contract(name, "(or/c (and/c file-stream-port? input-port?) #f)", 1, c, args); - } else - inport = NULL; + } if (SCHEME_SYMBOLP(args[2]) && !SCHEME_SYM_WEIRDP(args[2]) && !strcmp("stdout", SCHEME_SYM_VAL(args[2]))) { - errport = NULL; - stderr_is_stdout = 1; + flags |= RKTIO_PROCESS_STDOUT_AS_STDERR; } else if (SCHEME_TRUEP(args[2])) { errport = args[2]; if (SCHEME_OUTPUT_PORTP(errport) && SCHEME_TRUEP(scheme_file_stream_port_p(1, &errport))) { -#ifdef PROCESS_FUNCTION Scheme_Output_Port *op; op = scheme_output_port_record(errport); @@ -9876,18 +5943,13 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) if (SAME_OBJ(op->sub_type, file_output_port_type)) { int tmp; tmp = MSC_IZE(fileno)(((Scheme_Output_File *)op->port_data)->f); - err_subprocess[1] = tmp; - } -# ifdef MZ_FDS - else if (SAME_OBJ(op->sub_type, fd_output_port_type)) - err_subprocess[1] = ((Scheme_FD *)op->port_data)->fd; -# endif - mzCOPY_FILE_HANDLE(err_subprocess, 1); -#endif + stderr_fd = rktio_system_fd(tmp, RKTIO_OPEN_WRITE | RKTIO_NOT_REGFILE); + need_forget_err = 1; + } else if (SAME_OBJ(op->sub_type, fd_output_port_type)) + stderr_fd = ((Scheme_FD *)op->port_data)->fd; } else scheme_wrong_contract(name, "(or/c (and/c file-stream-port? output-port?) #f 'stdout)", 2, c, args); - } else - errport = NULL; + } if (!SCHEME_PATH_STRINGP(args[3])) scheme_wrong_contract(name, "path-string?", 3, c, args); @@ -9913,7 +5975,7 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) np = scheme_normal_path_seps(argv[0], &nplen, 0); argv[0] = np; } - + if ((c == 6) && SAME_OBJ(args[4], exact_symbol)) { argv[2] = NULL; if (!SCHEME_CHAR_STRINGP(args[5]) || scheme_any_string_has_null(args[5])) @@ -9923,15 +5985,14 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) bs = scheme_char_string_to_byte_string(args[5]); argv[1] = SCHEME_BYTE_STR_VAL(bs); } -#ifdef WINDOWS_PROCESSES - exact_cmdline = 1; -#else - /* 'exact-full only works in windows */ - scheme_contract_error(name, - "exact command line not supported on this platform", - "exact command", 1, args[5], - NULL); -#endif + + if (rktio_process_allowed_flags(scheme_rktio) & RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE) + flags |= RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE; + else + scheme_contract_error(name, + "exact command line not supported on this platform", + "exact command", 1, args[5], + NULL); } else { for (i = 4; i < c; i++) { if (((!SCHEME_CHAR_STRINGP(args[i]) && !SCHEME_BYTE_STRINGP(args[i])) @@ -9953,517 +6014,88 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) command = argv[0]; - if (!inport || !outport || !errport) + if (!stdin_fd || !stdout_fd || !stderr_fd) scheme_custodian_check_available(NULL, name, "file-stream"); + /*--------------------------------------*/ + /* Create subprocess */ + /*--------------------------------------*/ + cust_mode = scheme_get_param(scheme_current_config(), MZCONFIG_SUBPROC_GROUP_ENABLED); new_process_group = SCHEME_TRUEP(cust_mode); cust_mode = scheme_get_param(scheme_current_config(), MZCONFIG_SUBPROC_CUSTODIAN_MODE); - /*--------------------------------------*/ - /* Create needed pipes */ - /*--------------------------------------*/ + if (SCHEME_SYMBOLP(cust_mode) + && !strcmp(SCHEME_SYM_VAL(cust_mode), "kill") + && (rktio_process_allowed_flags(scheme_rktio) & RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION)) + flags |= RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION; - if (!inport && scheme_os_pipe(to_subprocess, 1)) { - errid = scheme_errno(); - if (outport) { mzCLOSE_FILE_HANDLE(from_subprocess, 1); } - if (errport) { mzCLOSE_FILE_HANDLE(err_subprocess, 1); } - scheme_system_error(name, "pipe", errid); - } - if (!outport && scheme_os_pipe(from_subprocess, 0)) { - errid = scheme_errno(); - if (!inport) { - scheme_close_file_fd(to_subprocess[0]); - scheme_close_file_fd(to_subprocess[1]); - } else { - mzCLOSE_FILE_HANDLE(to_subprocess, 0); - } - if (errport) { mzCLOSE_FILE_HANDLE(err_subprocess, 1); } - scheme_system_error(name, "pipe", errid); - } - if (!errport && stderr_is_stdout) { - err_subprocess[0] = from_subprocess[0]; - err_subprocess[1] = from_subprocess[1]; - } else if (!errport && scheme_os_pipe(err_subprocess, 0)) { - errid = scheme_errno(); - if (!inport) { - scheme_close_file_fd(to_subprocess[0]); - scheme_close_file_fd(to_subprocess[1]); - } else { - mzCLOSE_FILE_HANDLE(to_subprocess, 0); - } - if (!outport) { - scheme_close_file_fd(from_subprocess[0]); - scheme_close_file_fd(from_subprocess[1]); - } else { - mzCLOSE_FILE_HANDLE(from_subprocess, 1); - } - scheme_system_error(name, "pipe", errid); - } + current_dir = scheme_get_param(config, MZCONFIG_CURRENT_DIRECTORY); -#if defined(WINDOWS_PROCESSES) + envvars = environment_variables_to_envvars(scheme_get_param(config, MZCONFIG_CURRENT_ENV_VARS)); - /*--------------------------------------*/ - /* Execute: Windows */ - /*--------------------------------------*/ + result = rktio_process(scheme_rktio, + command, argc, argv, + stdout_fd, stdin_fd, stderr_fd, + SCHEME_PATH_VAL(current_dir), envvars, + flags, + unix_turn_off_timer); - /* Windows: quasi-stdin is locked, and we'll say it doesn't matter */ - fflush(stdin); - fflush(stdout); - fflush(stderr); + if (envvars) + rktio_envvars_free(envvars); - { - Scheme_Object *tcd, *envvar; - Scheme_Config *config; - char *env; - int need_free; - - if (!exact_cmdline) { - /* protect spaces, etc. in the arguments: */ - for (i = 0; i < (c - 3); i++) { - char *cla; - cla = cmdline_protect(argv[i]); - argv[i] = cla; - } - } - - config = scheme_current_config(); - - tcd = scheme_get_param(config, MZCONFIG_CURRENT_DIRECTORY); - - envvar = scheme_get_param(config, MZCONFIG_CURRENT_ENV_VARS); - - env = scheme_environment_variables_to_block(envvar, &need_free); - - spawn_status = mz_spawnv(command, (const char * const *)argv, - exact_cmdline, - to_subprocess[0], - from_subprocess[1], - err_subprocess[1], - &pid, - new_process_group, cust_mode, - env, SCHEME_BYTE_STR_VAL(tcd)); - - if (spawn_status != -1) - sc = (void *)spawn_status; - - if (need_free) free(env); - } - -#else - - - /*--------------------------------------*/ - /* Execute: Unix */ - /*--------------------------------------*/ - - { - /* Prepare CWD and environment variables */ - Scheme_Object *envvar; - Scheme_Config *config; - - config = scheme_current_config(); - - envvar = scheme_get_param(config, MZCONFIG_CURRENT_ENV_VARS); - env = scheme_environment_variables_to_block(envvar, &need_free); - - current_dir = scheme_get_param(config, MZCONFIG_CURRENT_DIRECTORY); - -#if !defined(MZ_PLACES_WAITPID) - init_sigchld(); - - sc = MALLOC_ONE_RT(System_Child); -# ifdef MZTAG_REQUIRED - sc->type = scheme_rt_system_child; -# endif - sc->id = 0; - sc->done = 0; - - scheme_block_child_signals(1); -#else - scheme_starting_child(); -#endif - -#if defined(__QNX__) - pid = vfork(); -#elif defined(SUBPROCESS_USE_FORK1) - pid = fork1(); -#else - pid = fork(); -#endif - - if (pid > 0) { - if (new_process_group) - /* there's a race condition between this use and the exec(), - and there's a race condition between the other setpgid() in - the child processand sending signals from the parent - process; so, we set in both, and at least one will - succeed; we could perform better error checking, since - EACCES is the only expected error */ - setpgid(pid, pid); - -#if defined(MZ_PLACES_WAITPID) - { - int *signal_fd; - int status; - signal_fd = scheme_get_signal_handle(); - scheme_places_register_child(pid, new_process_group, signal_fd, &status); - - /* printf("SUBPROCESS %i\n", pid); */ - } -#else - sc->next = scheme_system_children; - scheme_system_children = sc; - sc->id = pid; -#endif - } else if (!pid) { -#ifdef USE_ITIMER - /* Turn off the timer. */ - /* SIGPROF is masked at this point due to - block_child_signals() */ - struct itimerval t, old; - sigset_t sigs; - - t.it_value.tv_sec = 0; - t.it_value.tv_usec = 0; - t.it_interval.tv_sec = 0; - t.it_interval.tv_usec = 0; - - setitimer(ITIMER_PROF, &t, &old); - - /* Clear already-queued PROF signal, if any: */ - START_XFORM_SKIP; - sigemptyset(&sigs); - while (!sigpending(&sigs)) { - if (sigismember(&sigs, SIGPROF)) { - sigprocmask(SIG_SETMASK, NULL, &sigs); - sigdelset(&sigs, SIGPROF); - sigsuspend(&sigs); - sigemptyset(&sigs); - } else - break; - } - END_XFORM_SKIP; -#endif - if (new_process_group) - /* see also setpgid above */ - setpgid(getpid(), getpid()); /* setpgid(0, 0) would work on some platforms */ - } else { - fork_errno = errno; - } - -#if !defined(MZ_PLACES_WAITPID) - scheme_block_child_signals(0); -#else - if (!pid) - scheme_places_unblock_child_signal(); - else if (pid == -1) - scheme_ended_child(); -#endif - } - - switch (pid) - { - case -1: - /* Close unused descriptors. */ - if (!inport) { - scheme_close_file_fd(to_subprocess[0]); - scheme_close_file_fd(to_subprocess[1]); - } else { - mzCLOSE_FILE_HANDLE(to_subprocess, 0); - } - if (!outport) { - scheme_close_file_fd(from_subprocess[0]); - scheme_close_file_fd(from_subprocess[1]); - } else { - mzCLOSE_FILE_HANDLE(from_subprocess, 1); - } - if (!errport) { - if (!stderr_is_stdout) { - scheme_close_file_fd(err_subprocess[0]); - scheme_close_file_fd(err_subprocess[1]); - } - } else { - mzCLOSE_FILE_HANDLE(err_subprocess, 1); - } - scheme_system_error(name, "fork", fork_errno); - return scheme_false; - - case 0: /* child */ - - { - /* Copy pipe descriptors to stdin and stdout */ - do { - errid = MSC_IZE(dup2)(to_subprocess[0], 0); - } while (errid == -1 && errno == EINTR); - do { - errid = MSC_IZE(dup2)(from_subprocess[1], 1); - } while (errid == -1 && errno == EINTR); - do { - errid = MSC_IZE(dup2)(err_subprocess[1], 2); - } while (errid == -1 && errno == EINTR); - - /* Close unwanted descriptors. */ - if (!inport) { - scheme_close_file_fd(to_subprocess[0]); - scheme_close_file_fd(to_subprocess[1]); - } - if (!outport) { - scheme_close_file_fd(from_subprocess[0]); - scheme_close_file_fd(from_subprocess[1]); - } - if (!errport) { - if (!stderr_is_stdout) { - scheme_close_file_fd(err_subprocess[0]); - scheme_close_file_fd(err_subprocess[1]); - } - } - -#ifdef CLOSE_ALL_FDS_AFTER_FORK - close_fds_after_fork(0, 1, 2); -#endif - } - - /* Set real CWD: */ - if (!scheme_os_setcwd(SCHEME_PATH_VAL(current_dir), 1)) { - scheme_console_printf("racket: chdir failed to: %s\n", SCHEME_BYTE_STR_VAL(current_dir)); - _exit(1); - } - - /* Exec new process */ - - { - int err; - - /* Reset ignored signals: */ - START_XFORM_SKIP; -#ifndef DONT_IGNORE_FPE_SIGNAL - MZ_SIGSET(SIGFPE, SIG_DFL); -#endif -#ifndef DONT_IGNORE_PIPE_SIGNAL - MZ_SIGSET(SIGPIPE, SIG_DFL); -#endif - END_XFORM_SKIP; - - err = MSC_IZE(execve)(command, argv, (char **)env); - if (err) - err = errno; - - if (need_free) - free(env); - - /* If we get here it failed; give up */ - - /* using scheme_signal_error will leave us in the forked process, - so use scheme_console_printf instead */ - scheme_console_printf("racket: exec failed (%s%serrno=%d)\n", -#ifdef NO_STRERROR_AVAILABLE - "", "", -#else - strerror(err), "; ", -#endif - err); - - /* back to Racket signal dispositions: */ - START_XFORM_SKIP; -#ifndef DONT_IGNORE_FPE_SIGNAL - MZ_SIGSET(SIGFPE, SIG_IGN); -#endif -#ifndef DONT_IGNORE_PIPE_SIGNAL - MZ_SIGSET(SIGPIPE, SIG_IGN); -#endif - END_XFORM_SKIP; - - _exit(1); - } - - default: /* parent */ - - break; - } -#endif - - /*--------------------------------------*/ - /* Close unneeded descriptors */ - /*--------------------------------------*/ - - if (!inport) { - scheme_close_file_fd(to_subprocess[0]); - out = NULL; - } else { - mzCLOSE_FILE_HANDLE(to_subprocess, 0); - out = scheme_false; - } - if (!outport) { - scheme_close_file_fd(from_subprocess[1]); - in = NULL; - } else { - mzCLOSE_FILE_HANDLE(from_subprocess, 1); - in = scheme_false; - } - if (!errport) { - if (!stderr_is_stdout) - scheme_close_file_fd(err_subprocess[1]); - err = NULL; - } else { - mzCLOSE_FILE_HANDLE(err_subprocess, 1); - err = scheme_false; + if (!result) { + scheme_raise_exn(MZEXN_FAIL, + "subprocess: process creation failed"); } /*--------------------------------------*/ /* Create new port objects */ /*--------------------------------------*/ - in = (in ? in : make_fd_input_port(from_subprocess[0], scheme_intern_symbol("subprocess-stdout"), 0, 0, NULL, 0)); - out = (out ? out : make_fd_output_port(to_subprocess[1], scheme_intern_symbol("subprocess-stdin"), 0, 0, 0, -1, NULL)); - if (stderr_is_stdout) - err = scheme_false; - else - err = (err ? err : make_fd_input_port(err_subprocess[0], scheme_intern_symbol("subprocess-stderr"), 0, 0, NULL, 0)); - - /*--------------------------------------*/ - /* Return result info */ - /*--------------------------------------*/ - - subproc = MALLOC_ONE_TAGGED(Scheme_Subprocess); - subproc->so.type = scheme_subprocess_type; -#if !defined(MZ_PLACES_WAITPID) - subproc->handle = (void *)sc; -#endif - subproc->pid = pid; - subproc->is_group = new_process_group; -# if defined(WINDOWS_PROCESSES) - scheme_add_finalizer(subproc, close_subprocess_handle, NULL); -# else - scheme_add_finalizer(subproc, unused_process_record, NULL); -# endif - - if (SCHEME_TRUEP(cust_mode)) { - Scheme_Custodian_Reference *mref; - Scheme_Close_Custodian_Client *closer; - - if (!strcmp(SCHEME_SYM_VAL(cust_mode), "kill")) - closer = kill_subproc; - else - closer = interrupt_subproc; - - mref = scheme_add_managed_close_on_exit(NULL, (Scheme_Object *)subproc, closer, NULL); - subproc->mref = mref; - } - -#define cons scheme_make_pair - - a[0] = (Scheme_Object *)subproc; - a[1] = in; - a[2] = out; - a[3] = err; - - return scheme_values(4, a); - -#else -# ifdef MAC_CLASSIC_PROCESS_CONTROL - - /*--------------------------------------*/ - /* Macintosh hacks */ - /*--------------------------------------*/ - { - int i; - Scheme_Object *a[4], *appname; - Scheme_Subprocess *subproc; - - for (i = 0; i < 3; i++) { - if (!SCHEME_FALSEP(args[i])) - scheme_contract_error(name, - "non-#f port argument not allowed on this platform", - "port", 1, args[i], - NULL); - } - - if (c > 4) { - if (c == 5) { - Scheme_Object *bs; - if (!SCHEME_PATH_STRINGP(args[3])) - scheme_wrong_contract(name, "path-string?", 3, c, args); - if (SCHEME_PATHP(args[3])) - bs = args[3]; - else - bs = scheme_char_string_to_path(args[3]); - if (strcmp(SCHEME_PATH_VAL(bs), "by-id")) - scheme_contract_error(name, - "in five-argument mode on this platform, the 4th argument must be \"by-id\"", - "given", 1, args[3], - NULL); - - appname = args[4]; - i = scheme_mac_start_app((char *)name, 1, appname); - } else - scheme_contract_error(name, - "extra arguments after the application id are " - "not allowed on this platform", - "first extra argument", 1, args[5], - NULL); - } else { - appname = args[3]; - i = scheme_mac_start_app((char *)name, 0, appname); - } - - if (!i) { - scheme_raise_exn(MZEXN_FAIL, - "%s: launch failed\n" - " application: %Q", - name, appname); - return NULL; - } - + Scheme_Object *in = scheme_false, *out = scheme_false, *err = scheme_false; + + if (result->stdout_fd) + in = make_fd_input_port(result->stdout_fd, scheme_intern_symbol("subprocess-stdout"), NULL, 0); + if (result->stdin_fd) + out = make_fd_output_port(result_stdin_fd, scheme_intern_symbol("subprocess-stdin"), 0, -1, NULL); + if (result->stderr_fd) + err = (err ? err : make_fd_input_port(result->stderr_fd, scheme_intern_symbol("subprocess-stderr"), NULL, 0)); + + /*--------------------------------------*/ + /* Return result info */ + /*--------------------------------------*/ + subproc = MALLOC_ONE_TAGGED(Scheme_Subprocess); - subproc->type = scheme_subprocess_type; + subproc->so.type = scheme_subprocess_type; + subproc->proc = result->proc; + scheme_add_finalizer(subproc, close_subprocess_handle, NULL); + + if (SCHEME_TRUEP(cust_mode)) { + Scheme_Custodian_Reference *mref; + Scheme_Close_Custodian_Client *closer; + + if (!strcmp(SCHEME_SYM_VAL(cust_mode), "kill")) + closer = kill_subproc; + else + closer = interrupt_subproc; + + mref = scheme_add_managed_close_on_exit(NULL, (Scheme_Object *)subproc, closer, NULL); + subproc->mref = mref; + } + + free(result); a[0] = (Scheme_Object *)subproc; - a[1] = scheme_false; - a[2] = scheme_false; - a[3] = scheme_false; + a[1] = in; + a[2] = out; + a[3] = err; return scheme_values(4, a); } - -# else - /*--------------------------------------*/ - /* Subprocess functionality disabled */ - /*--------------------------------------*/ - - scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, - "%s: " NOT_SUPPORTED_STR, - name); - return NULL; -# endif -#endif } -#ifdef CLOSE_ALL_FDS_AFTER_FORK -static void close_fds_after_fork(int skip1, int skip2, int skip3) -{ - int i; - -# ifdef USE_ULIMIT - i = ulimit(4, 0); -# elif defined(__ANDROID__) - i = sysconf(_SC_OPEN_MAX); -# else - i = getdtablesize(); -# endif - while (i--) { - int cr; - if ((i != skip1) && (i != skip2) && (i != skip3)) { - do { - cr = close(i); - } while ((cr == -1) && (errno == EINTR)); - } - } -} -#endif - - static Scheme_Object *sch_shell_execute(int c, Scheme_Object *argv[]) { #ifdef WINDOWS_PROCESSES @@ -10602,355 +6234,21 @@ void scheme_release_file_descriptor(void) #endif } - /*========================================================================*/ /* sleeping */ /*========================================================================*/ -/* This code is used to implement sleeping when Racket is completely - blocked on external objects, such as ports. For Unix, sleeping is - essentially just a select(). */ - -/****************** Windows cleanup *****************/ - -#if defined(WIN32_FD_HANDLES) - -static void clean_up_wait(intptr_t result, OS_SEMAPHORE_TYPE *array, - int *rps, int count) -{ - if ((result >= (intptr_t)WAIT_OBJECT_0) && (result < (intptr_t)WAIT_OBJECT_0 + count)) { - result -= WAIT_OBJECT_0; - if (rps[result]) - ReleaseSemaphore(array[result], 1, NULL); - } - - /* Clear out break semaphore */ - WaitForSingleObject((HANDLE)scheme_break_semaphore, 0); -} - -static int made_progress; -static DWORD max_sleep_time; - -void scheme_notify_sleep_progress() -{ - made_progress = 1; -} - -#else - -void scheme_notify_sleep_progress() -{ -} - -#endif - -/******************** Main sleep function *****************/ -/* The simple select() stuff is buried in Windows complexity. */ - -static void clear_signal() - XFORM_SKIP_PROC -{ -#if defined(FILES_HAVE_FDS) - /* Clear external event flag */ - if (external_event_fd) { - int rc; - char buf[10]; - do { - rc = read(external_event_fd, buf, 10); - } while ((rc == -1) && errno == EINTR); - } -#endif -} - -static void default_sleep(float v, void *fds) -#ifdef OS_X - XFORM_SKIP_PROC -#endif -/* This sleep function is not allowed to allocate in OS X, because it - is called in a non-main thread. */ -{ - /* REMEMBER: don't allocate in this function (at least not GCable - memory) for OS X. Not that FD setups are ok, because they use - eternal mallocs. */ - -#ifdef USE_OSKIT_CONSOLE - /* Don't really sleep; keep polling the keyboard: */ - if (!v || (v > 0.01)) - v = 0.01; -#endif - - if (!fds) { - /* Nothing to block on - just sleep for some amount of time. */ -#if defined(FILES_HAVE_FDS) -# ifdef HAVE_POLL_SYSCALL - int timeout; - if (v <= 0.0) - timeout = -1; - else { - timeout = (int)(v * 1000.0); - if (timeout < 0) - timeout = 0; - } - if (external_event_fd) { - GC_CAN_IGNORE struct pollfd pfd[1]; - pfd[0].fd = external_event_fd; - pfd[0].events = POLLIN; - poll(pfd, 1, timeout); - } else { - poll(NULL, 0, timeout); - } -# else - /* Sleep by selecting on the external event fd */ - struct timeval time; - intptr_t secs = (intptr_t)v; - intptr_t usecs = (intptr_t)(fmod(v, 1.0) * 1000000); - - if (v && (v > 100000)) - secs = 100000; - if (usecs < 0) - usecs = 0; - if (usecs >= 1000000) - usecs = 999999; - - time.tv_sec = secs; - time.tv_usec = usecs; - - if (external_event_fd) { - DECL_FDSET(readfds, 1); - - INIT_DECL_RD_FDSET(readfds); - - MZ_FD_ZERO(readfds); - MZ_FD_SET(external_event_fd, readfds); - - select(external_event_fd + 1, readfds, NULL, NULL, &time); - } else { - select(0, NULL, NULL, NULL, &time); - } -# endif -#else -# ifndef NO_SLEEP -# ifndef NO_USLEEP - usleep((unsigned)(v * 1000)); -# else - sleep(v); -# endif -# endif -#endif - } else { - /* Something to block on - sort our the parts in Windows. */ - -#if defined(FILES_HAVE_FDS) || defined(USE_WINSOCK_TCP) -# ifndef HAVE_POLL_SYSCALL - int actual_limit; - fd_set *rd, *wr, *ex; - struct timeval time; -# endif - -# ifdef SIGCHILD_DOESNT_INTERRUPT_SELECT - if (scheme_system_children) { - /* Better poll every second or so... */ - if (!v || (v > 1)) - v = 1; - } -# endif - -# ifndef HAVE_POLL_SYSCALL - { - intptr_t secs = (intptr_t)v; - intptr_t usecs = (intptr_t)(fmod(v, 1.0) * 1000000); - - if (v && (v > 100000)) - secs = 100000; - if (usecs < 0) - usecs = 0; - if (usecs >= 1000000) - usecs = 999999; - - time.tv_sec = secs; - time.tv_usec = usecs; - } - - rd = (fd_set *)fds; - wr = (fd_set *)MZ_GET_FDSET(fds, 1); - ex = (fd_set *)MZ_GET_FDSET(fds, 2); - - actual_limit = scheme_get_fd_limit(fds); -# endif - - /******* Start Windows stuff *******/ - -#if defined(WIN32_FD_HANDLES) - { - intptr_t result; - OS_SEMAPHORE_TYPE *array, just_two_array[2], break_sema; - int count, rcount, *rps; - - if (((win_extended_fd_set *)rd)->no_sleep) - return; - - scheme_collapse_win_fd(fds); /* merges */ - - rcount = SCHEME_INT_VAL(((win_extended_fd_set *)fds)->num_handles); - count = SCHEME_INT_VAL(((win_extended_fd_set *)fds)->combined_len); - array = ((win_extended_fd_set *)fds)->combined_wait_array; - rps = ((win_extended_fd_set *)fds)->repost_sema; - - /* add break semaphore: */ - if (!count) { - array = just_two_array; - } - break_sema = (HANDLE)scheme_break_semaphore; - array[count++] = break_sema; - - /* Extensions may handle events. - If the event queue is empty (as reported by GetQueueStatus), - everything's ok. - - Otherwise, we have trouble sleeping until an event is ready. We - sometimes leave events on th queue because, say, an eventspace is - not ready. The problem is that MsgWait... only unblocks when a new - event appears. Since extensions may check the queue using a sequence of - PeekMessages, it's possible that an event is added during the - middle of the sequence, but doesn't get handled. - - To avoid this problem, we don't actually sleep indefinitely if an event - is pending. Instead, we slep 10 ms, then 20 ms, etc. This exponential - backoff ensures that we eventually handle a pending event, but we don't - spin and eat CPU cycles. The back-off is reset whenever a thread makes - progress. */ - - - if (SCHEME_INT_VAL(((win_extended_fd_set *)fds)->wait_event_mask) - && GetQueueStatus(SCHEME_INT_VAL(((win_extended_fd_set *)fds)->wait_event_mask))) { - if (!made_progress) { - /* Ok, we've gone around at least once. */ - if (max_sleep_time < 0x20000000) - max_sleep_time *= 2; - } else { - /* Starting back-off mode */ - made_progress = 0; - max_sleep_time = 5; - } - } else { - /* Disable back-off mode */ - made_progress = 1; - max_sleep_time = 0; - } - - /* Wait for HANDLE-based input: */ - { - DWORD msec; - if (v) { - if (v > 100000) - msec = 100000000; - else - msec = (DWORD)(v * 1000); - if (max_sleep_time && (msec > max_sleep_time)) - msec = max_sleep_time; - } else { - if (max_sleep_time) - msec = max_sleep_time; - else - msec = INFINITE; - } - - result = MsgWaitForMultipleObjects(count, array, FALSE, msec, - SCHEME_INT_VAL(((win_extended_fd_set *)fds)->wait_event_mask)); - } - clean_up_wait(result, array, rps, rcount); - scheme_collapse_win_fd(fds); /* cleans up */ - - return; - } -#endif - -#ifdef USE_WINSOCK_TCP - /* Stupid Windows: give select() empty fd_sets and it ignores the timeout. */ - if (!rd->fd_count && !wr->fd_count && !ex->fd_count) { - if (v) - Sleep((DWORD)(v * 1000)); - return; - } -#endif - - /******* End Windows stuff *******/ - -# ifdef HAVE_POLL_SYSCALL - { - struct mz_fd_set_data *data = ((struct mz_fd_set *)fds)->data; - intptr_t count = SCHEME_INT_VAL(data->count); - int timeout; - - if (v <= 0.0) - timeout = -1; - else if (v > 100000) - timeout = 100000000; - else { - timeout = (int)(v * 1000.0); - if (timeout < 0) - timeout = 0; - } - - if (external_event_fd) { - data->pfd[count].fd = external_event_fd; - data->pfd[count].events = POLLIN; - count++; - } - - poll(data->pfd, count, timeout); - } -#else -# if defined(FILES_HAVE_FDS) - /* Watch for external events, too: */ - if (external_event_fd) { - MZ_FD_SET(external_event_fd, rd); - if (external_event_fd >= actual_limit) - actual_limit = external_event_fd + 1; - } -# endif - - select(actual_limit, rd, wr, ex, v ? &time : NULL); -#endif - -#endif - } - - clear_signal(); -} - void scheme_signal_received_at(void *h) XFORM_SKIP_PROC /* Ensure that Racket wakes up if asleep. */ { -#if defined(FILES_HAVE_FDS) - int put_ext_event_fd = *(int *)h; - int saved_errno = errno; - if (put_ext_event_fd) { - int v; - do { - v = write(put_ext_event_fd, "!", 1); - } while ((v == -1) && (errno == EINTR)); - } - errno = saved_errno; -#endif -#if defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES) - ReleaseSemaphore(*(OS_SEMAPHORE_TYPE *)h, 1, NULL); -#endif + rktio_signal_received_at(h); } void *scheme_get_signal_handle() XFORM_SKIP_PROC { -#if defined(FILES_HAVE_FDS) - return &put_external_event_fd; -#else -# if defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES) - return &scheme_break_semaphore; -# else - return NULL; -# endif -#endif + return (void *)rktio_signal_received(scheme_rktio); } void scheme_signal_received(void) @@ -10962,43 +6260,7 @@ void scheme_signal_received(void) void scheme_wait_until_signal_received(void) XFORM_SKIP_PROC { -#if defined(FILES_HAVE_FDS) - int r; -# ifdef HAVE_POLL_SYSCALL - GC_CAN_IGNORE struct pollfd pfd[1]; - pfd[0].fd = external_event_fd; - pfd[0].events = POLLIN; - do { - r = poll(pfd, 1, -1); - } while ((r == -1) && (errno == EINTR)); -# else - DECL_FDSET(readfds, 1); - - INIT_DECL_RD_FDSET(readfds); - - MZ_FD_ZERO(readfds); - MZ_FD_SET(external_event_fd, readfds); - - do { - r = select(external_event_fd + 1, readfds, NULL, NULL, NULL); - } while ((r == -1) && (errno == EINTR)); -# endif -#else -# if defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES) - WaitForSingleObject((HANDLE)scheme_break_semaphore, INFINITE); -# endif -#endif - - clear_signal(); -} - -int scheme_get_external_event_fd(void) -{ -#if defined(FILES_HAVE_FDS) - return external_event_fd; -#else - return 0; -#endif + rktio_wait_until_signal_received(scheme_rktio); } #ifdef USE_WIN32_THREAD_TIMER @@ -11521,10 +6783,6 @@ static void register_traversers(void) GC_REG_TRAV(scheme_rt_system_child, mark_system_child); #endif -#ifdef USE_OSKIT_CONSOLE - GC_REG_TRAV(scheme_rt_oskit_console_input, mark_oskit_console_input); -#endif - GC_REG_TRAV(scheme_subprocess_type, mark_subprocess); GC_REG_TRAV(scheme_write_evt_type, mark_read_write_evt); diff --git a/racket/src/racket/src/portfun.c b/racket/src/racket/src/portfun.c index 7ade191ab8..512fed6d0e 100644 --- a/racket/src/racket/src/portfun.c +++ b/racket/src/racket/src/portfun.c @@ -2556,7 +2556,7 @@ make_output_port (int argc, Scheme_Object *argv[]) static Scheme_Object * open_input_file (int argc, Scheme_Object *argv[]) { - return scheme_do_open_input_file("open-input-file", 0, argc, argv, 0, NULL, NULL, 0); + return scheme_do_open_input_file("open-input-file", 0, argc, argv, 0, 0); } static Scheme_Object * @@ -2602,13 +2602,13 @@ open_input_char_string (int argc, Scheme_Object *argv[]) static Scheme_Object * open_output_file (int argc, Scheme_Object *argv[]) { - return scheme_do_open_output_file("open-output-file", 0, argc, argv, 0, 0, NULL, NULL); + return scheme_do_open_output_file("open-output-file", 0, argc, argv, 0, 0); } static Scheme_Object * open_input_output_file (int argc, Scheme_Object *argv[]) { - return scheme_do_open_output_file("open-input-output-file", 0, argc, argv, 1, 0, NULL, NULL); + return scheme_do_open_output_file("open-input-output-file", 0, argc, argv, 1, 0); } static Scheme_Object * @@ -2745,7 +2745,7 @@ call_with_output_file (int argc, Scheme_Object *argv[]) scheme_check_proc_arity("call-with-output-file", 1, 1, argc, argv); - port = scheme_do_open_output_file("call-with-output-file", 1, argc, argv, 0, 0, NULL, NULL); + port = scheme_do_open_output_file("call-with-output-file", 1, argc, argv, 0, 0); v = _scheme_apply_multi(argv[1], 1, &port); @@ -2770,7 +2770,7 @@ call_with_input_file(int argc, Scheme_Object *argv[]) scheme_check_proc_arity("call-with-input-file", 1, 1, argc, argv); - port = scheme_do_open_input_file("call-with-input-file", 1, argc, argv, 0, NULL, NULL, 0); + port = scheme_do_open_input_file("call-with-input-file", 1, argc, argv, 0, 0); v = _scheme_apply_multi(argv[1], 1, &port); @@ -2807,7 +2807,7 @@ with_output_to_file (int argc, Scheme_Object *argv[]) scheme_check_proc_arity("with-output-to-file", 0, 1, argc, argv); - port = scheme_do_open_output_file("with-output-to-file", 1, argc, argv, 0, 0, NULL, NULL); + port = scheme_do_open_output_file("with-output-to-file", 1, argc, argv, 0, 0); config = scheme_extend_config(scheme_current_config(), MZCONFIG_OUTPUT_PORT, @@ -2841,7 +2841,7 @@ with_input_from_file(int argc, Scheme_Object *argv[]) scheme_check_proc_arity("with-input-from-file", 0, 1, argc, argv); - port = scheme_do_open_input_file("with-input-from-file", 1, argc, argv, 0, NULL, NULL, 0); + port = scheme_do_open_input_file("with-input-from-file", 1, argc, argv, 0, 0); config = scheme_extend_config(scheme_current_config(), MZCONFIG_INPUT_PORT, @@ -4899,7 +4899,7 @@ static Scheme_Object *default_load(int argc, Scheme_Object *argv[]) "(or/c #f symbol? (cons/c (or/c #f symbol?) (non-empty-listof symbol?)))", 1, argc, argv); - port = scheme_do_open_input_file("default-load-handler", 0, 1, argv, 0, NULL, NULL, SCHEME_TRUEP(expected_module)); + port = scheme_do_open_input_file("default-load-handler", 0, 1, argv, 0, SCHEME_TRUEP(expected_module)); /* Turn on line/column counting, unless it's a .zo file: */ if (SCHEME_PATHP(argv[0])) { diff --git a/racket/src/racket/src/schfd.h b/racket/src/racket/src/schfd.h deleted file mode 100644 index 080c8534ad..0000000000 --- a/racket/src/racket/src/schfd.h +++ /dev/null @@ -1,37 +0,0 @@ - -#ifdef USE_FAR_MZ_FDCALLS -THREAD_LOCAL_DECL(extern struct mz_fd_set *scheme_fd_set); -# ifdef HAVE_POLL_SYSCALL -struct mz_fd_set { - struct mz_fd_set_data *data; - struct mz_fd_set *w; - struct mz_fd_set *e; - Scheme_Object *flags; -}; -struct mz_fd_set_data { - struct pollfd *pfd; - Scheme_Object *size, *count; -}; -# else -struct mz_fd_set { fd_set data; }; -# endif -#define DECL_FDSET(n, c) fd_set *n -#define INIT_DECL_FDSET(r, w, e) { \ - r = MZ_GET_FDSET(&scheme_fd_set->data, 0 ); \ - w = MZ_GET_FDSET(&scheme_fd_set->data, 1 ); \ - e = MZ_GET_FDSET(&scheme_fd_set->data, 2 ); \ - } -# define INIT_DECL_RD_FDSET(r) r = MZ_GET_FDSET(&scheme_fd_set->data, 0 ) -# define INIT_DECL_WR_FDSET(r) r = MZ_GET_FDSET(&scheme_fd_set->data, 1 ) -# define INIT_DECL_ER_FDSET(r) r = MZ_GET_FDSET(&scheme_fd_set->data, 2 ) -#else -# define DECL_FDSET(n, c) fd_set 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 */ -#endif - -void *scheme_merge_fd_sets(void *fds, void *src_fds); -void scheme_clean_fd_set(void *fds); -int scheme_get_fd_limit(void *fds); diff --git a/racket/src/racket/src/schpriv.h b/racket/src/racket/src/schpriv.h index 2f725c2528..3719965858 100644 --- a/racket/src/racket/src/schpriv.h +++ b/racket/src/racket/src/schpriv.h @@ -436,6 +436,7 @@ void scheme_register_network_evts(); void scheme_free_dynamic_extensions(void); void scheme_free_all_code(void); void scheme_free_ghbn_data(void); +void scheme_free_global_fdset(void); XFORM_NONGCING int scheme_is_multithreaded(int now); @@ -4351,7 +4352,7 @@ void scheme_flush_if_output_fds(Scheme_Object *o); Scheme_Object *scheme_file_stream_port_p(int, Scheme_Object *[]); Scheme_Object *scheme_terminal_port_p(int, Scheme_Object *[]); Scheme_Object *scheme_do_open_input_file(char *name, int offset, int argc, Scheme_Object *argv[], - int internal, char **err, int *eerrno, int for_module); + int internal, int for_module); Scheme_Object *scheme_do_open_output_file(char *name, int offset, int argc, Scheme_Object *argv[], int and_read, int internal, char **err, int *eerrno); Scheme_Object *scheme_file_position(int argc, Scheme_Object *argv[]); @@ -4365,9 +4366,7 @@ Scheme_Object *scheme_file_unlock(int argc, Scheme_Object **argv); void scheme_reserve_file_descriptor(void); void scheme_release_file_descriptor(void); -void scheme_init_kqueue(void); -void scheme_release_kqueue(void); -void scheme_release_inotify(void); +int scheme_get_port_rktio_file_descriptor(Scheme_Object *p, struct rktio_fd_t *_fd); void scheme_fs_change_properties(int *_supported, int *_scalable, int *_low_latency, int *_file_level); @@ -4428,8 +4427,13 @@ intptr_t scheme_redirect_get_or_peek_bytes(Scheme_Input_Port *orig_port, Scheme_Object *scheme_filesystem_change_evt(Scheme_Object *path, int flags, int report_errs); void scheme_filesystem_change_evt_cancel(Scheme_Object *evt, void *ignored_data); -int scheme_fd_regular_file(intptr_t fd, int dir_ok); +void scheme_init_fd_semaphores(void); +void scheme_release_fd_semaphores(void); + void scheme_check_fd_semaphores(void); +Scheme_Object *scheme_rktio_fd_to_semaphore(struct rktio_fd_t *fd, int mode); + +rktio_envvars_t *scheme_environment_variables_to_envvars(Scheme_Object *ev); /*========================================================================*/ /* memory debugging */ @@ -4743,7 +4747,6 @@ Scheme_Object *scheme_make_place_object(); void scheme_place_instance_destroy(int force); void scheme_kill_green_thread_timer(); void scheme_place_check_for_interruption(); -void scheme_check_place_port_ok(); void scheme_place_set_memory_use(intptr_t amt); void scheme_place_check_memory_use(); void scheme_clear_place_ifs_stack(); diff --git a/racket/src/racket/src/string.c b/racket/src/racket/src/string.c index c64fab04ac..50c296a9e1 100644 --- a/racket/src/racket/src/string.c +++ b/racket/src/racket/src/string.c @@ -2485,52 +2485,27 @@ static Scheme_Object *sch_getenv_names(int argc, Scheme_Object *argv[]) return r; } -/* Temporarily use internal function: */ -extern void *rktio_envvars_to_block(rktio_t *rktio, rktio_envvars_t *envvars); - -/* This will go away when we use rktio processes: */ -void *scheme_environment_variables_to_block(Scheme_Object *ev, int *_need_free) +rktio_envvars_t *scheme_environment_variables_to_envvars(Scheme_Object *ev) { + Scheme_Hash_Tree *ht = SCHEME_ENVVARS_TABLE(ev); + rktio_envvars_t *envvars; + mzlonglong i; + + if (!ht) + return NULL; + + envvars = rktio_empty_envvars(scheme_rktio); - Scheme_Hash_Tree *ht; - Scheme_Object *key, *val; - void *p; - - *_need_free = 1; - - ht = SCHEME_ENVVARS_TABLE(ev); - if (!ht) { - rktio_envvars_t *envvars; - envvars = rktio_envvars(scheme_rktio); - - p = rktio_envvars_to_block(scheme_rktio, envvars); + for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) { + scheme_hash_tree_index(ht, i, &key, &val); - rktio_envvars_free(scheme_rktio, envvars); - - return p; - } - - { - rktio_envvars_t *envvars; - mzlonglong i; - - envvars = rktio_empty_envvars(scheme_rktio); - - for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) { - scheme_hash_tree_index(ht, i, &key, &val); - - rktio_envvars_set(scheme_rktio, - envvars, - SCHEME_BYTE_STR_VAL(key), - SCHEME_BYTE_STR_VAL(val)); - } - - p = rktio_envvars_to_block(scheme_rktio, envvars); - - rktio_envvars_free(scheme_rktio, envvars); - - return p; + rktio_envvars_set(scheme_rktio, + envvars, + SCHEME_BYTE_STR_VAL(key), + SCHEME_BYTE_STR_VAL(val)); } + + return envvars; } /***********************************************************************/ diff --git a/racket/src/racket/src/thread.c b/racket/src/racket/src/thread.c index be1fda08f0..86d96516c8 100644 --- a/racket/src/racket/src/thread.c +++ b/racket/src/racket/src/thread.c @@ -41,42 +41,10 @@ #include "schpriv.h" #include "schmach.h" #include "schgc.h" +#include "schrktio.h" #ifdef MZ_USE_FUTURES # include "future.h" #endif -#ifndef PALMOS_STUFF -# include -#endif -#ifdef FILES_HAVE_FDS -# include -# include -# ifdef SELECT_INCLUDE -# include -# endif -# ifdef USE_BEOS_SOCKET_INCLUDE -# include -# endif -# ifdef HAVE_POLL_SYSCALL -# include -# endif -# ifdef HAVE_EPOLL_SYSCALL -# include -# endif -# ifdef HAVE_KQUEUE_SYSCALL -# include -# include -# include -# endif -# include -#endif -#ifdef USE_WINSOCK_TCP -# ifdef USE_TCP -# include -# endif -#endif -#ifdef USE_BEOS_PORT_THREADS -# include -#endif #ifdef USE_STACKAVAIL # include #endif @@ -88,11 +56,6 @@ # define SIGMZTHREAD SIGUSR2 #endif -#if defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES) -# include -THREAD_LOCAL_DECL(extern void *scheme_break_semaphore;) -#endif - #if defined(FILES_HAVE_FDS) \ || defined(USE_BEOS_PORT_THREADS) \ || (defined(USE_WINSOCK_TCP) && defined(USE_TCP)) \ @@ -103,8 +66,6 @@ THREAD_LOCAL_DECL(extern void *scheme_break_semaphore;) # endif #endif -#include "schfd.h" - #define DEFAULT_INIT_STACK_SIZE 1000 #define MAX_INIT_STACK_SIZE 100000 @@ -193,7 +154,7 @@ THREAD_LOCAL_DECL(MZ_MARK_STACK_TYPE scheme_current_cont_mark_stack); THREAD_LOCAL_DECL(MZ_MARK_POS_TYPE scheme_current_cont_mark_pos); #endif -THREAD_LOCAL_DECL(int scheme_semaphore_fd_kqueue); +THREAD_LOCAL_DECL(struct rktio_ltps_t *scheme_semaphore_fd_set); THREAD_LOCAL_DECL(static Scheme_Custodian *main_custodian); THREAD_LOCAL_DECL(static Scheme_Hash_Table *limited_custodians = NULL); @@ -3853,471 +3814,122 @@ static Scheme_Object *call_as_nested_thread(int argc, Scheme_Object *argv[]) /* thread scheduling and termination */ /*========================================================================*/ -void scheme_init_kqueue(void) +void scheme_init_fd_semaphores(void) { -#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL) - scheme_semaphore_fd_kqueue = -1; -#endif + scheme_semaphore_fd_set = rktio_open_ltps(scheme_rktio); } -void scheme_release_kqueue(void) +void scheme_release_fd_semaphores(void) { -#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL) - if (scheme_semaphore_fd_kqueue >= 0) { - intptr_t rc; - do { - rc = close(scheme_semaphore_fd_kqueue); - } while ((rc == -1) && (errno == EINTR)); + if (scheme_semaphore_fd_set) { + rktio_ltps_remove_all(scheme_rktio, scheme_semaphore_fd_set); + (void)check_fd_semaphores(); + rktio_ltps_close(scheme_semaphore_fd_set); } -#endif } -#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL) -static void log_kqueue_error(const char *action, int kr) +static void log_fd_semaphore_error() { - if (kr < 0) { + { Scheme_Logger *logger; logger = scheme_get_main_logger(); scheme_log(logger, SCHEME_LOG_WARNING, 0, -#ifdef HAVE_KQUEUE_SYSCALL - "kqueue" -#else - "epoll" -#endif - " error at %s: %E", - action, errno); + "error for long-term poll set: %R"); } } - -static void log_kqueue_fd(int fd, int flags) -{ - Scheme_Logger *logger; - logger = scheme_get_main_logger(); - scheme_log(logger, SCHEME_LOG_WARNING, 0, -#ifdef HAVE_KQUEUE_SYSCALL - "kqueue" -#else - "epoll" -#endif - " expected event %d %d", - fd, flags); -} #endif Scheme_Object *scheme_fd_to_semaphore(intptr_t fd, int mode, int is_socket) { -#ifdef USE_WINSOCK_TCP - return NULL; -#else - Scheme_Object *key, *v, *s = NULL; -#if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL) -# else - void *r, *w, *e; -# endif + rktio_fd_t *rfd; + + if (!scheme_semaphore_fd_mapping) + return NULL; + + rfd = rktio_system_fd(fd, (RKTIO_OPEN_READ + | RKTIO_OPEN_WRITE + | (is_socket ? RKTIO_OPEN_SOCKET : 0))); + + sema = scheme_rktio_fd_to_semaphore(rfd, mode); + + rktio_forget(rfd); + + return sema; +} + +Scheme_Object *scheme_rktio_fd_to_semaphore(rktio_fd_t *fd, int mode) +{ + rktio_handle_t *h; + void **ib; if (!scheme_semaphore_fd_mapping) return NULL; -# ifdef HAVE_KQUEUE_SYSCALL - if (!is_socket) { - /* kqueue() might not work on devices, such as ttys; also, while - Mac OS X kqueue() claims to work on FIFOs, there are problems: - watching for reads on a FIFO sometimes disables watching for - writes on the same FIFO with a different file descriptor */ - if (!scheme_fd_regular_file(fd, 1)) - return NULL; + switch(mode) { + case MZFD_CREATE_READ: + mode = RKTIO_LTPS_CREATE_READ; + break; + case MZFD_CREATE_WRITE: + mode = RKTIO_LTPS_CREATE_WRITE; + break; + case MZFD_CHECK_READ: + mode = RKTIO_LTPS_CHECK_READ; + break; + case MZFD_CHECK_WRITE: + mode = RKTIO_LTPS_CHECK_WRITE; + break; + case MZFD_REMOVE: + mode = RKTIO_LTPS_REMOVE; + break; } - if (scheme_semaphore_fd_kqueue < 0) { - scheme_semaphore_fd_kqueue = kqueue(); - if (scheme_semaphore_fd_kqueue < 0) { - log_kqueue_error("create", scheme_semaphore_fd_kqueue); + + h = rktio_ltps_add(scheme_rktio, scheme_semaphore_fd_mapping, fd, mode); + + if (!h) { + if (scheme_last_error_is_racket(RKTIO_ERROR_LTPS_REMOVED) + || scheme_last_error_is_racket(RKTIO_ERROR_LTPS_NOT_FOUND)) { + /* That's a kind of success, not failure. */ return NULL; } - } -# endif -# ifdef HAVE_EPOLL_SYSCALL - if (scheme_semaphore_fd_kqueue < 0) { - scheme_semaphore_fd_kqueue = epoll_create(5); - if (scheme_semaphore_fd_kqueue < 0) { - log_kqueue_error("create", scheme_semaphore_fd_kqueue); - return NULL; - } - } -# endif - - key = scheme_make_integer_value(fd); - v = scheme_hash_get(scheme_semaphore_fd_mapping, key); - if (!v && ((mode == MZFD_CHECK_READ) - || (mode == MZFD_CHECK_WRITE) - || (mode == MZFD_CHECK_VNODE) - || (mode == MZFD_REMOVE) - || (mode == MZFD_REMOVE_VNODE))) - return NULL; - - if (!v) { - v = scheme_make_vector(2, scheme_false); - scheme_hash_set(scheme_semaphore_fd_mapping, key, v); + log_fd_semaphore_error(); + return NULL; } -# if !defined(HAVE_KQUEUE_SYSCALL) && !defined(HAVE_EPOLL_SYSCALL) - r = MZ_GET_FDSET(scheme_semaphore_fd_set, 0); - w = MZ_GET_FDSET(scheme_semaphore_fd_set, 1); - e = MZ_GET_FDSET(scheme_semaphore_fd_set, 2); -# endif - - if ((mode == MZFD_REMOVE) || (mode == MZFD_REMOVE_VNODE)) { - s = SCHEME_VEC_ELS(v)[0]; - if (!SCHEME_FALSEP(s)) - scheme_post_sema_all(s); - s = SCHEME_VEC_ELS(v)[1]; - if (!SCHEME_FALSEP(s)) - scheme_post_sema_all(s); - s = NULL; - scheme_hash_set(scheme_semaphore_fd_mapping, key, NULL); -# ifdef HAVE_KQUEUE_SYSCALL - { - GC_CAN_IGNORE struct kevent kev[2]; - struct timespec timeout = {0, 0}; - int kr, pos = 0; - if (mode == MZFD_REMOVE_VNODE) { - EV_SET(&kev[pos], fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL); - pos++; - } else { - if (SCHEME_TRUEP(SCHEME_VEC_ELS(v)[0])) { - EV_SET(&kev[pos], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); - pos++; - } - if (SCHEME_TRUEP(SCHEME_VEC_ELS(v)[1])) { - EV_SET(&kev[pos], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - pos++; - } - } - do { - kr = kevent(scheme_semaphore_fd_kqueue, kev, pos, NULL, 0, &timeout); - } while ((kr == -1) && (errno == EINTR)); - log_kqueue_error("remove", kr); - } -# elif defined(HAVE_EPOLL_SYSCALL) - { - int kr; - kr = epoll_ctl(scheme_semaphore_fd_kqueue, EPOLL_CTL_DEL, fd, NULL); - log_kqueue_error("remove", kr); - } -# else - MZ_FD_CLR(fd, r); - MZ_FD_CLR(fd, w); - MZ_FD_CLR(fd, e); -# endif - s = NULL; - } else if ((mode == MZFD_CHECK_READ) - || (mode == MZFD_CREATE_READ) - || (mode == MZFD_CHECK_VNODE) - || (mode == MZFD_CREATE_VNODE)) { - s = SCHEME_VEC_ELS(v)[0]; - if (SCHEME_FALSEP(s)) { - if ((mode == MZFD_CREATE_READ) - || (mode == MZFD_CREATE_VNODE)) { - s = scheme_make_sema(0); - SCHEME_VEC_ELS(v)[0] = s; -# ifdef HAVE_KQUEUE_SYSCALL - { - GC_CAN_IGNORE struct kevent kev; - struct timespec timeout = {0, 0}; - int kr; - if (mode == MZFD_CREATE_READ) - EV_SET(&kev, fd, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, NULL); - else - EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, - (NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND - | NOTE_RENAME | NOTE_ATTRIB), - 0, NULL); - do { - kr = kevent(scheme_semaphore_fd_kqueue, &kev, 1, NULL, 0, &timeout); - } while ((kr == -1) && (errno == EINTR)); - log_kqueue_error("read", kr); - } -# elif defined(HAVE_EPOLL_SYSCALL) - { - GC_CAN_IGNORE struct epoll_event ev; - int already = !SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1]), kr; - memset(&ev, 0, sizeof(ev)); - ev.data.fd = fd; - ev.events = EPOLLIN | (already ? EPOLLOUT : 0); - kr = epoll_ctl(scheme_semaphore_fd_kqueue, - (already ? EPOLL_CTL_MOD : EPOLL_CTL_ADD), fd, &ev); - log_kqueue_error("read", kr); - } -# else - MZ_FD_SET(fd, r); - MZ_FD_SET(fd, e); -#endif - } else - s = NULL; - } - } else if ((mode == MZFD_CHECK_WRITE) - || (mode == MZFD_CREATE_WRITE)) { - s = SCHEME_VEC_ELS(v)[1]; - if (SCHEME_FALSEP(s)) { - if (mode == MZFD_CREATE_WRITE) { - s = scheme_make_sema(0); - SCHEME_VEC_ELS(v)[1] = s; -# ifdef HAVE_KQUEUE_SYSCALL - { - GC_CAN_IGNORE struct kevent kev; - struct timespec timeout = {0, 0}; - int kr; - EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL); - do { - kr = kevent(scheme_semaphore_fd_kqueue, &kev, 1, NULL, 0, &timeout); - } while ((kr == -1) && (errno == EINTR)); - log_kqueue_error("write", kr); - } - -# elif defined(HAVE_EPOLL_SYSCALL) - { - GC_CAN_IGNORE struct epoll_event ev; - int already = !SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0]), kr; - memset(&ev, 0, sizeof(ev)); - ev.data.fd = fd; - ev.events = EPOLLOUT | (already ? EPOLLIN : 0); - kr = epoll_ctl(scheme_semaphore_fd_kqueue, - (already ? EPOLL_CTL_MOD : EPOLL_CTL_ADD), fd, &ev); - log_kqueue_error("write", kr); - } -# else - MZ_FD_SET(fd, w); - MZ_FD_SET(fd, e); -#endif - } else - s = NULL; - } + ib = rktio_ltps_handle_get_data(scheme_rktio, h); + if (!ib) { + ib = scheme_malloc_immobile_box(scheme_make_sema(0)); + rktio_ltps_handle_set_data(scheme_rktio, ib); } - return s; -#endif + return *(Scheme_Object **)p; } static int check_fd_semaphores() { -#ifdef USE_WINSOCK_TCP - return 0; -#elif defined(HAVE_KQUEUE_SYSCALL) - Scheme_Object *v, *s, *key; - GC_CAN_IGNORE struct kevent kev; - struct timespec timeout = {0, 0}; - int kr, hit = 0; + rktio_ltps_handle_t *h; + int did = 0; - if (!scheme_semaphore_fd_mapping || (scheme_semaphore_fd_kqueue < 0)) + if (!scheme_semaphore_fd_set) return 0; while (1) { - do { - kr = kevent(scheme_semaphore_fd_kqueue, NULL, 0, &kev, 1, &timeout); - } while ((kr == -1) && (errno == EINTR)); - log_kqueue_error("wait", kr); - - if (kr > 0) { - key = scheme_make_integer_value(kev.ident); - v = scheme_hash_get(scheme_semaphore_fd_mapping, key); - if (v) { - if ((kev.filter == EVFILT_READ) || (kev.filter == EVFILT_VNODE)) { - s = SCHEME_VEC_ELS(v)[0]; - if (!SCHEME_FALSEP(s)) { - scheme_post_sema_all(s); - hit = 1; - SCHEME_VEC_ELS(v)[0] = scheme_false; - } - } else if (kev.filter == EVFILT_WRITE) { - s = SCHEME_VEC_ELS(v)[1]; - if (!SCHEME_FALSEP(s)) { - scheme_post_sema_all(s); - hit = 1; - SCHEME_VEC_ELS(v)[1] = scheme_false; - } - } - if (SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0]) - && SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1])) - scheme_hash_set(scheme_semaphore_fd_mapping, key, NULL); - } else { - log_kqueue_fd(kev.ident, kev.filter); - } + h = rktio_ltps_get_signaled_handle(scheme_rktio, scheme_semaphore_fd_set); + if (h) { + void *p; + p = rktio_ltps_handle_get_data(scheme_rktio, h); + free(h); + + sema = *(Scheme_Object **)p; + scheme_free_immobile_box(p); + + scheme_post_sema_all(sema); + + did = 1; } else break; } - return hit; -#elif defined(HAVE_EPOLL_SYSCALL) - Scheme_Object *v, *s, *key; - int kr, hit = 0; - GC_CAN_IGNORE struct epoll_event ev; - memset(&ev, 0, sizeof(ev)); - - if (!scheme_semaphore_fd_mapping || (scheme_semaphore_fd_kqueue < 0)) - return 0; - - while (1) { - - do { - kr = epoll_wait(scheme_semaphore_fd_kqueue, &ev, 1, 0); - } while ((kr == -1) && (errno == EINTR)); - log_kqueue_error("wait", kr); - - if (kr > 0) { - key = scheme_make_integer_value(ev.data.fd); - v = scheme_hash_get(scheme_semaphore_fd_mapping, key); - if (v) { - if (ev.events & (POLLIN | POLLHUP | POLLERR)) { - s = SCHEME_VEC_ELS(v)[0]; - if (!SCHEME_FALSEP(s)) { - scheme_post_sema_all(s); - hit = 1; - SCHEME_VEC_ELS(v)[0] = scheme_false; - } - } - if (ev.events & (POLLOUT | POLLHUP | POLLERR)) { - s = SCHEME_VEC_ELS(v)[1]; - if (!SCHEME_FALSEP(s)) { - scheme_post_sema_all(s); - hit = 1; - SCHEME_VEC_ELS(v)[1] = scheme_false; - } - } - if (SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0]) - && SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1])) { - scheme_hash_set(scheme_semaphore_fd_mapping, key, NULL); - kr = epoll_ctl(scheme_semaphore_fd_kqueue, EPOLL_CTL_DEL, ev.data.fd, NULL); - log_kqueue_error("remove*", kr); - } else { - ev.events = ((SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0]) ? 0 : POLLIN) - | (SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1]) ? 0 : POLLOUT)); - kr = epoll_ctl(scheme_semaphore_fd_kqueue, EPOLL_CTL_MOD, ev.data.fd, &ev); - log_kqueue_error("update", kr); - } - } else { - log_kqueue_fd(ev.data.fd, ev.events); - } - } else - break; - } - - return hit; -#elif defined(HAVE_POLL_SYSCALL) - struct pollfd *pfd; - intptr_t i, c; - Scheme_Object *v, *s, *key; - int sr, hit = 0; - - if (!scheme_semaphore_fd_mapping || !scheme_semaphore_fd_mapping->count) - return 0; - - scheme_clean_fd_set(scheme_semaphore_fd_set); - c = SCHEME_INT_VAL(scheme_semaphore_fd_set->data->count); - pfd = scheme_semaphore_fd_set->data->pfd; - - do { - sr = poll(pfd, c, 0); - } while ((sr == -1) && (errno == EINTR)); - - if (sr > 0) { - for (i = 0; i < c; i++) { - if (pfd[i].revents) { - key = scheme_make_integer_value(pfd[i].fd); - v = scheme_hash_get(scheme_semaphore_fd_mapping, key); - if (v) { - if (pfd[i].revents & (POLLIN | POLLHUP | POLLERR)) { - s = SCHEME_VEC_ELS(v)[0]; - if (!SCHEME_FALSEP(s)) { - scheme_post_sema_all(s); - hit = 1; - SCHEME_VEC_ELS(v)[0] = scheme_false; - } - pfd[i].events -= (pfd[i].events & POLLIN); - } - if (pfd[i].revents & (POLLOUT | POLLHUP | POLLERR)) { - s = SCHEME_VEC_ELS(v)[1]; - if (!SCHEME_FALSEP(s)) { - scheme_post_sema_all(s); - hit = 1; - SCHEME_VEC_ELS(v)[1] = scheme_false; - } - pfd[i].events -= (pfd[i].events & POLLOUT); - } - if (SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0]) - && SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1])) - scheme_hash_set(scheme_semaphore_fd_mapping, key, NULL); - } - } - } - } - - return hit; -#else - void *fds; - struct timeval time = {0, 0}; - int i, actual_limit, r, w, e, sr, hit = 0; - Scheme_Object *key, *v, *s; - DECL_FDSET(set, 3); - fd_set *set1, *set2; - - if (!scheme_semaphore_fd_mapping || !scheme_semaphore_fd_mapping->count) - return 0; - - INIT_DECL_FDSET(set, set1, set2); - set1 = (fd_set *) MZ_GET_FDSET(set, 1); - set2 = (fd_set *) MZ_GET_FDSET(set, 2); - - fds = (void *)set; - MZ_FD_ZERO(set); - MZ_FD_ZERO(set1); - MZ_FD_ZERO(set2); - - scheme_merge_fd_sets(fds, scheme_semaphore_fd_set); - - actual_limit = scheme_get_fd_limit(fds); - - do { - sr = select(actual_limit, set, set1, set2, &time); - } while ((sr == -1) && (errno == EINTR)); - - if (sr > 0) { - for (i = 0; i < actual_limit; i++) { - r = MZ_FD_ISSET(i, set); - w = MZ_FD_ISSET(i, set1); - e = MZ_FD_ISSET(i, set2); - if (r || w || e) { - key = scheme_make_integer_value(i); - v = scheme_hash_get(scheme_semaphore_fd_mapping, key); - if (v) { - if (r || e) { - s = SCHEME_VEC_ELS(v)[0]; - if (!SCHEME_FALSEP(s)) { - scheme_post_sema_all(s); - hit = 1; - SCHEME_VEC_ELS(v)[0] = scheme_false; - } - MZ_FD_CLR(i, MZ_GET_FDSET(scheme_semaphore_fd_set, 0)); - } - if (w || e) { - s = SCHEME_VEC_ELS(v)[1]; - if (!SCHEME_FALSEP(s)) { - scheme_post_sema_all(s); - hit = 1; - SCHEME_VEC_ELS(v)[1] = scheme_false; - } - MZ_FD_CLR(i, MZ_GET_FDSET(scheme_semaphore_fd_set, 1)); - } - if (SCHEME_FALSEP(SCHEME_VEC_ELS(v)[0]) - && SCHEME_FALSEP(SCHEME_VEC_ELS(v)[1])) { - MZ_FD_CLR(i, MZ_GET_FDSET(scheme_semaphore_fd_set, 2)); - scheme_hash_set(scheme_semaphore_fd_mapping, key, NULL); - } - } - } - } - } - - return hit; -#endif + return did; } void scheme_check_fd_semaphores(void) @@ -4434,19 +4046,8 @@ static int check_sleep(int need_activity, int sleep_now) scheme_active_but_sleeping = 1; if (have_activity && scheme_notify_multithread) scheme_notify_multithread(0); - -#if defined(USING_FDS) - INIT_DECL_FDSET(set, set1, set2); - set1 = (fd_set *) MZ_GET_FDSET(set, 1); - set2 = (fd_set *) MZ_GET_FDSET(set, 2); - fds = (void *)set; - MZ_FD_ZERO(set); - MZ_FD_ZERO(set1); - MZ_FD_ZERO(set2); -#else - fds = NULL; -#endif + fds = rktio_make_poll_set(scheme_rktio); needs_sleep_cancelled = 0; @@ -4497,23 +4098,15 @@ static int check_sleep(int need_activity, int sleep_now) p = p->next; } - if (needs_sleep_cancelled) + if (needs_sleep_cancelled) { + rktio_poll_set_close(scheme_rktio, fds); return 0; + } if (post_system_idle()) { + rktio_poll_set_close(scheme_rktio, fds); return 0; } - -# if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL) - if (scheme_semaphore_fd_mapping && (scheme_semaphore_fd_kqueue >= 0)) { - MZ_FD_SET(scheme_semaphore_fd_kqueue, set); - MZ_FD_SET(scheme_semaphore_fd_kqueue, set2); - } -# else - fds = scheme_merge_fd_sets(fds, scheme_semaphore_fd_set); -# endif - - scheme_clean_fd_set(fds); if (sleep_now) { float mst = (float)max_sleep_time; @@ -4535,6 +4128,8 @@ static int check_sleep(int need_activity, int sleep_now) } else if (scheme_wakeup_on_input) scheme_wakeup_on_input(fds); + rktio_poll_set_forget(scheme_rktio, fds); + return 1; } @@ -4897,10 +4492,6 @@ void scheme_break_kind_thread(Scheme_Thread *p, int kind) } } scheme_weak_resume_thread(p); -# if defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES) - if (SAME_OBJ(p, scheme_main_thread)) - ReleaseSemaphore((HANDLE)scheme_break_semaphore, 1, NULL); -# endif } void scheme_break_thread(Scheme_Thread *p) diff --git a/racket/src/rktio/demo.c b/racket/src/rktio/demo.c index e8c4aca5a7..8fab570845 100644 --- a/racket/src/rktio/demo.c +++ b/racket/src/rktio/demo.c @@ -189,7 +189,7 @@ static void wait_read(rktio_t *rktio, rktio_fd_t *fd) check_valid(ps); rktio_poll_add(rktio, fd, ps, RKTIO_POLL_READ); rktio_sleep(rktio, 0, ps, NULL); - rktio_poll_set_close(rktio, ps); + rktio_poll_set_forget(rktio, ps); } static void check_read_write_pair(rktio_t *rktio, rktio_fd_t *fd, rktio_fd_t *fd2, int immediate_available) @@ -337,7 +337,7 @@ void check_many_lookup(rktio_t *rktio) } rktio_sleep(rktio, 0, ps, NULL); - rktio_poll_set_close(rktio, ps); + rktio_poll_set_forget(rktio, ps); for (i = 0; i < LOOKUPS_N; i++) { if (lookup[i] && (rktio_poll_addrinfo_lookup_ready(rktio, lookup[i]) == RKTIO_POLL_READY)) { @@ -346,7 +346,7 @@ void check_many_lookup(rktio_t *rktio) else { addr = rktio_addrinfo_lookup_get(rktio, lookup[i]); check_valid(addr); - rktio_free_addrinfo(rktio, addr); + rktio_addrinfo_free(rktio, addr); } lookup[i] = NULL; break; @@ -371,7 +371,7 @@ rktio_addrinfo_t *lookup_loop(rktio_t *rktio, rktio_poll_add_addrinfo_lookup(rktio, lookup, ps); rktio_sleep(rktio, 0, ps, NULL); - rktio_poll_set_close(rktio, ps); + rktio_poll_set_forget(rktio, ps); check_valid(rktio_poll_addrinfo_lookup_ready(rktio, lookup) == RKTIO_POLL_READY); addr = rktio_addrinfo_lookup_get(rktio, lookup); @@ -396,7 +396,7 @@ static void pause_for_process(rktio_t *rktio, rktio_process_t *process, int dont } else { rktio_sleep(rktio, 0, ps, NULL); } - rktio_poll_set_close(rktio, ps); + rktio_poll_set_forget(rktio, ps); done = rktio_poll_process_done(rktio, process); check_valid(done != RKTIO_PROCESS_ERROR); } while (!done); @@ -417,7 +417,7 @@ static rktio_fd_t *connect_loop(rktio_t *rktio, rktio_addrinfo_t *addr, rktio_ad rktio_poll_add_connect(rktio, conn, ps); rktio_sleep(rktio, 0, ps, NULL); - rktio_poll_set_close(rktio, ps); + rktio_poll_set_forget(rktio, ps); check_valid(rktio_poll_connect_ready(rktio, conn) == RKTIO_POLL_READY); fd = rktio_connect_finish(rktio, conn); @@ -452,7 +452,7 @@ static char *week_day_name(rktio_t *rktio, int dow) int main(int argc, char **argv) { rktio_t *rktio; - rktio_size_t *sz; + rktio_filesize_t *sz; rktio_fd_t *fd, *fd2; intptr_t amt, i, saw_file; int perms; @@ -506,8 +506,7 @@ int main(int argc, char **argv) sz = rktio_file_size(rktio, "test1"); check_valid(sz); - check_valid(sz->lo == 5); - check_valid(sz->hi == 0); + check_valid(*sz == 5); free(sz); fd = rktio_open(rktio, "test2", RKTIO_OPEN_WRITE | RKTIO_OPEN_MUST_EXIST); @@ -655,7 +654,7 @@ int main(int argc, char **argv) lnr = rktio_listen(rktio, addr, 5, 1); check_valid(lnr); - rktio_free_addrinfo(rktio, addr); + rktio_addrinfo_free(rktio, addr); check_valid(!rktio_poll_accept_ready(rktio, lnr)); @@ -704,7 +703,7 @@ int main(int argc, char **argv) check_read_write_pair(rktio, fd, fd2, 0); fd = connect_loop(rktio, addr, NULL); - rktio_free_addrinfo(rktio, addr); + rktio_addrinfo_free(rktio, addr); fd2 = rktio_accept(rktio, lnr); @@ -734,7 +733,7 @@ int main(int argc, char **argv) addr = lookup_loop(rktio, NULL, 4536, -1, 1, 0); check_valid(addr); check_valid(rktio_udp_bind(rktio, fd, addr)); - rktio_free_addrinfo(rktio, addr); + rktio_addrinfo_free(rktio, addr); fd2 = rktio_udp_open(rktio, intf_addr); check_valid(fd2); @@ -742,7 +741,7 @@ int main(int argc, char **argv) addr = lookup_loop(rktio, "localhost", 4536, -1, 0, 0); check_valid(addr); check_valid(rktio_udp_connect(rktio, fd2, addr)); - rktio_free_addrinfo(rktio, addr); + rktio_addrinfo_free(rktio, addr); check_read_write_pair(rktio, fd, fd2, 0); @@ -755,7 +754,7 @@ int main(int argc, char **argv) addr = lookup_loop(rktio, NULL, 4536, -1, 1, 0); check_valid(addr); check_valid(rktio_udp_bind(rktio, fd, addr)); - rktio_free_addrinfo(rktio, addr); + rktio_addrinfo_free(rktio, addr); addr = lookup_loop(rktio, "localhost", 4536, -1, 0, 0); check_valid(addr); @@ -763,8 +762,8 @@ int main(int argc, char **argv) check_fill_write(rktio, fd2, addr, AMOUNT_FOR_UDP); check_drain_read(rktio, fd, AMOUNT_FOR_UDP+1); - rktio_free_addrinfo(rktio, addr); - rktio_free_addrinfo(rktio, intf_addr); + rktio_addrinfo_free(rktio, addr); + rktio_addrinfo_free(rktio, intf_addr); check_valid(rktio_close(rktio, fd)); check_valid(rktio_close(rktio, fd2)); @@ -927,7 +926,7 @@ int main(int argc, char **argv) start = rktio_get_inexact_milliseconds(); rktio_sleep(rktio, 0.1, ps, NULL); - rktio_poll_set_close(rktio, ps); + rktio_poll_set_forget(rktio, ps); check_valid(rktio_get_inexact_milliseconds() - start > 0.1); ps = rktio_make_poll_set(rktio); @@ -944,7 +943,7 @@ int main(int argc, char **argv) check_valid(rktio_poll_fs_change_ready(rktio, fc) == RKTIO_POLL_READY); check_valid(rktio_close(rktio, fd2)); - rktio_poll_set_close(rktio, ps); + rktio_poll_set_forget(rktio, ps); rktio_fs_change_forget(rktio, fc); } diff --git a/racket/src/rktio/rktio.h b/racket/src/rktio/rktio.h index 24f565bb04..6095f78f05 100644 --- a/racket/src/rktio/rktio.h +++ b/racket/src/rktio/rktio.h @@ -7,87 +7,184 @@ # define RKTIO_EXTERN extern #endif +typedef struct rktio_t rktio_t; /* A rktio_t value represents an instance of the Racket I/O system. Almost every rktio_...() function takes it as the first argument. */ -typedef struct rktio_t rktio_t; +RKTIO_EXTERN rktio_t *rktio_init(void); /* Call rktio_init() before anything else. The first call to rktio_init() must return before any additional calls (in other threads), but there's no ordering requirement after that. */ -RKTIO_EXTERN rktio_t *rktio_init(void); +RKTIO_EXTERN void rktio_destroy(rktio_t *); /* Call rktio_destroy() as the last thing. Everything else must be explicitly deallocated/closed/forgotten before calling rktio_destroy(). */ -RKTIO_EXTERN void rktio_destroy(rktio_t *); +RKTIO_EXTERN void rktio_free(void *p); /* Normally equivalent to free(), but ensures the same malloc()/free() that rktio function use: */ -RKTIO_EXTERN void rktio_free(void *p); typedef int rktio_ok_t; +/* A result of this type is 0 for failure (in which case an error is + available from `rktio_get_last_error`) and 1 for success. */ + typedef int rktio_tri_t; +/* A result of this type is a boolean, but a `...ERROR` value means + that an error value is available from `rktio_get_last_error`. */ + +typedef int rktio_bool_t; +/* 0 or 1. */ /*************************************************/ /* Reading and writing files */ typedef struct rktio_fd_t rktio_fd_t; +/* Mode flags shared in part by `rktio_open` and `rktio_system_fd`. */ + +/* Accepted by both, but `RKTIO_OPEN_READ` and `RKTIO_OPEN_WRITE` are + merely advisory for `rktio_system_fd` */ #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) -#define RKTIO_OPEN_SOCKET (1<<7) -#define RKTIO_OPEN_UDP (1<<8) +#define RKTIO_OPEN_TEXT (1<<2) + +/* Used for `rktio_open` with `RKTIO_OPEN_WRITE`: */ +#define RKTIO_OPEN_TRUNCATE (1<<3) +#define RKTIO_OPEN_APPEND (1<<4) +#define RKTIO_OPEN_REPLACE (1<<5) +#define RKTIO_OPEN_MUST_EXIST (1<<6) +#define RKTIO_OPEN_CAN_EXIST (1<<7) + +/* Used for `rktio_system_fd`: */ +#define RKTIO_OPEN_SOCKET (1<<8) +#define RKTIO_OPEN_UDP (1<<9) #define RKTIO_OPEN_REGFILE (1<<10) #define RKTIO_OPEN_NOT_REGFILE (1<<11) - /* If neither RKTIO_OPEN_REGILE nor RKTIO_OPEN_NOT_REGILE - are specified, then the value is inferred */ + are specified, then the value is inferred by `rtkio_system_fd`. */ +#define RKTIO_OPEN_INIT (1 << 12) +/* Make `rtkio_system_fd` set a socket as nonblocking, etc. */ +#define RKTIO_OPEN_OWN (1 << 13) +/* Make `rtkio_system_fd` record a socket for reliable clean up on pre-NT Windows. */ -/* A socket registered this way should be non-blocking: */ RKTIO_EXTERN rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes); -RKTIO_EXTERN intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd); +/* A socket (as opposed to other file descriptors) registered this way + should include include `RKTIO_OPEN_SOCKET` and be non-blocking or + use `RKTIO_OPEN_INIT`. */ -RKTIO_EXTERN int rktio_fd_is_regular_file(rktio_t *rktio, rktio_fd_t *rfd); -RKTIO_EXTERN int rktio_fd_is_socket(rktio_t *rktio, rktio_fd_t *rfd); -RKTIO_EXTERN int rktio_fd_is_udp(rktio_t *rktio, rktio_fd_t *rfd); -RKTIO_EXTERN int rktio_fd_is_terminal(rktio_t *rktio, rktio_fd_t *rfd); +RKTIO_EXTERN intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd); +/* Extracts a native file descriptor or socket. */ + +RKTIO_EXTERN rktio_bool_t rktio_fd_is_regular_file(rktio_t *rktio, rktio_fd_t *rfd); +RKTIO_EXTERN rktio_bool_t rktio_fd_is_socket(rktio_t *rktio, rktio_fd_t *rfd); +RKTIO_EXTERN rktio_bool_t rktio_fd_is_udp(rktio_t *rktio, rktio_fd_t *rfd); +RKTIO_EXTERN rktio_bool_t rktio_fd_is_terminal(rktio_t *rktio, rktio_fd_t *rfd); +RKTIO_EXTERN rktio_bool_t rktio_fd_is_text_converted(rktio_t *rktio, rktio_fd_t *rfd); +/* The functions mostly report values of recorded mode flags. */ RKTIO_EXTERN int rktio_fd_modes(rktio_t *rktio, rktio_fd_t *rfd); +/* Returns all of the recorded mode flags. */ RKTIO_EXTERN rktio_fd_t *rktio_open(rktio_t *rktio, char *src, int modes); +/* Can report `RKTIO_ERROR_DOES_NOT_EXIST` in place of system error, + and can report `RKTIO_ERROR_UNSUPPORTED_TEXT_MODE` on Windows:=. */ + RKTIO_EXTERN rktio_ok_t rktio_close(rktio_t *rktio, rktio_fd_t *fd); +/* Can report `RKTIO_ERROR_EXISTS` in place of system error, + and can report `RKTIO_ERROR_UNSUPPORTED_TEXT_MODE` on Windows. + See also `rktio_write` and `rktio_poll_write_flushed. */ RKTIO_EXTERN rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd); +/* Copies a file descriptor, where each must be closed or forgotten + independenty. */ + RKTIO_EXTERN void rktio_forget(rktio_t *rktio, rktio_fd_t *fd); +/* Deallocates a `rktio_fd_t` without closing the file descriptor, + but the descriptor is no longer recorded if it was opened with + `RKTIO_OPEN_OWN`. */ + +RKTIO_EXTERN rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which); +/* Gets stdin/stdout/stderr. + `which` values: */ +#define RKTIO_STDIN 0 +#define RKTIO_STDOUT 1 +#define RKTIO_STDERR 2 + +RKTIO_EXTERN intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len); +/* Returns the number of bytes read, possibly 0, in non-blocking mode. + Alternatively, the result can be `RKTIO_READ_EOF` for end-of-file + or `RKTIO_READ_ERROR` for an error. Although rktio_read is intended + to have no buffering, text-mode conversion (on Windows) and certain + uncooperative OS corners can buffer 1 byte. */ #define RKTIO_READ_EOF (-1) #define RKTIO_READ_ERROR (-2) + +RKTIO_EXTERN intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len); +/* Returns the number of bytes written, possibly 0, in non-blocking + mode. Alternatively, the result can be `RKTIO_WRITE_ERROR` for an + error. Although rktio_write() is intended to write only bytes that + can be fully delivered to the OS, there may be OS limitations that + require buffering (e.g., on Windows). Use + rktio_poll_write_flushed() to make sure it's completely flushed + before closing. */ + #define RKTIO_WRITE_ERROR (-2) -/* The read and write functions return the number of bytes read/write - in non-blocking mode, possibly 0. A read can produce `RKTIO_READ_EOF` - for end-of-file or `RKTIO_READ_ERROR` for an error. Similarly, write - can produce `RKTIO_WRITE_ERROR`. */ -RKTIO_EXTERN intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len); -RKTIO_EXTERN intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len); +RKTIO_EXTERN intptr_t rktio_read_converted(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len, + char *is_converted); +/* Like rktio_read(), but also reports whether each character was + original two characters that were converted to a single newline for + text mode. */ -#define RKTIO_POLL_ERROR (-2) -#define RKTIO_POLL_READY 1 +RKTIO_EXTERN intptr_t rktio_buffered_byte_count(rktio_t *rktio, rktio_fd_t *fd); +/* Reports the number of bytes that are buffered kfrom the file descriptor. + The result is normally zero, but text-mode conversion and the rare + uncooperative corner of an OS can make the result 1 byte. */ RKTIO_EXTERN rktio_tri_t rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd); RKTIO_EXTERN rktio_tri_t rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd); -RKTIO_EXTERN rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd); +/* Each polling function returns one of the following: */ +#define RKTIO_POLL_NOT_READY 0 +#define RKTIO_POLL_READY 1 +#define RKTIO_POLL_ERROR (-2) -#define RKTIO_LOCK_ERROR (-2) -#define RKTIO_LOCK_ACQUIRED 1 +RKTIO_EXTERN rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd); +/* See `rktio_write` above. */ RKTIO_EXTERN rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl); -RKTIO_EXTERN rktio_tri_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd); +RKTIO_EXTERN rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd); +/* Advisory file locks, where `excl` attempts to claim an exclusive + lock. Whether these work in various situations depend on many OS + details, where the differences involve promoting from non-exlcusive + to exclusive, taking a lock that is already held, getting an + exclusive lock for a file descriptor in read mode, getting a + non-exclusive lock in write mode, and whether a lock prevents + opening or using another file descriptor. */ + +#define RKTIO_LOCK_ERROR (-2) +#define RKTIO_LOCK_ACQUIRED 1 +#define RKTIO_LOCK_NOT_ACQUIRED 0 + +typedef rktio_int64_t rktio_filesize_t; + +rktio_ok_t rktio_set_file_position(rktio_t *rktio, rktio_fd_t *rfd, rktio_filesize_t pos, int whence); +/* Can report `RKTIO_ERROR_CANNOT_SET_FILE_POSITION` on Windows. */ +/* For `whence`: */ +enum { + RKTIO_POSITION_FROM_START, + RKTIO_POSITION_FROM_END +}; + +rktio_filesize_t *rktio_get_file_position(rktio_t *rktio, rktio_fd_t *rfd); +/* Returns the file position, not taking into account rare input + buffering (see `rktio_read`). On Windows, can report + `RKTIO_ERROR_CANNOT_SET_FILE_POSITION`, which doesn't have a + corresponding Windows error code. */ + +rktio_ok_t rktio_set_file_size(rktio_t *rktio, rktio_fd_t *rfd, rktio_filesize_t sz); +/* Can report `RKTIO_ERROR_CANNOT_SET_FILE_POSITION` on Windows. */ /*************************************************/ /* Network */ @@ -95,37 +192,64 @@ RKTIO_EXTERN rktio_tri_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd); typedef struct rktio_addrinfo_lookup_t rktio_addrinfo_lookup_t; typedef struct rktio_addrinfo_t rktio_addrinfo_t; -RKTIO_EXTERN int rktio_get_ipv4_family(rktio_t *rktio); - RKTIO_EXTERN rktio_addrinfo_lookup_t *rktio_start_addrinfo_lookup(rktio_t *rktio, const char *hostname, int portno, - int family, int passive, int tcp); -RKTIO_EXTERN int rktio_poll_addrinfo_lookup_ready(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup); -RKTIO_EXTERN rktio_addrinfo_t *rktio_addrinfo_lookup_get(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup); -RKTIO_EXTERN void rktio_addrinfo_lookup_stop(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup); + int family, rktio_bool_t passive, rktio_bool_t tcp); +/* The `family` argument should be one of the following: */ +#define RKTIO_FAMILY_ANY (-1) +RKTIO_EXTERN int rktio_get_ipv4_family(rktio_t *rktio); -RKTIO_EXTERN void rktio_free_addrinfo(rktio_t *rktio, struct rktio_addrinfo_t *a); +RKTIO_EXTERN rktio_tri_t rktio_poll_addrinfo_lookup_ready(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup); +/* Check whether an address is available for a lookup request. */ + +RKTIO_EXTERN rktio_addrinfo_t *rktio_addrinfo_lookup_get(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup); +/* Deallocates `lookup`. */ + +RKTIO_EXTERN void rktio_addrinfo_lookup_stop(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup); +/* Abandons a lookup whose result (or error) is not yet received. */ + +RKTIO_EXTERN void rktio_addrinfo_free(rktio_t *rktio, struct rktio_addrinfo_t *a); +/* Frees the result of a lookup. */ typedef struct rktio_listener_t rktio_listener_t; typedef struct rktio_connect_t rktio_connect_t; -#define RKTIO_SHUTDOWN_READ RKTIO_OPEN_READ -#define RKTIO_SHUTDOWN_WRITE RKTIO_OPEN_WRITE +RKTIO_EXTERN rktio_listener_t *rktio_listen(rktio_t *rktio, rktio_addrinfo_t *local, int backlog, rktio_bool_t reuse); +/* Can fail with `RKTIO_ERROR_TRY_AGAIN_WITH_IPV4`, which suggests + trying an address using the family reported by + `rktio_get_ipv4_family` instead of `RKTIO_FAMILY_ANY`. */ -RKTIO_EXTERN rktio_listener_t *rktio_listen(rktio_t *rktio, rktio_addrinfo_t *local, int backlog, int reuse); RKTIO_EXTERN void rktio_listen_stop(rktio_t *rktio, rktio_listener_t *l); -RKTIO_EXTERN int rktio_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener); -RKTIO_EXTERN rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener); +/* Stops a listener. */ + +RKTIO_EXTERN rktio_tri_t rktio_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener); +/* Returns one of `RKTIO_POLL_READY`, etc. */ + +RKTIO_EXTERN rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener); +/* Accepts one connection on a listener. */ -/* Addreses must not be freed until the connection is complete or stopped: */ RKTIO_EXTERN rktio_connect_t *rktio_start_connect(rktio_t *rktio, rktio_addrinfo_t *remote, rktio_addrinfo_t *local); -/* A `RKTIO_ERROR_CONNECT_TRYING_NEXT` error effectively means "try again", - and the connection object is still valid: */ +/* Starts a connection request. Addreses must not be freed until the + connection is complete, errored, or stopped. */ + RKTIO_EXTERN rktio_fd_t *rktio_connect_finish(rktio_t *rktio, rktio_connect_t *conn); +/* A `RKTIO_ERROR_CONNECT_TRYING_NEXT` error effectively means "try + again", and the connection object is still valid. On any other + error, or if the connection completes successfully, `conn` is + deallocated */ + RKTIO_EXTERN void rktio_connect_stop(rktio_t *rktio, rktio_connect_t *conn); -RKTIO_EXTERN int rktio_poll_connect_ready(rktio_t *rktio, rktio_connect_t *conn); +/* Stops a connection whose result or error has not been received. */ + +RKTIO_EXTERN rktio_tri_t rktio_poll_connect_ready(rktio_t *rktio, rktio_connect_t *conn); +/* Returns one of `RKTIO_POLL_READY`, etc. */ RKTIO_EXTERN int rktio_socket_shutdown(rktio_t *rktio, rktio_fd_t *rfd, int mode); +/* Useful for TCP to report an EOF to the other end. Does not close the socket, + but may make it ineligible for forther use. + `mode` values: */ +#define RKTIO_SHUTDOWN_READ 0 +#define RKTIO_SHUTDOWN_WRITE 1 RKTIO_EXTERN rktio_fd_t *rktio_udp_open(rktio_t *rktio, rktio_addrinfo_t *addr); RKTIO_EXTERN int rktio_udp_disconnect(rktio_t *rktio, rktio_fd_t *rfd); @@ -142,80 +266,81 @@ typedef struct rktio_length_and_addrinfo_t { RKTIO_EXTERN rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len); -#define RKTIO_PROP_ERROR (-2) - -/* The following accessors return RKTIO_PROP_ERROR on failure */ +/* The following accessors return `RKTIO_PROP_ERROR` on failure */ RKTIO_EXTERN int rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd); RKTIO_EXTERN int rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, int on); RKTIO_EXTERN int rktio_udp_get_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd); RKTIO_EXTERN int rktio_udp_set_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd, int ttl_val); +#define RKTIO_PROP_ERROR (-2) + RKTIO_EXTERN char **rktio_socket_address(rktio_t *rktio, rktio_fd_t *rfd); RKTIO_EXTERN char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd); +RKTIO_EXTERN char **rktio_listener_address(rktio_t *rktio, rktio_listener_t *lnr); +/* These return two strings in an array (where the array itself should + be deallocated), address and service. */ RKTIO_EXTERN char *rktio_udp_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd); RKTIO_EXTERN int rktio_udp_set_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr); -enum { - RKTIO_ADD_MEMBERSHIP, - RKTIO_DROP_MEMBERSHIP -}; - RKTIO_EXTERN int rktio_udp_change_multicast_group(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *group_addr, rktio_addrinfo_t *intf_addr, int action); +/* `action` values: */ +enum { + RKTIO_ADD_MEMBERSHIP, + RKTIO_DROP_MEMBERSHIP +}; /*************************************************/ /* Environment variables */ -/* Check whether a string is valid as a new (e.g., no "=") */ -RKTIO_EXTERN int rktio_is_ok_envvar_name(rktio_t *rktio, const char *name); +RKTIO_EXTERN rktio_bool_t rktio_is_ok_envvar_name(rktio_t *rktio, const char *name); +/* Checks whether a string is valid as a new (e.g., no "="). */ +RKTIO_EXTERN rktio_bool_t rktio_are_envvar_names_case_insensitive(rktio_t *rktio); /* Checks whether environment variables are case-folded by the OS. That doesn't mean that clients need to case-fold names, but clients may want to immitate the OS. */ -RKTIO_EXTERN int rktio_are_envvar_names_case_insensitive(rktio_t *rktio); +RKTIO_EXTERN char *rktio_getenv(rktio_t *rktio, const char *name); /* Gets an environment variable value, or reports `RKTIO_ERROR_NO_SUCH_ENVVAR` when returning NULL; the result must be freed. */ -RKTIO_EXTERN char *rktio_getenv(rktio_t *rktio, const char *name); +RKTIO_EXTERN rktio_ok_t rktio_setenv(rktio_t *rktio, const char *name, const char *val); /* Set an environment variable's value, where a NULL value for `val` unsets it. */ -RKTIO_EXTERN rktio_ok_t rktio_setenv(rktio_t *rktio, const char *name, const char *val); typedef struct rktio_envvars_t rktio_envvars_t; -/* Extracts all environment variables into a record */ RKTIO_EXTERN rktio_envvars_t *rktio_envvars(rktio_t *rktio); -/* Create an empty environment-variables record: */ -RKTIO_EXTERN rktio_envvars_t *rktio_empty_envvars(rktio_t *rktio); -/* Clones an environment-variable record: */ -RKTIO_EXTERN rktio_envvars_t *rktio_envvars_copy(rktio_t *rktio, rktio_envvars_t *envvars); -/* Deallocates an environment-variables record: */ -RKTIO_EXTERN void rktio_envvars_free(rktio_t *rktio, rktio_envvars_t *envvars); +/* Extracts all environment variables into a record */ + +RKTIO_EXTERN rktio_envvars_t *rktio_empty_envvars(rktio_t *rktio); +/* Create an empty environment-variables record. */ + +RKTIO_EXTERN rktio_envvars_t *rktio_envvars_copy(rktio_t *rktio, rktio_envvars_t *envvars); +/* Clones an environment-variable record. */ + +RKTIO_EXTERN void rktio_envvars_free(rktio_t *rktio, rktio_envvars_t *envvars); +/* Deallocates an environment-variables record: */ -/* Access/update environment-variables record by name: */ RKTIO_EXTERN char *rktio_envvars_get(rktio_t *rktio, rktio_envvars_t *envvars, char *name); RKTIO_EXTERN void rktio_envvars_set(rktio_t *rktio, rktio_envvars_t *envvars, char *name, char *value); +/* Access/update environment-variables record by name. */ -/* Access/update environment-variables record by index: */ RKTIO_EXTERN intptr_t rktio_envvars_count(rktio_t *rktio, rktio_envvars_t *envvars); RKTIO_EXTERN char *rktio_envvars_name_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i); RKTIO_EXTERN char *rktio_envvars_value_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i); +/* Access/update environment-variables record by index. */ /*************************************************/ /* Processes */ typedef struct rktio_process_t rktio_process_t; -#define RKTIO_PROCESS_NEW_GROUP (1<<0) -#define RKTIO_PROCESS_STDOUT_AS_STDERR (1<<1) -#define RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE (1<<2) -#define RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION (1<<3) - typedef struct rktio_process_result_t { rktio_process_t *process; rktio_fd_t *stdin_fd, *stdout_fd, *stderr_fd; @@ -227,67 +352,101 @@ RKTIO_EXTERN rktio_process_result_t *rktio_process(rktio_t *rktio, const char *current_directory, rktio_envvars_t *envvars, int flags, void (*unix_child_process_callback)()); +/* `flags` flags: */ +#define RKTIO_PROCESS_NEW_GROUP (1<<0) +#define RKTIO_PROCESS_STDOUT_AS_STDERR (1<<1) +#define RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE (1<<2) +#define RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION (1<<3) + +RKTIO_EXTERN int rktio_process_allowed_flags(rktio_t *rktio); +/* Reports the flags that are accepted by `rktio_process` on the + current OS. */ + +RKTIO_EXTERN int rktio_process_pid(rktio_t *rktio, rktio_process_t *sp); +/* Always succeeds, whether or not the process is still running. */ + +RKTIO_EXTERN rktio_ok_t rktio_process_kill(rktio_t *rktio, rktio_process_t *sp); +RKTIO_EXTERN rktio_ok_t rktio_process_interrupt(rktio_t *rktio, rktio_process_t *sp); +/* Interrupts or kills a process; does not deallocate the process record. */ -RKTIO_EXTERN int rktio_process_kill(rktio_t *rktio, rktio_process_t *sp); -RKTIO_EXTERN int rktio_process_interrupt(rktio_t *rktio, rktio_process_t *sp); RKTIO_EXTERN void rktio_process_forget(rktio_t *rktio, rktio_process_t *sp); +/* Deallocates a process record, whether or not the process has + stopped. */ -#define RKTIO_PROCESS_ERROR (-2) -#define RKTIO_PROCESS_DONE 1 - -RKTIO_EXTERN int rktio_poll_process_done(rktio_t *rktio, rktio_process_t *sp); +RKTIO_EXTERN rktio_ok_t rktio_poll_process_done(rktio_t *rktio, rktio_process_t *sp); +/* Check whether a process has completed: */ +#define RKTIO_PROCESS_ERROR (-2) +#define RKTIO_PROCESS_DONE 1 +#define RKTIO_PROCESS_RUNNING 0 typedef struct rktio_status_t { - int running; + rktio_bool_t running; int result; } rktio_status_t; RKTIO_EXTERN rktio_status_t *rktio_process_status(rktio_t *rktio, rktio_process_t *sp); +/* The `result` value is only value if `running` is 0. */ RKTIO_EXTERN void rktio_block_child_signals(rktio_t*rktio, int block); + /*************************************************/ /* Filesystem-change events */ +RKTIO_EXTERN int rktio_fs_change_properties(rktio_t *rktio); +/* Reports properties of the filesystem-change event implementation: */ #define RKTIO_FS_CHANGE_SUPPORTED (1 << 0) #define RKTIO_FS_CHANGE_SCALABLE (1 << 1) #define RKTIO_FS_CHANGE_LOW_LATENCY (1 << 2) #define RKTIO_FS_CHANGE_FILE_LEVEL (1 << 3) -RKTIO_EXTERN int rktio_fs_change_properties(rktio_t *rktio); - typedef struct rktio_fs_change_t rktio_fs_change_t; RKTIO_EXTERN rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, char *path); + RKTIO_EXTERN void rktio_fs_change_forget(rktio_t *rktio, rktio_fs_change_t *fc); -RKTIO_EXTERN int rktio_poll_fs_change_ready(rktio_t *rktio, rktio_fs_change_t *fc); + +RKTIO_EXTERN rktio_tri_t rktio_poll_fs_change_ready(rktio_t *rktio, rktio_fs_change_t *fc); +/* Returns one of `RKTIO_POLL_READY`, etc. */ /*************************************************/ /* File-descriptor sets for polling */ /* A poll set works for a single use via rktio_sleep(), as opposed to - "long-term" poll sets that can be used multiple times. */ + "long-term" poll sets that can be used multiple times. The + `rktio_sleep` function accepts one of each and combines them. */ typedef struct rktio_poll_set_t rktio_poll_set_t; -#define RKTIO_POLL_READ RKTIO_OPEN_READ -#define RKTIO_POLL_WRITE RKTIO_OPEN_WRITE - RKTIO_EXTERN rktio_poll_set_t *rktio_make_poll_set(rktio_t *rktio); -RKTIO_EXTERN void rktio_poll_set_close(rktio_t *rktio, rktio_poll_set_t *fds); +RKTIO_EXTERN void rktio_poll_set_forget(rktio_t *rktio, rktio_poll_set_t *fds); +/* Don't reuse a poll set after calling `rktio_sleep`, but do + explicitly forget it afterward. */ RKTIO_EXTERN void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes); -RKTIO_EXTERN void rktio_poll_add_receive(rktio_t *rktio, rktio_listener_t *listener, rktio_poll_set_t *fds); +/* Registers a wait on a file descriptor in read and/or write mode or + flush mode. The flush mode corresponds to + `rktio_poll_write_flushed`. + `modes` values: */ +#define RKTIO_POLL_READ RKTIO_OPEN_READ +#define RKTIO_POLL_WRITE RKTIO_OPEN_WRITE +#define RKTIO_POLL_FLUSH (RKTIO_OPEN_WRITE << 2) + +RKTIO_EXTERN void rktio_poll_add_accept(rktio_t *rktio, rktio_listener_t *listener, rktio_poll_set_t *fds); RKTIO_EXTERN void rktio_poll_add_connect(rktio_t *rktio, rktio_connect_t *conn, rktio_poll_set_t *fds); RKTIO_EXTERN void rktio_poll_add_addrinfo_lookup(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup, rktio_poll_set_t *fds); RKTIO_EXTERN void rktio_poll_add_process(rktio_t *rktio, rktio_process_t *sp, rktio_poll_set_t *fds); RKTIO_EXTERN void rktio_poll_add_fs_change(rktio_t *rktio, rktio_fs_change_t *fc, rktio_poll_set_t *fds); +/* Registers various other waits. */ RKTIO_EXTERN void rktio_poll_set_add_nosleep(rktio_t *rktio, rktio_poll_set_t *fds); +/* Causes a sleep given `fds` to return immediately. */ #ifdef RKTIO_SYSTEM_WINDOWS RKTIO_EXTERN void rktio_poll_set_add_handle(rktio_t *rktio, intptr_t h, rktio_poll_set_t *fds, int repost); RKTIO_EXTERN void rktio_poll_set_add_eventmask(rktio_t *rktio, rktio_poll_set_t *fds, int mask); +/* When sleeping on Windows, extra handles or eventmasks can be added + to trigger a wake up */ #endif /*************************************************/ @@ -300,6 +459,23 @@ RKTIO_EXTERN void rktio_poll_set_add_eventmask(rktio_t *rktio, rktio_poll_set_t typedef struct rktio_ltps_t rktio_ltps_t; typedef struct rktio_ltps_handle_t rktio_ltps_handle_t; +RKTIO_EXTERN rktio_ltps_t *rktio_open_ltps(rktio_t *rktio); + +RKTIO_EXTERN int rktio_ltps_close(rktio_t *rktio, rktio_ltps_t *lt); +/* Closing will signal all remianing handles and free all signaled + handles, but use `rktio_ltps_remove_all` and + `rktio_ltps_get_signaled_handle` is you need to clean up any + per-handle data: */ + +RKTIO_EXTERN rktio_ltps_handle_t *rktio_ltps_add(rktio_t *rktio, rktio_ltps_t *lt, rktio_fd_t *rfd, int mode); +/* Don't free the returned handle; use it with `rktio_ltps_handle_set_data` + and `rktio_ltps_handle_get_data`, and free it only when the same handle + is returned by `rktio_ltps_get_signaled_handle`. Using the `RKTIO_LTPS_REMOVE` + mode causes a previous created handle to be signaled. A successful remove + reports `RKTIO_ERROR_LTPS_REMOVED` while returning NULL. A `...CHECK...` + or `...REMOVE...` mode that doesn't find the handle reports + `RKTIO_ERROR_LTPS_NOT_FOUND`. + `mode` values: */ enum { RKTIO_LTPS_CREATE_READ = 1, RKTIO_LTPS_CREATE_WRITE, @@ -312,17 +488,21 @@ enum { RKTIO_LTPS_REMOVE_VNODE }; -RKTIO_EXTERN rktio_ltps_t *rktio_open_ltps(rktio_t *rktio); -RKTIO_EXTERN int rktio_ltps_close(rktio_t *rktio, rktio_ltps_t *lt); +RKTIO_EXTERN void rktio_ltps_handle_set_data(rktio_t *rktio, rktio_ltps_handle_t *s, void *data); +RKTIO_EXTERN void *rktio_ltps_handle_get_data(rktio_t *rktio, rktio_ltps_handle_t *s); -RKTIO_EXTERN rktio_ltps_handle_t *rktio_ltps_add(rktio_t *rktio, rktio_ltps_t *lt, rktio_fd_t *rfd, int mode); -RKTIO_EXTERN void rktio_ltps_handle_set_data(rktio_ltps_t *lt, rktio_ltps_handle_t *s, void *data); -RKTIO_EXTERN void *rktio_ltps_handle_get_data(rktio_ltps_t *lt, rktio_ltps_handle_t *s); +void rktio_ltps_remove_all(rktio_t *rktio, rktio_ltps_t *lt); +/* Removes all additions, signaling all handles. */ + +RKTIO_EXTERN rktio_ok_t rktio_ltps_poll(rktio_t *rktio, rktio_ltps_t *lt); +/* Enqueues signaled handles for retreival via `rktio_ltps_get_signaled_handle`. */ -RKTIO_EXTERN int rktio_ltps_poll(rktio_t *rktio, rktio_ltps_t *lt); RKTIO_EXTERN rktio_ltps_handle_t *rktio_ltps_get_signaled_handle(rktio_t *rktio, rktio_ltps_t *lt); +/* Free the returned handle when you're done with it. */ RKTIO_EXTERN void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds, rktio_ltps_t *lt); +/* Waits up to `nsecs` seconds (or forever if `nsecs` is 0) or until + something registered with `fds` or `lt` is ready. */ /*************************************************/ /* Files, directories, and links */ @@ -334,34 +514,33 @@ RKTIO_EXTERN int rktio_is_regular_file(rktio_t *rktio, char *filename); RKTIO_EXTERN rktio_ok_t rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail); -/* Can report `RKTIO_ERROR_EXISTS`: */ RKTIO_EXTERN rktio_ok_t rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok); +/* Can report `RKTIO_ERROR_EXISTS`. */ RKTIO_EXTERN char *rktio_get_current_directory(rktio_t *rktio); RKTIO_EXTERN rktio_ok_t rktio_set_current_directory(rktio_t *rktio, const char *path); -/* Can report `RKTIO_ERROR_EXISTS`: */ RKTIO_EXTERN rktio_ok_t rktio_make_directory(rktio_t *rktio, char *filename); +/* Can report `RKTIO_ERROR_EXISTS`. */ +RKTIO_EXTERN rktio_ok_t rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory, + int enable_write_on_fail); /* The `current_directory` argument is used on Windows to avoid being in `filename` (instead) as a directory while trying to delete it. The `enable_write_on_fail` argument also applied to Windows. */ -RKTIO_EXTERN rktio_ok_t rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory, - int enable_write_on_fail); +RKTIO_EXTERN char *rktio_readlink(rktio_t *rktio, char *fullfilename); /* Argument should not have a trailing separator. Can report `RKTIO_ERROR_NOT_A_LINK`. */ -RKTIO_EXTERN char *rktio_readlink(rktio_t *rktio, char *fullfilename); -/* The `dest_is_directory` argument is used only - on Windows. Can report `RKTIO_ERROR_EXISTS`. */ RKTIO_EXTERN rktio_ok_t rktio_make_link(rktio_t *rktio, char *src, char *dest, int dest_is_directory); +/* The `dest_is_directory` argument is used only + on Windows. Can report `RKTIO_ERROR_EXISTS`. */ /*************************************************/ /* File attributes */ -typedef rktio_int64_t rktio_filesize_t; typedef intptr_t rktio_timestamp_t; RKTIO_EXTERN rktio_filesize_t *rktio_file_size(rktio_t *rktio, char *filename); @@ -387,43 +566,44 @@ RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, char *path, i #define RKTIO_PERMISSION_ERROR (-1) +RKTIO_EXTERN int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int all_bits); /* Result is `RKTIO_PERMISSION_ERROR` for error, otherwise a combination of bits. If not `all_bits`, then use constants above. */ -RKTIO_EXTERN int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int all_bits); +RKTIO_EXTERN rktio_ok_t rktio_set_file_or_directory_permissions(rktio_t *rktio, char *filename, int new_bits); /* The `new_bits` format corresponds to `all_bits` for getting permissions. Can report `RKTIO_ERROR_BAD_PERMISSION` for bits that make no sense. */ -RKTIO_EXTERN rktio_ok_t rktio_set_file_or_directory_permissions(rktio_t *rktio, char *filename, int new_bits); /*************************************************/ /* Directory listing */ typedef struct rktio_directory_list_t rktio_directory_list_t; +RKTIO_EXTERN rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename); /* On Windows, the given `filename` must be normalized and not have `.` or `..`: */ -RKTIO_EXTERN rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename); +RKTIO_EXTERN char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl); /* Returns an unallocated "" and deallocates `dl` when the iteration is complete. A NULL result would mean an error without deallocating `dl`, but that doesn't currently happen. */ -RKTIO_EXTERN char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl); +RKTIO_EXTERN void rktio_directory_list_stop(rktio_t *rktio, rktio_directory_list_t *dl); /* Interrupt a directory list in progress, not needed after rktio_directory_list_step() returns "": */ -RKTIO_EXTERN void rktio_directory_list_stop(rktio_t *rktio, rktio_directory_list_t *dl); +RKTIO_EXTERN char **rktio_filesystem_root_list(rktio_t *rktio); /* Returns a NULL-terminated array. Free each string. Currently never errors. */ -RKTIO_EXTERN char **rktio_filesystem_root_list(rktio_t *rktio); /*************************************************/ /* File copying */ typedef struct rktio_file_copy_t rktio_file_copy_t; -/* Can report `RKTIO_ERROR_EXISTS`: */ -RKTIO_EXTERN rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, char *dest, char *src, int exists_ok); +RKTIO_EXTERN rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, char *dest, char *src, + rktio_bool_t exists_ok); +/* Can report `RKTIO_ERROR_EXISTS`. */ RKTIO_EXTERN int rktio_copy_file_is_done(rktio_t *rktio, rktio_file_copy_t *fc); RKTIO_EXTERN rktio_ok_t rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc); @@ -432,6 +612,8 @@ RKTIO_EXTERN void rktio_copy_file_stop(rktio_t *rktio, rktio_file_copy_t *fc); /*************************************************/ /* System paths */ +RKTIO_EXTERN char *rktio_system_path(rktio_t *rktio, int which); +/* `which` values: */ enum { RKTIO_PATH_SYS_DIR, RKTIO_PATH_TEMP_DIR, @@ -445,12 +627,10 @@ enum { RKTIO_PATH_INIT_FILE }; -RKTIO_EXTERN char *rktio_system_path(rktio_t *rktio, int which); - +RKTIO_EXTERN char *rktio_expand_user_tilde(rktio_t *rktio, char *filename); /* Path must start with tilde, otherwise `RKTIO_ERROR_NO_TILDE`. Other possible errors are `RKTIO_ERROR_ILL_FORMED_USER` and `RKTIO_ERROR_UNKNOWN_USER`. */ -RKTIO_EXTERN char *rktio_expand_user_tilde(rktio_t *rktio, char *filename); /*************************************************/ /* Sleep and signals */ @@ -461,6 +641,12 @@ RKTIO_EXTERN rktio_signal_handle_t *rktio_get_signal_handle(rktio_t *rktio); RKTIO_EXTERN void rktio_signal_received_at(rktio_signal_handle_t *h); RKTIO_EXTERN void rktio_signal_received(rktio_t *rktio); +RKTIO_EXTERN void rktio_wait_until_signal_received(rktio_t *rktio); + +#ifdef RKTIO_SYSTEM_UNIX +RKTIO_EXTERN int rktio_signal_handle_to_fd(); +#endif + /*************************************************/ /* Time and date */ @@ -471,7 +657,7 @@ typedef struct rktio_date_t { int day_of_year; int is_dst; int zone_offset; - char *zone_name; /* can be NULL */ + char *zone_name; /* can be NULL; otherwise, free it */ } rktio_date_t; RKTIO_EXTERN intptr_t rktio_get_milliseconds(void); @@ -486,23 +672,30 @@ RKTIO_EXTERN rktio_date_t *rktio_seconds_to_date(rktio_t *rktio, rktio_timestamp /*************************************************/ /* Errors */ +RKTIO_EXTERN int rktio_get_last_error_kind(rktio_t *rktio); + /* Kinds of error values: */ enum { RKTIO_ERROR_KIND_POSIX, RKTIO_ERROR_KIND_WINDOWS, - RKTIO_ERROR_KIND_GAI, /* => error sub-code available */ + RKTIO_ERROR_KIND_GAI, RKTIO_ERROR_KIND_RACKET }; +RKTIO_EXTERN int rktio_get_last_error(rktio_t *rktio); + /* Error IDs of kind RKTIO_ERROR_KIND_RACKET */ enum { RKTIO_ERROR_UNSUPPORTED = 1, + RKTIO_ERROR_DOES_NOT_EXIST, 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_UNSUPPORTED_TEXT_MODE, + RKTIO_ERROR_CANNOT_FILE_POSITION, RKTIO_ERROR_NO_TILDE, RKTIO_ERROR_ILL_FORMED_USER, RKTIO_ERROR_UNKNOWN_USER, @@ -519,20 +712,11 @@ enum { RKTIO_ERROR_NO_SUCH_ENVVAR, }; -/* GAI error sub-codes */ -enum { - RKTIO_ERROR_REMOTE_HOST_NOT_FOUND, - RKTIO_ERROR_LOCAL_HOST_NOT_FOUND, -}; - -RKTIO_EXTERN int rktio_get_last_error(rktio_t *rktio); -RKTIO_EXTERN int rktio_get_last_error_kind(rktio_t *rktio); - +RKTIO_EXTERN const char *rktio_get_last_error_string(rktio_t *rktio); +RKTIO_EXTERN const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid); /* The returned strings for `rktio_...error_string()` should not be deallocated, but it only lasts reliably until the next call to either of the functions. */ -RKTIO_EXTERN const char *rktio_get_last_error_string(rktio_t *rktio); -RKTIO_EXTERN const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid); /*************************************************/ diff --git a/racket/src/rktio/rktio_envvars.c b/racket/src/rktio/rktio_envvars.c index 2ddd0cd3b8..67f98c5855 100644 --- a/racket/src/rktio/rktio_envvars.c +++ b/racket/src/rktio/rktio_envvars.c @@ -19,6 +19,12 @@ extern char **environ; # define GET_ENVIRON_ARRAY environ #endif +#ifdef RKTIO_SYSTEM_UNIX +char **rktio_get_environ_array(void) +{ + return GET_ENVIRON_ARRAY; +} +#endif int rktio_is_ok_envvar_name(rktio_t *rktio, const char *s) { diff --git a/racket/src/rktio/rktio_error.c b/racket/src/rktio/rktio_error.c index 8a061205b8..9ae754c5bc 100644 --- a/racket/src/rktio/rktio_error.c +++ b/racket/src/rktio/rktio_error.c @@ -13,12 +13,15 @@ typedef struct err_str_t { err_str_t err_strs[] = { { RKTIO_ERROR_UNSUPPORTED, "unsupported" }, - { RKTIO_ERROR_EXISTS, "file or directory already exists"}, + { RKTIO_ERROR_DOES_NOT_EXIST, "no such file or directory" }, + { RKTIO_ERROR_EXISTS, "file or directory already exists" }, { RKTIO_ERROR_LINK_FAILED, "link creation failed" }, { RKTIO_ERROR_NOT_A_LINK, "not a link" }, { RKTIO_ERROR_BAD_PERMISSION, "unsupported permission value" }, { RKTIO_ERROR_IS_A_DIRECTORY, "path refers to a directory" }, { RKTIO_ERROR_NOT_A_DIRECTORY, "path does not refer to a directory" }, + { RKTIO_ERROR_UNSUPPORTED_TEXT_MODE, "cannot use text mode on a non-file device" }, + { RKTIO_ERROR_CANNOT_FILE_POSITION, "cannot get/set position/size on device" }, { RKTIO_ERROR_NO_TILDE, "path does not start with a tilde" }, { RKTIO_ERROR_ILL_FORMED_USER, "ill-formed username in path" }, { RKTIO_ERROR_UNKNOWN_USER, "unknown username in path" }, diff --git a/racket/src/rktio/rktio_fd.c b/racket/src/rktio/rktio_fd.c index 0dbc4451a8..d76e876e7c 100644 --- a/racket/src/rktio/rktio_fd.c +++ b/racket/src/rktio/rktio_fd.c @@ -39,6 +39,7 @@ struct rktio_fd_t { struct Win_FD_Output_Thread *oth; /* output mode */ int unblocked; /* whether non-blocking mode is installed */ char *buffer; /* shared with reading thread */ + int pending_cr; /* for text-mode input, may be dropped by a following lf */ #endif }; @@ -112,6 +113,10 @@ static CSI_proc get_csi(void) return csi; } +static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, intptr_t got); +static char *rktio_adjust_output_text(char *buffer, intptr_t *towrite); +static intptr_t rktio_recount_output_text(char *orig_buffer, char *buffer, intptr_t wrote); + #endif /*========================================================================*/ @@ -173,7 +178,7 @@ rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes) { rktio_fd_t *rfd; - rfd = malloc(sizeof(rktio_fd_t)); + rfd = calloc(1, sizeof(rktio_fd_t)); rfd->modes = modes; #ifdef RKTIO_SYSTEM_UNIX @@ -202,6 +207,12 @@ rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes) if (modes & RKTIO_OPEN_READ) init_read_fd(rktio, rfd); + + if ((modes & RKTIO_OPEN_SOCKET) && (modes & RKTIO_OPEN_INIT)) + rktio_socket_init(rktio, rfd); + + if ((modes & RKTIO_OPEN_SOCKET) && (modes & RKTIO_OPEN_OWN)) + rktio_socket_own(rktio, rfd); return rfd; } @@ -219,6 +230,30 @@ intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd) #endif } +rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which) +{ + int mode = ((which == RKTIO_STDIN) + ? RKTIO_OPEN_READ + : RKTIO_OPEN_WRITE); +#ifdef RKTIO_SYSTEM_UNIX + return rktio_system_fd(rktio, which, mode); +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + switch (which) { + case RKTIO_STDIN: + which = STD_INPUT_HANDLE; + break; + case RKTIO_STDOUT: + which = STD_OUTPUT_HANDLE; + break; + case RKTIO_STDERR: + which = STD_ERROR_HANDLE; + break; + } + return rktio_system_fd(rktio, (intptr_t)GetStdHandle(which), mode); +#endif +} + int rktio_fd_is_regular_file(rktio_t *rktio, rktio_fd_t *rfd) { return ((rfd->modes & RKTIO_OPEN_REGFILE) ? 1 : 0); @@ -261,6 +296,15 @@ int rktio_fd_is_terminal(rktio_t *rktio, rktio_fd_t *rfd) return rktio_system_fd_is_terminal(rktio, (intptr_t)rfd->fd); } +int rktio_fd_is_text_converted(rktio_t *rktio, rktio_fd_t *rfd) +{ +#ifdef RKTIO_SYSTEM_WINDOWS + if (rfd->modes & RKTIO_OPEN_TEXT) + return 1; +#endif + return 0; +} + rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd) { #ifdef RKTIO_SYSTEM_UNIX @@ -382,12 +426,6 @@ int rktio_close(rktio_t *rktio, rktio_fd_t *rfd) void rktio_forget(rktio_t *rktio, rktio_fd_t *rfd) { -#ifdef RKTIO_SYSTEM_WINDOWS - if (rfd->modes & RKTIO_OPEN_SOCKET) { - rktio_socket_forget(rktio, rfd); - return; - } -#endif free(rfd); } @@ -661,6 +699,13 @@ void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int else rktio_poll_set_add_nosleep(rktio, fds); } + + if (modes & RKTIO_POLL_FLUSH) { + if (rfd->oth && !rktio_poll_flush_ready(rktio, rfd)) + rktio_poll_set_add_handle(rktio, (intptr_t)rfd->oth->ready_sema, fds, 1); + else + rktio_poll_set_add_nosleep(rktio, fds); + } } #endif } @@ -677,6 +722,14 @@ intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len) if (rfd->modes & RKTIO_OPEN_SOCKET) return rktio_socket_read(rktio, rfd, buffer, len); +# ifdef SOME_FDS_ARE_NOT_SELECTABLE + if (rfd->bufcount && len) { + buffer[0] = rfd->buffer[0]; + rfd->bufcount = 0; + return 1; + } +# endif + if (rktio_fd_is_regular_file(rktio, rfd)) { /* Reading regular file never blocks */ do { @@ -728,7 +781,12 @@ intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len) if (!rfd->th) { /* We can read directly. This must be a regular file, where reading never blocks. */ - DWORD rgot; + DWORD rgot; + + if (rfd->pending_cr && len) { + /* just in case we need to add the cr */ + len--; + } if (!ReadFile((HANDLE)rfd->fd, buffer, len, &rgot, NULL)) { get_windows_error(); @@ -737,6 +795,8 @@ intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len) if (!rgot) return RKTIO_READ_EOF; + else if (rfd->modes & RKTIO_OPEN_TEXT) + return rktio_adjust_input_text(rfd, buffer, rgot); else return rgot; } else { @@ -764,7 +824,46 @@ intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len) #endif } +RKTIO_EXTERN intptr_t rktio_buffered_byte_count(rktio_t *rktio, rktio_fd_t *fd) +{ +#ifdef RKTIO_SYSTEM_UNIX +# ifdef SOME_FDS_ARE_NOT_SELECTABLE + return rfd->bufcount; +# else + return 0; +# endif +#endif #ifdef RKTIO_SYSTEM_WINDOWS + return (fd-?pending_cr : 1 : 0); +#endif +} + +#ifdef RKTIO_SYSTEM_WINDOWS + +static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, intptr_t got) +{ + int i, j; + + if (rfd->pending_cr) { + MSC_IZE(memmove)(buffer+1, buffer, got); + buffer[0] = '\r'; + rfd->pending_cr = 0; + got++; + } + if (got && (buffer[got-1] == '\r')) { + rfd->pending_cr = 1; + --got; + } + + for (i = 0, j = 0; i < got-1; i++) { + if ((buffer[i] == '\r') && (buffer[i+1] == '\n')) + buffer[j++] = '\n'; + else + buffer[j++] = buffer[i++]; + } + + return j; +} static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th) { @@ -887,16 +986,20 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len if (rfd->modes & RKTIO_OPEN_SOCKET) return rktio_socket_write(rktio, rfd, buffer, len); - if (rktio_fd_is_regular_file(rktio, rfd)) { + if (rktio_fd_is_regular_file(rktio, rfd) + || rktio_fd_is_terminal(rktio, rfd)) { /* Regular files never block, so this code looks like the Unix - code. We've cheated in the make_fd proc and called - consoles regular files, because they cannot block, either. */ + code. */ /* If we try to write too much at once, the result is ERROR_NOT_ENOUGH_MEMORY (as opposed to a partial write). */ int ok; intptr_t towrite = len; + char *orig_buffer = buffer; int err; + + if (rfd->modes & RKTIO_OPEN_TEXT) + buffer = rktio_adjust_output_text(buffer, &towrite); while (1) { ok = WriteFile((HANDLE)rfd->fd, buffer, towrite, &winwrote, NULL); @@ -905,6 +1008,11 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len if (!ok && (err == ERROR_NOT_ENOUGH_MEMORY)) { towrite = towrite >> 1; + if (towrite && (buffer != orig_buffer)) { + /* don't write half of a CRLF: */ + if ((buffer[towrite-1] == '\r') && (buffer[towrite-1] == '\n')) + --towrite; + } if (!towrite) break; } else @@ -916,6 +1024,11 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len return RKTIO_WRITE_ERROR; } + if (buffer != orig_buffer) { + /* Convert converted count back to original count: */ + winwrote = rktio_recount_output_text(orig_buffer, buffer, winwrote); + } + return winwrote; } else { /* If we don't have a thread yet, we'll need to start it. If @@ -1152,6 +1265,54 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len #ifdef RKTIO_SYSTEM_WINDOWS +static char *rktio_adjust_output_text(char *buffer, intptr_t *towrite) +{ + intptr_t len = *towrite, i, j, newlines = 0; + char *new_buffer; + + /* Limit work done here to avoid O(N^2) work if a client tried + repeatedly to write a O(N)-sized buffer and only part goes out + each time. */ + if (len > 4096) + len = 4096; + + for (i = 0; i < len; i++) { + if (buffer[i] == '\n') + newlines++; + } + + if (!newlines) + return buffer; + + new_buffer = malloc(len + newlines); + *towrite = len + newlines; + + for (i = 0, j = 0; i < len; i++) { + if (buffer[i] == '\n') { + new_buffer[j++] = '\r'; + new_buffer[j++] = '\n'; + } else + new_buffer[j++] = buffer[i]; + } + + return new_buffer; +} + +static intptr_t rktio_recount_output_text(char *orig_buffer, char *buffer, intptr_t wrote) +{ + intptr_t i = 0, j = 0; + + while (j < wrote) { + if (buffer[i] == '\n') + j += 2; + or + j++; + i++; + } + + return i; +} + static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth) { DWORD towrite, wrote, start; diff --git a/racket/src/rktio/rktio_file.c b/racket/src/rktio/rktio_file.c index f3aac19f74..560bce7c9b 100644 --- a/racket/src/rktio/rktio_file.c +++ b/racket/src/rktio/rktio_file.c @@ -12,9 +12,9 @@ # include #endif -/*************************************************************/ -/* opening a file fd */ -/*************************************************************/ +/*========================================================================*/ +/* Opening a file */ +/*========================================================================*/ static rktio_fd_t *open_read(rktio_t *rktio, char *filename) { @@ -27,7 +27,10 @@ static rktio_fd_t *open_read(rktio_t *rktio, char *filename) } while ((fd == -1) && (errno == EINTR)); if (fd == -1) { - get_posix_error(); + if (errno == ENOENT) { + set_racket_error(RKTIO_ERROR_DOES_NOT_EXIST); + } else + get_posix_error(); return NULL; } else { int cr; @@ -60,6 +63,7 @@ static rktio_fd_t *open_read(rktio_t *rktio, char *filename) #endif #ifdef RKTIO_SYSTEM_WINDOWS HANDLE fd; + rktio_fd_t *rfd; fd = CreateFileW(WIDE_PATH_temp(filename), GENERIC_READ, @@ -70,11 +74,24 @@ static rktio_fd_t *open_read(rktio_t *rktio, char *filename) NULL); if (fd == INVALID_HANDLE_VALUE) { - get_windows_error(); + if (GetLastError() == ERROR_FILE_NOT_FOUND) { + set_racket_error(RKTIO_ERROR_DOES_NOT_EXIST); + } else + get_windows_error(); return NULL; } - return rktio_system_fd(rktio, (intptr_t)fd, RKTIO_OPEN_READ); + rfd = rktio_system_fd(rktio, (intptr_t)fd, RKTIO_OPEN_READ); + + if (modes & RKTIO_MODE_TEXT) { + if (!rktio_fd_is_regular_file(rfd)) { + rktio_fd_forget(rfd); + set_racket_error(RKTIO_ERROR_UNSUPPORTED_TEXT_MODE); + return NULL; + } + } + + return rfd; #endif } @@ -222,6 +239,14 @@ static rktio_fd_t *open_write(rktio_t *rktio, char *filename, int modes) rfd = rktio_system_fd(rktio, (intptr_t)fd, modes); + if (modes & RKTIO_MODE_TEXT) { + if (!rktio_fd_is_regular_file(rfd)) { + rktio_fd_forget(rfd); + set_racket_error(RKTIO_ERROR_UNSUPPORTED_TEXT_MODE); + return NULL; + } + } + if ((modes & RKTIO_OPEN_APPEND) && rktio_fd_is_regular_file(rktio, rfd)) { SetFilePointer(fd, 0, NULL, FILE_END); } @@ -238,3 +263,131 @@ rktio_fd_t *rktio_open(rktio_t *rktio, char *filename, int modes) return open_read(rktio, filename); } +/*========================================================================*/ +/* File positions */ +/*========================================================================*/ + +#ifdef WINDOWS_FILE_HANDLES +static int win_seekable(intptr_t fd) +{ + /* SetFilePointer() requires " a file stored on a seeking device". + I'm not sure how to test that, so we approximate as "regular + file". */ + return GetFileType((HANDLE)fd) == FILE_TYPE_DISK; +} +#endif + +rktio_ok_t rktio_set_file_position(rktio_t *rktio, rktio_fd_t *rfd, rktio_filesize_t pos, int whence) +{ + intptr_t fd = rktio_fd_system_fd(rktio, rfd); + +#ifdef RKTIO_SYSTEM_UNIX + if (whence == RKTIO_POSITION_FROM_START) + whence = SEEK_SET; + else + whence = SEEK_END; + if (BIG_OFF_T_IZE(lseek)(fd, pos, whence) < 0) { + get_posix_error(); + return 0; + } + return 1; +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + if (win_seekable(fd)) { + DWORD r; + LONG lo_w, hi_w; + lo_w = (LONG)(pos & 0xFFFFFFFF); + hi_w = (LONG)(pos >> 32); + r = SetFilePointer((HANDLE)fd, lo_w, &hi_w, + ((whence == RKTIO_POSITION_FROM_START) ? FILE_BEGIN : FILE_END)); + if ((r == INVALID_SET_FILE_POINTER) + && GetLastError() != NO_ERROR) { + get_windows_error(); + return 0; + } else + return 1; + } else { + set_racket_error(RKTIO_ERROR_CANNOT_SET_FILE_POSITION); + return 0; + } +#endif +} + +rktio_filesize_t *rktio_get_file_position(rktio_t *rktio, rktio_fd_t *rfd) +{ + intptr_t fd = rktio_fd_system_fd(rktio, rfd); + rktio_filesize_t pll, *r; + +#ifdef RKTIO_SYSTEM_UNIX + pll = BIG_OFF_T_IZE(lseek)(fd, 0, 1); + if (pll < 0) { + get_posix_error(); + return NULL; + } +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + if (win_seekable(fd)) { + DWORD lo_w, hi_w; + hi_w = 0; + lo_w = SetFilePointer((HANDLE)fd, 0, &hi_w, FILE_CURRENT); + if ((lo_w == INVALID_SET_FILE_POINTER) + && GetLastError() != NO_ERROR) { + get_windows_error(); + return NULL; + } else + pll = ((mzlonglong)hi_w << 32) | lo_w; + } else { + set_racket_error(RKTIO_ERROR_CANNOT_SET_FILE_POSITION); + return NULL; + } +#endif + + r = malloc(sizeof(rktio_filesize_t)); + *r = pll; + return r; +} + +rktio_ok_t rktio_set_file_size(rktio_t *rktio, rktio_fd_t *rfd, rktio_filesize_t sz) +{ + intptr_t fd = rktio_fd_system_fd(rktio, rfd); + +#ifdef RKTIO_SYSTEM_UNIX + if (!BIG_OFF_T_IZE(ftruncate)(fd, sz)) + return 1; + get_posix_error(); + return 0; +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + if (win_seekable(fd)) { + DWORD r; + LONG lo_w, hi_w, old_lo_w, old_hi_w; + old_hi_w = 0; + old_lo_w = SetFilePointer((HANDLE)fd, 0, &old_hi_w, FILE_CURRENT); + if ((old_lo_w == INVALID_SET_FILE_POINTER) + && GetLastError() != NO_ERROR) { + get_windows_error(); + return 0; + } else { + lo_w = (LONG)(sz & 0xFFFFFFFF); + hi_w = (LONG)(sz >> 32); + r = SetFilePointer((HANDLE)fd, lo_w, &hi_w, FILE_BEGIN); + if ((r == INVALID_SET_FILE_POINTER) + && GetLastError() != NO_ERROR) { + get_windows_error(); + return 0; + } else { + if (SetEndOfFile((HANDLE)fd)) { + /* we assume that this works: */ + (void)SetFilePointer((HANDLE)fd, lo_w, &hi_w, FILE_BEGIN); + return 1; + } + get_windows_error(); + return 0; + } + } + } else { + set_racket_error(RKTIO_ERROR_CANNOT_SET_FILE_POSITION); + return 0; + } +#endif +} diff --git a/racket/src/rktio/rktio_flock.c b/racket/src/rktio/rktio_flock.c index 5bd7253e56..23d970e8a7 100644 --- a/racket/src/rktio/rktio_flock.c +++ b/racket/src/rktio/rktio_flock.c @@ -215,7 +215,7 @@ void rktio_release_lockf(rktio_t *rktio, int fd) } #endif -int rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd) +rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd) { intptr_t fd = rktio_fd_system_fd(rktio, rfd); int ok; @@ -240,5 +240,6 @@ int rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd) if (!ok) get_windows_error(); #endif + return ok; } diff --git a/racket/src/rktio/rktio_fs.c b/racket/src/rktio/rktio_fs.c index 972ae08f61..5bd182ea35 100644 --- a/racket/src/rktio/rktio_fs.c +++ b/racket/src/rktio/rktio_fs.c @@ -46,12 +46,6 @@ #endif #define IS_A_SEP(c) ((c) == A_PATH_SEP) -#ifdef USE_TRANSITIONAL_64_FILE_OPS -# define BIG_OFF_T_IZE(n) n ## 64 -#else -# define BIG_OFF_T_IZE(n) n -#endif - #if defined(RKTIO_SYSTEM_UNIX) && !defined(NO_UNIX_USERS) static int have_user_ids = 0; static uid_t uid; diff --git a/racket/src/rktio/rktio_hash.c b/racket/src/rktio/rktio_hash.c index 7d4ac18ea6..97864395b4 100644 --- a/racket/src/rktio/rktio_hash.c +++ b/racket/src/rktio/rktio_hash.c @@ -10,7 +10,6 @@ struct rktio_hash_t { 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; @@ -41,6 +40,19 @@ int rktio_hash_is_empty(rktio_hash_t *ht) return (ht->count == 0); } +intptr_t rktio_hash_size(rktio_hash_t *ht) +{ + return ht->size; +} + +intptr_t rktio_hash_get_key(rktio_hash_t *ht, intptr_t i) +{ + if (ht->buckets[i].v) + return ht->buckets[i].key; + else + return -1; +} + static void do_rehash(rktio_hash_t *ht, intptr_t new_size) { if (new_size >= 16) { @@ -81,7 +93,7 @@ void *rktio_hash_get(rktio_hash_t *ht, intptr_t key) return NULL; } -void rktio_hash_remove(rktio_hash_t *ht, intptr_t key) +void rktio_hash_remove(rktio_hash_t *ht, intptr_t key, int dont_rehash) { if (ht->buckets) { intptr_t mask = (ht->size - 1); @@ -93,8 +105,10 @@ void rktio_hash_remove(rktio_hash_t *ht, intptr_t 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); + if (!dont_rehash) { + 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 */ diff --git a/racket/src/rktio/rktio_ltps.c b/racket/src/rktio/rktio_ltps.c index 5c4cc64c40..bdaae4cf44 100644 --- a/racket/src/rktio/rktio_ltps.c +++ b/racket/src/rktio/rktio_ltps.c @@ -82,12 +82,12 @@ void ltps_signal_handle(rktio_ltps_t *lt, rktio_ltps_handle_t *s) lt->signaled = s; } -void rktio_ltps_handle_set_data(rktio_ltps_t *lt, rktio_ltps_handle_t *s, void *data) +void rktio_ltps_handle_set_data(rktio_t *rktio, rktio_ltps_handle_t *s, void *data) { s->data = data; } -void *rktio_ltps_handle_get_data(rktio_ltps_t *lt, rktio_ltps_handle_t *s) +void *rktio_ltps_handle_get_data(rktio_t *rktio, rktio_ltps_handle_t *s) { return s->data; } @@ -131,6 +131,8 @@ int rktio_ltps_close(rktio_t *rktio, rktio_ltps_t *lt) { rktio_ltps_handle_t *s; + rktio_ltps_remove_all(rktio, lt); + while ((s = rktio_ltps_get_signaled_handle(rktio, lt))) free(s); @@ -167,19 +169,17 @@ rktio_ltps_handle_t *rktio_ltps_get_signaled_handle(rktio_t *rktio, rktio_ltps_t #if defined(HAVE_KQUEUE_SYSCALL) || defined(HAVE_EPOLL_SYSCALL) static void log_kqueue_error(const char *action, int kr) { +#if 0 if (kr < 0) { - fprintf(stderr, "%s error at %s: %d\n", -#ifdef HAVE_KQUEUE_SYSCALL - "kqueue", -#else - "epoll", -#endif + fprintf(stderr, "ltps error at %s: %d\n", action, errno); } +#endif } static void log_kqueue_fd(int fd, int flags) { + /* ... "expected event %d %d" ... */ } #endif @@ -254,6 +254,7 @@ rktio_ltps_handle_t *rktio_ltps_add(rktio_t *rktio, rktio_ltps_t *lt, rktio_fd_t s = v->write_handle; if (s) ltps_signal_handle(lt, s); ltps_hash_remove(lt, fd); + /* `v` is freed below */ s = NULL; # ifdef HAVE_KQUEUE_SYSCALL { @@ -630,7 +631,7 @@ static void ltps_hash_set(rktio_ltps_t *lt, intptr_t fd, rktio_ltps_handle_pair_ static void ltps_hash_remove(rktio_ltps_t *lt, intptr_t fd) { - rktio_hash_remove(lt->fd_handles, fd); + rktio_hash_remove(lt->fd_handles, fd, 0); } static void ltps_hash_init(rktio_ltps_t *lt) @@ -644,3 +645,29 @@ static void ltps_hash_free(rktio_ltps_t *lt) } #endif + +void rktio_ltps_remove_all(rktio_t *rktio, rktio_ltps_t *lt) +{ +#ifdef RKTIO_SYSTEM_UNIX + intptr_t sz, i; + + sz = rktio_hash_size(lt->fd_handles); + for (i = 0; i < sz; i++) { + intptr_t fd; + fd = rktio_hash_get_key(lt->fd_handles, i); + if (fd != -1) { + rktio_ltps_handle_pair_t *v; + rktio_ltps_handle_t *s; + v = ltps_hash_get(lt, fd); + if (v) { + s = v->read_handle; + if (s) ltps_signal_handle(lt, s); + s = v->write_handle; + if (s) ltps_signal_handle(lt, s); + rktio_hash_remove(lt->fd_handles, fd, 1); + free(v); + } + } + } +#endif +} diff --git a/racket/src/rktio/rktio_network.c b/racket/src/rktio/rktio_network.c index 9a858b0f98..6e83a0269c 100644 --- a/racket/src/rktio/rktio_network.c +++ b/racket/src/rktio/rktio_network.c @@ -726,7 +726,7 @@ rktio_addrinfo_lookup_t *rktio_start_addrinfo_lookup(rktio_t *rktio, return start_lookup(rktio, lookup); } -void rktio_free_addrinfo(rktio_t *rktio, rktio_addrinfo_t *a) +void rktio_addrinfo_free(rktio_t *rktio, rktio_addrinfo_t *a) { do_freeaddrinfo(RKTIO_AS_ADDRINFO(a)); } @@ -852,6 +852,38 @@ void rktio_winsock_done(rktio_t *rktio) /* TCP sockets */ /*========================================================================*/ +void rktio_socket_init(rktio_t *rktio, rktio_fd_t *rfd) +{ + rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); + +#ifdef RKTIO_SYSTEM_UNIX + fcntl(s, F_SETFL, RKTIO_NONBLOCKING); +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + { + unsigned long ioarg = 1; + ioctlsocket(s, FIONBIO, &ioarg); + } +#endif + + if (rktio_fd_is_udp(rktio, rfd)) { +#ifdef RKTIO_SYSTEM_UNIX +# ifdef SO_BROADCAST + { + int bc = 1; + setsockopt(s, SOL_SOCKET, SO_BROADCAST, &bc, sizeof(bc)); + } +# endif +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + { + BOOL bc = 1; + setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)(&bc), sizeof(BOOL)); + } +#endif + } +} + int rktio_socket_close(rktio_t *rktio, rktio_fd_t *rfd) { #ifdef RKTIO_SYSTEM_UNIX @@ -867,15 +899,19 @@ int rktio_socket_close(rktio_t *rktio, rktio_fd_t *rfd) #endif } -void rktio_socket_forget(rktio_t *rktio, rktio_fd_t *rfd) +void rktio_socket_own(rktio_t *rktio, rktio_fd_t *rfd) { -#ifdef RKTIO_SYSTEM_UNIX - rktio_forget(rktio, rfd); +#ifdef RKTIO_SYSTEM_WINDOWS + rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); + REGISTER_SOCKET(s); #endif +} + +void rktio_socket_forget_owned(rktio_t *rktio, rktio_fd_t *rfd) +{ #ifdef RKTIO_SYSTEM_WINDOWS rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); UNREGISTER_SOCKET(s); - closesocket(s); #endif } @@ -947,19 +983,6 @@ int rktio_socket_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd) #endif } -static void init_socket(rktio_socket_t s) -{ -#ifdef RKTIO_SYSTEM_UNIX - fcntl(s, F_SETFL, RKTIO_NONBLOCKING); -#endif -#ifdef RKTIO_SYSTEM_WINDOWS - { - unsigned long ioarg = 1; - ioctlsocket(s, FIONBIO, &ioarg); - } -#endif -} - rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd) { #ifdef RKTIO_SYSTEM_UNIX @@ -980,8 +1003,7 @@ rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd) get_socket_error(); return NULL; } - REGISTER_SOCKET(nsocket); - return rktio_system_fd(rktio, nsocket, rktio_fd_modes(rktio, rfd)); + return rktio_system_fd(rktio, nsocket, rktio_fd_modes(rktio, rfd) | RKTIO_OPEN_OWN); #endif } @@ -1137,9 +1159,7 @@ static rktio_connect_t *try_connect(rktio_t *rktio, rktio_connect_t *conn) errno = status; #endif - REGISTER_SOCKET(s); - - conn->trying_fd = rktio_system_fd(rktio, s, RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE); + conn->trying_fd = rktio_system_fd(rktio, s, RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE | RKTIO_OPEN_OWN); conn->inprogress = inprogress; return conn; @@ -1212,8 +1232,6 @@ rktio_fd_t *rktio_connect_finish(rktio_t *rktio, rktio_connect_t *conn) } } - init_socket(rktio_fd_system_fd(rktio, rfd)); - conn_free(conn); return rfd; @@ -1519,7 +1537,7 @@ int rktio_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener) return do_poll_accept_ready(rktio, listener, 0); } -void rktio_poll_add_receive(rktio_t *rktio, rktio_listener_t *listener, rktio_poll_set_t *fds) +void rktio_poll_add_accept(rktio_t *rktio, rktio_listener_t *listener, rktio_poll_set_t *fds) { int i; rktio_socket_t s; @@ -1562,10 +1580,7 @@ rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener) RKTIO_WHEN_SET_SOCKBUF_SIZE(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(int))); # endif - init_socket(s); - REGISTER_SOCKET(s); - - return rktio_system_fd(rktio, s, RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE); + return rktio_system_fd(rktio, s, RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE | RKTIO_OPEN_OWN); } else { get_socket_error(); return NULL; @@ -1635,6 +1650,20 @@ char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd) return get_numeric_strings(rktio, name, name_len); } +char **rktio_listener_address(rktio_t *rktio, rktio_listener_t *lnr) +{ + char name[RKTIO_SOCK_NAME_MAX_LEN]; + rktio_sockopt_len_t name_len; + + name_len = sizeof(name); + if (getsockname(lnr->s[0], (struct sockaddr *)name, &name_len)) { + get_socket_error(); + return NULL; + } + + return get_numeric_strings(rktio, name, name_len); +} + /*========================================================================*/ /* UDP */ /*========================================================================*/ diff --git a/racket/src/rktio/rktio_poll_set.c b/racket/src/rktio/rktio_poll_set.c index de30325312..703cb08d54 100644 --- a/racket/src/rktio/rktio_poll_set.c +++ b/racket/src/rktio/rktio_poll_set.c @@ -898,7 +898,7 @@ rktio_poll_set_t *rktio_make_poll_set(rktio_t *rktio) return fds; } -void rktio_poll_set_close(rktio_t *rktio, rktio_poll_set_t *fds) +void rktio_poll_set_forget(rktio_t *rktio, rktio_poll_set_t *fds) { free_fdset_arrays(fds); } diff --git a/racket/src/rktio/rktio_private.h b/racket/src/rktio/rktio_private.h index 3793136dcf..fe0db54a27 100644 --- a/racket/src/rktio/rktio_private.h +++ b/racket/src/rktio/rktio_private.h @@ -175,8 +175,11 @@ struct pollfd *rktio_get_poll_fd_array(rktio_poll_set_t *fds); /* Network */ /*========================================================================*/ +void rktio_socket_init(rktio_t *rktio, rktio_fd_t *rfd); + int rktio_socket_close(rktio_t *rktio, rktio_fd_t *rfd); -void rktio_socket_forget(rktio_t *rktio, rktio_fd_t *rfd); +void rktio_socket_own(rktio_t *rktio, rktio_fd_t *rfd); +void rktio_socket_forget_owned(rktio_t *rktio, rktio_fd_t *rfd); rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd); int rktio_socket_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd); @@ -235,9 +238,12 @@ 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_remove(rktio_hash_t *ht, intptr_t key, int dont_rehash); void rktio_hash_set(rktio_hash_t *ht, intptr_t key, void *v); +intptr_t rktio_hash_size(rktio_hash_t *ht); +intptr_t rktio_hash_get_key(rktio_hash_t *ht, intptr_t i); + /*========================================================================*/ /* Misc */ /*========================================================================*/ @@ -289,3 +295,13 @@ void rktio_init_wide(rktio_t *rktio); #ifdef RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS void rktio_release_lockf(rktio_t *rktio, int fd); #endif + +#ifdef RKTIO_SYSTEM_UNIX +char **rktio_get_environ_array(void); +#endif + +#ifdef USE_TRANSITIONAL_64_FILE_OPS +# define BIG_OFF_T_IZE(n) n ## 64 +#else +# define BIG_OFF_T_IZE(n) n +#endif diff --git a/racket/src/rktio/rktio_process.c b/racket/src/rktio/rktio_process.c index 8bcd7dba0a..f50f5ddc51 100644 --- a/racket/src/rktio/rktio_process.c +++ b/racket/src/rktio/rktio_process.c @@ -1225,6 +1225,16 @@ static void CloseFileHandleForSubprocess(intptr_t *hs, int pos) #endif +int rktio_process_allowed_flags(rktio_t *rktio) +{ + int flags = (RKTIO_PROCESS_NEW_GROUP + | RKTIO_PROCESS_STDOUT_AS_STDERR); +#ifdef RKTIO_SYSTEM_WINDOWS + flags |= (RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE + | RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION) +#endif +} + /*========================================================================*/ /* Main process-creation function */ /*========================================================================*/ @@ -1298,7 +1308,10 @@ rktio_process_result_t *rktio_process(rktio_t *rktio, return NULL; } - env = rktio_envvars_to_block(rktio, envvars); + if (envvars) + env = rktio_envvars_to_block(rktio, envvars); + else + env = NULL; #if defined(RKTIO_SYSTEM_WINDOWS) @@ -1504,11 +1517,15 @@ rktio_process_result_t *rktio_process(rktio_t *rktio, } new_argv[i] = NULL; + if (!env) + env = rktio_get_environ_array(); + err = MSC_IZE(execve)(command, new_argv, (char **)env); if (err) err = errno; - - free(env); + + if (envvars) + free(env); /* If we get here it failed; give up */ @@ -1583,6 +1600,11 @@ rktio_process_result_t *rktio_process(rktio_t *rktio, return result; } +int rktio_process_pid(rktio_t *rktio, rktio_process_t *sp) +{ + return sp->pid; +} + #ifdef RKTIO_SYSTEM_UNIX void rktio_close_fds_after_fork(int skip1, int skip2, int skip3) {