From 09703b94f70289b4a739544ee73188acd218df88 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Fri, 9 Jun 2017 13:55:57 -0600 Subject: [PATCH] rktio: put "globals" in an rktio_t Avoid thread-local state by threading a `rktio_t` record through everything. --- racket/src/rktio/Makefile.in | 11 +- racket/src/rktio/main.c | 221 ++++++++++++----- racket/src/rktio/rktio.h | 109 ++++---- racket/src/rktio/rktio_error.c | 36 +-- racket/src/rktio/rktio_filesystem.c | 180 +++++++------- racket/src/rktio/rktio_main.c | 33 +++ racket/src/rktio/rktio_poll_set.c | 370 +++++++++++++++++++++++++++- racket/src/rktio/rktio_private.h | 103 +++++--- racket/src/rktio/rktio_read_write.c | 55 ++--- racket/src/rktio/rktio_sleep.c | 0 10 files changed, 842 insertions(+), 276 deletions(-) create mode 100644 racket/src/rktio/rktio_main.c create mode 100644 racket/src/rktio/rktio_sleep.c diff --git a/racket/src/rktio/Makefile.in b/racket/src/rktio/Makefile.in index b811e6b6d7..e7cdb67adf 100644 --- a/racket/src/rktio/Makefile.in +++ b/racket/src/rktio/Makefile.in @@ -9,13 +9,17 @@ RKTIO_HEADERS = $(srcdir)/rktio.h $(srcdir)/rktio_private.h rktio_config.h OBJS = rktio_filesystem.o \ rktio_read_write.o \ rktio_poll_set.o \ - rktio_error.o + rktio_error.o \ + rktio_main.o all: $(OBJS) -demo: $(OBJS) main.o +demo: $(OBJS) main.o demo_fifo $(CC) -o demo $(CFLAGS) $(LDFLAGS) main.o $(OBJS) +demo_fifo: + mkfifo demo_fifo + rktio_filesystem.o: $(srcdir)/rktio_filesystem.c $(RKTIO_HEADERS) $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_filesystem.o -c $(srcdir)/rktio_filesystem.c @@ -28,5 +32,8 @@ rktio_poll_set.o: $(srcdir)/rktio_poll_set.c $(RKTIO_HEADERS) rktio_error.o: $(srcdir)/rktio_error.c $(RKTIO_HEADERS) $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.o -c $(srcdir)/rktio_error.c +rktio_main.o: $(srcdir)/rktio_main.c $(RKTIO_HEADERS) + $(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_main.o -c $(srcdir)/rktio_main.c + main.o: $(srcdir)/main.c $(RKTIO_HEADERS) $(CC) $(CFLAGS) -I$(srcdir) -I. -o main.o -c $(srcdir)/main.c diff --git a/racket/src/rktio/main.c b/racket/src/rktio/main.c index eb0466a8bf..b834e6bf78 100644 --- a/racket/src/rktio/main.c +++ b/racket/src/rktio/main.c @@ -3,19 +3,20 @@ #include #include -static void do_check_valid(int ok, int where) +static void do_check_valid(rktio_t *rktio, int ok, int where) { if (!ok) { printf("error at %d: %d@%d = %s\n", where, - rktio_get_last_error(), - rktio_get_last_error_kind(), - rktio_get_error_string(rktio_get_last_error(), - rktio_get_last_error_kind())); + rktio_get_last_error(rktio), + rktio_get_last_error_kind(rktio), + rktio_get_error_string(rktio, + rktio_get_last_error_kind(rktio), + rktio_get_last_error(rktio))); } } -static void do_check_expected_error(int err, int where) +static void do_check_expected_error(rktio_t *rktio, int err, int where) { if (!err) { printf("error expected at %d\n", @@ -23,121 +24,165 @@ static void do_check_expected_error(int err, int where) } } -static void do_check_expected_racket_error(int err, int what, int where) +static void do_check_expected_racket_error(rktio_t *rktio, int err, int what, int where) { if (!err) { printf("error expected at %d\n", where); - } else if ((what != rktio_get_last_error()) - || (RKTIO_ERROR_KIND_RACKET != rktio_get_last_error_kind())) { + } else if ((what != rktio_get_last_error(rktio)) + || (RKTIO_ERROR_KIND_RACKET != rktio_get_last_error_kind(rktio))) { printf("wrong error at %d: %d@%d = %s\n", where, - rktio_get_last_error(), - rktio_get_last_error_kind(), - rktio_get_error_string(rktio_get_last_error(), - rktio_get_last_error_kind())); + rktio_get_last_error(rktio), + rktio_get_last_error_kind(rktio), + rktio_get_error_string(rktio, + rktio_get_last_error_kind(rktio), + rktio_get_last_error(rktio))); } } -#define check_valid(e) do_check_valid(e, __LINE__) -#define check_expected_error(e) do_check_expected_error(e, __LINE__) -#define check_expected_racket_error(e, what) do_check_expected_racket_error(e, what, __LINE__) +#define check_valid(e) do_check_valid(rktio, e, __LINE__) +#define check_expected_error(e) do_check_expected_error(rktio, e, __LINE__) +#define check_expected_racket_error(e, what) do_check_expected_racket_error(rktio, e, what, __LINE__) -static void check_hello_content(char *fn) +static void check_hello_content(rktio_t *rktio, char *fn) { rktio_fd_t *fd; intptr_t amt; char buffer[256], *s; - fd = rktio_open(fn, RKTIO_OPEN_READ); + fd = rktio_open(rktio, fn, RKTIO_OPEN_READ); check_valid(!!fd); - check_valid(rktio_poll_read_ready(fd) != RKTIO_POLL_ERROR); - amt = rktio_read(fd, buffer, sizeof(buffer)); + check_valid(rktio_poll_read_ready(rktio, fd) != RKTIO_POLL_ERROR); + amt = rktio_read(rktio, fd, buffer, sizeof(buffer)); check_valid(amt == 5); check_valid(!strncmp(buffer, "hello", 5)); - check_valid(rktio_close(fd)); + amt = rktio_read(rktio, fd, buffer, sizeof(buffer)); + check_valid(amt == RKTIO_READ_EOF); + check_valid(rktio_close(rktio, fd)); } int main() { + rktio_t *rktio; rktio_size_t *sz; - rktio_fd_t *fd; - intptr_t amt, i,saw_file; - char *s, *pwd; + rktio_fd_t *fd, *fd2; + intptr_t amt, i, saw_file; + int perms; + char buffer[256], *s, *pwd; rktio_directory_list_t *ls; rktio_file_copy_t *cp; + rktio_timestamp_t *ts1, *ts1a; - fd = rktio_open("test1", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST); + rktio = rktio_init(); + + /* Basic file I/O */ + + fd = rktio_open(rktio, "test1", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST); check_valid(!!fd); - check_valid(rktio_poll_write_ready(fd) != RKTIO_POLL_ERROR); - amt = rktio_write(fd, "hello", 5); + check_valid(rktio_poll_write_ready(rktio, fd) != RKTIO_POLL_ERROR); + amt = rktio_write(rktio, fd, "hello", 5); check_valid(amt == 5); - check_valid(rktio_close(fd)); + check_valid(rktio_close(rktio, fd)); - check_valid(rktio_file_exists("test1")); - check_valid(!rktio_directory_exists("test1")); - check_valid(rktio_is_regular_file("test1")); + check_valid(rktio_file_exists(rktio, "test1")); + check_valid(!rktio_directory_exists(rktio, "test1")); + check_valid(rktio_is_regular_file(rktio, "test1")); - s = rktio_get_current_directory(); + s = rktio_get_current_directory(rktio); check_valid(!!s); - check_valid(rktio_directory_exists(s)); - check_valid(!rktio_file_exists(s)); - check_valid(!rktio_is_regular_file(s)); - check_expected_racket_error(!rktio_open(s, RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST), + check_valid(rktio_directory_exists(rktio, s)); + check_valid(!rktio_file_exists(rktio, s)); + check_valid(!rktio_is_regular_file(rktio, s)); + check_expected_racket_error(!rktio_open(rktio, s, RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST), RKTIO_ERROR_IS_A_DIRECTORY); pwd = s; - sz = rktio_file_size("test1"); + sz = rktio_file_size(rktio, "test1"); check_valid(!!sz); check_valid(sz->lo == 5); check_valid(sz->hi == 0); free(sz); - fd = rktio_open("test2", RKTIO_OPEN_WRITE | RKTIO_OPEN_MUST_EXIST); + fd = rktio_open(rktio, "test2", RKTIO_OPEN_WRITE | RKTIO_OPEN_MUST_EXIST); check_expected_error(!fd); - fd = rktio_open("test1", RKTIO_OPEN_WRITE); + fd = rktio_open(rktio, "test1", RKTIO_OPEN_WRITE); check_expected_racket_error(!fd, RKTIO_ERROR_EXISTS); - check_hello_content("test1"); + check_hello_content(rktio, "test1"); - if (rktio_file_exists("test1a")) - check_valid(rktio_delete_file("test1a", 1)); - if (rktio_file_exists("test1b")) - check_valid(rktio_delete_file("test1b", 1)); + /* Copying, renaming, and deleting files */ - cp = rktio_copy_file_start("test1a", "test1", 0); + if (rktio_file_exists(rktio, "test1a")) + check_valid(rktio_delete_file(rktio, "test1a", 1)); + if (rktio_file_exists(rktio, "test1b")) + check_valid(rktio_delete_file(rktio, "test1b", 1)); + + ts1 = rktio_get_file_modify_seconds(rktio, "test1a"); + check_expected_error(!ts1); + perms = rktio_get_file_or_directory_permissions(rktio, "test1a", 1); + check_expected_error(perms == -1); + check_expected_error(!rktio_set_file_or_directory_permissions(rktio, "test1a", 511)); + + ts1 = rktio_get_file_modify_seconds(rktio, "test1"); + perms = rktio_get_file_or_directory_permissions(rktio, "test1", 0); + check_valid(perms != -1); + check_valid(perms & (RKTIO_PERMISSION_READ << 6)); + check_valid(perms & (RKTIO_PERMISSION_WRITE << 6)); + perms = rktio_get_file_or_directory_permissions(rktio, "test1", 1); + check_valid(perms != -1); + check_valid(perms & (RKTIO_PERMISSION_READ << 6)); + check_valid(perms & (RKTIO_PERMISSION_WRITE << 6)); + check_valid(rktio_set_file_or_directory_permissions(rktio, "test1", perms & (0x7 << 6))); + check_valid((perms & (0x7 << 6)) == rktio_get_file_or_directory_permissions(rktio, "test1", 1)); + rktio_set_file_or_directory_permissions(rktio, "test1", perms); + + cp = rktio_copy_file_start(rktio, "test1a", "test1", 0); check_valid(!!cp); - while (!rktio_copy_file_is_done(cp)) { - check_valid(rktio_copy_file_step(cp)); + while (!rktio_copy_file_is_done(rktio, cp)) { + check_valid(rktio_copy_file_step(rktio, cp)); } - rktio_copy_file_stop(cp); - check_hello_content("test1a"); + rktio_copy_file_stop(rktio, cp); + check_hello_content(rktio, "test1a"); - check_valid(rktio_file_exists("test1a")); - cp = rktio_copy_file_start("test1a", "test1", 0); + ts1a = rktio_get_file_modify_seconds(rktio, "test1a"); + check_valid(*ts1a >= *ts1); + + rktio_set_file_modify_seconds(rktio, "test1a", *ts1 - 10); + free(ts1a); + ts1a = rktio_get_file_modify_seconds(rktio, "test1a"); + check_valid(*ts1a == (*ts1 - 10)); + + free(ts1); + free(ts1a); + + check_valid(rktio_file_exists(rktio, "test1a")); + cp = rktio_copy_file_start(rktio, "test1a", "test1", 0); check_expected_racket_error(!cp, RKTIO_ERROR_EXISTS); - cp = rktio_copy_file_start("test1a", "test1", 1); + cp = rktio_copy_file_start(rktio, "test1a", "test1", 1); check_valid(!!cp); - rktio_copy_file_stop(cp); + rktio_copy_file_stop(rktio, cp); - check_valid(rktio_rename_file("test1b", "test1a", 0)); - check_valid(rktio_file_exists("test1b")); - check_expected_racket_error(!rktio_rename_file("test1b", "test1", 0), + check_valid(rktio_rename_file(rktio, "test1b", "test1a", 0)); + check_valid(rktio_file_exists(rktio, "test1b")); + check_expected_racket_error(!rktio_rename_file(rktio, "test1b", "test1", 0), RKTIO_ERROR_EXISTS); - check_valid(rktio_file_exists("test1")); - check_valid(rktio_file_exists("test1b")); - check_valid(!rktio_file_exists("test1a")); + check_valid(rktio_file_exists(rktio, "test1")); + check_valid(rktio_file_exists(rktio, "test1b")); + check_valid(!rktio_file_exists(rktio, "test1a")); - check_valid(rktio_delete_file("test1b", 0)); - check_valid(!rktio_file_exists("test1b")); + check_valid(rktio_delete_file(rktio, "test1b", 0)); + check_valid(!rktio_file_exists(rktio, "test1b")); - ls = rktio_directory_list_start(pwd, 0); + /* Listing directory content */ + + ls = rktio_directory_list_start(rktio, pwd, 0); check_valid(!!ls); saw_file = 0; while (1) { - s = rktio_directory_list_step(ls); + s = rktio_directory_list_step(rktio, ls); check_valid(!!s); if (!*s) break; if (!strcmp(s, "test1")) @@ -145,6 +190,54 @@ int main() check_valid(strcmp(s, "test1b")); } check_valid(saw_file); - + + /* Pipes and non-blocking operations */ + + fd = rktio_open(rktio, "demo_fifo", RKTIO_OPEN_READ); + check_valid(!!fd); + check_valid(!rktio_poll_read_ready(rktio, fd)); + fd2 = rktio_open(rktio, "demo_fifo", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST); + check_valid(!!fd2); + check_valid(!rktio_poll_read_ready(rktio, fd)); + + amt = rktio_write(rktio, fd2, "hello", 5); + check_valid(amt == 5); + check_valid(rktio_poll_read_ready(rktio, fd)); + amt = rktio_read(rktio, fd, buffer, sizeof(buffer)); + check_valid(amt == 5); + check_valid(!strncmp(buffer, "hello", 5)); + check_valid(!rktio_poll_read_ready(rktio, fd)); + + check_valid(rktio_close(rktio, fd2)); + amt = rktio_read(rktio, fd, buffer, sizeof(buffer)); + check_valid(amt == RKTIO_READ_EOF); + check_valid(rktio_close(rktio, fd)); + + fd2 = rktio_open(rktio, "demo_fifo", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST); + check_valid(!!fd2); + /* should eventually block: */ + for (i = 0; i < 100000; i++) { + amt = rktio_write(rktio, fd2, "hello", 5); + check_valid(amt != RKTIO_WRITE_ERROR); + if (!amt) + break; + } + check_valid(i < 100000); + + fd = rktio_open(rktio, "demo_fifo", RKTIO_OPEN_READ); + check_valid(!!fd); + /* should eventually block: */ + for (i = 0; i < 100000; i++) { + amt = rktio_read(rktio, fd2, buffer, sizeof(buffer)); + check_valid(amt != RKTIO_READ_ERROR); + check_valid(amt != RKTIO_READ_EOF); + if (!amt) + break; + } + check_valid(i < 100000); + + check_valid(rktio_close(rktio, fd)); + check_valid(rktio_close(rktio, fd2)); + return 0; } diff --git a/racket/src/rktio/rktio.h b/racket/src/rktio/rktio.h index 21728f2214..d8bf3c4354 100644 --- a/racket/src/rktio/rktio.h +++ b/racket/src/rktio/rktio.h @@ -3,6 +3,18 @@ #include "rktio_config.h" +/* A rktio_t value represents an instance of the Racket I/O system. + Every rktio_...() function takes it as the first argument, except + for rktio_init(), rktio_signal_received_at(), and rktio_free(). */ +typedef struct rktio_t rktio_t; + +rktio_t *rktio_init(void); +void rktio_destroy(rktio_t *); + +/* Normally equivalent to free(), but ensures the same malloc()/free() + that rktio function use: */ +void rktio_free(void *p); + /*************************************************/ /* Reading and writing files */ @@ -16,23 +28,23 @@ typedef struct rktio_fd_t rktio_fd_t; #define RKTIO_OPEN_MUST_EXIST (1<<5) #define RKTIO_OPEN_CAN_EXIST (1<<6) -rktio_fd_t *rktio_system_fd(intptr_t system_fd, int modes); -intptr_t rktio_fd_system_fd(rktio_fd_t *rfd); +rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes); +intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd); -rktio_fd_t *rktio_open(char *src, int modes); -int rktio_close(rktio_fd_t *fd); +rktio_fd_t *rktio_open(rktio_t *rktio, char *src, int modes); +int rktio_close(rktio_t *rktio, rktio_fd_t *fd); #define RKTIO_READ_EOF (-1) #define RKTIO_READ_ERROR (-2) #define RKTIO_WRITE_ERROR (-2) #define RKTIO_POLL_ERROR (-2) -intptr_t rktio_read(rktio_fd_t *fd, char *buffer, intptr_t len); -intptr_t rktio_write(rktio_fd_t *fd, char *buffer, intptr_t len); +intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len); +intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len); -int rktio_poll_read_ready(rktio_fd_t *rfd); -int rktio_poll_write_ready(rktio_fd_t *rfd); -int rktio_poll_write_flushed(rktio_fd_t *rfd); +int rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd); +int rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd); +int rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd); /*************************************************/ /* File-descriptor sets */ @@ -42,26 +54,26 @@ typedef struct rktio_poll_set_t rktio_poll_set_t; #define RKTIO_POLL_READ RKTIO_OPEN_READ #define RKTIO_POLL_WRITE RKTIO_OPEN_WRITE -void rktio_poll_add(rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes); +void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes); /*************************************************/ /* Files, directories, and links */ -int rktio_file_exists(char *filename); -int rktio_directory_exists(char *dirname); -int rktio_link_exists(char *filename); -int rktio_is_regular_file(char *filename); +int rktio_file_exists(rktio_t *rktio, char *filename); +int rktio_directory_exists(rktio_t *rktio, char *dirname); +int rktio_link_exists(rktio_t *rktio, char *filename); +int rktio_is_regular_file(rktio_t *rktio, char *filename); -int rktio_delete_file(char *fn, int enable_write_on_fail); -int rktio_rename_file(char *dest, char *src, int exists_ok); +int rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail); +int rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok); -char *rktio_get_current_directory(); -int rktio_set_current_directory(char *expanded); -int rktio_make_directory(char *filename); -int rktio_delete_directory(char *filename, char *current_directory, int enable_write_on_fail); +char *rktio_get_current_directory(rktio_t *rktio); +int rktio_set_current_directory(rktio_t *rktio, char *expanded); +int rktio_make_directory(rktio_t *rktio, char *filename); +int rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory, int enable_write_on_fail); -char *rktio_readlink(char *fullfilename); -int rktio_make_link(char *src, char *dest, int dest_is_directory); +char *rktio_readlink(rktio_t *rktio, char *fullfilename); +int rktio_make_link(rktio_t *rktio, char *src, char *dest, int dest_is_directory); /*************************************************/ /* File attributes */ @@ -76,43 +88,44 @@ typedef struct { uintptr_t a, b, c; } rktio_identity_t; -rktio_size_t *rktio_file_size(char *filename); +rktio_size_t *rktio_file_size(rktio_t *rktio, char *filename); -rktio_timestamp_t *rktio_get_file_modify_seconds(char *file); -int rktio_set_file_modify_seconds(char *file, rktio_timestamp_t secs); +rktio_timestamp_t *rktio_get_file_modify_seconds(rktio_t *rktio, char *file); +int rktio_set_file_modify_seconds(rktio_t *rktio, char *file, rktio_timestamp_t secs); -rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path); +rktio_identity_t *rktio_fd_identity(rktio_t *rktio, rktio_fd_t *fd); +rktio_identity_t *rktio_path_identity(rktio_t *rktio, char *path, int follow_links); /*************************************************/ /* Permissions */ /* Must match OS bits: */ -#define RKTIO_PERMISSION_READ 0x1 +#define RKTIO_PERMISSION_READ 0x4 #define RKTIO_PERMISSION_WRITE 0x2 -#define RKTIO_PERMISSION_EXEC 0x4 +#define RKTIO_PERMISSION_EXEC 0x1 -int rktio_get_file_or_directory_permissions(char *filename, int all_bits); -int rktio_set_file_or_directory_permissions(char *filename, int new_bits); +int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int all_bits); +int 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_directory_list_t *rktio_directory_list_start(char *filename, int is_drive); -char *rktio_directory_list_step(rktio_directory_list_t *dl); +rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive); +char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl); -char **rktio_filesystem_root_list(); +char **rktio_filesystem_root_list(rktio_t *rktio); /*************************************************/ /* File copying */ typedef struct rktio_file_copy_t rktio_file_copy_t; -rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok); -int rktio_copy_file_is_done(rktio_file_copy_t *fc); -int rktio_copy_file_step(rktio_file_copy_t *fc); -void rktio_copy_file_stop(rktio_file_copy_t *fc); +rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, char *dest, char *src, int exists_ok); +int rktio_copy_file_is_done(rktio_t *rktio, rktio_file_copy_t *fc); +int rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc); +void rktio_copy_file_stop(rktio_t *rktio, rktio_file_copy_t *fc); /*************************************************/ /* System paths */ @@ -130,8 +143,17 @@ enum { RKTIO_PATH_INIT_FILE }; -char *rktio_system_path(int which); -char *rktio_expand_user_tilde(char *filename); +char *rktio_system_path(rktio_t *rktio, int which); +char *rktio_expand_user_tilde(rktio_t *rktio, char *filename); + +/*************************************************/ +/* Sleep and signals */ + +typedef struct rktio_signal_handle_t rktio_signal_handle_t; + +rktio_signal_handle_t *rktio_get_signal_handle(rktio_t *rktio); +void rktio_signal_received_at(rktio_signal_handle_t *h); +void rktio_signal_received(rktio_t *rktio); /*************************************************/ /* Errors */ @@ -155,13 +177,14 @@ enum { RKTIO_ERROR_NOT_A_DIRECTORY, RKTIO_ERROR_NO_TILDE, RKTIO_ERROR_ILL_FORMED_USER, - RKTIO_ERROR_UNKNOWN_USER + RKTIO_ERROR_UNKNOWN_USER, + RKTIO_ERROR_INIT_FAILED }; -int rktio_get_last_error(void); -int rktio_get_last_error_kind(void); +int rktio_get_last_error(rktio_t *rktio); +int rktio_get_last_error_kind(rktio_t *rktio); -char *rktio_get_error_string(int kind, int errid); +char *rktio_get_error_string(rktio_t *rktio, int kind, int errid); /*************************************************/ diff --git a/racket/src/rktio/rktio_error.c b/racket/src/rktio/rktio_error.c index f673ef3d8c..18e6ef4781 100644 --- a/racket/src/rktio/rktio_error.c +++ b/racket/src/rktio/rktio_error.c @@ -4,41 +4,43 @@ # include #endif #include +#include -THREAD_LOCAL_DECL(static intptr_t errid); -THREAD_LOCAL_DECL(static int errkind); - -void rktio_get_posix_error(void) +void rktio_get_posix_error(rktio_t *rktio) { - errid = errno; - errkind = RKTIO_ERROR_KIND_POSIX; + rktio->errid = errno; + rktio->errkind = RKTIO_ERROR_KIND_POSIX; } -void rktio_set_racket_error(int new_errid) +void rktio_set_racket_error(rktio_t *rktio, int new_errid) { - errid = new_errid; - errkind = RKTIO_ERROR_KIND_RACKET; + rktio->errid = new_errid; + rktio->errkind = RKTIO_ERROR_KIND_RACKET; } #ifdef RKTIO_SYSTEM_WINDOWS -void rktio_get_windows_error(void) +void rktio_get_windows_error(rktio_t *rktio) { - errid = GetLastError(); - errkind = RKTIO_ERROR_KIND_WINDOWS; + rktio->errid = GetLastError(); + rktio->errkind = RKTIO_ERROR_KIND_WINDOWS; } #endif -int rktio_get_last_error(void) +int rktio_get_last_error(rktio_t *rktio) { - return errid; + return rktio->errid; } -int rktio_get_last_error_kind(void) +int rktio_get_last_error_kind(rktio_t *rktio) { - return errkind; + return rktio->errkind; } -char *rktio_get_error_string(int kind, int errid) +char *rktio_get_error_string(rktio_t *rktio, int kind, int errid) { + char *s = NULL; + if (kind == RKTIO_ERROR_KIND_POSIX) + s = strerror(errid); + if (s) return s; return "???"; } diff --git a/racket/src/rktio/rktio_filesystem.c b/racket/src/rktio/rktio_filesystem.c index e982e6f45d..0cecfe9951 100644 --- a/racket/src/rktio/rktio_filesystem.c +++ b/racket/src/rktio/rktio_filesystem.c @@ -14,9 +14,6 @@ #include #include #endif -#ifdef RKTIO_SYSTEM_WINDOWS -# include -#endif #ifdef RKTIO_SYSTEM_UNIX # define A_PATH_SEP '/' @@ -43,12 +40,11 @@ static gid_t egid; #define GROUP_MEMBER_CACHE_STATE_UNUSED 0 #define GROUP_MEMBER_CACHE_STATE_IN 1 #define GROUP_MEMBER_CACHE_STATE_NOT_IN 2 -typedef struct { +typedef struct group_member_cache_entry_t { int state; gid_t gid; uid_t uid; } group_member_cache_entry_t; -THREAD_LOCAL_DECL(static group_member_cache_entry_t *group_member_cache); # define GROUP_CACHE_SIZE 10 #endif @@ -307,7 +303,7 @@ static char *UNC_readlink(const char *fn) return buffer; } -static int UNC_stat(const char *dirname, int *flags, int *isdir, int *islink, +static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir, int *islink, rktio_timestamp_t **date, rktio_file_size_t *filesize, const char **resolved_path, int set_flags) /* dirname must be absolute */ @@ -337,7 +333,7 @@ static int UNC_stat(const char *dirname, int *flags, int *isdir, int *islink, copy = malloc(len+1); memcpy(copy, dirname, len+1); - if (!rktio_windows_nt_or_later() + if (!rktio->windows_nt_or_later || ((len >= 4) && (copy[0] == '\\') && (copy[1] == '\\') @@ -478,7 +474,7 @@ static int UNC_stat(const char *dirname, int *flags, int *isdir, int *islink, } #endif -int rktio_file_exists(char *filename) +int rktio_file_exists(rktio_t *rktio, char *filename) /* Windows: check for special filenames before calling */ { # ifdef NO_STAT_PROC @@ -494,7 +490,7 @@ int rktio_file_exists(char *filename) # ifdef RKTIO_SYSTEM_WINDOWS { int isdir; - return (UNC_stat(filename, NULL, &isdir, NULL, NULL, NULL, NULL, -1) + return (UNC_stat(rktio, filename, NULL, &isdir, NULL, NULL, NULL, NULL, -1) && !isdir); } # else @@ -510,7 +506,7 @@ int rktio_file_exists(char *filename) # endif } -int rktio_directory_exists(char *dirname) +int rktio_directory_exists(rktio_t *rktio, char *dirname) { # ifdef NO_STAT_PROC return 0; @@ -518,7 +514,7 @@ int rktio_directory_exists(char *dirname) # ifdef RKTIO_SYSTEM_WINDOWS int isdir; - return (UNC_stat(dirname, NULL, &isdir, NULL, NULL, NULL, NULL, -1) + return (UNC_stat(rktio, dirname, NULL, &isdir, NULL, NULL, NULL, NULL, -1) && isdir); # else struct MSC_IZE(stat) buf; @@ -535,7 +531,7 @@ int rktio_directory_exists(char *dirname) # endif } -int rktio_is_regular_file(char *filename) +int rktio_is_regular_file(rktio_t *rktio, char *filename) /* Windows: check for special filenames before calling */ { # ifdef NO_STAT_PROC @@ -554,12 +550,12 @@ int rktio_is_regular_file(char *filename) # endif } -int rktio_link_exists(char *filename) +int rktio_link_exists(rktio_t *rktio, char *filename) { #ifdef RKTIO_SYSTEM_WINDOWS { int islink; - if (UNC_stat(filename, NULL, NULL, &islink, NULL, NULL, NULL, -1) + if (UNC_stat(rktio, filename, NULL, NULL, &islink, NULL, NULL, NULL, -1) && islink) return 1; else @@ -583,7 +579,7 @@ int rktio_link_exists(char *filename) #endif } -char *rktio_get_current_directory() +char *rktio_get_current_directory(rktio_t *rktio) { #ifdef RKTIO_SYSTEM_WINDOWS int need_l, bl = 256; @@ -631,7 +627,7 @@ char *rktio_get_current_directory() #endif } -int rktio_set_current_directory(char *expanded) +int rktio_set_current_directory(rktio_t *rktio, char *expanded) { int err; @@ -646,8 +642,7 @@ int rktio_set_current_directory(char *expanded) return !err; } -rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path) -/* If path is supplied, then fd is 0 for stat, 1 for lstat */ +static rktio_identity_t *get_identity(rktio_t *rktio, rktio_fd_t *fd, char *path, int follow_links) { uintptr_t devi = 0, inoi = 0, inoi2 = 0; @@ -656,11 +651,11 @@ rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path) struct MSC_IZE(stat) buf; while (1) { - if (!path && !MSC_IZE(fstat)(fd, &buf)) + if (!path && !MSC_IZE(fstat)(rktio_fd_system_fd(rktio, fd), &buf)) break; - else if (path && !fd && !MSC_IZE(stat)(path, &buf)) + else if (path && follow_links && !MSC_IZE(stat)(path, &buf)) break; - else if (path && fd && !MSC_IZE(lstat)(path, &buf)) + else if (path && !follow_links && !MSC_IZE(lstat)(path, &buf)) break; else if (errno != EINTR) { errid = errno; @@ -679,7 +674,7 @@ rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path) #endif #ifdef WINDOWS_FILE_HANDLES BY_HANDLE_FILE_INFORMATION info; - HANDLE fdh = (HANDLE)fd; + HANDLE fdh; init_procs(); @@ -698,7 +693,8 @@ rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path) get_windows_error(); return NULL; } - } + } else + fdh = (HANDLE)rktio_fd_system_fd(rktio, fd); if (!GetFileInformationByHandle(fdh, &info)) { get_windows_error(); @@ -726,16 +722,26 @@ rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path) } } +rktio_identity_t *rktio_fd_identity(rktio_t *rktio, rktio_fd_t *fd) +{ + return get_identity(rktio, fd, NULL, 0); +} + +rktio_identity_t *rktio_path_identity(rktio_t *rktio, char *path, int follow_links) +{ + return get_identity(rktio, NULL, path, follow_links); +} + #ifdef RKTIO_SYSTEM_WINDOWS static int enable_write_permission(const char *fn) { int flags; - return UNC_stat(fn, &flags, NULL, NULL, NULL, NULL, NULL, MZ_UNC_WRITE); + return UNC_stat(rktio, fn, &flags, NULL, NULL, NULL, NULL, NULL, MZ_UNC_WRITE); } #endif -int rktio_delete_file(char *fn, int enable_write_on_fail) +int rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail) { int errid; @@ -767,7 +773,7 @@ int rktio_delete_file(char *fn, int enable_write_on_fail) #endif } -int rktio_rename_file(char *dest, char *src, int exists_ok) +int rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok) { #ifdef RKTIO_SYSTEM_WINDOWS int errid; @@ -798,7 +804,7 @@ int rktio_rename_file(char *dest, char *src, int exists_ok) free(src_w); return 0; #else - if (!exists_ok && (rktio_file_exists(dest) || rktio_directory_exists(dest))) { + if (!exists_ok && (rktio_file_exists(rktio, dest) || rktio_directory_exists(rktio, dest))) { /* We use a specialized error here, because it's not a system error (e.g., setting `errval` to `EEXIST` would be a lie). */ @@ -818,10 +824,10 @@ int rktio_rename_file(char *dest, char *src, int exists_ok) #endif } -char *rktio_readlink(char *fullfilename) +char *rktio_readlink(rktio_t *rktio, char *fullfilename) { #ifdef RKTIO_SYSTEM_WINDOWS - if (UNC_stat(fullfilename, NULL, NULL, &is_link, NULL, NULL, NULL, -1) + if (UNC_stat(rktio, fullfilename, NULL, NULL, &is_link, NULL, NULL, NULL, -1) && is_link) { return UNC_readlink(fullfilename); } else { @@ -852,7 +858,7 @@ char *rktio_readlink(char *fullfilename) #endif } -int rktio_make_directory(char *filename) +int rktio_make_directory(rktio_t *rktio, char *filename) { #ifdef NO_MKDIR set_racket_error(RKTIO_ERROR_UNSUPPORTED); @@ -893,7 +899,7 @@ int rktio_make_directory(char *filename) return 0; } -int rktio_delete_directory(char *filename, char *current_directory, int enable_write_on_fail) +int rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory, int enable_write_on_fail) { #ifdef RKTIO_SYSTEM_WINDOWS int tried_cwd = 0, tried_perm = 0; @@ -922,7 +928,7 @@ int rktio_delete_directory(char *filename, char *current_directory, int enable_w #endif } -int rktio_make_link(char *src, char *dest, int dest_is_directory) +int rktio_make_link(rktio_t *rktio, char *src, char *dest, int dest_is_directory) /* `src` is the file that is written, and `dest` is written to that file */ { @@ -960,12 +966,12 @@ int rktio_make_link(char *src, char *dest, int dest_is_directory) #endif } -rktio_timestamp_t *rktio_get_file_modify_seconds(char *file) +rktio_timestamp_t *rktio_get_file_modify_seconds(rktio_t *rktio, char *file) { #ifdef RKTIO_SYSTEM_WINDOWS rktio_timestamp_t *secs; - if (UNC_stat(file, NULL, NULL, NULL, &secs, NULL, NULL, -1)) + if (UNC_stat(rktio, file, NULL, NULL, NULL, &secs, NULL, NULL, -1)) return secs; return NULL; #else @@ -986,7 +992,7 @@ rktio_timestamp_t *rktio_get_file_modify_seconds(char *file) #endif } -int rktio_set_file_modify_seconds(char *file, rktio_timestamp_t secs) +int rktio_set_file_modify_seconds(rktio_t *rktio, char *file, rktio_timestamp_t secs) { while (1) { struct MSC_IZE(utimbuf) ut; @@ -1003,20 +1009,20 @@ int rktio_set_file_modify_seconds(char *file, rktio_timestamp_t secs) } #if defined(RKTIO_SYSTEM_UNIX) && !defined(NO_UNIX_USERS) -static int user_in_group(uid_t uid, gid_t gid) +static int user_in_group(rktio_t *rktio, uid_t uid, gid_t gid) { struct group *g; struct passwd *pw; int i, in; - if (!group_member_cache) - group_member_cache = calloc(GROUP_CACHE_SIZE, sizeof(group_member_cache_entry_t)); + if (!rktio->group_member_cache) + rktio->group_member_cache = calloc(GROUP_CACHE_SIZE, sizeof(group_member_cache_entry_t)); for (i = 0; i < GROUP_CACHE_SIZE; i++) { - if ((group_member_cache[i].state != GROUP_MEMBER_CACHE_STATE_UNUSED) - && (group_member_cache[i].gid == gid) - && (group_member_cache[i].uid == uid)) - return (group_member_cache[i].state == GROUP_MEMBER_CACHE_STATE_IN); + if ((rktio->group_member_cache[i].state != GROUP_MEMBER_CACHE_STATE_UNUSED) + && (rktio->group_member_cache[i].gid == gid) + && (rktio->group_member_cache[i].uid == uid)) + return (rktio->group_member_cache[i].state == GROUP_MEMBER_CACHE_STATE_IN); } pw = getpwuid(uid); @@ -1035,10 +1041,10 @@ static int user_in_group(uid_t uid, gid_t gid) in = !!(g->gr_mem[i]); for (i = 0; i < GROUP_CACHE_SIZE; i++) { - if (group_member_cache[i].state == GROUP_MEMBER_CACHE_STATE_UNUSED) { - group_member_cache[i].gid = gid; - group_member_cache[i].uid = uid; - group_member_cache[i].state = (in + if (rktio->group_member_cache[i].state == GROUP_MEMBER_CACHE_STATE_UNUSED) { + rktio->group_member_cache[i].gid = gid; + rktio->group_member_cache[i].uid = uid; + rktio->group_member_cache[i].state = (in ? GROUP_MEMBER_CACHE_STATE_IN : GROUP_MEMBER_CACHE_STATE_NOT_IN); break; @@ -1049,7 +1055,7 @@ static int user_in_group(uid_t uid, gid_t gid) } #endif -int rktio_get_file_or_directory_permissions(char *filename, int all_bits) +int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int all_bits) /* -1 result indicates an error */ { # ifdef NO_STAT_PROC @@ -1117,13 +1123,13 @@ int rktio_get_file_or_directory_permissions(char *filename, int all_bits) { /* Use stat, because setuid, or because or no user info available */ struct stat buf; - int ok, read, write, execute; + int cr, read, write, execute; do { - ok = stat(filename, &buf); - } while ((ok == -1) && (errno == EINTR)); + cr = stat(filename, &buf); + } while ((cr == -1) && (errno == EINTR)); - if (ok) { + if (cr) { get_posix_error(); return -1; } else { @@ -1145,7 +1151,7 @@ int rktio_get_file_or_directory_permissions(char *filename, int all_bits) read = !!(buf.st_mode & S_IRUSR); write = !!(buf.st_mode & S_IWUSR); execute = !!(buf.st_mode & S_IXUSR); - } else if ((egid == buf.st_gid) || user_in_group(euid, buf.st_gid)) { + } else if ((egid == buf.st_gid) || user_in_group(rktio, euid, buf.st_gid)) { read = !!(buf.st_mode & S_IRGRP); write = !!(buf.st_mode & S_IWGRP); execute = !!(buf.st_mode & S_IXGRP); @@ -1171,7 +1177,7 @@ int rktio_get_file_or_directory_permissions(char *filename, int all_bits) { int flags; - if (UNC_stat(filename, &flags, NULL, NULL, NULL, NULL, NULL, -1)) { + if (UNC_stat(rktio, filename, &flags, NULL, NULL, NULL, NULL, NULL, -1)) { if (as_bits) return (flags | (flags << 3) | (flags << 6)); else { @@ -1187,7 +1193,7 @@ int rktio_get_file_or_directory_permissions(char *filename, int all_bits) # endif } -int rktio_set_file_or_directory_permissions(char *filename, int new_bits) +int rktio_set_file_or_directory_permissions(rktio_t *rktio, char *filename, int new_bits) { # ifdef NO_STAT_PROC set_racket_error(RKTIO_ERROR_UNSUPPORTED); @@ -1221,7 +1227,7 @@ int rktio_set_file_or_directory_permissions(char *filename, int new_bits) return 0; } - if (UNC_stat(filename, NULL, NULL, NULL, NULL, NULL, NULL, new_bits)) + if (UNC_stat(rktio, filename, NULL, NULL, NULL, NULL, NULL, NULL, new_bits)) return 1; return 0; @@ -1230,12 +1236,12 @@ int rktio_set_file_or_directory_permissions(char *filename, int new_bits) # endif } -rktio_size_t *rktio_file_size(char *filename) +rktio_size_t *rktio_file_size(rktio_t *rktio, char *filename) { rktio_size_t *sz = NULL; #ifdef RKTIO_SYSTEM_WINDOWS { - if (UNC_stat(filename, NULL, NULL, NULL, NULL, &sz, NULL, -1)) { + if (UNC_stat(rktio, filename, NULL, NULL, NULL, NULL, &sz, NULL, -1)) { return sz; } return NULL; @@ -1281,7 +1287,7 @@ struct rktio_directory_list_t { FF_TYPE info; }; -rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive) +rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive) /* path must be normalized */ { char *pattern; @@ -1340,7 +1346,7 @@ rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive) if ((err_val == ERROR_DIRECTORY) && CreateSymbolicLinkProc) { /* check for symbolic link */ const char *resolved; - if (UNC_stat(filename, NULL, NULL, NULL, NULL, NULL, &resolved, -1)) { + if (UNC_stat(rktio, filename, NULL, NULL, NULL, NULL, NULL, &resolved, -1)) { if (resolved) { filename = (char *)resolved; goto retry; @@ -1358,7 +1364,7 @@ rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive) return dl; } -char *rktio_directory_list_step(rktio_directory_list_t *dl) +char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl) /* empty-strng result (don't deallocate) means done */ { while (dl->first_ready || FIND_NEXT(dl->hfile, &dl->info)) { @@ -1385,7 +1391,7 @@ struct rktio_directory_list_t { DIR *dir; }; -rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive) +rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive) { rktio_directory_list_t *dl; DIR *dir; @@ -1403,7 +1409,7 @@ rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive) return dl; } -char *rktio_directory_list_step(rktio_directory_list_t *dl) +char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl) /* empty-strng result (don't deallocate) means done */ { struct dirent *e; @@ -1437,13 +1443,13 @@ char *rktio_directory_list_step(rktio_directory_list_t *dl) #else -rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive) +rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive) { set_racket_error(RKTIO_ERROR_UNSUPPORTED); return NULL; } -char *rktio_directory_list_step(rktio_directory_list_t *dl) +char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl) { set_racket_error(RKTIO_ERROR_UNSUPPORTED); return NULL; @@ -1460,7 +1466,7 @@ struct rktio_file_copy_t { rktio_fd_t *src_fd, *dest_fd; }; -rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok) +rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, char *dest, char *src, int exists_ok) { #ifdef RKTIO_SYSTEM_UNIX { @@ -1469,12 +1475,12 @@ rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok) struct stat buf; rktio_fd_t *src_fd, *dest_fd; - src_fd = rktio_open(src, RKTIO_OPEN_READ); + src_fd = rktio_open(rktio, src, RKTIO_OPEN_READ); if (!src_fd) return NULL; do { - ok = fstat(rktio_fd_system_fd(src_fd), &buf); + ok = fstat(rktio_fd_system_fd(rktio, src_fd), &buf); } while ((ok == -1) && (errno == EINTR)); if (ok || S_ISDIR(buf.st_mode)) { @@ -1482,14 +1488,14 @@ rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok) get_posix_error(); else set_racket_error(RKTIO_ERROR_IS_A_DIRECTORY); - rktio_close(src_fd); + rktio_close(rktio, src_fd); return NULL; } - dest_fd = rktio_open(dest, (RKTIO_OPEN_WRITE - | (exists_ok ? RKTIO_OPEN_TRUNCATE : 0))); + dest_fd = rktio_open(rktio, dest, (RKTIO_OPEN_WRITE + | (exists_ok ? RKTIO_OPEN_TRUNCATE : 0))); if (!dest_fd) { - rktio_close(src_fd); + rktio_close(rktio, src_fd); return NULL; } @@ -1532,12 +1538,12 @@ rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok) #endif } -int rktio_copy_file_is_done(rktio_file_copy_t *fc) +int rktio_copy_file_is_done(rktio_t *rktio, rktio_file_copy_t *fc) { return fc->done; } -int rktio_copy_file_step(rktio_file_copy_t *fc) +int rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc) { #ifdef RKTIO_SYSTEM_UNIX char buffer[4096]; @@ -1546,7 +1552,7 @@ int rktio_copy_file_step(rktio_file_copy_t *fc) if (fc->done) return 1; - len = rktio_read(fc->src_fd, buffer, sizeof(buffer)); + len = rktio_read(rktio, fc->src_fd, buffer, sizeof(buffer)); if (len == RKTIO_READ_EOF) { fc->done = 1; return 1; @@ -1556,7 +1562,7 @@ int rktio_copy_file_step(rktio_file_copy_t *fc) intptr_t done = 0, amt; while (done < len) { - amt = rktio_write(fc->dest_fd, buffer + done, len - done); + amt = rktio_write(rktio, fc->dest_fd, buffer + done, len - done); if (amt < 0) return 0; done += amt; @@ -1569,11 +1575,11 @@ int rktio_copy_file_step(rktio_file_copy_t *fc) #endif } -void rktio_copy_file_stop(rktio_file_copy_t *fc) +void rktio_copy_file_stop(rktio_t *rktio, rktio_file_copy_t *fc) { #ifdef RKTIO_SYSTEM_UNIX - rktio_close(fc->src_fd); - rktio_close(fc->dest_fd); + rktio_close(rktio, fc->src_fd); + rktio_close(rktio, fc->dest_fd); #endif free(fc); } @@ -1582,7 +1588,7 @@ void rktio_copy_file_stop(rktio_file_copy_t *fc) /* filesystem root list */ /*************************************************************/ -char **rktio_filesystem_root_list(void) +char **rktio_filesystem_root_list(rktio_t *rktio) /* returns a NULL-terminated array of strings */ { #ifdef RKTIO_SYSTEM_WINDOWS @@ -1645,7 +1651,7 @@ char **rktio_filesystem_root_list(void) /* expand user tilde & system paths */ /*************************************************************/ -char *rktio_expand_user_tilde(char *filename) { +char *rktio_expand_user_tilde(rktio_t *rktio, char *filename) { #ifdef RKTIO_SYSTEM_WINDOWS set_racket_error(RKTIO_ERROR_UNSUPPORTED); return NULL; @@ -1737,7 +1743,7 @@ static char *append_paths(char *a, char *b, int free_a, int free_b) return s; } -char *rktio_system_path(int which) +char *rktio_system_path(rktio_t *rktio, int which) { #ifdef RKTIO_SYSTEM_UNIX if (which == RKTIO_PATH_SYS_DIR) { @@ -1748,20 +1754,20 @@ char *rktio_system_path(int which) char *p; if ((p = getenv("TMPDIR"))) { - if (rktio_directory_exists(p)) + if (rktio_directory_exists(rktio, p)) return strdup(p); } - if (rktio_directory_exists("/var/tmp")) + if (rktio_directory_exists(rktio, "/var/tmp")) return strdup("/var/tmp"); - if (rktio_directory_exists("/usr/tmp")) + if (rktio_directory_exists(rktio, "/usr/tmp")) return strdup("/usr/tmp"); - if (rktio_directory_exists("/tmp")) + if (rktio_directory_exists(rktio, "/tmp")) return strdup("/tmp"); - return rktio_get_current_directory(); + return rktio_get_current_directory(rktio); } { @@ -1797,7 +1803,7 @@ char *rktio_system_path(int which) if (alt_home) home = append_paths(alt_home, home_str + 2, 0, 0); else { - home = rktio_expand_user_tilde(home_str); + home = rktio_expand_user_tilde(rktio, home_str); if (!home) { /* Something went wrong with the user lookup. Just drop "~'. */ diff --git a/racket/src/rktio/rktio_main.c b/racket/src/rktio/rktio_main.c new file mode 100644 index 0000000000..78712d3564 --- /dev/null +++ b/racket/src/rktio/rktio_main.c @@ -0,0 +1,33 @@ +#include "rktio.h" +#include "rktio_private.h" +#include +#include + +rktio_t *rktio_init(void) +{ + rktio_t *rktio; + + rktio = malloc(sizeof(rktio_t)); + memset(rktio, 0, sizeof(rktio_t)); + + rktio_alloc_global_poll_set(rktio); + if (!rktio_initialize_signal(rktio)) { + rktio_destroy(rktio); + return NULL; + } + + return rktio; +} + +void rktio_destroy(rktio_t *rktio) +{ + free(rktio); +} + +/* Useful on Windows to make sure everyone is using the same malloc() + and fre(): */ +void rktio_free(void *p) +{ + free(p); +} + diff --git a/racket/src/rktio/rktio_poll_set.c b/racket/src/rktio/rktio_poll_set.c index a1c8649503..2a93e133c1 100644 --- a/racket/src/rktio/rktio_poll_set.c +++ b/racket/src/rktio/rktio_poll_set.c @@ -3,6 +3,9 @@ #ifdef RKTIO_SYSTEM_UNIX # include # include +# include +# include +# include #endif #ifdef RKTIO_SYSTEM_WINDOWS # include @@ -13,13 +16,9 @@ special hooks for Windows "descriptors" like even queues and semaphores, etc. */ +void rktio_alloc_global_poll_set(rktio_t *rktio) { #ifdef USE_FAR_RKTIO_FDCALLS -THREAD_LOCAL_DECL(rktio_poll_set_t *rktio_global_poll_set); -#endif - -void rktio_alloc_global_poll_set() { -#ifdef USE_FAR_RKTIO_FDCALLS - rktio_global_poll_set = rktio_alloc_fdset_array(3); + rktio->rktio_global_poll_set = rktio_alloc_fdset_array(3); #endif } @@ -777,3 +776,362 @@ int rktio_get_fd_limit(rktio_poll_set_t *fds) } #endif + +/************************************************************/ +/* Sleeping as a generalized select() */ +/************************************************************/ + +int rktio_initialize_signal(rktio_t *rktio) +{ +#ifdef RKTIO_SYSTEM_UNIX + /* Set up a pipe for signaling external events: */ + int fds[2]; + if (!pipe(fds)) { + rktio->external_event_fd = fds[0]; + rktio->put_external_event_fd = fds[1]; + fcntl(rktio->external_event_fd, F_SETFL, RKTIO_NONBLOCKING); + fcntl(rktio->put_external_event_fd, F_SETFL, RKTIO_NONBLOCKING); + return 1; + } else { + set_racket_error(RKTIO_ERROR_INIT_FAILED); + return 0; + } +#endif + +#ifdef WIN32_FD_HANDLES + break_semaphore = (void*)CreateSemaphore(NULL, 0, 1, NULL); +#endif +} + +rktio_signal_handle_t *rktio_get_signal_handle(rktio_t *rktio) +{ +#ifdef RKTIO_SYSTEM_UNIX + return (rktio_signal_handle_t *)&rktio->put_external_event_fd; +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + return (rktio_signal_handle_t *)rktio->break_semaphore; +#endif +} + +void rktio_signal_received(rktio_t *rktio) +{ + rktio_signal_received_at(rktio_get_signal_handle(rktio)); +} + +void rktio_signal_received_at(rktio_signal_handle_t *h) +{ +#ifdef RKTIO_SYSTEM_UNIX + 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 +#ifdef RKTIO_SYSTEM_WINDOWS + ReleaseSemaphore(*(HANDLE *)h, 1, NULL); +#endif +} + +static void clear_signal(rktio_t *rktio) +{ +#ifdef RKTIO_SYSTEM_UNIX + /* Clear external event flag */ + if (rktio->external_event_fd) { + int rc; + char buf[10]; + do { + rc = read(rktio->external_event_fd, buf, 10); + } while ((rc == -1) && errno == EINTR); + } +#endif +} + +void rktio_wait_until_signal_received(rktio_t *rktio) +{ +#ifdef RKTIO_SYSTEM_UNIX + int r; +# ifdef HAVE_POLL_SYSCALL + GC_CAN_IGNORE struct pollfd pfd[1]; + pfd[0].fd = rktio->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); + + RKTIO_FD_ZERO(readfds); + RKTIO_FD_SET(rktio->external_event_fd, readfds); + + do { + r = select(rktio->external_event_fd + 1, RKTIO_FDS(readfds), NULL, NULL, NULL); + } while ((r == -1) && (errno == EINTR)); +# endif +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + WaitForSingleObject(rktio->break_semaphore, INFINITE); +#endif + + clear_signal(rktio); +} + +/****************** Windows cleanup *****************/ + +#if RKTIO_SYSTEM_WINDOWS + +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 rkio_notify_sleep_progress(void) +{ + made_progress = 1; +} + +#else + +void rkio_notify_sleep_progress(void) +{ +} + +#endif + +/******************** Main sleep function *****************/ +/* The simple select() stuff is buried in various kinds of complexity. */ + +/* FIXME: don't forget SIGCHILD_DOESNT_INTERRUPT_SELECT handling in Racket */ + +void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds) +{ + if (!fds) { + /* Nothing to block on - just sleep for some amount of time. */ +#ifdef RKTIO_SYSTEM_UNIX +# ifdef HAVE_POLL_SYSCALL + int timeout; + if (nsecs <= 0.0) + timeout = -1; + else { + timeout = (int)(nsecs * 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)nsecs; + intptr_t usecs = (intptr_t)(fmod(nsecs, 1.0) * 1000000); + + if (nsecs && (nsecs > 100000)) + secs = 100000; + if (usecs < 0) + usecs = 0; + if (usecs >= 1000000) + usecs = 999999; + + time.tv_sec = secs; + time.tv_usec = usecs; + + if (rktio->external_event_fd) { + DECL_FDSET(readfds, 1); + + INIT_DECL_RD_FDSET(readfds); + + RKTIO_FD_ZERO(readfds); + RKTIO_FD_SET(rktio->external_event_fd, readfds); + + select(rktio->external_event_fd + 1, RKTIO_FDS(readfds), NULL, NULL, &time); + } else { + select(0, NULL, NULL, NULL, &time); + } +# endif +#else +# ifndef NO_SLEEP +# ifndef NO_USLEEP + usleep((unsigned)(nsecs * 1000)); +# else + sleep(nsecs); +# endif +# endif +#endif + } else { + /* Something to block on.... */ + +#ifdef HAVE_POLL_SYSCALL + + /******* poll() variant *******/ + + { + struct mz_fd_set_data_t *data = fds->data; + intptr_t count = 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); + } +#elif !defined(RKTIO_SYSTEM_WINDOWS) + + /******* select() variant *******/ + + { + int actual_limit; + fd_set *rd, *wr, *ex; + struct timeval time; + intptr_t secs = (intptr_t)nsecs; + intptr_t usecs = (intptr_t)(fmod(nsecs, 1.0) * 1000000); + + if (nsecs && (nsecs > 100000)) + secs = 100000; + if (usecs < 0) + usecs = 0; + if (usecs >= 1000000) + usecs = 999999; + + time.tv_sec = secs; + time.tv_usec = usecs; + + rd = RKTIO_FDS(fds); + wr = RKTIO_FDS(RKTIO_GET_FDSET(fds, 1)); + ex = RKTIO_FDS(RKTIO_GET_FDSET(fds, 2)); + + actual_limit = rktio_get_fd_limit(fds); + + /* Watch for external events, too: */ + if (rktio->external_event_fd) { + FD_SET(rktio->external_event_fd, rd); + if (rktio->external_event_fd >= actual_limit) + actual_limit = rktio->external_event_fd + 1; + } + + select(actual_limit, rd, wr, ex, nsecs ? &time : NULL); + } + +#else + + /******* Windows variant *******/ + + { + intptr_t result; + HANDLE *array, just_two_array[2], break_sema; + int count, rcount, *rps; + + if (fds->no_sleep) + return; + + scheme_collapse_win_fd(fds); /* merges */ + + rcount = fds->num_handles; + count = fds->combined_len; + array = fds->combined_wait_array; + rps = 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 (nsecs) { + if (nsecs > 100000) + msec = 100000000; + else + msec = (DWORD)(nsecs * 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 + } + + clear_signal(rktio); +} diff --git a/racket/src/rktio/rktio_private.h b/racket/src/rktio/rktio_private.h index 6aca9a7e02..0f2d4526b5 100644 --- a/racket/src/rktio/rktio_private.h +++ b/racket/src/rktio/rktio_private.h @@ -1,33 +1,15 @@ -#if ((defined(_MSC_VER) || defined(__MINGW32__)) \ +#if ((defined(_MSC_VER) || defined(__MINGW32__)) \ && (defined(__WIN32__) || defined(WIN32) || defined(_WIN32))) # define RKTIO_SYSTEM_WINDOWS -# define MSC_IZE(n) _ ## n -# define MSC_W_IZE(n) _w ## n -# define MSC_WIDE_PATH_temp(n) WIDE_PATH_temp(n) #else # define RKTIO_SYSTEM_UNIX -# define MSC_IZE(n) n -# define MSC_W_IZE(n) MSC_IZE(n) -# define MSC_WIDE_PATH_temp(n) n #endif -#define THREAD_LOCAL_DECL(decl) decl - -void rktio_get_posix_error(void); -#define get_posix_error() rktio_get_posix_error() - -void rktio_set_racket_error(int errid); -#define set_racket_error(e) rktio_set_racket_error(e) #ifdef RKTIO_SYSTEM_WINDOWS -void rktio_get_windows_error(void); -# define get_windows_error() rktio_get_windows_error() +# include #endif -/*******************************************************************/ - -typedef struct rktio_poll_set_t rktio_poll_set_t; - #if RKTIO_SYSTEM_WINDOWS # define USE_FAR_RKTIO_FDCALLS #endif @@ -38,19 +20,47 @@ typedef struct rktio_poll_set_t rktio_poll_set_t; # define USE_FAR_RKTIO_FDCALLS #endif -#ifdef USE_FAR_RKTIO_FDCALLS -/* A single fdset that can be reused for immediate actions: */ -THREAD_LOCAL_DECL(extern rktio_poll_set_t *rktio_global_fd_set); +/************************************************************/ +/* Globals, as gathered into `rktio_t` */ +/************************************************************/ +struct rktio_t { + intptr_t errid; + int errkind; +#ifdef RKTIO_SYSTEM_UNIX + struct group_member_cache_entry_t *group_member_cache; + int external_event_fd; + int put_external_event_fd; +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + int windows_nt_or_later; + HANDLE break_semaphore; +#endif +#ifdef USE_FAR_RKTIO_FDCALLS + /* A single fdset that can be reused for immediate actions: */ + struct rktio_poll_set_t *rktio_global_fd_set; +#endif +}; + +/************************************************************/ +/* Poll sets */ +/************************************************************/ + +typedef struct rktio_poll_set_t rktio_poll_set_t; + +void rktio_alloc_global_poll_set(rktio_t *rktio); +int rktio_initialize_signal(rktio_t *rktio); + +#ifdef USE_FAR_RKTIO_FDCALLS # define DECL_FDSET(n, c) fd_set *n # define INIT_DECL_FDSET(r, w, e) { \ - r = RKTIO_GET_FDSET(rktio_global_poll_set, 0 ); \ - w = RKTIO_GET_FDSET(rktio_global_poll_set, 1 ); \ - e = RKTIO_GET_FDSET(rktio_global_poll_set, 2 ); \ + r = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 0 ); \ + w = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 1 ); \ + e = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 2 ); \ } -# define INIT_DECL_RD_FDSET(r) r = RKTIO_GET_FDSET(rktio_global_poll_set, 0 ) -# define INIT_DECL_WR_FDSET(r) r = RKTIO_GET_FDSET(rktio_global_poll_set, 1 ) -# define INIT_DECL_ER_FDSET(r) r = RKTIO_GET_FDSET(rktio_global_poll_set, 2 ) +# define INIT_DECL_RD_FDSET(r) r = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 0 ) +# define INIT_DECL_WR_FDSET(r) r = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 1 ) +# define INIT_DECL_ER_FDSET(r) r = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 2 ) # define RKTIO_GET_FDSET(p, n) rktio_get_fdset(p, n) # define RKTIO_FD_ZERO(p) rktio_fdzero(p) @@ -58,6 +68,10 @@ THREAD_LOCAL_DECL(extern rktio_poll_set_t *rktio_global_fd_set); # define RKTIO_FD_CLR(n, p) rktio_fdclr(p, n) # define RKTIO_FD_ISSET(n, p) rktio_fdisset(p, n) +# if !defined(HAVE_POLL_SYSCALL) && !defined(RKTIO_SYSTEM_WINDOWS) +# define RKTIO_FDS(p) ((fd_set *)fds) +# endif + #else #include @@ -82,3 +96,34 @@ struct rktio_poll_set_t { fd_set data; }; rktio_poll_set_t *rktio_merge_fd_sets(rktio_poll_set_t *fds, rktio_poll_set_t *src_fds); void rktio_clean_fd_set(rktio_poll_set_t *fds); int rktio_get_fd_limit(rktio_poll_set_t *fds); + +/************************************************************/ +/* Misc */ +/************************************************************/ + +#ifdef RKTIO_SYSTEM_WINDOWS +# define MSC_IZE(n) _ ## n +# define MSC_W_IZE(n) _w ## n +# define MSC_WIDE_PATH_temp(n) WIDE_PATH_temp(n) +#else +# define MSC_IZE(n) n +# define MSC_W_IZE(n) MSC_IZE(n) +# define MSC_WIDE_PATH_temp(n) n +#endif + +void rktio_get_posix_error(rktio_t *rktio); +#define get_posix_error() rktio_get_posix_error(rktio) + +void rktio_set_racket_error(rktio_t *rktio, int errid); +#define set_racket_error(e) rktio_set_racket_error(rktio, e) + +#ifdef RKTIO_SYSTEM_WINDOWS +void rktio_get_windows_error(rktio_t *rktio); +# define get_windows_error() rktio_get_windows_error(rktio) +#endif + +#if defined(USE_FCNTL_O_NONBLOCK) +# define RKTIO_NONBLOCKING O_NONBLOCK +#else +# define RKTIO_NONBLOCKING FNDELAY +#endif diff --git a/racket/src/rktio/rktio_read_write.c b/racket/src/rktio/rktio_read_write.c index e3095208ad..6f30838923 100644 --- a/racket/src/rktio/rktio_read_write.c +++ b/racket/src/rktio/rktio_read_write.c @@ -12,12 +12,6 @@ # include #endif -#if defined(USE_FCNTL_O_NONBLOCK) -# define RKTIO_NONBLOCKING O_NONBLOCK -#else -# define RKTIO_NONBLOCKING FNDELAY -#endif - #ifndef RKTIO_BINARY # define RKTIO_BINARY 0 #endif @@ -97,7 +91,7 @@ static void init_read_fd(rktio_fd_t *rfd) #endif } -rktio_fd_t *rktio_system_fd(intptr_t system_fd, int modes) +rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes) { rktio_fd_t *rfd; @@ -128,7 +122,7 @@ rktio_fd_t *rktio_system_fd(intptr_t system_fd, int modes) return rfd; } -intptr_t rktio_fd_system_fd(rktio_fd_t *rfd) +intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd) { return rfd->fd; } @@ -137,7 +131,7 @@ intptr_t rktio_fd_system_fd(rktio_fd_t *rfd) /* opening a file fd */ /*************************************************************/ -static rktio_fd_t *open_read(char *filename) +static rktio_fd_t *open_read(rktio_t *rktio, char *filename) { #ifdef RKTIO_SYSTEM_UNIX int fd; @@ -212,7 +206,7 @@ static rktio_fd_t *open_read(char *filename) #endif } -static rktio_fd_t *open_write(char *filename, int modes) +static rktio_fd_t *open_write(rktio_t *rktio, char *filename, int modes) { #ifdef RKTIO_SYSTEM_UNIX int fd; @@ -369,19 +363,19 @@ static rktio_fd_t *open_write(char *filename, int modes) #endif } -rktio_fd_t *rktio_open(char *filename, int modes) +rktio_fd_t *rktio_open(rktio_t *rktio, char *filename, int modes) { if (modes & RKTIO_OPEN_WRITE) - return open_write(filename, modes); + return open_write(rktio, filename, modes); else - return open_read(filename); + return open_read(rktio, filename); } /*************************************************************/ /* closing */ /*************************************************************/ -int rktio_close(rktio_fd_t *rfd) +int rktio_close(rktio_t *rktio, rktio_fd_t *rfd) { #ifdef RKTIO_SYSTEM_UNIX int cr; @@ -483,7 +477,7 @@ static int try_get_fd_char(int fd, int *ready) } #endif -int rktio_poll_read_ready(rktio_fd_t *rfd) +int rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd) { if (rfd->regfile) return 1; @@ -573,7 +567,7 @@ int rktio_poll_read_ready(rktio_fd_t *rfd) #endif } -int poll_write_ready_or_flushed(rktio_fd_t *rfd, int check_flushed) +int poll_write_ready_or_flushed(rktio_t *rktio, rktio_fd_t *rfd, int check_flushed) { #ifdef RKTIO_SYSTEM_UNIX if (check_flushed) @@ -645,17 +639,17 @@ int poll_write_ready_or_flushed(rktio_fd_t *rfd, int check_flushed) #endif } -int rktio_poll_write_ready(rktio_fd_t *rfd) +int rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd) { - return poll_write_ready_or_flushed(rfd, 0); + return poll_write_ready_or_flushed(rktio, rfd, 0); } -int rktio_poll_write_flushed(rktio_fd_t *rfd) +int rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd) { - return poll_write_ready_or_flushed(rfd, 1); + return poll_write_ready_or_flushed(rktio, rfd, 1); } -void rktio_poll_add(rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes) +void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes) { #ifdef RKTIO_SYSTEM_UNIX rktio_poll_set_t *fds2; @@ -708,7 +702,7 @@ void rktio_poll_add(rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes) /* reading */ /*************************************************************/ -intptr_t rktio_read(rktio_fd_t *rfd, char *buffer, intptr_t len) +intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len) { #ifdef RKTIO_SYSTEM_UNIX intptr_t bc; @@ -875,10 +869,10 @@ static void WindowsFDICleanup(Win_FD_Input_Thread *th) /* writing */ /*************************************************************/ -intptr_t rktio_write(rktio_fd_t *rfd, char *buffer, intptr_t len) +intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len) { #ifdef RKTIO_SYSTEM_UNIX - int flags; + int flags, errsaved; intptr_t amt; flags = fcntl(rfd->fd, F_GETFL, 0); @@ -898,15 +892,20 @@ intptr_t rktio_write(rktio_fd_t *rfd, char *buffer, intptr_t len) amt = amt >> 1; } while ((len == -1) && (errno == EAGAIN) && (amt > 0)); - if (len == -1) + if (len == -1) { + errsaved = errno; get_posix_error(); + } if (!(flags & RKTIO_NONBLOCKING)) fcntl(rfd->fd, F_SETFL, flags); - if (len == -1) - return RKTIO_WRITE_ERROR; - else + if (len == -1) { + if (errsaved == EAGAIN) + return 0; + else + return RKTIO_WRITE_ERROR; + } else return len; #endif #ifdef RKTIO_SYSTEM_WINDOWS diff --git a/racket/src/rktio/rktio_sleep.c b/racket/src/rktio/rktio_sleep.c new file mode 100644 index 0000000000..e69de29bb2