diff --git a/contrib/win32/win32compat/fileio.c b/contrib/win32/win32compat/fileio.c index e529d71..193fba5 100644 --- a/contrib/win32/win32compat/fileio.c +++ b/contrib/win32/win32compat/fileio.c @@ -43,8 +43,11 @@ #define WRITE_BUFFER_SIZE 100*1024 #define errno_from_Win32LastError() errno_from_Win32Error(GetLastError()) +int termio_initiate_read(struct w32_io* pio); +int termio_initiate_write(struct w32_io* pio, DWORD num_bytes); + /* maps Win32 error to errno */ -int +int errno_from_Win32Error(int win32_error) { switch (win32_error) { @@ -68,7 +71,7 @@ static int pipe_counter = 0; * pipe() implementation. Creates an inbound named pipe, uses CreateFile to connect * to it. These handles are associated with read end and write end of the pipe */ -int +int fileio_pipe(struct w32_io* pio[2]) { HANDLE read_handle = INVALID_HANDLE_VALUE, write_handle = INVALID_HANDLE_VALUE; struct w32_io *pio_read = NULL, *pio_write = NULL; @@ -82,7 +85,7 @@ fileio_pipe(struct w32_io* pio[2]) { } /* create name for named pipe */ - if (-1 == sprintf_s(pipe_name, MAX_PATH, "\\\\.\\Pipe\\W32PosixPipe.%08x.%08x", + if (-1 == sprintf_s(pipe_name, MAX_PATH, "\\\\.\\Pipe\\W32PosixPipe.%08x.%08x", GetCurrentProcessId(), pipe_counter++)) { errno = EOTHER; debug("pipe - ERROR sprintf_s %d", errno); @@ -163,15 +166,15 @@ struct createFile_flags { }; /* maps open() file modes and flags to ones needed by CreateFile */ -static int +static int createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) { /* check flags */ int rwflags = flags & 0xf; int c_s_flags = flags & 0xfffffff0; - /* - * should be one of one of the following access modes: + /* + * should be one of one of the following access modes: * O_RDONLY, O_WRONLY, or O_RDWR */ if ((rwflags != O_RDONLY) && (rwflags != O_WRONLY) && (rwflags != O_RDWR)) { @@ -182,7 +185,7 @@ createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) { /*only following create and status flags currently supported*/ if (c_s_flags & ~(O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC - | O_EXCL | O_BINARY)) { + | O_EXCL | O_BINARY)) { debug("open - ERROR: Unsupported flags: %d", flags); errno = ENOTSUP; return -1; @@ -234,8 +237,8 @@ createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) { } /* open() implementation. Uses CreateFile to open file, console, device, etc */ -struct w32_io* -fileio_open(const char *pathname, int flags, int mode) { +struct w32_io* + fileio_open(const char *pathname, int flags, int mode) { struct w32_io* pio = NULL; struct createFile_flags cf_flags; HANDLE handle; @@ -253,9 +256,9 @@ fileio_open(const char *pathname, int flags, int mode) { return NULL; /* TODO - Use unicode version.*/ - handle = CreateFileA(pathname, cf_flags.dwDesiredAccess, cf_flags.dwShareMode, - &cf_flags.securityAttributes, cf_flags.dwCreationDisposition, - cf_flags.dwFlagsAndAttributes, NULL); + handle = CreateFileA(pathname, cf_flags.dwDesiredAccess, cf_flags.dwShareMode, + &cf_flags.securityAttributes, cf_flags.dwCreationDisposition, + cf_flags.dwFlagsAndAttributes, NULL); if (handle == INVALID_HANDLE_VALUE) { errno = errno_from_Win32LastError(); @@ -280,13 +283,13 @@ fileio_open(const char *pathname, int flags, int mode) { } VOID CALLBACK ReadCompletionRoutine( - _In_ DWORD dwErrorCode, - _In_ DWORD dwNumberOfBytesTransfered, - _Inout_ LPOVERLAPPED lpOverlapped + _In_ DWORD dwErrorCode, + _In_ DWORD dwNumberOfBytesTransfered, + _Inout_ LPOVERLAPPED lpOverlapped ) { - struct w32_io* pio = - (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped)); - debug2("ReadCB pio:%p, pending_state:%d, error:%d, received:%d", + struct w32_io* pio = + (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped)); + debug2("ReadCB pio:%p, pending_state:%d, error:%d, received:%d", pio, pio->read_details.pending, dwErrorCode, dwNumberOfBytesTransfered); pio->read_details.error = dwErrorCode; pio->read_details.remaining = dwNumberOfBytesTransfered; @@ -296,11 +299,11 @@ VOID CALLBACK ReadCompletionRoutine( } /* initiate an async read */ -int +int fileio_ReadFileEx(struct w32_io* pio) { debug2("ReadFileEx io:%p", pio); - if (pio->read_details.buf == NULL){ + if (pio->read_details.buf == NULL) { pio->read_details.buf = malloc(READ_BUFFER_SIZE); if (!pio->read_details.buf) { errno = ENOMEM; @@ -311,7 +314,7 @@ fileio_ReadFileEx(struct w32_io* pio) { } if (ReadFileEx(WINHANDLE(pio), pio->read_details.buf, pio->read_details.buf_size, - &pio->read_overlapped, &ReadCompletionRoutine)) + &pio->read_overlapped, &ReadCompletionRoutine)) pio->read_details.pending = TRUE; else { errno = errno_from_Win32LastError(); @@ -323,7 +326,7 @@ fileio_ReadFileEx(struct w32_io* pio) { } /* read() implementation */ -int +int fileio_read(struct w32_io* pio, void *dst, unsigned int max) { int bytes_copied; @@ -344,15 +347,21 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) { } if (fileio_is_io_available(pio, TRUE) == FALSE) { - if (-1 == fileio_ReadFileEx(pio)) { - if ((FILETYPE(pio) == FILE_TYPE_PIPE) - && (errno == ERROR_NEGATIVE_SEEK)) { - /* write end of the pipe closed */ - debug2("read - no more data, io:%p", pio); - errno = 0; - return 0; + if (FILETYPE(pio) == FILE_TYPE_CHAR) { + if (-1 == termio_initiate_read(pio)) + return -1; + } + else { + if (-1 == fileio_ReadFileEx(pio)) { + if ((FILETYPE(pio) == FILE_TYPE_PIPE) + && (errno == ERROR_NEGATIVE_SEEK)) { + /* write end of the pipe closed */ + debug2("read - no more data, io:%p", pio); + errno = 0; + return 0; + } + return -1; } - return -1; } /* pick up APC if IO has completed */ @@ -375,7 +384,7 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) { if (pio->read_details.error) { errno = errno_from_Win32Error(pio->read_details.error); /*write end of the pipe is closed or pipe broken or eof reached*/ - if ((pio->read_details.error == ERROR_BROKEN_PIPE) || + if ((pio->read_details.error == ERROR_BROKEN_PIPE) || (pio->read_details.error == ERROR_HANDLE_EOF)) { debug2("read - (2) no more data, io:%p", pio); errno = 0; @@ -391,8 +400,8 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) { memcpy(dst, pio->read_details.buf + pio->read_details.completed, bytes_copied); pio->read_details.remaining -= bytes_copied; pio->read_details.completed += bytes_copied; - debug2("read - io:%p read: %d remaining: %d", pio, bytes_copied, - pio->read_details.remaining); + debug2("read - io:%p read: %d remaining: %d", pio, bytes_copied, + pio->read_details.remaining); return bytes_copied; } @@ -401,25 +410,25 @@ VOID CALLBACK WriteCompletionRoutine( _In_ DWORD dwNumberOfBytesTransfered, _Inout_ LPOVERLAPPED lpOverlapped ) { - struct w32_io* pio = - (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, write_overlapped)); - debug2("WriteCB - pio:%p, pending_state:%d, error:%d, transferred:%d of remaining: %d", - pio, pio->write_details.pending, dwErrorCode, dwNumberOfBytesTransfered, - pio->write_details.remaining); + struct w32_io* pio = + (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, write_overlapped)); + debug2("WriteCB - pio:%p, pending_state:%d, error:%d, transferred:%d of remaining: %d", + pio, pio->write_details.pending, dwErrorCode, dwNumberOfBytesTransfered, + pio->write_details.remaining); pio->write_details.error = dwErrorCode; /* TODO - assert that remaining == dwNumberOfBytesTransfered */ if ((dwErrorCode == 0) && (pio->write_details.remaining != dwNumberOfBytesTransfered)) { debug("WriteCB - ERROR: broken assumption, io:%p, wrote:%d, remaining:%d", pio, dwNumberOfBytesTransfered, pio->write_details.remaining); DebugBreak(); - } + } pio->write_details.remaining -= dwNumberOfBytesTransfered; pio->write_details.pending = FALSE; *((__int64*)&lpOverlapped->Offset) += dwNumberOfBytesTransfered; } /* write() implementation */ -int +int fileio_write(struct w32_io* pio, const void *buf, unsigned int max) { int bytes_copied; @@ -461,44 +470,54 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) { bytes_copied = min(max, pio->write_details.buf_size); memcpy(pio->write_details.buf, buf, bytes_copied); - if (WriteFileEx(WINHANDLE(pio), pio->write_details.buf, bytes_copied, - &pio->write_overlapped, &WriteCompletionRoutine)) { - pio->write_details.pending = TRUE; - pio->write_details.remaining = bytes_copied; - /* execute APC if write has completed */ - if (wait_for_any_event(NULL, 0, 0) == -1) - return -1; - - if (w32_io_is_blocking(pio)) { - while (pio->write_details.pending) { - if (wait_for_any_event(NULL, 0, INFINITE) == -1) - return -1; - } + if (FILETYPE(pio) == FILE_TYPE_CHAR) { + if (termio_initiate_write(pio, bytes_copied) == 0) { + pio->write_details.pending = TRUE; + pio->write_details.remaining = bytes_copied; } - if (!pio->write_details.pending && pio->write_details.error) { - errno = errno_from_Win32Error(pio->write_details.error); - debug("write - ERROR from cb:%d, io:%p", pio->write_details.error, pio); - pio->write_details.error = 0; + else return -1; - } - debug2("write - reporting %d bytes written, io:%p", bytes_copied, pio); - return bytes_copied; } else { - errno = errno_from_Win32LastError(); - /* read end of the pipe closed ? */ - if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_NEGATIVE_SEEK)) { - debug("write - ERROR:read end of the pipe closed, io:%p", pio); - errno = EPIPE; + if (WriteFileEx(WINHANDLE(pio), pio->write_details.buf, bytes_copied, + &pio->write_overlapped, &WriteCompletionRoutine)) { + pio->write_details.pending = TRUE; + pio->write_details.remaining = bytes_copied; + /* execute APC if write has completed */ + if (wait_for_any_event(NULL, 0, 0) == -1) + return -1; } - debug("write ERROR from cb(2):%d, io:%p", errno, pio); + else { + errno = errno_from_Win32LastError(); + /* read end of the pipe closed ? */ + if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_NEGATIVE_SEEK)) { + debug("write - ERROR:read end of the pipe closed, io:%p", pio); + errno = EPIPE; + } + debug("write ERROR from cb(2):%d, io:%p", errno, pio); + return -1; + } + } + + if (w32_io_is_blocking(pio)) { + while (pio->write_details.pending) { + if (wait_for_any_event(NULL, 0, INFINITE) == -1) + return -1; + } + } + if (!pio->write_details.pending && pio->write_details.error) { + errno = errno_from_Win32Error(pio->write_details.error); + debug("write - ERROR from cb:%d, io:%p", pio->write_details.error, pio); + pio->write_details.error = 0; return -1; } + debug2("write - reporting %d bytes written, io:%p", bytes_copied, pio); + return bytes_copied; } /* fstat() implemetation */ -int +int fileio_fstat(struct w32_io* pio, struct _stat64 *buf) { int fd = _open_osfhandle((intptr_t)pio->handle, 0); @@ -511,12 +530,12 @@ fileio_fstat(struct w32_io* pio, struct _stat64 *buf) { return _fstat64(fd, buf); } -int +int fileio_stat(const char *path, struct _stat64 *buf) { return _stat64(path, buf); } -long +long fileio_lseek(struct w32_io* pio, long offset, int origin) { debug2("lseek - pio:%p", pio); if (origin != SEEK_SET) { @@ -531,7 +550,7 @@ fileio_lseek(struct w32_io* pio, long offset, int origin) { } /* fdopen implementation */ -FILE* +FILE* fileio_fdopen(struct w32_io* pio, const char *mode) { int fd_flags = 0; @@ -570,20 +589,23 @@ fileio_fdopen(struct w32_io* pio, const char *mode) { return _fdopen(fd, mode); } -int +int fileio_on_select(struct w32_io* pio, BOOL rd) { if (!rd) return 0; if (!pio->read_details.pending && !fileio_is_io_available(pio, rd)) - return fileio_ReadFileEx(pio); + if (FILETYPE(pio) == FILE_TYPE_CHAR) + return termio_initiate_read(pio); + else + return fileio_ReadFileEx(pio); return 0; } -int +int fileio_close(struct w32_io* pio) { debug2("fileclose - pio:%p", pio); @@ -605,7 +627,7 @@ fileio_close(struct w32_io* pio) { return 0; } -BOOL +BOOL fileio_is_io_available(struct w32_io* pio, BOOL rd) { if (rd) { if (pio->read_details.remaining || pio->read_details.error) diff --git a/contrib/win32/win32compat/termio.c b/contrib/win32/win32compat/termio.c index 3fc6d67..1c21b66 100644 --- a/contrib/win32/win32compat/termio.c +++ b/contrib/win32/win32compat/termio.c @@ -3,10 +3,9 @@ #include "inc/defs.h" #define TERM_IO_BUF_SIZE 2048 -int errno_from_Win32Error(int win32_error); struct io_status { - char* buf[TERM_IO_BUF_SIZE]; + DWORD to_transfer; DWORD transferred; DWORD error; }; @@ -17,79 +16,137 @@ static VOID CALLBACK ReadAPCProc( _In_ ULONG_PTR dwParam ) { struct w32_io* pio = (struct w32_io*)dwParam; + debug3("TermRead CB - io:%p, bytes: %d, pending: %d, error: %d", pio, read_status.transferred, + pio->read_details.pending, read_status.error); pio->read_details.error = read_status.error; pio->read_details.remaining = read_status.transferred; pio->read_details.completed = 0; pio->read_details.pending = FALSE; + WaitForSingleObject(pio->read_overlapped.hEvent, INFINITE); + CloseHandle(pio->read_overlapped.hEvent); + pio->read_overlapped.hEvent = 0; } static DWORD WINAPI ReadThread( _In_ LPVOID lpParameter ) { struct w32_io* pio = (struct w32_io*)lpParameter; + debug3("TermRead thread, io:%p", pio); memset(&read_status, 0, sizeof(read_status)); - if (!ReadFile(WINHANDLE(pio), read_status.buf, TERM_IO_BUF_SIZE, &read_status.transferred, NULL)) { + if (!ReadFile(WINHANDLE(pio), pio->read_details.buf, + pio->read_details.buf_size, &read_status.transferred, NULL)) { read_status.error = GetLastError(); + debug("TermRead thread - ReadFile failed %d, io:%p", GetLastError(), pio); } - - if (0 == QueueUserAPC(ReadAPCProc, main_thread, pio)) + + if (0 == QueueUserAPC(ReadAPCProc, main_thread, (ULONG_PTR)pio)) { + debug("TermRead thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio); DebugBreak(); -} - -static int -termio_initiate_read(struct w32_io* pio) { - HANDLE read_thread = CreateThread(NULL, 0, ReadThread, pio, 0, NULL); - if (read_thread == NULL) { - errno = errno_from_Win32Error(GetLastError()); - return -1; } - return 0; } -int -termio_on_select(struct w32_io* pio, BOOL rd) { - if (!rd) - return 0; +int +termio_initiate_read(struct w32_io* pio) { + HANDLE read_thread; - if ((!fileio_is_io_available(pio, rd)) && (!pio->read_details.pending)) - return termio_initiate_read(pio); + debug3("TermRead initiate io:%p", pio); + + if (pio->read_details.buf_size == 0) { + pio->read_details.buf = malloc(TERM_IO_BUF_SIZE); + if (pio->read_details.buf == NULL) { + errno = ENOMEM; + return -1; + } + pio->read_details.buf_size = TERM_IO_BUF_SIZE; + } + + read_thread = CreateThread(NULL, 0, ReadThread, pio, 0, NULL); + if (read_thread == NULL) { + errno = errno_from_Win32Error(GetLastError()); + debug("TermRead initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio); + return -1; + } + + pio->read_overlapped.hEvent = read_thread; + pio->read_details.pending = TRUE; + return 0; } -int -termio_read(struct w32_io* pio, void *dst, unsigned int max) { - return fileio_read(pio, dst, max); +static VOID CALLBACK WriteAPCProc( + _In_ ULONG_PTR dwParam + ) { + struct w32_io* pio = (struct w32_io*)dwParam; + debug3("TermWrite CB - io:%p, bytes: %d, pending: %d, error: %d", pio, write_status.transferred, + pio->write_details.pending, write_status.error); + pio->write_details.error = write_status.error; + pio->write_details.remaining -= write_status.transferred; + /*TODO- assert that reamining is 0 by now*/ + pio->write_details.completed = 0; + pio->write_details.pending = FALSE; + WaitForSingleObject(pio->write_overlapped.hEvent, INFINITE); + CloseHandle(pio->write_overlapped.hEvent); + pio->write_overlapped.hEvent = 0; } -int -termio_write(struct w32_io* pio, const void *buf, unsigned int max) { - //{ - // /* assert that io is in blocking mode */ - // if (w32_io_is_blocking(pio) == FALSE) { - // debug("write - ERROR, nonblocking write to term is not supported"); - // errno = ENOTSUP; - // return -1; - // } - // pio->write_details.remaining = bytes_copied; - // if (!WriteFile(h, buf, bytes_copied, &pio->write_details.completed, NULL)) - // pio->write_details.error = GetLastError(); - // else if (bytes_copied != pio->write_details.completed) - // pio->write_details.error = ERROR_INTERNAL_ERROR; +static DWORD WINAPI WriteThread( + _In_ LPVOID lpParameter + ) { + struct w32_io* pio = (struct w32_io*)lpParameter; + debug3("TermWrite thread, io:%p", pio); + if (!WriteFile(WINHANDLE(pio), pio->write_details.buf, write_status.to_transfer, + &write_status.transferred, NULL)) { + write_status.error = GetLastError(); + debug("TermWrite thread - ReadFile failed %d, io:%p", GetLastError(), pio); + } - // if (pio->write_details.error != 0) { - // debug("write - ERROR writing to term %d", pio->write_details.error); - // errno = errno_from_Win32Error(pio->write_details.error); - // return -1; - // } - // else { - // pio->write_details.completed = 0; - // return bytes_copied; - // } - - //} - return fileio_write(pio, buf, max); + if (0 == QueueUserAPC(WriteAPCProc, main_thread, (ULONG_PTR)pio)) { + debug("TermWrite thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio); + DebugBreak(); + } + return 0; } +int +termio_initiate_write(struct w32_io* pio, DWORD num_bytes) { + HANDLE write_thread; + + debug3("TermWrite initiate io:%p", pio); + memset(&write_status, 0, sizeof(write_status)); + write_status.to_transfer = num_bytes; + write_thread = CreateThread(NULL, 0, WriteThread, pio, 0, NULL); + if (write_thread == NULL) { + errno = errno_from_Win32Error(GetLastError()); + debug("TermWrite initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio); + return -1; + } + + pio->write_overlapped.hEvent = write_thread; + return 0; +} + + int termio_close(struct w32_io* pio) { - return fileio_close(pio); -} \ No newline at end of file + debug2("termio_close - pio:%p", pio); + + CancelIoEx(WINHANDLE(pio), NULL); + /* If io is pending, let worker threads exit*/ + if (pio->read_details.pending) + WaitForSingleObject(pio->read_overlapped.hEvent, INFINITE); + if (pio->write_details.pending) + WaitForSingleObject(pio->write_overlapped.hEvent, INFINITE); + /* drain queued APCs */ + SleepEx(0, TRUE); + if (pio->type != STD_IO_FD) {//STD handles are never explicitly closed + CloseHandle(WINHANDLE(pio)); + + if (pio->read_details.buf) + free(pio->read_details.buf); + + if (pio->write_details.buf) + free(pio->write_details.buf); + + free(pio); + } + return 0; +} diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c index 350908d..c1db9fc 100644 --- a/contrib/win32/win32compat/w32fd.c +++ b/contrib/win32/win32compat/w32fd.c @@ -123,7 +123,7 @@ w32posix_initialize() { if ((fd_table_initialize() != 0) || (socketio_initialize() != 0)) DebugBreak(); - main_thread = GetCurrentThread(); + main_thread = OpenThread(THREAD_SET_CONTEXT, FALSE, GetCurrentThreadId()); signalio_initialize(); } @@ -156,13 +156,8 @@ w32_io_on_select(struct w32_io* pio, BOOL rd) { if ((pio->type == SOCK_FD)) return socketio_on_select(pio, rd); - else - switch (FILETYPE(pio)) { - case FILE_TYPE_CHAR: - return termio_on_select(pio, rd); - default: - return fileio_on_select(pio, rd); - } + + return fileio_on_select(pio, rd); } #define CHECK_FD(fd) do { \ @@ -371,13 +366,8 @@ w32_read(int fd, void *dst, unsigned int max) { if (fd_table.w32_ios[fd]->type == SOCK_FD) return socketio_recv(fd_table.w32_ios[fd], dst, max, 0); - else - switch (FILETYPE(fd_table.w32_ios[fd])) { - case FILE_TYPE_CHAR: - return termio_read(fd_table.w32_ios[fd], dst, max); - default: - return fileio_read(fd_table.w32_ios[fd], dst, max); - } + + return fileio_read(fd_table.w32_ios[fd], dst, max); } int @@ -386,13 +376,8 @@ w32_write(int fd, const void *buf, unsigned int max) { if (fd_table.w32_ios[fd]->type == SOCK_FD) return socketio_send(fd_table.w32_ios[fd], buf, max, 0); - else - switch (FILETYPE(fd_table.w32_ios[fd])) { - case FILE_TYPE_CHAR: - return termio_write(fd_table.w32_ios[fd], buf, max); - default: - return fileio_write(fd_table.w32_ios[fd], buf, max); - } + + return fileio_write(fd_table.w32_ios[fd], buf, max); } int diff --git a/contrib/win32/win32compat/w32fd.h b/contrib/win32/win32compat/w32fd.h index b9e4a3a..ba70181 100644 --- a/contrib/win32/win32compat/w32fd.h +++ b/contrib/win32/win32compat/w32fd.h @@ -119,9 +119,6 @@ long fileio_lseek(struct w32_io* pio, long offset, int origin); FILE* fileio_fdopen(struct w32_io* pio, const char *mode); /* terminal io specific versions */ -int termio_on_select(struct w32_io* pio, BOOL rd); -int termio_read(struct w32_io* pio, void *dst, unsigned int max); -int termio_write(struct w32_io* pio, const void *buf, unsigned int max); int termio_close(struct w32_io* pio); /* signal related APIs*/