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
#include <sys/types.h>
#include <sys/time.h>
#ifndef DOS_FILE_SYSTEM
# include <sys/time.h>
#endif
#ifndef NO_USER_BREAK_HANDLER
# include <signal.h>
#endif

View File

@ -200,8 +200,6 @@ static int do_main_stack_setup(int no_auto_statics, Scheme_Nested_Main _main, vo
#endif
scheme_set_stack_base(PROMPT_STACK(stack_start), no_auto_statics);
scheme_rktio = rktio_init();
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_init_os_thread();
scheme_rktio = rktio_init();
#ifdef MZ_USE_MZRT
scheme_init_glib_log_queue();
#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)
{
rktio_poll_set_t *ps;
ps = rktio_make_poll_set(rktio);
check_valid(ps);
rktio_poll_add(rktio, fd, ps, RKTIO_POLL_READ);
rktio_sleep(rktio, 0, ps, NULL);
rktio_poll_set_forget(rktio, ps);
while (rktio_poll_read_ready(rktio, fd) == RKTIO_POLL_NOT_READY) {
rktio_poll_set_t *ps;
ps = rktio_make_poll_set(rktio);
check_valid(ps);
rktio_poll_add(rktio, fd, ps, RKTIO_POLL_READ);
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)
{
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: */
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
amt = rktio_write(rktio, fd2, "hello", 5);
amt = rktio_write(rktio, fd2, "hola\n", 5);
check_valid(amt == 5);
if (!immediate_available) {
/* Wait for read to be ready; should not block for long */
wait_read(rktio, fd);
}
check_valid(rktio_poll_read_ready(rktio, fd) == RKTIO_POLL_READY);
if (lt) {
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
amt = rktio_read(rktio, fd, buffer, sizeof(buffer));
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));
/* 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_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;
int r;
if (!limit)
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);
if (!amt)
break;
if (amt == RKTIO_WRITE_ERROR)
break;
}
check_valid(i > 0);
if (!rktio_fd_is_udp(rktio, fd2))
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;
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 < limit);
if (verbose)
printf(" read empty after %ld\n", (long)i);
}
void check_many_lookup(rktio_t *rktio)
@ -329,7 +372,7 @@ void check_many_lookup(rktio_t *rktio)
check_valid(lookup[i]);
}
for (j = 0; j < LOOKUPS_N; j++) {
for (j = 0; j < LOOKUPS_N; ) {
ps = rktio_make_poll_set(rktio);
check_valid(ps);
@ -343,6 +386,7 @@ void check_many_lookup(rktio_t *rktio)
for (i = 0; i < LOOKUPS_N; i++) {
if (lookup[i] && (rktio_poll_addrinfo_lookup_ready(rktio, lookup[i]) == RKTIO_POLL_READY)) {
j++;
if ((i % 3) == 2)
rktio_addrinfo_lookup_stop(rktio, lookup[i]);
else {
@ -351,7 +395,6 @@ void check_many_lookup(rktio_t *rktio)
rktio_addrinfo_free(rktio, addr);
}
lookup[i] = NULL;
break;
}
}
}
@ -363,17 +406,20 @@ rktio_addrinfo_t *lookup_loop(rktio_t *rktio,
{
rktio_addrinfo_lookup_t *lookup;
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);
check_valid(lookup);
rktio_poll_add_addrinfo_lookup(rktio, lookup, ps);
rktio_sleep(rktio, 0, ps, NULL);
rktio_poll_set_forget(rktio, ps);
while (rktio_poll_addrinfo_lookup_ready(rktio, lookup) == RKTIO_POLL_NOT_READY) {
rktio_poll_set_t *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);
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_poll_set_t *ps;
rktio_fd_t *fd;
rktio_fd_t *fd = NULL;
conn = rktio_start_connect(rktio, addr, local_addr);
check_valid(conn);
while (1) {
while (!fd) {
ps = rktio_make_poll_set(rktio);
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)) {
/* loop to try again */
} else {
/* report other error: */
check_valid(fd);
}
} else
break;
}
}
return fd;
@ -541,9 +587,17 @@ int main(int argc, char **argv)
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);
{
int ok;
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);
check_valid(cp);
@ -638,7 +692,7 @@ int main(int argc, char **argv)
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: */
pipe_fds = rktio_make_pipe(rktio, 0);
@ -647,9 +701,12 @@ int main(int argc, char **argv)
fd2 = pipe_fds[1];
free(pipe_fds);
check_fill_write(rktio, fd2, NULL, 0);
check_drain_read(rktio, fd, 0);
check_fill_write(rktio, fd2, NULL, 0, verbose);
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, fd2));
}
@ -664,7 +721,7 @@ int main(int argc, char **argv)
rktio_listener_t *lnr;
check_many_lookup(rktio);
addr = lookup_loop(rktio, NULL, 4536, -1, 1, 1);
lnr = rktio_listen(rktio, addr, 5, 1);
@ -722,8 +779,10 @@ int main(int argc, char **argv)
fd2 = rktio_accept(rktio, lnr);
check_fill_write(rktio, fd2, NULL, 0);
check_drain_read(rktio, fd, 0);
printf(" fill\n");
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, fd2));
@ -774,8 +833,8 @@ int main(int argc, char **argv)
addr = lookup_loop(rktio, "localhost", 4536, -1, 0, 0);
check_valid(addr);
check_fill_write(rktio, fd2, addr, AMOUNT_FOR_UDP);
check_drain_read(rktio, fd, AMOUNT_FOR_UDP+1);
check_fill_write(rktio, fd2, addr, AMOUNT_FOR_UDP, verbose);
check_drain_read(rktio, fd, AMOUNT_FOR_UDP+1, verbose);
rktio_addrinfo_free(rktio, addr);
rktio_addrinfo_free(rktio, intf_addr);
@ -792,12 +851,18 @@ int main(int argc, char **argv)
{
rktio_status_t *status;
rktio_process_result_t *result;
#ifdef RKTIO_SYSTEM_UNIX
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_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;
result = rktio_process(rktio, argv[0], 1, argv,
result = rktio_process(rktio, argv[0], argc, argv,
NULL, NULL, err_fd,
pwd, envvars,
0);
@ -826,8 +891,14 @@ int main(int argc, char **argv)
rktio_process_forget(rktio, result->process);
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` */
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,
NULL, NULL, err_fd,
pwd, envvars,
@ -852,7 +923,7 @@ int main(int argc, char **argv)
}
pause_for_process(rktio, result->process, dont_rely_on_sigchild);
status = rktio_process_status(rktio, result->process);
check_valid(status);
check_valid(!status->running);
@ -862,8 +933,9 @@ int main(int argc, char **argv)
{
char buffer[1];
intptr_t amt;
wait_read(rktio, result->stdout_fd);
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));
@ -874,8 +946,18 @@ int main(int argc, char **argv)
}
{
#ifdef RKTIO_SYSTEM_UNIX
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)
printf(" envvars\n");
@ -886,10 +968,10 @@ int main(int argc, char **argv)
check_valid(!strcmp(s, "howdy"));
free(s);
result = rktio_process(rktio, argv[0], 2, argv,
result = rktio_process(rktio, argv[0], argc, argv,
NULL, NULL, err_fd,
pwd, envvars,
0);
flags);
check_valid(result);
/* Assume that a pipe can buffer the minimal output from `printenv`: */
@ -900,8 +982,13 @@ int main(int argc, char **argv)
char buffer[32];
intptr_t amt;
amt = rktio_read(rktio, result->stdout_fd, buffer, sizeof(buffer));
check_valid(amt == 6);
check_valid(!strncmp(buffer, "howdy\n", 6));
if (expect_crlf) {
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));
@ -919,7 +1006,11 @@ int main(int argc, char **argv)
/* Filesystem-change events */
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_poll_set_t *ps;
rktio_ltps_t *lt;
@ -956,7 +1047,19 @@ int main(int argc, char **argv)
amt = rktio_write(rktio, fd2, "hola", 4);
check_valid(amt == 4);
printf("wait...\n");
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);
@ -967,6 +1070,8 @@ int main(int argc, char **argv)
if (lt)
rktio_ltps_close(rktio, lt);
free(path);
}
if (verbose)
@ -1061,7 +1166,7 @@ int main(int argc, char **argv)
today->zone_offset, today->zone_offset / (60 * 60),
(today->is_dst ? ";DST" : ""),
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);
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);
/* Can report `RKTIO_ERROR_EXISTS` in place of system error,
and can report `RKTIO_ERROR_UNSUPPORTED_TEXT_MODE` on Windows.
See also `rktio_write` and `rktio_poll_write_flushed. */
See also `rktio_write` and `rktio_poll_write_flushed`. */
RKTIO_EXTERN void rktio_close_noerr(rktio_t *rktio, rktio_fd_t *fd);
/* 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
error. Although rktio_write() is intended to write only bytes that
can be fully delivered to the OS, there may be OS limitations that
require buffering (e.g., on Windows). Use
rktio_poll_write_flushed() to make sure it's completely flushed
before closing. */
require buffering (e.g., on Windows). Use `rktio_poll_write_flushed`
to make sure the data is received by the destination before closing
`fd`. */
#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)
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_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);
/* Waits up to `nsecs` seconds (or forever if `nsecs` is 0) or until
something registered with `fds` or `lt` is ready. */
/* Waits up to `nsecs` seconds (or forever if `nsecs` is 0), until
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 */

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 i = strlen(s);
intptr_t i = strlen(s);
#ifdef RKTIO_SYSTEM_WINDOWS
if (!s[0]) return 0;
#endif
@ -159,8 +159,7 @@ rktio_envvars_t *rktio_envvars(rktio_t *rktio)
i = 0;
while (e[i]) {
count++;
for (i = 0; e[i]; ) {
}
while (e[i]) i++;
i++;
}
@ -171,7 +170,8 @@ rktio_envvars_t *rktio_envvars(rktio_t *rktio)
envvars->vals = malloc(count * sizeof(char *));
count = 0;
for (i = 0; e[i]; ) {
i = 0;
while (e[i]) {
start = i;
while (e[i]) { i++; }
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);
free(p);
i++;
count++;
}
FreeEnvironmentStringsW(e);
@ -382,7 +383,7 @@ void *rktio_envvars_to_block(rktio_t *rktio, rktio_envvars_t *envvars)
intptr_t len = 0, slen;
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->vals[i]));
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
else if (kind == RKTIO_ERROR_KIND_WINDOWS) {
wchar_t mbuf[256];
int len, i;
intptr_t len, i;
if ((len = FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS),
NULL,
@ -128,7 +128,7 @@ const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid)
mbuf[len] = 0;
es = NARROW_PATH_copy(mbuf);
/* Remove newlines: */
for (i = strlen(s) - 1; i > 0; i--) {
for (i = strlen(es) - 1; i > 0; i--) {
if (isspace(es[i]))
es[i] = 0;
else

View File

@ -34,7 +34,7 @@ struct rktio_fd_t {
#ifdef RKTIO_SYSTEM_WINDOWS
union {
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_Output_Thread *oth; /* output mode */
@ -53,11 +53,11 @@ struct rktio_fd_t {
typedef struct Win_FD_Input_Thread {
/* This is malloced for use in a Win32 thread */
HANDLE fd;
volatile int avail, err, checking;
int avail, offset, err, checking, you_clean_up;
int *refcount;
HANDLE eof;
unsigned char *buffer;
HANDLE checking_sema, ready_sema, you_clean_up_sema;
HANDLE lock_sema, checking_sema, ready_sema;
HANDLE 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
write has ben flushed, which in turn is needed to
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
to the main thread. For efficiency, we request
flush checking only when needed (instead of
after every write); needflush indicates that
a flush check is currently needed, but hasn't
been started. */
volatile int done, err_no;
volatile unsigned int buflen, bufstart, bufend; /* used for blocking, only */
int done, err_no, you_clean_up;
unsigned int buflen, bufstart, bufend; /* used for blocking, only */
unsigned char *buffer; /* used for blocking, only */
int *refcount;
HANDLE lock_sema, work_sema, ready_sema, you_clean_up_sema;
/* lock_sema protects the fields, work_sema starts the flush or
flush-checking thread to work, ready_sema indicates that a flush
finished, and you_clean_up_sema is essentially a reference
count */
HANDLE lock_sema, work_sema, ready_sema;
HANDLE thread;
} Win_FD_Output_Thread;
# 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 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 void WindowsFDOCleanup(Win_FD_Output_Thread *oth);
static void WindowsFDOCleanup(Win_FD_Output_Thread *oth, int close_mode);
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 */
/*========================================================================*/
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 *rfd;
@ -200,7 +155,7 @@ rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes)
#ifdef RKTIO_SYSTEM_WINDOWS
if (modes & RKTIO_OPEN_SOCKET)
rfd->sock = system_fd;
rfd->sock = (SOCKET)system_fd;
else
rfd->fd = (HANDLE)system_fd;
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
if (modes & RKTIO_OPEN_READ)
init_read_fd(rktio, rfd);
if ((modes & RKTIO_OPEN_SOCKET) && (modes & RKTIO_OPEN_INIT))
rktio_socket_init(rktio, rfd);
@ -236,7 +188,7 @@ intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd)
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
if (rfd->modes & RKTIO_OPEN_SOCKET)
return rfd->sock;
return (intptr_t)rfd->sock;
else
return (intptr_t)rfd->fd;
#endif
@ -262,7 +214,9 @@ rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which)
which = STD_ERROR_HANDLE;
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
}
@ -400,53 +354,8 @@ static rktio_ok_t do_close(rktio_t *rktio, rktio_fd_t *rfd, int set_error)
#ifdef RKTIO_SYSTEM_WINDOWS
if (rfd->modes & RKTIO_OPEN_SOCKET)
return rktio_socket_close(rktio, rfd, set_error);
if (rfd->th) {
CSI_proc csi;
/* -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 (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 */
}
deinit_fd(rktio, rfd, 1);
ok = 1;
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)
{
#ifdef RKTIO_WINDOWS_SYSTEM
deinit_fd(rktio, rfd, 1);
#endif
free(rfd);
}
@ -572,7 +484,9 @@ int rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd)
#ifdef RKTIO_SYSTEM_WINDOWS
if (rfd->modes & RKTIO_OPEN_SOCKET)
return rktio_socket_poll_read_ready(rktio, rfd);
init_read_fd(rktio, rfd);
if (!rfd->th) {
/* No thread -- so wait works. This case isn't actually used
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;
} else {
/* Has the reader thread pulled in data? */
WaitForSingleObject(rfd->th->lock_sema, INFINITE);
if (rfd->th->checking) {
/* The thread is still trying, last we knew. Check the
data-is-ready sema: */
if (WaitForSingleObject(rfd->th->ready_sema, 0) == WAIT_OBJECT_0) {
rfd->th->checking = 0;
return RKTIO_POLL_READY;
}
} else if (rfd->th->avail || rfd->th->err || rfd->th->eof)
/* The thread is still trying.
Clean up any signals that we may have ignored before. */
WaitForSingleObject(rfd->th->ready_sema, 0);
} else if (rfd->th->avail || rfd->th->err || rfd->th->eof) {
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
return RKTIO_POLL_READY; /* other thread found data */
else {
} else {
/* Doesn't have anything, and it's not even looking. Tell it
to look: */
rfd->th->checking = 1;
ReleaseSemaphore(rfd->th->checking_sema, 1, NULL);
}
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
}
return 0;
@ -647,11 +561,14 @@ int poll_write_ready_or_flushed(rktio_t *rktio, rktio_fd_t *rfd, int check_flush
}
#endif
#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);
}
if (rfd->oth) {
/* Pipe output that can block... */
/* Pipe output that can block or needs a background flush */
int retval;
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;
} else
retval = oth->flushed;
} else
retval = (oth->err_no || (check_flushed
? !oth->buflen
: (oth->buflen < RKTIO_FD_BUFFSIZE)));
if (!retval && !check_flushed)
WaitForSingleObject(oth->ready_sema, 0); /* clear any leftover state */
if (!retval) {
/* While we hold the lock, clear any leftover notifications */
WaitForSingleObject(oth->ready_sema, 0);
}
} else {
/* 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);
return retval;
return (retval ? RKTIO_POLL_READY : 0);
} else
return RKTIO_POLL_READY; /* non-blocking output, such as a console, or haven't written yet */
#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;
if (modes & RKTIO_POLL_READ) {
RKTIO_FD_SET(rfd->sock, fds);
RKTIO_FD_SET((intptr_t)rfd->sock, fds);
}
if (modes & RKTIO_POLL_WRITE) {
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);
RKTIO_FD_SET(rfd->sock, fds2);
RKTIO_FD_SET((intptr_t)rfd->sock, fds2);
} else {
if (modes & RKTIO_POLL_READ) {
init_read_fd(rktio, rfd);
if (rfd->th) {
/* See fd_byte_ready */
WaitForSingleObject(rfd->th->lock_sema, INFINITE);
if (!rfd->th->checking) {
if (rfd->th->avail || rfd->th->err || rfd->th->eof) {
/* Data is ready. We shouldn't be trying to sleep, so force an
immediate wake-up: */
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
rktio_poll_set_add_nosleep(rktio, fds);
} else {
/* Ask the reader thread to start checking for data */
rfd->th->checking = 1;
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);
}
} else
} else {
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
rktio_poll_set_add_handle(rktio, (intptr_t)rfd->th->ready_sema, fds, 1);
}
} else if (rktio_fd_is_regular_file(rktio, rfd)) {
/* regular files never block */
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
if (rfd->modes & RKTIO_OPEN_SOCKET)
return rktio_socket_read(rktio, rfd, buffer, len);
init_read_fd(rktio, rfd);
if (!rfd->th) {
/* We can read directly. This must be a regular file, where
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))
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. */
WaitForSingleObject(rfd->th->lock_sema, INFINITE);
if (rfd->th->eof) {
if (rfd->th->eof != INVALID_HANDLE_VALUE) {
ReleaseSemaphore(rfd->th->eof, 1, NULL);
rfd->th->eof = NULL;
}
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
return RKTIO_READ_EOF;
} else if (rfd->th->err) {
ReleaseSemaphore(rfd->th->lock_sema, 1, NULL);
set_windows_error(rfd->th->err);
return RKTIO_READ_ERROR;
} else {
intptr_t bc = rfd->th->avail;
rfd->th->avail = 0;
memcpy(buffer, rfd->buffer, bc);
if (bc > len)
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;
}
}
@ -923,6 +869,88 @@ static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, char *is_
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)
{
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: */
WaitForSingleObject(th->checking_sema, INFINITE);
WaitForSingleObject(th->lock_sema, INFINITE);
if (th->checking < 0)
break;
if (ReadFile(th->fd, th->buffer, toget, &got, NULL)) {
th->avail = got;
if (!got) {
/* We interpret a send of 0 bytes as a mid-stream EOF. */
eof_wait = CreateSemaphore(NULL, 0, 1, NULL);
th->eof = eof_wait;
}
if (th->avail) {
/* Spurious wake-up? */
ReleaseSemaphore(th->lock_sema, 1, NULL);
} else {
int err;
err = GetLastError();
if (err == ERROR_BROKEN_PIPE) {
th->eof = INVALID_HANDLE_VALUE;
perma_eof = 1;
} else
th->err = err;
}
ReleaseSemaphore(th->lock_sema, 1, NULL);
if (ReadFile(th->fd, th->buffer, toget, &got, NULL)) {
WaitForSingleObject(th->lock_sema, INFINITE);
th->avail = got;
th->offset = 0;
if (!got) {
/* We interpret a send of 0 bytes as a mid-stream EOF. */
eof_wait = CreateSemaphore(NULL, 0, 1, NULL);
th->eof = eof_wait;
}
/* 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: */
ReleaseSemaphore(th->ready_sema, 1, NULL);
th->checking = 0;
if (eof_wait) {
WaitForSingleObject(eof_wait, INFINITE);
eof_wait = NULL;
/* Notify main program that we found something: */
ReleaseSemaphore(th->ready_sema, 1, 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: */
if (WaitForSingleObject(th->you_clean_up_sema, 0) != WAIT_OBJECT_0) {
WindowsFDICleanup(th);
} /* otherwise, main program is responsible for clean-up */
if (th->you_clean_up) {
WindowsFDICleanup(th, th->you_clean_up);
} else {
/* otherwise, main program is responsible for clean-up */
th->you_clean_up = 1;
ReleaseSemaphore(th->lock_sema, 1, NULL);
}
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->ready_sema);
CloseHandle(th->you_clean_up_sema);
CloseHandle(th->fd);
if (close_mode != -1)
CloseHandle(th->fd);
free(th->buffer);
free(th);
@ -1097,7 +1150,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
flushed). */
intptr_t out_len = 0;
int ok, errsaved;
if (!rfd->oth || rfd->oth->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));
} else
nonblocking = 1; /* must be, or we would not have gotten here */
if (nonblocking) {
/* Unless we're still trying to flush old data, write to the
pipe and have the other thread start flushing it. */
@ -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))) {
towrite = towrite >> 1;
if (!towrite) {
get_windows_error();
return RKTIO_WRITE_ERROR;
/* leave ok as 1 and winwrote as 0 */
break;
}
} else
break;
@ -1177,32 +1230,42 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
if (ok)
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... */
if (!rfd->oth) {
if (ok && (out_len > 0) && !rfd->oth) {
/* We create a thread even for pipes that can be put in
non-blocking mode, because that seems to be the only
way to get evt behavior. */
way to get evt behavior of knowing that a write will
succeed because the previous content is flushed. */
Win_FD_Output_Thread *oth;
HANDLE h;
DWORD id;
unsigned char *bfr;
HANDLE sm;
oth = malloc(sizeof(Win_FD_Output_Thread));
oth = calloc(1, sizeof(Win_FD_Output_Thread));
rfd->oth = oth;
oth->nonblocking = nonblocking;
if (!nonblocking) {
/* Create the buffer to communicate with the writing thread. */
bfr = malloc(RKTIO_FD_BUFFSIZE);
oth->buffer = bfr;
oth->flushed = 0;
oth->needflush = 0;
} else {
/* No buffer needed */
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;
}
@ -1219,9 +1282,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
oth->work_sema = sm;
sm = CreateSemaphore(NULL, 1, 1, NULL);
oth->ready_sema = sm;
sm = CreateSemaphore(NULL, 1, 1, NULL);
oth->you_clean_up_sema = sm;
h = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)WindowsFDWriter, oth, 0, &id);
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
done... */
if (!rfd->oth->nonblocking) {
if (rfd->oth && !rfd->oth->nonblocking) {
/* This case is for Win 95/98/Me anonymous pipes and
character devices. We haven't written anything yet! We
write to a buffer read by the other thread, and return --
@ -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
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;
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;
ok = 0;
} 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;
} else {
intptr_t topp;
@ -1305,13 +1370,6 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
ok = 1;
}
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)
@ -1373,23 +1431,54 @@ static intptr_t rktio_recount_output_text(const char *orig_buffer, const char *b
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)
{
DWORD towrite, wrote, start;
int ok, more_work = 0, err_no;
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) {
ReleaseSemaphore(oth->lock_sema, 1, NULL);
WaitForSingleObject(oth->work_sema, INFINITE);
FlushFileBuffers(oth->fd);
WaitForSingleObject(oth->lock_sema, INFINITE);
oth->flushed = 1;
ReleaseSemaphore(oth->ready_sema, 1, NULL);
ReleaseSemaphore(oth->lock_sema, 1, NULL);
}
/* lock held on loop exit */
} else {
/* Blocking mode. We do the writing work. This case is for
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)
WaitForSingleObject(oth->work_sema, INFINITE);
WaitForSingleObject(oth->lock_sema, INFINITE);
if (oth->done)
break;
WaitForSingleObject(oth->lock_sema, INFINITE);
towrite = oth->buflen;
if (towrite > (RKTIO_FD_BUFFSIZE - oth->bufstart))
towrite = RKTIO_FD_BUFFSIZE - oth->bufstart;
start = oth->bufstart;
ReleaseSemaphore(oth->lock_sema, 1, 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->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;
}
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->work_sema);
CloseHandle(oth->you_clean_up_sema);
CloseHandle(oth->fd);
if (close_mode != -1)
CloseHandle(oth->fd);
if (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;
}
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 (!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)) {
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)) {
SetFilePointer(fd, 0, NULL, FILE_END);
if ((modes & (RKTIO_OPEN_APPEND |RKTIO_OPEN_TRUNCATE))
&& rktio_fd_is_regular_file(rktio, rfd)) {
if (modes & RKTIO_OPEN_APPEND)
SetFilePointer(fd, 0, NULL, FILE_END);
else
SetEndOfFile(fd);
}
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)
{
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
int errid = 0;
@ -830,6 +830,9 @@ int rktio_rename_file(rktio_t *rktio, const char *dest, const char *src, int exi
return 1;
}
get_windows_error();
} else if (errid == ERROR_ALREADY_EXISTS) {
set_racket_error(RKTIO_ERROR_EXISTS);
return 0;
} else
get_windows_error();

View File

@ -26,6 +26,8 @@
#define RKTIO_SHUT_RD SHUT_RD
#define RKTIO_SHUT_WR SHUT_WR
#define RKTIO_SOCKS(s) s
typedef intptr_t rktio_socket_t;
typedef unsigned int rktio_sockopt_len_t;
@ -81,6 +83,9 @@ struct SOCKADDR_IN {
typedef SOCKET rktio_socket_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;
# define REGISTER_SOCKET(s) winsock_remember(s)
# define UNREGISTER_SOCKET(s) winsock_forget(s)
@ -858,9 +863,14 @@ void rktio_winsock_done(rktio_t *rktio)
/* 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)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
#ifdef RKTIO_SYSTEM_UNIX
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
#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;
UNREGISTER_SOCKET(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)
{
#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);
#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)
{
#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);
#endif
}
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))) {
get_socket_error();
@ -948,7 +958,7 @@ int rktio_socket_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd)
#endif
#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(exnfds);
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_SET(s, exnfds);
sr = select(s + 1, NULL, writefds, exnfds, &time);
sr = select(RKTIO_SOCKS(s + 1), NULL, writefds, exnfds, &time);
if (sr == -1) {
get_socket_error();
@ -982,7 +992,7 @@ int rktio_socket_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd)
#endif
#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(exnfds);
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_SET(s, exnfds);
sr = select(s + 1, readfds, NULL, exnfds, &time);
sr = select(RKTIO_SOCKS(s + 1), readfds, NULL, exnfds, &time);
if (sr == -1) {
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);
#endif
#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;
intptr_t rc;
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)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
int rn;
do {
@ -1061,7 +1071,7 @@ static intptr_t do_socket_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buf
/* for UDP sendto: */
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;
int errid = 0;
@ -1183,7 +1193,9 @@ static rktio_connect_t *try_connect(rktio_t *rktio, rktio_connect_t *conn)
errno = status;
#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;
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: */
int 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) {
errid = SOCK_ERRNO();
} else
@ -1541,7 +1553,7 @@ static int do_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener, int
}
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));
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++) {
s = listener->s[i];
RKTIO_FD_SET(s, fds);
RKTIO_FD_SET(s, fds2);
RKTIO_FD_SET((intptr_t)s, fds);
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;
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();
return NULL;
}
@ -1674,7 +1686,7 @@ char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd)
rktio_sockopt_len_t name_len;
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();
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)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
int err;
#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)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
int err;
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)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
int err;
/* 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_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
rktio_length_and_addrinfo_t *r;
int rn, errid;
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)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
u_char loop;
rktio_sockopt_len_t loop_len = sizeof(loop);
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)
{
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);
rktio_sockopt_len_t loop_len = sizeof(loop);
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)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
u_char ttl;
rktio_sockopt_len_t ttl_len = sizeof(ttl);
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)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
u_char ttl = ttl_val;
rktio_sockopt_len_t ttl_len = sizeof(ttl);
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)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
struct in_addr intf;
rktio_sockopt_len_t intf_len = sizeof(intf);
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)
{
rktio_socket_t s = rktio_fd_system_fd(rktio, rfd);
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
struct in_addr intf;
rktio_sockopt_len_t intf_len = sizeof(intf);
int status;
@ -1964,7 +1976,7 @@ int rktio_udp_change_multicast_group(rktio_t *rktio, rktio_fd_t *rfd,
rktio_addrinfo_t *intf_addr,
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;
rktio_sockopt_len_t mreq_len = sizeof(mreq);
int status;

View File

@ -26,7 +26,7 @@ static int MyPipe(intptr_t *ph, int flags, rktio_t *rktio)
a[1] = w;
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
close the inheritable one: */
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;
}
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 i;
@ -111,7 +111,7 @@ static int find_fd_pos(struct rktio_fd_set_data_t *data, int n)
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;
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;
intptr_t flag = fd->flags;
@ -157,7 +157,7 @@ void rktio_fdset(rktio_poll_set_t *fd, int n)
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;
intptr_t flag = fd->flags;
@ -469,27 +469,27 @@ void rktio_fdzero(rktio_poll_set_t *fd)
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--; ) {
if (fd->sockets[i] == n)
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) {
int na;
intptr_t na;
na = next_size(fd->last_alloc);
fd->last_alloc = na;
}
if (fd->added >= fd->alloc) {
SOCKET *naya;
int na;
intptr_t na;
na = next_size(fd->alloc);
naya = malloc(na * 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;
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--; ) {
if (fd->sockets[i] == n)
if (fd->sockets[i] == (SOCKET)n)
return 1;
}
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)
{
int i;
intptr_t i;
for (i = src_fds->added; i--; ) {
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;
rktio_poll_set_t *efd = fds;
HANDLE *hs;
int i, new_i, *rps;
intptr_t i, new_i;
int *rps;
if (efd->num_handles == 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;
HANDLE *wa, e;
int i, p = 0, mask, j;
intptr_t i, p = 0, mask, j;
SOCKET s;
rfd = fds;
@ -781,12 +782,12 @@ static int fdset_has_nosleep(rktio_poll_set_t *fds)
#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);
}
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
int mx;
@ -797,7 +798,7 @@ void rktio_fdset(rktio_poll_set_t *fd, int n)
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);
}
@ -1207,7 +1208,8 @@ void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds, rktio_ltps_
{
intptr_t result;
HANDLE *array, just_two_array[2];
int count, rcount, *rps;
intptr_t count, rcount;
int *rps;
rktio_collapse_win_fd(fds); /* merges */

View File

@ -31,7 +31,7 @@
/*========================================================================*/
struct rktio_t {
intptr_t errid;
int errid;
int errkind;
#ifdef RKTIO_SYSTEM_WINDOWS
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);
void rktio_fdzero(rktio_poll_set_t *fd);
void rktio_fdset(rktio_poll_set_t *fd, int n);
void rktio_fdclr(rktio_poll_set_t *fd, int n);
int rktio_fdisset(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, intptr_t n);
int rktio_fdisset(rktio_poll_set_t *fd, intptr_t n);
# define DECL_FDSET(n, c) rktio_poll_set_t *n
# 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,
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 new_process_group, int chain_termination_here_to_child,
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;
char *cmdline;
wchar_t *cmdline_w, *wd_w;
@ -1043,14 +1044,14 @@ static intptr_t do_spawnv(rktio_t *rktio,
if (exact_cmdline) {
cmdline = (char *)argv[1];
} else {
for (i = 0; argv[i]; i++) {
for (i = 0; i < argc; i++) {
len += strlen(argv[i]) + 1;
}
cmdline = malloc(len);
len = 0;
for (i = 0; argv[i]; i++) {
for (i = 0; i < argc; i++) {
l = strlen(argv[i]);
memcpy(cmdline + len, argv[i], 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 i;
#endif
/* avoid compiler warnings: */
to_subprocess[0] = -1;
to_subprocess[1] = -1;
@ -1228,8 +1229,8 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
if (stdin_fd) {
to_subprocess[0] = rktio_fd_system_fd(rktio, stdin_fd);
RKTIO_COPY_FOR_SUBPROCESS(to_subprocess, 0);
} else if (rktio_make_os_pipe(rktio, to_subprocess, 1)) {
if (stdout_fd) { RKTIO_CLOSE_SUBPROCESS_COPY(from_subprocess, RKTIO_NO_INHERIT_OUTPUT); }
} else if (rktio_make_os_pipe(rktio, to_subprocess, RKTIO_NO_INHERIT_OUTPUT)) {
if (stdout_fd) { RKTIO_CLOSE_SUBPROCESS_COPY(from_subprocess, 1); }
return NULL;
}
@ -1276,7 +1277,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
pid = 0;
spawn_status = do_spawnv(rktio,
command, (const char * const *)argv,
command, argc, (const char * const *)argv,
windows_exact_cmdline,
to_subprocess[0],
from_subprocess[1],

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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