rktio: repairs for Windows

Might break other systems...
This commit is contained in:
Matthew Flatt 2017-06-17 09:20:41 -06:00
parent 773050805b
commit 1e0a55cc8f
22 changed files with 603 additions and 359 deletions

View File

@ -62,7 +62,9 @@ START_XFORM_SUSPEND;
#endif #endif
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #ifndef DOS_FILE_SYSTEM
# include <sys/time.h>
#endif
#ifndef NO_USER_BREAK_HANDLER #ifndef NO_USER_BREAK_HANDLER
# include <signal.h> # include <signal.h>
#endif #endif

View File

@ -200,8 +200,6 @@ static int do_main_stack_setup(int no_auto_statics, Scheme_Nested_Main _main, vo
#endif #endif
scheme_set_stack_base(PROMPT_STACK(stack_start), no_auto_statics); scheme_set_stack_base(PROMPT_STACK(stack_start), no_auto_statics);
scheme_rktio = rktio_init();
return_code = _main(data); return_code = _main(data);
@ -320,6 +318,7 @@ int scheme_main_stack_setup(int no_auto_statics, Scheme_Nested_Main _main, void
{ {
scheme_setup_thread_local_key_if_needed(); scheme_setup_thread_local_key_if_needed();
scheme_init_os_thread(); scheme_init_os_thread();
scheme_rktio = rktio_init();
#ifdef MZ_USE_MZRT #ifdef MZ_USE_MZRT
scheme_init_glib_log_queue(); scheme_init_glib_log_queue();
#endif #endif

View File

@ -184,14 +184,24 @@ static void check_hello_content(rktio_t *rktio, char *fn)
static void wait_read(rktio_t *rktio, rktio_fd_t *fd) static void wait_read(rktio_t *rktio, rktio_fd_t *fd)
{ {
rktio_poll_set_t *ps; while (rktio_poll_read_ready(rktio, fd) == RKTIO_POLL_NOT_READY) {
ps = rktio_make_poll_set(rktio); rktio_poll_set_t *ps;
check_valid(ps); ps = rktio_make_poll_set(rktio);
rktio_poll_add(rktio, fd, ps, RKTIO_POLL_READ); check_valid(ps);
rktio_sleep(rktio, 0, ps, NULL); rktio_poll_add(rktio, fd, ps, RKTIO_POLL_READ);
rktio_poll_set_forget(rktio, ps); rktio_sleep(rktio, 0, ps, NULL);
rktio_poll_set_forget(rktio, ps);
}
} }
/* On Unix, we expect writing to a pipe to make the bytes
immediately available. On Windows, we expect a delay. */
#ifdef RKTIO_SYSTEM_UNIX
# define PIPE_IMMEDIATELY_READY 1
#else
# define PIPE_IMMEDIATELY_READY 0
#endif
static void check_read_write_pair(rktio_t *rktio, rktio_fd_t *fd, rktio_fd_t *fd2, int immediate_available) static void check_read_write_pair(rktio_t *rktio, rktio_fd_t *fd, rktio_fd_t *fd2, int immediate_available)
{ {
rktio_ltps_t *lt; rktio_ltps_t *lt;
@ -217,16 +227,16 @@ static void check_read_write_pair(rktio_t *rktio, rktio_fd_t *fd, rktio_fd_t *fd
/* Round-trip data through pipe: */ /* Round-trip data through pipe: */
if (rktio_fd_is_udp(rktio, fd2)) { if (rktio_fd_is_udp(rktio, fd2)) {
amt = rktio_udp_sendto(rktio, fd2, NULL, "hello", 5); amt = rktio_udp_sendto(rktio, fd2, NULL, "hola\n", 5);
} else } else
amt = rktio_write(rktio, fd2, "hello", 5); amt = rktio_write(rktio, fd2, "hola\n", 5);
check_valid(amt == 5); check_valid(amt == 5);
if (!immediate_available) { if (!immediate_available) {
/* Wait for read to be ready; should not block for long */ /* Wait for read to be ready; should not block for long */
wait_read(rktio, fd); wait_read(rktio, fd);
} }
check_valid(rktio_poll_read_ready(rktio, fd) == RKTIO_POLL_READY); check_valid(rktio_poll_read_ready(rktio, fd) == RKTIO_POLL_READY);
if (lt) { if (lt) {
check_ltps_read_ready(rktio, lt, h1); check_ltps_read_ready(rktio, lt, h1);
@ -249,7 +259,7 @@ static void check_read_write_pair(rktio_t *rktio, rktio_fd_t *fd, rktio_fd_t *fd
} else } else
amt = rktio_read(rktio, fd, buffer, sizeof(buffer)); amt = rktio_read(rktio, fd, buffer, sizeof(buffer));
check_valid(amt == 5); check_valid(amt == 5);
check_valid(!strncmp(buffer, "hello", 5)); check_valid(!strncmp(buffer, "hola\n", 5));
check_valid(!rktio_poll_read_ready(rktio, fd)); check_valid(!rktio_poll_read_ready(rktio, fd));
/* Close pipe ends: */ /* Close pipe ends: */
@ -271,10 +281,11 @@ static void check_read_write_pair(rktio_t *rktio, rktio_fd_t *fd, rktio_fd_t *fd
#define AMOUNT_TO_WRITE_AND_BLOCK 1000000 #define AMOUNT_TO_WRITE_AND_BLOCK 1000000
#define AMOUNT_FOR_UDP 1000 #define AMOUNT_FOR_UDP 1000
static void check_fill_write(rktio_t *rktio, rktio_fd_t *fd2, rktio_addrinfo_t *dest_addr, intptr_t limit) static void check_fill_write(rktio_t *rktio, rktio_fd_t *fd2, rktio_addrinfo_t *dest_addr, intptr_t limit, int verbose)
{ {
intptr_t i, amt; intptr_t i, amt;
int r;
if (!limit) if (!limit)
limit = AMOUNT_TO_WRITE_AND_BLOCK; limit = AMOUNT_TO_WRITE_AND_BLOCK;
@ -287,13 +298,43 @@ static void check_fill_write(rktio_t *rktio, rktio_fd_t *fd2, rktio_addrinfo_t *
check_valid(amt != RKTIO_WRITE_ERROR); check_valid(amt != RKTIO_WRITE_ERROR);
if (!amt) if (!amt)
break; break;
if (amt == RKTIO_WRITE_ERROR)
break;
} }
check_valid(i > 0); check_valid(i > 0);
if (!rktio_fd_is_udp(rktio, fd2)) if (!rktio_fd_is_udp(rktio, fd2))
check_valid(i < limit); check_valid(i < limit);
if (verbose)
printf(" write full after %ld\n", (long)i);
#ifdef RKTIO_SYSTEM_WINDOWS
if (rktio_fd_is_socket(rktio, fd2)) {
check_valid(rktio_poll_write_flushed(rktio, fd2) == RKTIO_POLL_READY);
} else {
/* pipe needs reader to count as flushed */
check_valid(rktio_poll_write_flushed(rktio, fd2) == RKTIO_POLL_NOT_READY);
{
/* Make sure that flushing doesn't claim to finish even if
we sleep for a while, because flushing on Windows means
data is received by the other end. */
rktio_poll_set_t *ps;
double start;
ps = rktio_make_poll_set(rktio);
check_valid(ps);
rktio_poll_add(rktio, fd2, ps, RKTIO_POLL_FLUSH);
start = rktio_get_inexact_milliseconds();
rktio_sleep(rktio, 0.1, ps, NULL);
check_valid(rktio_get_inexact_milliseconds() - start > 0.1);
rktio_poll_set_forget(rktio, ps);
check_valid(rktio_poll_write_flushed(rktio, fd2) == RKTIO_POLL_NOT_READY);
}
}
#else
check_valid(rktio_poll_write_flushed(rktio, fd2) == RKTIO_POLL_READY);
#endif
} }
static void check_drain_read(rktio_t *rktio, rktio_fd_t *fd2, intptr_t limit) static void check_drain_read(rktio_t *rktio, rktio_fd_t *fd2, intptr_t limit, int verbose)
{ {
intptr_t i, amt; intptr_t i, amt;
char buffer[256]; char buffer[256];
@ -311,6 +352,8 @@ static void check_drain_read(rktio_t *rktio, rktio_fd_t *fd2, intptr_t limit)
} }
check_valid(i > 0); check_valid(i > 0);
check_valid(i < limit); check_valid(i < limit);
if (verbose)
printf(" read empty after %ld\n", (long)i);
} }
void check_many_lookup(rktio_t *rktio) void check_many_lookup(rktio_t *rktio)
@ -329,7 +372,7 @@ void check_many_lookup(rktio_t *rktio)
check_valid(lookup[i]); check_valid(lookup[i]);
} }
for (j = 0; j < LOOKUPS_N; j++) { for (j = 0; j < LOOKUPS_N; ) {
ps = rktio_make_poll_set(rktio); ps = rktio_make_poll_set(rktio);
check_valid(ps); check_valid(ps);
@ -343,6 +386,7 @@ void check_many_lookup(rktio_t *rktio)
for (i = 0; i < LOOKUPS_N; i++) { for (i = 0; i < LOOKUPS_N; i++) {
if (lookup[i] && (rktio_poll_addrinfo_lookup_ready(rktio, lookup[i]) == RKTIO_POLL_READY)) { if (lookup[i] && (rktio_poll_addrinfo_lookup_ready(rktio, lookup[i]) == RKTIO_POLL_READY)) {
j++;
if ((i % 3) == 2) if ((i % 3) == 2)
rktio_addrinfo_lookup_stop(rktio, lookup[i]); rktio_addrinfo_lookup_stop(rktio, lookup[i]);
else { else {
@ -351,7 +395,6 @@ void check_many_lookup(rktio_t *rktio)
rktio_addrinfo_free(rktio, addr); rktio_addrinfo_free(rktio, addr);
} }
lookup[i] = NULL; lookup[i] = NULL;
break;
} }
} }
} }
@ -363,17 +406,20 @@ rktio_addrinfo_t *lookup_loop(rktio_t *rktio,
{ {
rktio_addrinfo_lookup_t *lookup; rktio_addrinfo_lookup_t *lookup;
rktio_addrinfo_t *addr; rktio_addrinfo_t *addr;
rktio_poll_set_t *ps;
ps = rktio_make_poll_set(rktio);
check_valid(ps);
lookup = rktio_start_addrinfo_lookup(rktio, hostname, portno, family, passive, tcp); lookup = rktio_start_addrinfo_lookup(rktio, hostname, portno, family, passive, tcp);
check_valid(lookup); check_valid(lookup);
rktio_poll_add_addrinfo_lookup(rktio, lookup, ps); while (rktio_poll_addrinfo_lookup_ready(rktio, lookup) == RKTIO_POLL_NOT_READY) {
rktio_sleep(rktio, 0, ps, NULL); rktio_poll_set_t *ps;
rktio_poll_set_forget(rktio, ps); ps = rktio_make_poll_set(rktio);
check_valid(ps);
rktio_poll_add_addrinfo_lookup(rktio, lookup, ps);
rktio_sleep(rktio, 0, ps, NULL);
rktio_poll_set_forget(rktio, ps);
}
check_valid(rktio_poll_addrinfo_lookup_ready(rktio, lookup) == RKTIO_POLL_READY); check_valid(rktio_poll_addrinfo_lookup_ready(rktio, lookup) == RKTIO_POLL_READY);
addr = rktio_addrinfo_lookup_get(rktio, lookup); addr = rktio_addrinfo_lookup_get(rktio, lookup);
@ -408,12 +454,12 @@ static rktio_fd_t *connect_loop(rktio_t *rktio, rktio_addrinfo_t *addr, rktio_ad
{ {
rktio_connect_t *conn; rktio_connect_t *conn;
rktio_poll_set_t *ps; rktio_poll_set_t *ps;
rktio_fd_t *fd; rktio_fd_t *fd = NULL;
conn = rktio_start_connect(rktio, addr, local_addr); conn = rktio_start_connect(rktio, addr, local_addr);
check_valid(conn); check_valid(conn);
while (1) { while (!fd) {
ps = rktio_make_poll_set(rktio); ps = rktio_make_poll_set(rktio);
check_valid(ps); check_valid(ps);
@ -428,10 +474,10 @@ static rktio_fd_t *connect_loop(rktio_t *rktio, rktio_addrinfo_t *addr, rktio_ad
&& (rktio_get_last_error(rktio) == RKTIO_ERROR_CONNECT_TRYING_NEXT)) { && (rktio_get_last_error(rktio) == RKTIO_ERROR_CONNECT_TRYING_NEXT)) {
/* loop to try again */ /* loop to try again */
} else { } else {
/* report other error: */
check_valid(fd); check_valid(fd);
} }
} else }
break;
} }
return fd; return fd;
@ -541,9 +587,17 @@ int main(int argc, char **argv)
check_valid(perms != -1); check_valid(perms != -1);
check_valid(perms & (RKTIO_PERMISSION_READ << 6)); check_valid(perms & (RKTIO_PERMISSION_READ << 6));
check_valid(perms & (RKTIO_PERMISSION_WRITE << 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)); int ok;
rktio_set_file_or_directory_permissions(rktio, "test1", perms); ok = rktio_set_file_or_directory_permissions(rktio, "test1", perms & (0x7 << 6));
if (ok
|| (RKTIO_ERROR_KIND_RACKET != rktio_get_last_error_kind(rktio))
|| (RKTIO_ERROR_BAD_PERMISSION != rktio_get_last_error(rktio))) {
check_valid(ok);
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); cp = rktio_copy_file_start(rktio, "test1a", "test1", 0);
check_valid(cp); check_valid(cp);
@ -638,7 +692,7 @@ int main(int argc, char **argv)
free(pipe_fds); free(pipe_fds);
check_read_write_pair(rktio, fd, fd2, 1); check_read_write_pair(rktio, fd, fd2, PIPE_IMMEDIATELY_READY);
/* Open pipe ends again: */ /* Open pipe ends again: */
pipe_fds = rktio_make_pipe(rktio, 0); pipe_fds = rktio_make_pipe(rktio, 0);
@ -647,9 +701,12 @@ int main(int argc, char **argv)
fd2 = pipe_fds[1]; fd2 = pipe_fds[1];
free(pipe_fds); free(pipe_fds);
check_fill_write(rktio, fd2, NULL, 0); check_fill_write(rktio, fd2, NULL, 0, verbose);
check_drain_read(rktio, fd, 0); if (!PIPE_IMMEDIATELY_READY)
wait_read(rktio, fd);
check_drain_read(rktio, fd, 0, verbose);
check_valid(rktio_poll_write_flushed(rktio, fd2) == RKTIO_POLL_READY);
check_valid(rktio_close(rktio, fd)); check_valid(rktio_close(rktio, fd));
check_valid(rktio_close(rktio, fd2)); check_valid(rktio_close(rktio, fd2));
} }
@ -664,7 +721,7 @@ int main(int argc, char **argv)
rktio_listener_t *lnr; rktio_listener_t *lnr;
check_many_lookup(rktio); check_many_lookup(rktio);
addr = lookup_loop(rktio, NULL, 4536, -1, 1, 1); addr = lookup_loop(rktio, NULL, 4536, -1, 1, 1);
lnr = rktio_listen(rktio, addr, 5, 1); lnr = rktio_listen(rktio, addr, 5, 1);
@ -722,8 +779,10 @@ int main(int argc, char **argv)
fd2 = rktio_accept(rktio, lnr); fd2 = rktio_accept(rktio, lnr);
check_fill_write(rktio, fd2, NULL, 0); printf(" fill\n");
check_drain_read(rktio, fd, 0); check_fill_write(rktio, fd2, NULL, 0, verbose);
printf(" drain\n");
check_drain_read(rktio, fd, 0, verbose);
check_valid(rktio_close(rktio, fd)); check_valid(rktio_close(rktio, fd));
check_valid(rktio_close(rktio, fd2)); check_valid(rktio_close(rktio, fd2));
@ -774,8 +833,8 @@ int main(int argc, char **argv)
addr = lookup_loop(rktio, "localhost", 4536, -1, 0, 0); addr = lookup_loop(rktio, "localhost", 4536, -1, 0, 0);
check_valid(addr); check_valid(addr);
check_fill_write(rktio, fd2, addr, AMOUNT_FOR_UDP); check_fill_write(rktio, fd2, addr, AMOUNT_FOR_UDP, verbose);
check_drain_read(rktio, fd, AMOUNT_FOR_UDP+1); check_drain_read(rktio, fd, AMOUNT_FOR_UDP+1, verbose);
rktio_addrinfo_free(rktio, addr); rktio_addrinfo_free(rktio, addr);
rktio_addrinfo_free(rktio, intf_addr); rktio_addrinfo_free(rktio, intf_addr);
@ -792,12 +851,18 @@ int main(int argc, char **argv)
{ {
rktio_status_t *status; rktio_status_t *status;
rktio_process_result_t *result; rktio_process_result_t *result;
#ifdef RKTIO_SYSTEM_UNIX
char *argv[1] = { "/bin/cat" }; char *argv[1] = { "/bin/cat" };
int argc = 1;
#else
char *argv[3] = { "c:\\windows\\system32\\bash.exe", "-c", "cat" };
int argc = 3;
#endif
rktio_envvars_t *envvars = rktio_envvars(rktio); rktio_envvars_t *envvars = rktio_envvars(rktio);
rktio_fd_t *err_fd = rktio_system_fd(rktio, 2, RKTIO_OPEN_WRITE); rktio_fd_t *err_fd = rktio_std_fd(rktio, RKTIO_STDERR);
int i; int i;
result = rktio_process(rktio, argv[0], 1, argv, result = rktio_process(rktio, argv[0], argc, argv,
NULL, NULL, err_fd, NULL, NULL, err_fd,
pwd, envvars, pwd, envvars,
0); 0);
@ -826,8 +891,14 @@ int main(int argc, char **argv)
rktio_process_forget(rktio, result->process); rktio_process_forget(rktio, result->process);
free(result); free(result);
#ifdef RKTIO_SYSTEM_UNIX
# define CAN_INTERRUPT_NON_GROUP 1
#else
# define CAN_INTERRUPT_NON_GROUP 0
#endif
/* Run and then break or kill `cat` */ /* Run and then break or kill `cat` */
for (i = 0; i < 2; i++) { for (i = (CAN_INTERRUPT_NON_GROUP ? 0 : 1); i < 2; i++) {
result = rktio_process(rktio, argv[0], 1, argv, result = rktio_process(rktio, argv[0], 1, argv,
NULL, NULL, err_fd, NULL, NULL, err_fd,
pwd, envvars, pwd, envvars,
@ -852,7 +923,7 @@ int main(int argc, char **argv)
} }
pause_for_process(rktio, result->process, dont_rely_on_sigchild); pause_for_process(rktio, result->process, dont_rely_on_sigchild);
status = rktio_process_status(rktio, result->process); status = rktio_process_status(rktio, result->process);
check_valid(status); check_valid(status);
check_valid(!status->running); check_valid(!status->running);
@ -862,8 +933,9 @@ int main(int argc, char **argv)
{ {
char buffer[1]; char buffer[1];
intptr_t amt; intptr_t amt;
wait_read(rktio, result->stdout_fd);
amt = rktio_read(rktio, result->stdout_fd, buffer, sizeof(buffer)); amt = rktio_read(rktio, result->stdout_fd, buffer, sizeof(buffer));
check_valid(amt == RKTIO_READ_EOF); check_valid(amt == RKTIO_READ_EOF);
} }
check_valid(rktio_close(rktio, result->stdin_fd)); check_valid(rktio_close(rktio, result->stdin_fd));
@ -874,8 +946,18 @@ int main(int argc, char **argv)
} }
{ {
#ifdef RKTIO_SYSTEM_UNIX
char *argv[2] = { "/usr/bin/printenv", "RKTIO_EXAMPLE" }; char *argv[2] = { "/usr/bin/printenv", "RKTIO_EXAMPLE" };
int argc = 2;
int flags = 0;
int expect_crlf = 0;
#else
char *argv[2] = { "c:\\windows\\system32\\cmd.exe", "/c echo %RKTIO_EXAMPLE%" };
int argc = 2;
int flags = RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE;
int expect_crlf = 1;
#endif
if (verbose) if (verbose)
printf(" envvars\n"); printf(" envvars\n");
@ -886,10 +968,10 @@ int main(int argc, char **argv)
check_valid(!strcmp(s, "howdy")); check_valid(!strcmp(s, "howdy"));
free(s); free(s);
result = rktio_process(rktio, argv[0], 2, argv, result = rktio_process(rktio, argv[0], argc, argv,
NULL, NULL, err_fd, NULL, NULL, err_fd,
pwd, envvars, pwd, envvars,
0); flags);
check_valid(result); check_valid(result);
/* Assume that a pipe can buffer the minimal output from `printenv`: */ /* Assume that a pipe can buffer the minimal output from `printenv`: */
@ -900,8 +982,13 @@ int main(int argc, char **argv)
char buffer[32]; char buffer[32];
intptr_t amt; intptr_t amt;
amt = rktio_read(rktio, result->stdout_fd, buffer, sizeof(buffer)); amt = rktio_read(rktio, result->stdout_fd, buffer, sizeof(buffer));
check_valid(amt == 6); if (expect_crlf) {
check_valid(!strncmp(buffer, "howdy\n", 6)); check_valid(amt == 7);
check_valid(!strncmp(buffer, "howdy\r\n", 7));
} else {
check_valid(amt == 6);
check_valid(!strncmp(buffer, "howdy\n", 6));
}
} }
check_valid(rktio_close(rktio, result->stdin_fd)); check_valid(rktio_close(rktio, result->stdin_fd));
@ -919,7 +1006,11 @@ int main(int argc, char **argv)
/* Filesystem-change events */ /* Filesystem-change events */
if (rktio_fs_change_properties(rktio) & RKTIO_FS_CHANGE_SUPPORTED) { if (rktio_fs_change_properties(rktio) & RKTIO_FS_CHANGE_SUPPORTED) {
char *path = "test1"; #ifdef RKTIO_SYSTEM_UNIX
char *path = strdup("test1");
#else
char *path = rktio_get_current_directory(rktio);
#endif
rktio_fs_change_t *fc; rktio_fs_change_t *fc;
rktio_poll_set_t *ps; rktio_poll_set_t *ps;
rktio_ltps_t *lt; rktio_ltps_t *lt;
@ -956,7 +1047,19 @@ int main(int argc, char **argv)
amt = rktio_write(rktio, fd2, "hola", 4); amt = rktio_write(rktio, fd2, "hola", 4);
check_valid(amt == 4); check_valid(amt == 4);
printf("wait...\n");
rktio_sleep(rktio, 0, ps, NULL); rktio_sleep(rktio, 0, ps, NULL);
printf("done\n");
while (rktio_poll_fs_change_ready(rktio, fc) == RKTIO_POLL_NOT_READY) {
/* sleep woke up early - not what we want, but allowed by the spec */
rktio_poll_set_forget(rktio, ps);
ps = rktio_make_poll_set(rktio);
check_valid(ps);
rktio_poll_add_fs_change(rktio, fc, ps);
rktio_sleep(rktio, 0, ps, NULL);
}
check_valid(rktio_poll_fs_change_ready(rktio, fc) == RKTIO_POLL_READY); check_valid(rktio_poll_fs_change_ready(rktio, fc) == RKTIO_POLL_READY);
check_valid(rktio_poll_fs_change_ready(rktio, fc) == RKTIO_POLL_READY); check_valid(rktio_poll_fs_change_ready(rktio, fc) == RKTIO_POLL_READY);
@ -967,6 +1070,8 @@ int main(int argc, char **argv)
if (lt) if (lt)
rktio_ltps_close(rktio, lt); rktio_ltps_close(rktio, lt);
free(path);
} }
if (verbose) if (verbose)
@ -1061,7 +1166,7 @@ int main(int argc, char **argv)
today->zone_offset, today->zone_offset / (60 * 60), today->zone_offset, today->zone_offset / (60 * 60),
(today->is_dst ? ";DST" : ""), (today->is_dst ? ";DST" : ""),
week_day_name(rktio, today->day_of_week), week_day_name(rktio, today->day_of_week),
today->day, month_name(rktio, today->month), today->year, today->day, month_name(rktio, today->month), (long)today->year,
today->day_of_year); today->day_of_year);
if (today->zone_name) if (today->zone_name)

View File

@ -0,0 +1,5 @@
@echo off
echo ============================================
echo Assumes that the "librktio" project is built
echo ============================================
cl /I..\worksp\librktio demo.c ..\worksp\librktio\x32\Release\librktio.lib ws2_32.lib user32.lib shell32.lib

View File

@ -0,0 +1,5 @@
@echo off
echo ============================================
echo Assumes that the "librktio" project is built
echo ============================================
cl /I..\worksp\librktio demo.c ..\worksp\librktio\x64\Release\librktio.lib ws2_32.lib user32.lib shell32.lib

View File

@ -158,7 +158,7 @@ RKTIO_EXTERN rktio_fd_t *rktio_open(rktio_t *rktio, const char *src, int modes);
RKTIO_EXTERN rktio_ok_t rktio_close(rktio_t *rktio, rktio_fd_t *fd); RKTIO_EXTERN rktio_ok_t rktio_close(rktio_t *rktio, rktio_fd_t *fd);
/* Can report `RKTIO_ERROR_EXISTS` in place of system error, /* Can report `RKTIO_ERROR_EXISTS` in place of system error,
and can report `RKTIO_ERROR_UNSUPPORTED_TEXT_MODE` on Windows. and can report `RKTIO_ERROR_UNSUPPORTED_TEXT_MODE` on Windows.
See also `rktio_write` and `rktio_poll_write_flushed. */ See also `rktio_write` and `rktio_poll_write_flushed`. */
RKTIO_EXTERN void rktio_close_noerr(rktio_t *rktio, rktio_fd_t *fd); RKTIO_EXTERN void rktio_close_noerr(rktio_t *rktio, rktio_fd_t *fd);
/* The same as `rktio_close`, but without reporting errors. There's /* The same as `rktio_close`, but without reporting errors. There's
@ -197,9 +197,9 @@ RKTIO_EXTERN intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, const char *bu
mode. Alternatively, the result can be `RKTIO_WRITE_ERROR` for an mode. Alternatively, the result can be `RKTIO_WRITE_ERROR` for an
error. Although rktio_write() is intended to write only bytes that error. Although rktio_write() is intended to write only bytes that
can be fully delivered to the OS, there may be OS limitations that can be fully delivered to the OS, there may be OS limitations that
require buffering (e.g., on Windows). Use require buffering (e.g., on Windows). Use `rktio_poll_write_flushed`
rktio_poll_write_flushed() to make sure it's completely flushed to make sure the data is received by the destination before closing
before closing. */ `fd`. */
#define RKTIO_WRITE_ERROR (-2) #define RKTIO_WRITE_ERROR (-2)
@ -222,7 +222,10 @@ RKTIO_EXTERN rktio_tri_t rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd)
#define RKTIO_POLL_ERROR (-2) #define RKTIO_POLL_ERROR (-2)
RKTIO_EXTERN rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd); RKTIO_EXTERN rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd);
/* See `rktio_write` above. */ /* See `rktio_write` above. Currently, the result is `RKTIO_POLL_NO_READY`
only on Windows, and only for a pipe or similar non-regular file.
A pipe counts as "flushed" when the other end has received the data
(because the sent data doesn't persist beyond closing the pipe). */
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_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl);
RKTIO_EXTERN rktio_ok_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);
@ -634,8 +637,9 @@ enum {
}; };
RKTIO_EXTERN void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds, rktio_ltps_t *lt); 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 /* Waits up to `nsecs` seconds (or forever if `nsecs` is 0), until
something registered with `fds` or `lt` is ready. */ something registered with `fds` or `lt` is ready, or until there's
some other activity that sometimes causes an early wakeup. */
/*************************************************/ /*************************************************/
/* Files, directories, and links */ /* Files, directories, and links */

View File

@ -32,7 +32,7 @@ char **rktio_get_environ_array(void)
int rktio_is_ok_envvar_name(rktio_t *rktio, const char *s) int rktio_is_ok_envvar_name(rktio_t *rktio, const char *s)
{ {
int i = strlen(s); intptr_t i = strlen(s);
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
if (!s[0]) return 0; if (!s[0]) return 0;
#endif #endif
@ -159,8 +159,7 @@ rktio_envvars_t *rktio_envvars(rktio_t *rktio)
i = 0; i = 0;
while (e[i]) { while (e[i]) {
count++; count++;
for (i = 0; e[i]; ) { while (e[i]) i++;
}
i++; i++;
} }
@ -171,7 +170,8 @@ rktio_envvars_t *rktio_envvars(rktio_t *rktio)
envvars->vals = malloc(count * sizeof(char *)); envvars->vals = malloc(count * sizeof(char *));
count = 0; count = 0;
for (i = 0; e[i]; ) { i = 0;
while (e[i]) {
start = i; start = i;
while (e[i]) { i++; } while (e[i]) { i++; }
p = NARROW_PATH_copy(e + start); p = NARROW_PATH_copy(e + start);
@ -182,6 +182,7 @@ rktio_envvars_t *rktio_envvars(rktio_t *rktio)
envvars->vals[count] = MSC_IZE(strdup)(p+j+1); envvars->vals[count] = MSC_IZE(strdup)(p+j+1);
free(p); free(p);
i++; i++;
count++;
} }
FreeEnvironmentStringsW(e); FreeEnvironmentStringsW(e);
@ -382,7 +383,7 @@ void *rktio_envvars_to_block(rktio_t *rktio, rktio_envvars_t *envvars)
intptr_t len = 0, slen; intptr_t len = 0, slen;
wchar_t *r, *s; wchar_t *r, *s;
for (i = 0; i < envvars->count; i++) { for (i = 0; i < envvars->count; i++) {
len += wcslen(WIDE_PATH_temp(envvars->names[i])); len += wcslen(WIDE_PATH_temp(envvars->names[i]));
len += wcslen(WIDE_PATH_temp(envvars->vals[i])); len += wcslen(WIDE_PATH_temp(envvars->vals[i]));
len += 2; len += 2;

View File

@ -115,7 +115,7 @@ const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid)
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
else if (kind == RKTIO_ERROR_KIND_WINDOWS) { else if (kind == RKTIO_ERROR_KIND_WINDOWS) {
wchar_t mbuf[256]; wchar_t mbuf[256];
int len, i; intptr_t len, i;
if ((len = FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM if ((len = FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS), | FORMAT_MESSAGE_IGNORE_INSERTS),
NULL, NULL,
@ -128,7 +128,7 @@ const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid)
mbuf[len] = 0; mbuf[len] = 0;
es = NARROW_PATH_copy(mbuf); es = NARROW_PATH_copy(mbuf);
/* Remove newlines: */ /* Remove newlines: */
for (i = strlen(s) - 1; i > 0; i--) { for (i = strlen(es) - 1; i > 0; i--) {
if (isspace(es[i])) if (isspace(es[i]))
es[i] = 0; es[i] = 0;
else else

View File

@ -34,7 +34,7 @@ struct rktio_fd_t {
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
union { union {
HANDLE fd; HANDLE fd;
int sock; /* when `modes & RKTIO_OPEN_SOCKET` */ SOCKET sock; /* when `modes & RKTIO_OPEN_SOCKET` */
}; };
struct Win_FD_Input_Thread *th; /* input mode */ struct Win_FD_Input_Thread *th; /* input mode */
struct Win_FD_Output_Thread *oth; /* output mode */ struct Win_FD_Output_Thread *oth; /* output mode */
@ -53,11 +53,11 @@ struct rktio_fd_t {
typedef struct Win_FD_Input_Thread { typedef struct Win_FD_Input_Thread {
/* This is malloced for use in a Win32 thread */ /* This is malloced for use in a Win32 thread */
HANDLE fd; HANDLE fd;
volatile int avail, err, checking; int avail, offset, err, checking, you_clean_up;
int *refcount; int *refcount;
HANDLE eof; HANDLE eof;
unsigned char *buffer; unsigned char *buffer;
HANDLE checking_sema, ready_sema, you_clean_up_sema; HANDLE lock_sema, checking_sema, ready_sema;
HANDLE thread; HANDLE thread;
} Win_FD_Input_Thread; } Win_FD_Input_Thread;
@ -68,32 +68,38 @@ typedef struct Win_FD_Output_Thread {
works. We still use a thread to detect when the works. We still use a thread to detect when the
write has ben flushed, which in turn is needed to write has ben flushed, which in turn is needed to
know whether future writes will immediately succeed. */ know whether future writes will immediately succeed. */
volatile int flushed, needflush; /* Used for non-blocking, only. The flushed int flushed, needflush; /* Used for non-blocking, only. The flushed
flag communicates from the flush-testing thread flag communicates from the flush-testing thread
to the main thread. For efficiency, we request to the main thread. For efficiency, we request
flush checking only when needed (instead of flush checking only when needed (instead of
after every write); needflush indicates that after every write); needflush indicates that
a flush check is currently needed, but hasn't a flush check is currently needed, but hasn't
been started. */ been started. */
volatile int done, err_no; int done, err_no, you_clean_up;
volatile unsigned int buflen, bufstart, bufend; /* used for blocking, only */ unsigned int buflen, bufstart, bufend; /* used for blocking, only */
unsigned char *buffer; /* used for blocking, only */ unsigned char *buffer; /* used for blocking, only */
int *refcount; int *refcount;
HANDLE lock_sema, work_sema, ready_sema, you_clean_up_sema; HANDLE lock_sema, work_sema, ready_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; HANDLE thread;
} Win_FD_Output_Thread; } Win_FD_Output_Thread;
# define RKTIO_FD_BUFFSIZE 4096 # define RKTIO_FD_BUFFSIZE 4096
static void init_read_fd(rktio_t *rktio, rktio_fd_t *rfd);
static void deinit_read_fd(rktio_t *rktio, rktio_fd_t *rfd, int full_close);
static void deinit_write_fd(rktio_t *rktio, rktio_fd_t *rfd, int full_close);
static void deinit_fd(rktio_t *rktio, rktio_fd_t *rfd, int full_close)
{
deinit_read_fd(rktio, rfd, full_close);
deinit_write_fd(rktio, rfd, full_close);
}
static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th); static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th);
static void WindowsFDICleanup(Win_FD_Input_Thread *th); static void WindowsFDICleanup(Win_FD_Input_Thread *th, int close_mode);
static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth); static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth);
static void WindowsFDOCleanup(Win_FD_Output_Thread *oth); static void WindowsFDOCleanup(Win_FD_Output_Thread *oth, int close_mode);
typedef BOOL (WINAPI* CSI_proc)(HANDLE); typedef BOOL (WINAPI* CSI_proc)(HANDLE);
@ -124,57 +130,6 @@ static intptr_t rktio_recount_output_text(const char *orig_buffer, const char *b
/* creating an fd */ /* creating an fd */
/*========================================================================*/ /*========================================================================*/
static void init_read_fd(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_UNIX
# ifdef SOME_FDS_ARE_NOT_SELECTABLE
rfd->bufcount = 0;
# endif
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
if (!rktio_fd_is_regular_file(rktio, rfd)) {
/* 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;
HANDLE sm;
char *bfr;
th = malloc(sizeof(Win_FD_Input_Thread));
rfd->th = th;
/* Replace buffer with a malloced one: */
bfr = malloc(RKTIO_FD_BUFFSIZE);
rfd->buffer = bfr;
th->buffer = (unsigned char *)bfr;
th->fd = rfd->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;
h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDReader, th, 0, &id);
th->thread = h;
}
#endif
}
rktio_fd_t *rktio_system_fd(rktio_t *rktio, 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; rktio_fd_t *rfd;
@ -200,7 +155,7 @@ rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes)
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
if (modes & RKTIO_OPEN_SOCKET) if (modes & RKTIO_OPEN_SOCKET)
rfd->sock = system_fd; rfd->sock = (SOCKET)system_fd;
else else
rfd->fd = (HANDLE)system_fd; rfd->fd = (HANDLE)system_fd;
if (!(modes & (RKTIO_OPEN_REGFILE | RKTIO_OPEN_NOT_REGFILE | RKTIO_OPEN_SOCKET))) { if (!(modes & (RKTIO_OPEN_REGFILE | RKTIO_OPEN_NOT_REGFILE | RKTIO_OPEN_SOCKET))) {
@ -217,9 +172,6 @@ rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes)
} }
#endif #endif
if (modes & RKTIO_OPEN_READ)
init_read_fd(rktio, rfd);
if ((modes & RKTIO_OPEN_SOCKET) && (modes & RKTIO_OPEN_INIT)) if ((modes & RKTIO_OPEN_SOCKET) && (modes & RKTIO_OPEN_INIT))
rktio_socket_init(rktio, rfd); rktio_socket_init(rktio, rfd);
@ -236,7 +188,7 @@ intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd)
#endif #endif
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
if (rfd->modes & RKTIO_OPEN_SOCKET) if (rfd->modes & RKTIO_OPEN_SOCKET)
return rfd->sock; return (intptr_t)rfd->sock;
else else
return (intptr_t)rfd->fd; return (intptr_t)rfd->fd;
#endif #endif
@ -262,7 +214,9 @@ rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which)
which = STD_ERROR_HANDLE; which = STD_ERROR_HANDLE;
break; break;
} }
return rktio_system_fd(rktio, (intptr_t)GetStdHandle(which), mode | RKTIO_OPEN_NOT_DIR); return rktio_system_fd(rktio,
(intptr_t)GetStdHandle(which),
mode | RKTIO_OPEN_NOT_DIR);
#endif #endif
} }
@ -400,53 +354,8 @@ static rktio_ok_t do_close(rktio_t *rktio, rktio_fd_t *rfd, int set_error)
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
if (rfd->modes & RKTIO_OPEN_SOCKET) if (rfd->modes & RKTIO_OPEN_SOCKET)
return rktio_socket_close(rktio, rfd, set_error); return rktio_socket_close(rktio, rfd, set_error);
if (rfd->th) {
CSI_proc csi;
/* -1 for checking means "shut down" */ deinit_fd(rktio, rfd, 1);
rfd->th->checking = -1;
ReleaseSemaphore(rfd->th->checking_sema, 1, NULL);
if (rfd->th->eof && (rfd->th->eof != INVALID_HANDLE_VALUE)) {
ReleaseSemaphore(rfd->th->eof, 1, NULL);
rfd->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(rfd->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(rfd->th->you_clean_up_sema, 0) != WAIT_OBJECT_0) {
/* The other thread exited and left us with clean-up: */
WindowsFDICleanup(rfd->th);
} /* otherwise, thread is responsible for clean-up */
}
if (rfd->oth) {
CSI_proc csi;
csi = get_csi();
if (csi) {
/* See also call to csi in fd_close_input */
csi(rfd->oth->thread);
}
CloseHandle(rfd->oth->thread);
rfd->oth->done = 1;
ReleaseSemaphore(rfd->oth->work_sema, 1, NULL);
/* Try to leave clean-up to the other thread: */
if (WaitForSingleObject(rfd->oth->you_clean_up_sema, 0) != WAIT_OBJECT_0) {
/* Other thread is already done, so we're stuck with clean-up: */
WindowsFDOCleanup(rfd->oth);
} /* otherwise, thread is responsible for clean-up */
}
ok = 1; ok = 1;
if (!rfd->th && !rfd->oth) { if (!rfd->th && !rfd->oth) {
@ -476,6 +385,9 @@ void rktio_close_noerr(rktio_t *rktio, rktio_fd_t *rfd)
void rktio_forget(rktio_t *rktio, rktio_fd_t *rfd) void rktio_forget(rktio_t *rktio, rktio_fd_t *rfd)
{ {
#ifdef RKTIO_WINDOWS_SYSTEM
deinit_fd(rktio, rfd, 1);
#endif
free(rfd); free(rfd);
} }
@ -572,7 +484,9 @@ int rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd)
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
if (rfd->modes & RKTIO_OPEN_SOCKET) if (rfd->modes & RKTIO_OPEN_SOCKET)
return rktio_socket_poll_read_ready(rktio, rfd); return rktio_socket_poll_read_ready(rktio, rfd);
init_read_fd(rktio, rfd);
if (!rfd->th) { if (!rfd->th) {
/* No thread -- so wait works. This case isn't actually used /* No thread -- so wait works. This case isn't actually used
right now, because wait doesn't seem to work reliably for right now, because wait doesn't seem to work reliably for
@ -582,21 +496,21 @@ int rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd)
return RKTIO_POLL_READY; return RKTIO_POLL_READY;
} else { } else {
/* Has the reader thread pulled in data? */ /* Has the reader thread pulled in data? */
WaitForSingleObject(rfd->th->lock_sema, INFINITE);
if (rfd->th->checking) { if (rfd->th->checking) {
/* The thread is still trying, last we knew. Check the /* The thread is still trying.
data-is-ready sema: */ Clean up any signals that we may have ignored before. */
if (WaitForSingleObject(rfd->th->ready_sema, 0) == WAIT_OBJECT_0) { WaitForSingleObject(rfd->th->ready_sema, 0);
rfd->th->checking = 0; } else if (rfd->th->avail || rfd->th->err || rfd->th->eof) {
return RKTIO_POLL_READY; ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
}
} else if (rfd->th->avail || rfd->th->err || rfd->th->eof)
return RKTIO_POLL_READY; /* other thread found data */ return RKTIO_POLL_READY; /* other thread found data */
else { } else {
/* Doesn't have anything, and it's not even looking. Tell it /* Doesn't have anything, and it's not even looking. Tell it
to look: */ to look: */
rfd->th->checking = 1; rfd->th->checking = 1;
ReleaseSemaphore(rfd->th->checking_sema, 1, NULL); ReleaseSemaphore(rfd->th->checking_sema, 1, NULL);
} }
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
} }
return 0; return 0;
@ -647,11 +561,14 @@ int poll_write_ready_or_flushed(rktio_t *rktio, rktio_fd_t *rfd, int check_flush
} }
#endif #endif
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
if (rfd->modes & RKTIO_OPEN_SOCKET) if (rfd->modes & RKTIO_OPEN_SOCKET) {
if (check_flushed)
return RKTIO_POLL_READY;
return rktio_socket_poll_write_ready(rktio, rfd); return rktio_socket_poll_write_ready(rktio, rfd);
}
if (rfd->oth) { if (rfd->oth) {
/* Pipe output that can block... */ /* Pipe output that can block or needs a background flush */
int retval; int retval;
Win_FD_Output_Thread *oth = rfd->oth; Win_FD_Output_Thread *oth = rfd->oth;
@ -664,15 +581,27 @@ int poll_write_ready_or_flushed(rktio_t *rktio, rktio_fd_t *rfd, int check_flush
retval = 0; retval = 0;
} else } else
retval = oth->flushed; retval = oth->flushed;
} else if (!retval) {
retval = (oth->err_no || (check_flushed /* While we hold the lock, clear any leftover notifications */
? !oth->buflen WaitForSingleObject(oth->ready_sema, 0);
: (oth->buflen < RKTIO_FD_BUFFSIZE))); }
if (!retval && !check_flushed) } else {
WaitForSingleObject(oth->ready_sema, 0); /* clear any leftover state */ /* Using separate writing thread for Windows 95 */
if (oth->err_no) {
/* Delay error report until next write */
retval = 1;
} else
retval = (check_flushed
? !oth->buflen
: (oth->buflen < RKTIO_FD_BUFFSIZE));
if (!retval && !check_flushed) {
/* clear any leftover notifications */
WaitForSingleObject(oth->ready_sema, 0);
}
}
ReleaseSemaphore(oth->lock_sema, 1, NULL); ReleaseSemaphore(oth->lock_sema, 1, NULL);
return retval; return (retval ? RKTIO_POLL_READY : 0);
} else } else
return RKTIO_POLL_READY; /* non-blocking output, such as a console, or haven't written yet */ return RKTIO_POLL_READY; /* non-blocking output, such as a console, or haven't written yet */
#endif #endif
@ -709,30 +638,38 @@ void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int
rktio_poll_set_t *fds2; rktio_poll_set_t *fds2;
if (modes & RKTIO_POLL_READ) { if (modes & RKTIO_POLL_READ) {
RKTIO_FD_SET(rfd->sock, fds); RKTIO_FD_SET((intptr_t)rfd->sock, fds);
} }
if (modes & RKTIO_POLL_WRITE) { if (modes & RKTIO_POLL_WRITE) {
fds2 = RKTIO_GET_FDSET(fds, 1); fds2 = RKTIO_GET_FDSET(fds, 1);
RKTIO_FD_SET(rfd->sock, fds2); RKTIO_FD_SET((intptr_t)rfd->sock, fds2);
} }
fds2 = RKTIO_GET_FDSET(fds, 2); fds2 = RKTIO_GET_FDSET(fds, 2);
RKTIO_FD_SET(rfd->sock, fds2); RKTIO_FD_SET((intptr_t)rfd->sock, fds2);
} else { } else {
if (modes & RKTIO_POLL_READ) { if (modes & RKTIO_POLL_READ) {
init_read_fd(rktio, rfd);
if (rfd->th) { if (rfd->th) {
/* See fd_byte_ready */ WaitForSingleObject(rfd->th->lock_sema, INFINITE);
if (!rfd->th->checking) { if (!rfd->th->checking) {
if (rfd->th->avail || rfd->th->err || rfd->th->eof) { if (rfd->th->avail || rfd->th->err || rfd->th->eof) {
/* Data is ready. We shouldn't be trying to sleep, so force an /* Data is ready. We shouldn't be trying to sleep, so force an
immediate wake-up: */ immediate wake-up: */
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
rktio_poll_set_add_nosleep(rktio, fds); rktio_poll_set_add_nosleep(rktio, fds);
} else { } else {
/* Ask the reader thread to start checking for data */
rfd->th->checking = 1; rfd->th->checking = 1;
ReleaseSemaphore(rfd->th->checking_sema, 1, NULL); ReleaseSemaphore(rfd->th->checking_sema, 1, NULL);
/* clear any notifications that we may have ignored before */
WaitForSingleObject(rfd->th->ready_sema, 0);
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
rktio_poll_set_add_handle(rktio, (intptr_t)rfd->th->ready_sema, fds, 1); rktio_poll_set_add_handle(rktio, (intptr_t)rfd->th->ready_sema, fds, 1);
} }
} else } else {
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
rktio_poll_set_add_handle(rktio, (intptr_t)rfd->th->ready_sema, fds, 1); rktio_poll_set_add_handle(rktio, (intptr_t)rfd->th->ready_sema, fds, 1);
}
} else if (rktio_fd_is_regular_file(rktio, rfd)) { } else if (rktio_fd_is_regular_file(rktio, rfd)) {
/* regular files never block */ /* regular files never block */
rktio_poll_set_add_nosleep(rktio, fds); rktio_poll_set_add_nosleep(rktio, fds);
@ -827,7 +764,9 @@ intptr_t rktio_read_converted(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, int
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
if (rfd->modes & RKTIO_OPEN_SOCKET) if (rfd->modes & RKTIO_OPEN_SOCKET)
return rktio_socket_read(rktio, rfd, buffer, len); return rktio_socket_read(rktio, rfd, buffer, len);
init_read_fd(rktio, rfd);
if (!rfd->th) { if (!rfd->th) {
/* We can read directly. This must be a regular file, where /* We can read directly. This must be a regular file, where
reading never blocks. */ reading never blocks. */
@ -853,21 +792,28 @@ intptr_t rktio_read_converted(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, int
if (!rktio_poll_read_ready(rktio, rfd)) if (!rktio_poll_read_ready(rktio, rfd))
return 0; return 0;
/* If we get this far, there's definitely data available. /* If we get this far, there should be data available.
Extract data made available by the reader thread. */ Extract data made available by the reader thread. */
WaitForSingleObject(rfd->th->lock_sema, INFINITE);
if (rfd->th->eof) { if (rfd->th->eof) {
if (rfd->th->eof != INVALID_HANDLE_VALUE) { if (rfd->th->eof != INVALID_HANDLE_VALUE) {
ReleaseSemaphore(rfd->th->eof, 1, NULL); ReleaseSemaphore(rfd->th->eof, 1, NULL);
rfd->th->eof = NULL; rfd->th->eof = NULL;
} }
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
return RKTIO_READ_EOF; return RKTIO_READ_EOF;
} else if (rfd->th->err) { } else if (rfd->th->err) {
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
set_windows_error(rfd->th->err); set_windows_error(rfd->th->err);
return RKTIO_READ_ERROR; return RKTIO_READ_ERROR;
} else { } else {
intptr_t bc = rfd->th->avail; intptr_t bc = rfd->th->avail;
rfd->th->avail = 0; if (bc > len)
memcpy(buffer, rfd->buffer, bc); bc = len;
rfd->th->avail -= bc;
memcpy(buffer, rfd->buffer + rfd->th->offset, bc);
rfd->th->offset += bc;
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
return bc; return bc;
} }
} }
@ -923,6 +869,88 @@ static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, char *is_
return j; return j;
} }
static void init_read_fd(rktio_t *rktio, rktio_fd_t *rfd)
{
if (!rktio_fd_is_regular_file(rktio, rfd) && !rfd->th) {
/* 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;
HANDLE sm;
char *bfr;
th = calloc(1, sizeof(Win_FD_Input_Thread));
rfd->th = th;
bfr = malloc(RKTIO_FD_BUFFSIZE);
th->buffer = (unsigned char *)bfr;
rfd->buffer = bfr;
th->fd = rfd->fd;
th->avail = 0;
th->offset = 0;
th->err = 0;
th->eof = NULL;
th->checking = 0;
sm = CreateSemaphore(NULL, 1, 1, NULL);
th->lock_sema = sm;
sm = CreateSemaphore(NULL, 0, 1, NULL);
th->checking_sema = sm;
sm = CreateSemaphore(NULL, 0, 1, NULL);
th->ready_sema = sm;
h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDReader, th, 0, &id);
th->thread = h;
}
}
static void deinit_read_fd(rktio_t *rktio, rktio_fd_t *rfd, int full_close)
{
if (rfd->th) {
CSI_proc csi;
WaitForSingleObject(rfd->th->lock_sema, INFINITE);
/* -1 for checking means "shut down" */
rfd->th->checking = -1;
ReleaseSemaphore(rfd->th->checking_sema, 1, NULL);
if (rfd->th->eof && (rfd->th->eof != INVALID_HANDLE_VALUE)) {
ReleaseSemaphore(rfd->th->eof, 1, NULL);
rfd->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(rfd->th->thread);
}
/* Try to get out of cleaning up the records (since they can't be
cleaned until the thread is also done: */
if (rfd->th->you_clean_up) {
/* The other thread exited and left us with clean-up: */
WindowsFDICleanup(rfd->th, (full_close ? 1 : -1));
} else {
/* otherwise, thread is responsible for clean-up */
rfd->th->you_clean_up = (full_close ? 1 : -1);
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
}
}
}
static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th) static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th)
{ {
DWORD toget, got; DWORD toget, got;
@ -941,50 +969,75 @@ static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th)
/* Wait until we're supposed to look for input: */ /* Wait until we're supposed to look for input: */
WaitForSingleObject(th->checking_sema, INFINITE); WaitForSingleObject(th->checking_sema, INFINITE);
WaitForSingleObject(th->lock_sema, INFINITE);
if (th->checking < 0) if (th->checking < 0)
break; break;
if (ReadFile(th->fd, th->buffer, toget, &got, NULL)) { if (th->avail) {
th->avail = got; /* Spurious wake-up? */
if (!got) { ReleaseSemaphore(th->lock_sema, 1, NULL);
/* We interpret a send of 0 bytes as a mid-stream EOF. */
eof_wait = CreateSemaphore(NULL, 0, 1, NULL);
th->eof = eof_wait;
}
} else { } else {
int err; ReleaseSemaphore(th->lock_sema, 1, NULL);
err = GetLastError(); if (ReadFile(th->fd, th->buffer, toget, &got, NULL)) {
if (err == ERROR_BROKEN_PIPE) { WaitForSingleObject(th->lock_sema, INFINITE);
th->eof = INVALID_HANDLE_VALUE; th->avail = got;
perma_eof = 1; th->offset = 0;
} else if (!got) {
th->err = err; /* We interpret a send of 0 bytes as a mid-stream EOF. */
} eof_wait = CreateSemaphore(NULL, 0, 1, NULL);
th->eof = eof_wait;
}
/* lock is still held... */
} else {
int err;
err = GetLastError();
WaitForSingleObject(th->lock_sema, INFINITE);
if (err == ERROR_BROKEN_PIPE) {
th->eof = INVALID_HANDLE_VALUE;
perma_eof = 1;
} else
th->err = err;
/* lock is still held... */
}
/* Notify main program that we found something: */ th->checking = 0;
ReleaseSemaphore(th->ready_sema, 1, NULL);
if (eof_wait) { /* Notify main program that we found something: */
WaitForSingleObject(eof_wait, INFINITE); ReleaseSemaphore(th->ready_sema, 1, NULL);
eof_wait = NULL;
if (!perma_eof && !th->err) {
ReleaseSemaphore(th->lock_sema, 1, NULL);
if (eof_wait) {
WaitForSingleObject(eof_wait, INFINITE);
CloseHandle(eof_wait);
eof_wait = NULL;
}
}
} }
} }
/* lock is still held on `break` out of loop */
/* We have to clean up if the main program has abandoned us: */ /* We have to clean up if the main program has abandoned us: */
if (WaitForSingleObject(th->you_clean_up_sema, 0) != WAIT_OBJECT_0) { if (th->you_clean_up) {
WindowsFDICleanup(th); WindowsFDICleanup(th, th->you_clean_up);
} /* otherwise, main program is responsible for clean-up */ } else {
/* otherwise, main program is responsible for clean-up */
th->you_clean_up = 1;
ReleaseSemaphore(th->lock_sema, 1, NULL);
}
return 0; return 0;
} }
static void WindowsFDICleanup(Win_FD_Input_Thread *th) static void WindowsFDICleanup(Win_FD_Input_Thread *th, int close_mode)
{ {
CloseHandle(th->lock_sema);
CloseHandle(th->checking_sema); CloseHandle(th->checking_sema);
CloseHandle(th->ready_sema); CloseHandle(th->ready_sema);
CloseHandle(th->you_clean_up_sema);
CloseHandle(th->fd); if (close_mode != -1)
CloseHandle(th->fd);
free(th->buffer); free(th->buffer);
free(th); free(th);
@ -1097,7 +1150,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
flushed). */ flushed). */
intptr_t out_len = 0; intptr_t out_len = 0;
int ok, errsaved; int ok, errsaved;
if (!rfd->oth || rfd->oth->nonblocking) { if (!rfd->oth || rfd->oth->nonblocking) {
int nonblocking; int nonblocking;
@ -1110,7 +1163,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
&& (GetFileType((HANDLE)rfd->fd) == FILE_TYPE_PIPE)); && (GetFileType((HANDLE)rfd->fd) == FILE_TYPE_PIPE));
} else } else
nonblocking = 1; /* must be, or we would not have gotten here */ nonblocking = 1; /* must be, or we would not have gotten here */
if (nonblocking) { if (nonblocking) {
/* Unless we're still trying to flush old data, write to the /* Unless we're still trying to flush old data, write to the
pipe and have the other thread start flushing it. */ pipe and have the other thread start flushing it. */
@ -1163,8 +1216,8 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
|| (!ok && (errsaved == ERROR_NOT_ENOUGH_MEMORY))) { || (!ok && (errsaved == ERROR_NOT_ENOUGH_MEMORY))) {
towrite = towrite >> 1; towrite = towrite >> 1;
if (!towrite) { if (!towrite) {
get_windows_error(); /* leave ok as 1 and winwrote as 0 */
return RKTIO_WRITE_ERROR; break;
} }
} else } else
break; break;
@ -1177,32 +1230,42 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
if (ok) if (ok)
out_len = winwrote; out_len = winwrote;
} else {
/* Claim success for now to make `rfd->oth` get created,
and continuae non-blocking handling after that. */
ok = 1;
out_len = 1;
} }
/* and create the writer thread... */ /* and create the writer thread... */
if (!rfd->oth) { if (ok && (out_len > 0) && !rfd->oth) {
/* We create a thread even for pipes that can be put in /* We create a thread even for pipes that can be put in
non-blocking mode, because that seems to be the only non-blocking mode, because that seems to be the only
way to get evt behavior. */ way to get evt behavior of knowing that a write will
succeed because the previous content is flushed. */
Win_FD_Output_Thread *oth; Win_FD_Output_Thread *oth;
HANDLE h; HANDLE h;
DWORD id; DWORD id;
unsigned char *bfr; unsigned char *bfr;
HANDLE sm; HANDLE sm;
oth = malloc(sizeof(Win_FD_Output_Thread)); oth = calloc(1, sizeof(Win_FD_Output_Thread));
rfd->oth = oth; rfd->oth = oth;
oth->nonblocking = nonblocking; oth->nonblocking = nonblocking;
if (!nonblocking) { if (!nonblocking) {
/* Create the buffer to communicate with the writing thread. */
bfr = malloc(RKTIO_FD_BUFFSIZE); bfr = malloc(RKTIO_FD_BUFFSIZE);
oth->buffer = bfr; oth->buffer = bfr;
oth->flushed = 0; oth->flushed = 0;
oth->needflush = 0; oth->needflush = 0;
} else { } else {
/* No buffer needed */
oth->buffer = NULL; oth->buffer = NULL;
oth->flushed = 1; /* Some data was written, so it's not yet flushed,
and we need a flush. */
oth->flushed = 0;
oth->needflush = 1; oth->needflush = 1;
} }
@ -1219,9 +1282,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
oth->work_sema = sm; oth->work_sema = sm;
sm = CreateSemaphore(NULL, 1, 1, NULL); sm = CreateSemaphore(NULL, 1, 1, NULL);
oth->ready_sema = sm; oth->ready_sema = sm;
sm = CreateSemaphore(NULL, 1, 1, NULL);
oth->you_clean_up_sema = sm;
h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDWriter, oth, 0, &id); h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDWriter, oth, 0, &id);
oth->thread = h; oth->thread = h;
@ -1231,7 +1292,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
/* We have a thread, if only to watch when the flush is /* We have a thread, if only to watch when the flush is
done... */ done... */
if (!rfd->oth->nonblocking) { if (rfd->oth && !rfd->oth->nonblocking) {
/* This case is for Win 95/98/Me anonymous pipes and /* This case is for Win 95/98/Me anonymous pipes and
character devices. We haven't written anything yet! We character devices. We haven't written anything yet! We
write to a buffer read by the other thread, and return -- write to a buffer read by the other thread, and return --
@ -1242,6 +1303,9 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
handle, same "device"), the port writes can get out of handle, same "device"), the port writes can get out of
order. We try to avoid the problem by sleeping. */ order. We try to avoid the problem by sleeping. */
/* At this point, `out_len` is set ot 1, and we
need to set it to a value. */
Win_FD_Output_Thread *oth = rfd->oth; Win_FD_Output_Thread *oth = rfd->oth;
WaitForSingleObject(oth->lock_sema, INFINITE); WaitForSingleObject(oth->lock_sema, INFINITE);
@ -1249,7 +1313,8 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
errsaved = oth->err_no; errsaved = oth->err_no;
ok = 0; ok = 0;
} else if (oth->buflen == RKTIO_FD_BUFFSIZE) { } else if (oth->buflen == RKTIO_FD_BUFFSIZE) {
WaitForSingleObject(oth->ready_sema, 0); /* clear any leftover state */ /* clear any leftover notifications */
WaitForSingleObject(oth->ready_sema, 0);
ok = 1; ok = 1;
} else { } else {
intptr_t topp; intptr_t topp;
@ -1305,13 +1370,6 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
ok = 1; ok = 1;
} }
ReleaseSemaphore(oth->lock_sema, 1, NULL); ReleaseSemaphore(oth->lock_sema, 1, NULL);
} else {
if (out_len > 0) {
/* We've already written, which implies that no flush is
in progress. We'll need a flush check in the future. */
rfd->oth->needflush = 1;
}
ok = 1;
} }
if (ok) if (ok)
@ -1373,23 +1431,54 @@ static intptr_t rktio_recount_output_text(const char *orig_buffer, const char *b
return i; return i;
} }
static void deinit_write_fd(rktio_t *rktio, rktio_fd_t *rfd, int full_close)
{
if (rfd->oth) {
CSI_proc csi;
WaitForSingleObject(rfd->oth->lock_sema, INFINITE);
csi = get_csi();
if (csi) {
/* See also call above */
csi(rfd->oth->thread);
}
CloseHandle(rfd->oth->thread);
rfd->oth->done = 1;
ReleaseSemaphore(rfd->oth->work_sema, 1, NULL);
/* Try to leave clean-up to the other thread: */
if (rfd->oth->you_clean_up) {
/* Other thread is already done, so we're stuck with clean-up: */
WindowsFDOCleanup(rfd->oth, (full_close ? 1 : -1));
} else {
/* otherwise, thread is responsible for clean-up */
rfd->oth->you_clean_up = (full_close ? 1 : -1);
ReleaseSemaphore(rfd->oth->lock_sema, 1, NULL);
}
}
}
static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth) static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth)
{ {
DWORD towrite, wrote, start; DWORD towrite, wrote, start;
int ok, more_work = 0, err_no; int ok, more_work = 0, err_no;
if (oth->nonblocking) { if (oth->nonblocking) {
/* Non-blocking mode (Win NT pipes). Just flush. */ /* Non-blocking mode (Win NT pipes). Just handle flush requests. */
WaitForSingleObject(oth->lock_sema, INFINITE);
while (!oth->done) { while (!oth->done) {
ReleaseSemaphore(oth->lock_sema, 1, NULL);
WaitForSingleObject(oth->work_sema, INFINITE); WaitForSingleObject(oth->work_sema, INFINITE);
FlushFileBuffers(oth->fd); FlushFileBuffers(oth->fd);
WaitForSingleObject(oth->lock_sema, INFINITE); WaitForSingleObject(oth->lock_sema, INFINITE);
oth->flushed = 1; oth->flushed = 1;
ReleaseSemaphore(oth->ready_sema, 1, NULL); ReleaseSemaphore(oth->ready_sema, 1, NULL);
ReleaseSemaphore(oth->lock_sema, 1, NULL);
} }
/* lock held on loop exit */
} else { } else {
/* Blocking mode. We do the writing work. This case is for /* Blocking mode. We do the writing work. This case is for
Win 95/98/Me anonymous pipes and character devices (such Win 95/98/Me anonymous pipes and character devices (such
@ -1398,14 +1487,15 @@ static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth)
if (!more_work) if (!more_work)
WaitForSingleObject(oth->work_sema, INFINITE); WaitForSingleObject(oth->work_sema, INFINITE);
WaitForSingleObject(oth->lock_sema, INFINITE);
if (oth->done) if (oth->done)
break; break;
WaitForSingleObject(oth->lock_sema, INFINITE);
towrite = oth->buflen; towrite = oth->buflen;
if (towrite > (RKTIO_FD_BUFFSIZE - oth->bufstart)) if (towrite > (RKTIO_FD_BUFFSIZE - oth->bufstart))
towrite = RKTIO_FD_BUFFSIZE - oth->bufstart; towrite = RKTIO_FD_BUFFSIZE - oth->bufstart;
start = oth->bufstart; start = oth->bufstart;
ReleaseSemaphore(oth->lock_sema, 1, NULL); ReleaseSemaphore(oth->lock_sema, 1, NULL);
ok = WriteFile(oth->fd, oth->buffer + start, towrite, &wrote, NULL); ok = WriteFile(oth->fd, oth->buffer + start, towrite, &wrote, NULL);
@ -1428,21 +1518,27 @@ static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth)
ReleaseSemaphore(oth->ready_sema, 1, NULL); ReleaseSemaphore(oth->ready_sema, 1, NULL);
ReleaseSemaphore(oth->lock_sema, 1, NULL); ReleaseSemaphore(oth->lock_sema, 1, NULL);
} }
/* lock is still held on `break` out of loop */
}
if (oth->you_clean_up) {
WindowsFDOCleanup(oth, oth->you_clean_up);
} else {
/* otherwise, main thread is responsible for clean-up */
oth->you_clean_up = 1;
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; return 0;
} }
static void WindowsFDOCleanup(Win_FD_Output_Thread *oth) static void WindowsFDOCleanup(Win_FD_Output_Thread *oth, int close_mode)
{ {
CloseHandle(oth->lock_sema); CloseHandle(oth->lock_sema);
CloseHandle(oth->work_sema); CloseHandle(oth->work_sema);
CloseHandle(oth->you_clean_up_sema);
if (close_mode != -1)
CloseHandle(oth->fd); CloseHandle(oth->fd);
if (oth->buffer) if (oth->buffer)
free(oth->buffer); free(oth->buffer);

View File

@ -81,7 +81,7 @@ static rktio_fd_t *open_read(rktio_t *rktio, const char *filename, int modes)
return NULL; return NULL;
} }
rfd = rktio_system_fd(rktio, (intptr_t)fd, RKTIO_OPEN_READ); rfd = rktio_system_fd(rktio, (intptr_t)fd, RKTIO_OPEN_READ | RKTIO_OPEN_NOT_DIR);
if (modes & RKTIO_OPEN_TEXT) { if (modes & RKTIO_OPEN_TEXT) {
if (!rktio_fd_is_regular_file(rktio, rfd)) { if (!rktio_fd_is_regular_file(rktio, rfd)) {
@ -228,7 +228,7 @@ static rktio_fd_t *open_write(rktio_t *rktio, const char *filename, int modes)
} }
} }
rfd = rktio_system_fd(rktio, (intptr_t)fd, modes | RKTIO_OPEN_NOT_DIR); rfd = rktio_system_fd(rktio, (intptr_t)fd, modes);
if (rktio_fd_is_directory(rktio, rfd)) { if (rktio_fd_is_directory(rktio, rfd)) {
rktio_close(rktio, rfd); rktio_close(rktio, rfd);
@ -244,8 +244,12 @@ static rktio_fd_t *open_write(rktio_t *rktio, const char *filename, int modes)
} }
} }
if ((modes & RKTIO_OPEN_APPEND) && rktio_fd_is_regular_file(rktio, rfd)) { if ((modes & (RKTIO_OPEN_APPEND |RKTIO_OPEN_TRUNCATE))
SetFilePointer(fd, 0, NULL, FILE_END); && rktio_fd_is_regular_file(rktio, rfd)) {
if (modes & RKTIO_OPEN_APPEND)
SetFilePointer(fd, 0, NULL, FILE_END);
else
SetEndOfFile(fd);
} }
return rfd; return rfd;

View File

@ -669,7 +669,7 @@ int rktio_set_current_directory(rktio_t *rktio, const char *path)
static rktio_identity_t *get_identity(rktio_t *rktio, rktio_fd_t *fd, const char *path, int follow_links) static rktio_identity_t *get_identity(rktio_t *rktio, rktio_fd_t *fd, const char *path, int follow_links)
{ {
uintptr_t devi = 0, inoi = 0, inoi2 = 0; uintptr_t devi = 0, inoi = 0, inoi2 = 0;
uintptr_t devi_bits = 0, inoi_bits = 0, inoi2_bits = 0; int devi_bits = 0, inoi_bits = 0, inoi2_bits = 0;
#ifdef RKTIO_SYSTEM_UNIX #ifdef RKTIO_SYSTEM_UNIX
int errid = 0; int errid = 0;
@ -830,6 +830,9 @@ int rktio_rename_file(rktio_t *rktio, const char *dest, const char *src, int exi
return 1; return 1;
} }
get_windows_error(); get_windows_error();
} else if (errid == ERROR_ALREADY_EXISTS) {
set_racket_error(RKTIO_ERROR_EXISTS);
return 0;
} else } else
get_windows_error(); get_windows_error();

View File

@ -26,6 +26,8 @@
#define RKTIO_SHUT_RD SHUT_RD #define RKTIO_SHUT_RD SHUT_RD
#define RKTIO_SHUT_WR SHUT_WR #define RKTIO_SHUT_WR SHUT_WR
#define RKTIO_SOCKS(s) s
typedef intptr_t rktio_socket_t; typedef intptr_t rktio_socket_t;
typedef unsigned int rktio_sockopt_len_t; typedef unsigned int rktio_sockopt_len_t;
@ -81,6 +83,9 @@ struct SOCKADDR_IN {
typedef SOCKET rktio_socket_t; typedef SOCKET rktio_socket_t;
typedef int rktio_sockopt_len_t; typedef int rktio_sockopt_len_t;
/* Avoid warnings, since select() first argument is ignored: */
#define RKTIO_SOCKS(s) 0
typedef struct SOCKADDR_IN rktio_unspec_address; typedef struct SOCKADDR_IN rktio_unspec_address;
# define REGISTER_SOCKET(s) winsock_remember(s) # define REGISTER_SOCKET(s) winsock_remember(s)
# define UNREGISTER_SOCKET(s) winsock_forget(s) # define UNREGISTER_SOCKET(s) winsock_forget(s)
@ -858,9 +863,14 @@ void rktio_winsock_done(rktio_t *rktio)
/* TCP sockets */ /* TCP sockets */
/*========================================================================*/ /*========================================================================*/
rktio_socket_t rktio_fd_socket(rktio_t *rktio, rktio_fd_t *rfd)
{
return (rktio_socket_t)rktio_fd_system_fd(rktio, rfd);
}
void rktio_socket_init(rktio_t *rktio, rktio_fd_t *rfd) void rktio_socket_init(rktio_t *rktio, rktio_fd_t *rfd)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
#ifdef RKTIO_SYSTEM_UNIX #ifdef RKTIO_SYSTEM_UNIX
fcntl(s, F_SETFL, RKTIO_NONBLOCKING); fcntl(s, F_SETFL, RKTIO_NONBLOCKING);
@ -901,7 +911,7 @@ int rktio_socket_close(rktio_t *rktio, rktio_fd_t *rfd, int set_error)
} }
#endif #endif
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
int err; int err;
UNREGISTER_SOCKET(s); UNREGISTER_SOCKET(s);
err = closesocket(s); err = closesocket(s);
@ -916,7 +926,7 @@ int rktio_socket_close(rktio_t *rktio, rktio_fd_t *rfd, int set_error)
void rktio_socket_own(rktio_t *rktio, rktio_fd_t *rfd) void rktio_socket_own(rktio_t *rktio, rktio_fd_t *rfd)
{ {
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
REGISTER_SOCKET(s); REGISTER_SOCKET(s);
#endif #endif
} }
@ -924,14 +934,14 @@ void rktio_socket_own(rktio_t *rktio, rktio_fd_t *rfd)
void rktio_socket_forget_owned(rktio_t *rktio, rktio_fd_t *rfd) void rktio_socket_forget_owned(rktio_t *rktio, rktio_fd_t *rfd)
{ {
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
UNREGISTER_SOCKET(s); UNREGISTER_SOCKET(s);
#endif #endif
} }
int rktio_socket_shutdown(rktio_t *rktio, rktio_fd_t *rfd, int mode) int rktio_socket_shutdown(rktio_t *rktio, rktio_fd_t *rfd, int mode)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
if (shutdown(s, ((mode == RKTIO_SHUTDOWN_READ) ? RKTIO_SHUT_RD : RKTIO_SHUT_WR))) { if (shutdown(s, ((mode == RKTIO_SHUTDOWN_READ) ? RKTIO_SHUT_RD : RKTIO_SHUT_WR))) {
get_socket_error(); get_socket_error();
@ -948,7 +958,7 @@ int rktio_socket_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd)
#endif #endif
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
DECL_SOCK_FDSET(writefds); DECL_SOCK_FDSET(writefds);
DECL_SOCK_FDSET(exnfds); DECL_SOCK_FDSET(exnfds);
struct timeval time = {0, 0}; struct timeval time = {0, 0};
@ -962,7 +972,7 @@ int rktio_socket_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd)
RKTIO_SOCK_FD_ZERO(exnfds); RKTIO_SOCK_FD_ZERO(exnfds);
RKTIO_SOCK_FD_SET(s, exnfds); RKTIO_SOCK_FD_SET(s, exnfds);
sr = select(s + 1, NULL, writefds, exnfds, &time); sr = select(RKTIO_SOCKS(s + 1), NULL, writefds, exnfds, &time);
if (sr == -1) { if (sr == -1) {
get_socket_error(); get_socket_error();
@ -982,7 +992,7 @@ int rktio_socket_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd)
#endif #endif
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
DECL_SOCK_FDSET(readfds); DECL_SOCK_FDSET(readfds);
DECL_SOCK_FDSET(exnfds); DECL_SOCK_FDSET(exnfds);
struct timeval time = {0, 0}; struct timeval time = {0, 0};
@ -996,7 +1006,7 @@ int rktio_socket_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd)
RKTIO_SOCK_FD_ZERO(exnfds); RKTIO_SOCK_FD_ZERO(exnfds);
RKTIO_SOCK_FD_SET(s, exnfds); RKTIO_SOCK_FD_SET(s, exnfds);
sr = select(s + 1, readfds, NULL, exnfds, &time); sr = select(RKTIO_SOCKS(s + 1), readfds, NULL, exnfds, &time);
if (sr == -1) { if (sr == -1) {
get_socket_error(); get_socket_error();
@ -1015,7 +1025,7 @@ rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd)
return rktio_dup(rktio, rfd); return rktio_dup(rktio, rfd);
#endif #endif
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
rktio_socket_t nsocket; rktio_socket_t nsocket;
intptr_t rc; intptr_t rc;
WSAPROTOCOL_INFO protocolInfo; WSAPROTOCOL_INFO protocolInfo;
@ -1035,7 +1045,7 @@ rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd)
intptr_t rktio_socket_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len) intptr_t rktio_socket_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
int rn; int rn;
do { do {
@ -1061,7 +1071,7 @@ static intptr_t do_socket_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buf
/* for UDP sendto: */ /* for UDP sendto: */
rktio_addrinfo_t *addr) rktio_addrinfo_t *addr)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
intptr_t sent; intptr_t sent;
int errid = 0; int errid = 0;
@ -1183,7 +1193,9 @@ static rktio_connect_t *try_connect(rktio_t *rktio, rktio_connect_t *conn)
errno = status; errno = status;
#endif #endif
conn->trying_fd = rktio_system_fd(rktio, s, RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE | RKTIO_OPEN_OWN); conn->trying_fd = rktio_system_fd(rktio,
(intptr_t)s,
RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE | RKTIO_OPEN_OWN);
conn->inprogress = inprogress; conn->inprogress = inprogress;
return conn; return conn;
@ -1223,7 +1235,7 @@ rktio_fd_t *rktio_connect_finish(rktio_t *rktio, rktio_connect_t *conn)
/* Check whether connect succeeded, or get error: */ /* Check whether connect succeeded, or get error: */
int errid; int errid;
rktio_sockopt_len_t so_len = sizeof(errid); rktio_sockopt_len_t so_len = sizeof(errid);
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&errid, &so_len) != 0) { if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&errid, &so_len) != 0) {
errid = SOCK_ERRNO(); errid = SOCK_ERRNO();
} else } else
@ -1541,7 +1553,7 @@ static int do_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener, int
} }
do { do {
sr = select(mx + 1, RKTIO_SOCK_FDS(readfds), NULL, RKTIO_SOCK_FDS(exnfds), &time); sr = select(RKTIO_SOCKS(mx + 1), RKTIO_SOCK_FDS(readfds), NULL, RKTIO_SOCK_FDS(exnfds), &time);
} while ((sr == -1) && NOT_WINSOCK(errno == EINTR)); } while ((sr == -1) && NOT_WINSOCK(errno == EINTR));
if (sr > 0) { if (sr > 0) {
@ -1579,8 +1591,8 @@ void rktio_poll_add_accept(rktio_t *rktio, rktio_listener_t *listener, rktio_pol
for (i = 0; i < listener->count; i++) { for (i = 0; i < listener->count; i++) {
s = listener->s[i]; s = listener->s[i];
RKTIO_FD_SET(s, fds); RKTIO_FD_SET((intptr_t)s, fds);
RKTIO_FD_SET(s, fds2); RKTIO_FD_SET((intptr_t)s, fds2);
} }
} }
@ -1660,7 +1672,7 @@ char **rktio_socket_address(rktio_t *rktio, rktio_fd_t *rfd)
rktio_sockopt_len_t name_len; rktio_sockopt_len_t name_len;
name_len = sizeof(name); name_len = sizeof(name);
if (getsockname(rktio_fd_system_fd(rktio, rfd), (struct sockaddr *)name, &name_len)) { if (getsockname(rktio_fd_socket(rktio, rfd), (struct sockaddr *)name, &name_len)) {
get_socket_error(); get_socket_error();
return NULL; return NULL;
} }
@ -1674,7 +1686,7 @@ char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd)
rktio_sockopt_len_t name_len; rktio_sockopt_len_t name_len;
name_len = sizeof(name); name_len = sizeof(name);
if (getpeername(rktio_fd_system_fd(rktio, rfd), (struct sockaddr *)name, &name_len)) { if (getpeername(rktio_fd_socket(rktio, rfd), (struct sockaddr *)name, &name_len)) {
get_socket_error(); get_socket_error();
return NULL; return NULL;
} }
@ -1727,7 +1739,7 @@ rktio_fd_t *rktio_udp_open(rktio_t *rktio, rktio_addrinfo_t *addr, int family)
int rktio_udp_disconnect(rktio_t *rktio, rktio_fd_t *rfd) int rktio_udp_disconnect(rktio_t *rktio, rktio_fd_t *rfd)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
int err; int err;
#ifdef USE_NULL_TO_DISCONNECT_UDP #ifdef USE_NULL_TO_DISCONNECT_UDP
@ -1757,7 +1769,7 @@ int rktio_udp_disconnect(rktio_t *rktio, rktio_fd_t *rfd)
int rktio_udp_bind(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr, rktio_bool_t reuse) int rktio_udp_bind(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr, rktio_bool_t reuse)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
int err; int err;
if (reuse) { if (reuse) {
@ -1782,7 +1794,7 @@ int rktio_udp_bind(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr, rkti
int rktio_udp_connect(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr) int rktio_udp_connect(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
int err; int err;
/* connect using first address that works: */ /* connect using first address that works: */
@ -1804,7 +1816,7 @@ intptr_t rktio_udp_sendto(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *add
rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len) rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
rktio_length_and_addrinfo_t *r; rktio_length_and_addrinfo_t *r;
int rn, errid; int rn, errid;
char src_addr[RKTIO_SOCK_NAME_MAX_LEN]; char src_addr[RKTIO_SOCK_NAME_MAX_LEN];
@ -1855,7 +1867,7 @@ rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd,
int rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd) int rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
u_char loop; u_char loop;
rktio_sockopt_len_t loop_len = sizeof(loop); rktio_sockopt_len_t loop_len = sizeof(loop);
int status; int status;
@ -1871,7 +1883,7 @@ int rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd)
int rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, int on) int rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, int on)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
u_char loop = (on ? 1 : 0); u_char loop = (on ? 1 : 0);
rktio_sockopt_len_t loop_len = sizeof(loop); rktio_sockopt_len_t loop_len = sizeof(loop);
int status; int status;
@ -1887,7 +1899,7 @@ int rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, int on)
int rktio_udp_get_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd) int rktio_udp_get_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
u_char ttl; u_char ttl;
rktio_sockopt_len_t ttl_len = sizeof(ttl); rktio_sockopt_len_t ttl_len = sizeof(ttl);
int status; int status;
@ -1903,7 +1915,7 @@ int rktio_udp_get_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd)
int rktio_udp_set_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd, int ttl_val) int rktio_udp_set_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd, int ttl_val)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
u_char ttl = ttl_val; u_char ttl = ttl_val;
rktio_sockopt_len_t ttl_len = sizeof(ttl); rktio_sockopt_len_t ttl_len = sizeof(ttl);
int status; int status;
@ -1919,7 +1931,7 @@ int rktio_udp_set_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd, int ttl_val)
char *rktio_udp_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd) char *rktio_udp_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
struct in_addr intf; struct in_addr intf;
rktio_sockopt_len_t intf_len = sizeof(intf); rktio_sockopt_len_t intf_len = sizeof(intf);
int status; int status;
@ -1939,7 +1951,7 @@ char *rktio_udp_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd)
int rktio_udp_set_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *intf_addr) int rktio_udp_set_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *intf_addr)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
struct in_addr intf; struct in_addr intf;
rktio_sockopt_len_t intf_len = sizeof(intf); rktio_sockopt_len_t intf_len = sizeof(intf);
int status; int status;
@ -1964,7 +1976,7 @@ int rktio_udp_change_multicast_group(rktio_t *rktio, rktio_fd_t *rfd,
rktio_addrinfo_t *intf_addr, rktio_addrinfo_t *intf_addr,
int action) int action)
{ {
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); rktio_socket_t s = rktio_fd_socket(rktio, rfd);
struct ip_mreq mreq; struct ip_mreq mreq;
rktio_sockopt_len_t mreq_len = sizeof(mreq); rktio_sockopt_len_t mreq_len = sizeof(mreq);
int status; int status;

View File

@ -26,7 +26,7 @@ static int MyPipe(intptr_t *ph, int flags, rktio_t *rktio)
a[1] = w; a[1] = w;
for (near_index = 0; near_index < 2; near_index++) { for (near_index = 0; near_index < 2; near_index++) {
if (flags & (near_index ? RKTIO_NO_INHERIT_INPUT : RKTIO_NO_INHERIT_OUTPUT)) { if (flags & (!near_index ? RKTIO_NO_INHERIT_INPUT : RKTIO_NO_INHERIT_OUTPUT)) {
/* Change the near end to make it non-inheritable, then /* Change the near end to make it non-inheritable, then
close the inheritable one: */ close the inheritable one: */
if (!DuplicateHandle(GetCurrentProcess(), a[near_index], if (!DuplicateHandle(GetCurrentProcess(), a[near_index],

View File

@ -94,7 +94,7 @@ void rktio_fdzero(rktio_poll_set_t *fd)
fd->data->skip_sleep = 0; fd->data->skip_sleep = 0;
} }
static int find_fd_pos(struct rktio_fd_set_data_t *data, int n) static int find_fd_pos(struct rktio_fd_set_data_t *data, intptr_t n)
{ {
intptr_t count = data->count; intptr_t count = data->count;
intptr_t i; intptr_t i;
@ -111,7 +111,7 @@ static int find_fd_pos(struct rktio_fd_set_data_t *data, int n)
return -1; return -1;
} }
void rktio_fdclr(rktio_poll_set_t *fd, int n) void rktio_fdclr(rktio_poll_set_t *fd, intptr_t n)
{ {
struct rktio_fd_set_data_t *data = fd->data; struct rktio_fd_set_data_t *data = fd->data;
intptr_t flag = fd->flags; intptr_t flag = fd->flags;
@ -125,7 +125,7 @@ void rktio_fdclr(rktio_poll_set_t *fd, int n)
} }
} }
void rktio_fdset(rktio_poll_set_t *fd, int n) void rktio_fdset(rktio_poll_set_t *fd, intptr_t n)
{ {
struct rktio_fd_set_data_t *data = fd->data; struct rktio_fd_set_data_t *data = fd->data;
intptr_t flag = fd->flags; intptr_t flag = fd->flags;
@ -157,7 +157,7 @@ void rktio_fdset(rktio_poll_set_t *fd, int n)
data->count = count; data->count = count;
} }
int rktio_fdisset(rktio_poll_set_t *fd, int n) int rktio_fdisset(rktio_poll_set_t *fd, intptr_t n)
{ {
struct rktio_fd_set_data_t *data = fd->data; struct rktio_fd_set_data_t *data = fd->data;
intptr_t flag = fd->flags; intptr_t flag = fd->flags;
@ -469,27 +469,27 @@ void rktio_fdzero(rktio_poll_set_t *fd)
init_fdset_array(fd, 1); init_fdset_array(fd, 1);
} }
void rktio_fdclr(rktio_poll_set_t *fd, int n) void rktio_fdclr(rktio_poll_set_t *fd, intptr_t n)
{ {
int i; intptr_t i;
for (i = fd->added; i--; ) { for (i = fd->added; i--; ) {
if (fd->sockets[i] == n) if (fd->sockets[i] == n)
fd->sockets[i] = INVALID_SOCKET; fd->sockets[i] = INVALID_SOCKET;
} }
} }
static int next_size(int v) { return (v ? (2 * v) : 10); } static intptr_t next_size(intptr_t v) { return (v ? (2 * v) : 10); }
void rktio_fdset(rktio_poll_set_t *fd, int n) void rktio_fdset(rktio_poll_set_t *fd, intptr_t n)
{ {
if (fd->added >= fd->last_alloc) { if (fd->added >= fd->last_alloc) {
int na; intptr_t na;
na = next_size(fd->last_alloc); na = next_size(fd->last_alloc);
fd->last_alloc = na; fd->last_alloc = na;
} }
if (fd->added >= fd->alloc) { if (fd->added >= fd->alloc) {
SOCKET *naya; SOCKET *naya;
int na; intptr_t na;
na = next_size(fd->alloc); na = next_size(fd->alloc);
naya = malloc(na * sizeof(SOCKET)); naya = malloc(na * sizeof(SOCKET));
memcpy(naya, fd->sockets, fd->alloc * sizeof(SOCKET)); memcpy(naya, fd->sockets, fd->alloc * sizeof(SOCKET));
@ -498,14 +498,14 @@ void rktio_fdset(rktio_poll_set_t *fd, int n)
fd->alloc = na; fd->alloc = na;
reset_wait_array(fd); reset_wait_array(fd);
} }
fd->sockets[fd->added++] = n; fd->sockets[fd->added++] = (SOCKET)n;
} }
int rktio_fdisset(rktio_poll_set_t *fd, int n) int rktio_fdisset(rktio_poll_set_t *fd, intptr_t n)
{ {
int i; intptr_t i;
for (i = fd->added; i--; ) { for (i = fd->added; i--; ) {
if (fd->sockets[i] == n) if (fd->sockets[i] == (SOCKET)n)
return 1; return 1;
} }
return 0; return 0;
@ -513,10 +513,10 @@ int rktio_fdisset(rktio_poll_set_t *fd, int n)
void rktio_merge_fd_sets(rktio_poll_set_t *fds, rktio_poll_set_t *src_fds) void rktio_merge_fd_sets(rktio_poll_set_t *fds, rktio_poll_set_t *src_fds)
{ {
int i; intptr_t i;
for (i = src_fds->added; i--; ) { for (i = src_fds->added; i--; ) {
if (src_fds->sockets[i] != INVALID_SOCKET) if (src_fds->sockets[i] != INVALID_SOCKET)
rktio_fdset(fds, src_fds->sockets[i]); rktio_fdset(fds, (intptr_t)src_fds->sockets[i]);
} }
} }
@ -534,7 +534,8 @@ void rktio_poll_set_add_handle(rktio_t *rktio, intptr_t _h, rktio_poll_set_t *fd
HANDLE h = (HANDLE)_h; HANDLE h = (HANDLE)_h;
rktio_poll_set_t *efd = fds; rktio_poll_set_t *efd = fds;
HANDLE *hs; HANDLE *hs;
int i, new_i, *rps; intptr_t i, new_i;
int *rps;
if (efd->num_handles == efd->last_alloc_handles) { if (efd->num_handles == efd->last_alloc_handles) {
i = next_size(efd->last_alloc_handles); i = next_size(efd->last_alloc_handles);
@ -606,7 +607,7 @@ void rktio_collapse_win_fd(rktio_poll_set_t *fds)
{ {
rktio_poll_set_t *rfd, *wfd, *efd; rktio_poll_set_t *rfd, *wfd, *efd;
HANDLE *wa, e; HANDLE *wa, e;
int i, p = 0, mask, j; intptr_t i, p = 0, mask, j;
SOCKET s; SOCKET s;
rfd = fds; rfd = fds;
@ -781,12 +782,12 @@ static int fdset_has_nosleep(rktio_poll_set_t *fds)
#ifdef USE_PLAIN_FDS_SET_OPS #ifdef USE_PLAIN_FDS_SET_OPS
void rktio_fdclr(rktio_poll_set_t *fd, int n) void rktio_fdclr(rktio_poll_set_t *fd, intptr_t n)
{ {
FD_CLR(n, &(fd)->data); FD_CLR(n, &(fd)->data);
} }
void rktio_fdset(rktio_poll_set_t *fd, int n) void rktio_fdset(rktio_poll_set_t *fd, intptr_t n)
{ {
# ifdef STORED_ACTUAL_FDSET_LIMIT # ifdef STORED_ACTUAL_FDSET_LIMIT
int mx; int mx;
@ -797,7 +798,7 @@ void rktio_fdset(rktio_poll_set_t *fd, int n)
FD_SET(n, &(fd)->data); FD_SET(n, &(fd)->data);
} }
int rktio_fdisset(rktio_poll_set_t *fd, int n) int rktio_fdisset(rktio_poll_set_t *fd, intptr_t n)
{ {
return FD_ISSET(n, &(fd)->data); return FD_ISSET(n, &(fd)->data);
} }
@ -1207,7 +1208,8 @@ void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds, rktio_ltps_
{ {
intptr_t result; intptr_t result;
HANDLE *array, just_two_array[2]; HANDLE *array, just_two_array[2];
int count, rcount, *rps; intptr_t count, rcount;
int *rps;
rktio_collapse_win_fd(fds); /* merges */ rktio_collapse_win_fd(fds); /* merges */

View File

@ -31,7 +31,7 @@
/*========================================================================*/ /*========================================================================*/
struct rktio_t { struct rktio_t {
intptr_t errid; int errid;
int errkind; int errkind;
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
char *last_err_str; char *last_err_str;
@ -108,9 +108,9 @@ int rktio_initialize_signal(rktio_t *rktio);
rktio_poll_set_t *rktio_get_fdset(rktio_poll_set_t *fdarray, int pos); rktio_poll_set_t *rktio_get_fdset(rktio_poll_set_t *fdarray, int pos);
void rktio_fdzero(rktio_poll_set_t *fd); void rktio_fdzero(rktio_poll_set_t *fd);
void rktio_fdset(rktio_poll_set_t *fd, int n); void rktio_fdset(rktio_poll_set_t *fd, intptr_t n);
void rktio_fdclr(rktio_poll_set_t *fd, int n); void rktio_fdclr(rktio_poll_set_t *fd, intptr_t n);
int rktio_fdisset(rktio_poll_set_t *fd, int n); int rktio_fdisset(rktio_poll_set_t *fd, intptr_t n);
# define DECL_FDSET(n, c) rktio_poll_set_t *n # define DECL_FDSET(n, c) rktio_poll_set_t *n
# define INIT_DECL_FDSET(r, w, e) { \ # define INIT_DECL_FDSET(r, w, e) { \

View File

@ -1028,12 +1028,13 @@ static char *cmdline_protect(char *s)
} }
static intptr_t do_spawnv(rktio_t *rktio, static intptr_t do_spawnv(rktio_t *rktio,
const char *command, const char * const *argv, const char *command, int argc, const char * const *argv,
int exact_cmdline, intptr_t sin, intptr_t sout, intptr_t serr, int *pid, int exact_cmdline, intptr_t sin, intptr_t sout, intptr_t serr, int *pid,
int new_process_group, int chain_termination_here_to_child, int new_process_group, int chain_termination_here_to_child,
void *env, const char *wd) void *env, const char *wd)
{ {
int i, l, len = 0, use_jo; intptr_t i, l, len = 0;
int use_jo;
intptr_t cr_flag; intptr_t cr_flag;
char *cmdline; char *cmdline;
wchar_t *cmdline_w, *wd_w; wchar_t *cmdline_w, *wd_w;
@ -1043,14 +1044,14 @@ static intptr_t do_spawnv(rktio_t *rktio,
if (exact_cmdline) { if (exact_cmdline) {
cmdline = (char *)argv[1]; cmdline = (char *)argv[1];
} else { } else {
for (i = 0; argv[i]; i++) { for (i = 0; i < argc; i++) {
len += strlen(argv[i]) + 1; len += strlen(argv[i]) + 1;
} }
cmdline = malloc(len); cmdline = malloc(len);
len = 0; len = 0;
for (i = 0; argv[i]; i++) { for (i = 0; i < argc; i++) {
l = strlen(argv[i]); l = strlen(argv[i]);
memcpy(cmdline + len, argv[i], l); memcpy(cmdline + len, argv[i], l);
cmdline[len + l] = ' '; cmdline[len + l] = ' ';
@ -1205,7 +1206,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
int windows_chain_termination_to_child = (flags & RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION); int windows_chain_termination_to_child = (flags & RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION);
int i; int i;
#endif #endif
/* avoid compiler warnings: */ /* avoid compiler warnings: */
to_subprocess[0] = -1; to_subprocess[0] = -1;
to_subprocess[1] = -1; to_subprocess[1] = -1;
@ -1228,8 +1229,8 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
if (stdin_fd) { if (stdin_fd) {
to_subprocess[0] = rktio_fd_system_fd(rktio, stdin_fd); to_subprocess[0] = rktio_fd_system_fd(rktio, stdin_fd);
RKTIO_COPY_FOR_SUBPROCESS(to_subprocess, 0); RKTIO_COPY_FOR_SUBPROCESS(to_subprocess, 0);
} else if (rktio_make_os_pipe(rktio, to_subprocess, 1)) { } else if (rktio_make_os_pipe(rktio, to_subprocess, RKTIO_NO_INHERIT_OUTPUT)) {
if (stdout_fd) { RKTIO_CLOSE_SUBPROCESS_COPY(from_subprocess, RKTIO_NO_INHERIT_OUTPUT); } if (stdout_fd) { RKTIO_CLOSE_SUBPROCESS_COPY(from_subprocess, 1); }
return NULL; return NULL;
} }
@ -1276,7 +1277,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
pid = 0; pid = 0;
spawn_status = do_spawnv(rktio, spawn_status = do_spawnv(rktio,
command, (const char * const *)argv, command, argc, (const char * const *)argv,
windows_exact_cmdline, windows_exact_cmdline,
to_subprocess[0], to_subprocess[0],
from_subprocess[1], from_subprocess[1],

View File

@ -13,6 +13,8 @@
*/*.suo */*.suo
*/*.sdf */*.sdf
*/*.sln.cache */*.sln.cache
*/*.db
*/.vs
# potentially generated by "genvsx" # potentially generated by "genvsx"
*/*X.vcxproj */*X.vcxproj

View File

@ -21,8 +21,8 @@
<Configurations> <Configurations>
<Configuration <Configuration
Name="Debug|Win32" Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)" OutputDirectory="$(SolutionDir)\..\libffi\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" IntermediateDirectory="..\libffi\$(PlatformName)\$(ConfigurationName)"
ConfigurationType="4" ConfigurationType="4"
CharacterSet="1" CharacterSet="1"
> >
@ -41,8 +41,8 @@
</Configuration> </Configuration>
<Configuration <Configuration
Name="Debug|x64" Name="Debug|x64"
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" OutputDirectory="$(SolutionDir)\..\libffi\$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" IntermediateDirectory="..\libffi\$(PlatformName)\$(ConfigurationName)"
ConfigurationType="4" ConfigurationType="4"
CharacterSet="1" CharacterSet="1"
> >
@ -61,8 +61,8 @@
</Configuration> </Configuration>
<Configuration <Configuration
Name="Release|Win32" Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)" OutputDirectory="$(SolutionDir)\..\libffi\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" IntermediateDirectory="..\libffi\$(PlatformName)\$(ConfigurationName)"
ConfigurationType="4" ConfigurationType="4"
CharacterSet="1" CharacterSet="1"
WholeProgramOptimization="1" WholeProgramOptimization="1"
@ -82,8 +82,8 @@
</Configuration> </Configuration>
<Configuration <Configuration
Name="Release|x64" Name="Release|x64"
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" OutputDirectory="$(SolutionDir)\..\libffi\$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" IntermediateDirectory="..\libffi\$(PlatformName)\$(ConfigurationName)"
ConfigurationType="4" ConfigurationType="4"
CharacterSet="1" CharacterSet="1"
WholeProgramOptimization="1" WholeProgramOptimization="1"

View File

@ -65,8 +65,8 @@
<PropertyGroup> <PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion> <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
<TargetName>libffi</TargetName> <TargetName>libffi</TargetName>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> <OutDir>$(SolutionDir)\..\libffi\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir> <IntDir>..\libffi\$(Platform)\$(Configuration)\</IntDir>
<PlatformToolset>v100</PlatformToolset> <PlatformToolset>v100</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup> <ItemDefinitionGroup>

View File

@ -21,8 +21,8 @@
<Configurations> <Configurations>
<Configuration <Configuration
Name="Debug|Win32" Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)" OutputDirectory="$(SolutionDir)\..\librktio\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" IntermediateDirectory="..\librktio\$(PlatformName)\$(ConfigurationName)"
ConfigurationType="4" ConfigurationType="4"
CharacterSet="1" CharacterSet="1"
> >
@ -41,8 +41,8 @@
</Configuration> </Configuration>
<Configuration <Configuration
Name="Debug|x64" Name="Debug|x64"
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" OutputDirectory="$(SolutionDir)\..\librktio\$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" IntermediateDirectory="..\librktio\$(PlatformName)\$(ConfigurationName)"
ConfigurationType="4" ConfigurationType="4"
CharacterSet="1" CharacterSet="1"
> >
@ -61,8 +61,8 @@
</Configuration> </Configuration>
<Configuration <Configuration
Name="Release|Win32" Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)" OutputDirectory="$(SolutionDir)\..\librktio\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" IntermediateDirectory="..\librktio\$(PlatformName)\$(ConfigurationName)"
ConfigurationType="4" ConfigurationType="4"
CharacterSet="1" CharacterSet="1"
WholeProgramOptimization="1" WholeProgramOptimization="1"
@ -82,8 +82,8 @@
</Configuration> </Configuration>
<Configuration <Configuration
Name="Release|x64" Name="Release|x64"
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" OutputDirectory="$(SolutionDir)\..\librktio\$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" IntermediateDirectory="..\librktio\$(PlatformName)\$(ConfigurationName)"
ConfigurationType="4" ConfigurationType="4"
CharacterSet="1" CharacterSet="1"
WholeProgramOptimization="1" WholeProgramOptimization="1"

View File

@ -65,8 +65,8 @@
<PropertyGroup> <PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion> <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
<TargetName>librktio</TargetName> <TargetName>librktio</TargetName>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> <OutDir>$(SolutionDir)\..\librktio\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir> <IntDir>..\librktio\$(Platform)\$(Configuration)\</IntDir>
<PlatformToolset>v100</PlatformToolset> <PlatformToolset>v100</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup> <ItemDefinitionGroup>

View File

@ -2,5 +2,8 @@
#include <stddef.h> #include <stddef.h>
typedef _int64 rktio_int64_t;
typedef unsigned _int64 rktio_uint64_t;
/* whether getaddrinfo works */ /* whether getaddrinfo works */
#define HAVE_GETADDRINFO 1 #define HAVE_GETADDRINFO 1