Term IO implemented to support Vista and Win7

This commit is contained in:
manojampalam 2016-03-15 18:38:08 -07:00
parent fb93bb95e2
commit a8fcb8d673
4 changed files with 211 additions and 150 deletions

View File

@ -43,6 +43,9 @@
#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
errno_from_Win32Error(int win32_error)
@ -344,6 +347,11 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) {
}
if (fileio_is_io_available(pio, TRUE) == FALSE) {
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)) {
@ -354,6 +362,7 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) {
}
return -1;
}
}
/* pick up APC if IO has completed */
if (-1 == wait_for_any_event(NULL, 0, 0))
@ -461,6 +470,15 @@ 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 (FILETYPE(pio) == FILE_TYPE_CHAR) {
if (termio_initiate_write(pio, bytes_copied) == 0) {
pio->write_details.pending = TRUE;
pio->write_details.remaining = bytes_copied;
}
else
return -1;
}
else {
if (WriteFileEx(WINHANDLE(pio), pio->write_details.buf, bytes_copied,
&pio->write_overlapped, &WriteCompletionRoutine)) {
pio->write_details.pending = TRUE;
@ -468,6 +486,18 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) {
/* execute APC if write has completed */
if (wait_for_any_event(NULL, 0, 0) == -1)
return -1;
}
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) {
@ -483,17 +513,6 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) {
}
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;
}
debug("write ERROR from cb(2):%d, io:%p", errno, pio);
return -1;
}
}
@ -577,6 +596,9 @@ fileio_on_select(struct w32_io* pio, BOOL rd) {
return 0;
if (!pio->read_details.pending && !fileio_is_io_available(pio, rd))
if (FILETYPE(pio) == FILE_TYPE_CHAR)
return termio_initiate_read(pio);
else
return fileio_ReadFileEx(pio);
return 0;

View File

@ -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();
}
return 0;
}
static int
int
termio_initiate_read(struct w32_io* pio) {
HANDLE read_thread = CreateThread(NULL, 0, ReadThread, pio, 0, NULL);
HANDLE read_thread;
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;
}
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;
}
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 (0 == QueueUserAPC(WriteAPCProc, main_thread, (ULONG_PTR)pio)) {
debug("TermWrite thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio);
DebugBreak();
}
return 0;
}
int
termio_on_select(struct w32_io* pio, BOOL rd) {
if (!rd)
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;
if ((!fileio_is_io_available(pio, rd)) && (!pio->read_details.pending))
return termio_initiate_read(pio);
}
int
termio_read(struct w32_io* pio, void *dst, unsigned int max) {
return fileio_read(pio, dst, max);
}
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;
// 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);
}
int termio_close(struct w32_io* pio) {
return fileio_close(pio);
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;
}

View File

@ -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,14 +156,9 @@ 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);
}
}
#define CHECK_FD(fd) do { \
debug3("%s fd:%d", __FUNCTION__, fd); \
@ -371,14 +366,9 @@ 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);
}
}
int
w32_write(int fd, const void *buf, unsigned int max) {
@ -386,14 +376,9 @@ 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);
}
}
int
w32_fstat(int fd, struct w32_stat *buf) {

View File

@ -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*/