From ad7538bfc5873811678becf3e858128236a7f210 Mon Sep 17 00:00:00 2001 From: Marcus Meissner Date: Mon, 14 Dec 1998 18:15:10 +0000 Subject: [PATCH] Made async IO (SIGIO) stuff from WINSOCK generic useable. Added async IO support to FILE and CONSOLE objects. --- files/Makefile.in | 1 + files/async.c | 186 +++++++++++++++++++++++++++++++++++++++++++++ files/file.c | 27 +++++-- include/async.h | 6 ++ include/file.h | 3 + loader/signal.c | 4 +- misc/winsock_dns.c | 84 +++++--------------- win32/console.c | 40 ++++++++-- 8 files changed, 273 insertions(+), 78 deletions(-) create mode 100644 files/async.c create mode 100644 include/async.h diff --git a/files/Makefile.in b/files/Makefile.in index eb37b8965e1..b1937e1c7ca 100644 --- a/files/Makefile.in +++ b/files/Makefile.in @@ -8,6 +8,7 @@ VPATH = @srcdir@ MODULE = files C_SRCS = \ + async.c \ change.c \ directory.c \ dos_fs.c \ diff --git a/files/async.c b/files/async.c new file mode 100644 index 00000000000..7f1c69fec03 --- /dev/null +++ b/files/async.c @@ -0,0 +1,186 @@ +/* + * Generic async UNIX file IO handling + * + * Copyright 1996,1997 Alex Korobka + * Copyright 1998 Marcus Meissner + */ +/* + * This file handles asynchronous signaling for UNIX filedescriptors. + * The passed handler gets called when input arrived for the filedescriptor. + * + * This is done either by the kernel or (in the WINSOCK case) by the pipe + * handler, since pipes do not support asynchronous signaling. + * (Not all possible filedescriptors support async IO. Generic files do not + * for instance, sockets do, ptys don't.) + * + * To make this a bit better, we would need an additional thread doing select() + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_SYS_FILIO_H +# include +#endif +#ifdef __svr4__ +# include +#endif + +#include "xmalloc.h" +#include "wintypes.h" +#include "miscemu.h" +#include "selectors.h" +#include "sig_context.h" +#include "async.h" +#include "debug.h" + +typedef struct _async_fd { + int unixfd; + void (*handler)(int fd,void *private); + void *private; +} ASYNC_FD; + +static ASYNC_FD *asyncfds = NULL; +static int nrofasyncfds = 0; + +/*************************************************************************** + * ASYNC_sigio [internal] + * + * Signal handler for asynchronous IO. + * + * Note: This handler and the function it calls may not block. Neither they + * are allowed to use blocking IO (write/read). No memory management. + * No possible blocking synchronization of any kind. + */ +HANDLER_DEF(ASYNC_sigio) { + struct timeval timeout; + fd_set rset,wset; + int i,maxfd=0; + + HANDLER_INIT(); + + if (!nrofasyncfds) + return; + FD_ZERO(&rset); + FD_ZERO(&wset); + for (i=nrofasyncfds;i--;) { + if (asyncfds[i].unixfd == -1) + continue; + FD_SET(asyncfds[i].unixfd,&rset); + FD_SET(asyncfds[i].unixfd,&wset); + if (maxfd"); +#endif +#ifdef FASYNC + if (-1==fcntl(unixfd,F_GETFL,&flags)) { + perror("fcntl F_GETFL"); + return FALSE; + } + if (async) + flags|=FASYNC; + else + flags&=~FASYNC; + if (-1==fcntl(unixfd,F_SETFL,&flags)) { + perror("fcntl F_SETFL FASYNC"); + return FALSE; + } + return TRUE; +#else + return FALSE; +#endif +} + +/*************************************************************************** + * ASYNC_RegisterFD [internal] + * + * Register a UNIX filedescriptor with handler and private data pointer. + * this function is _NOT_ safe to be called from a signal handler. + * + * Additional Constraint: The handler passed to this function _MUST_ adhere + * to the same signalsafeness as ASYNC_sigio itself. (nonblocking, no thread/ + * signal unsafe operations, no blocking synchronization) + */ +void ASYNC_RegisterFD(int unixfd,void (*handler)(int fd,void *private),void *private) { + int i; + + SIGNAL_MaskAsyncEvents( TRUE ); + for (i=0;itype = FILE_TYPE_DISK; (*file)->pos = 0; (*file)->mode = 0; + (*file)->wait_queue = NULL; handle = HANDLE_Alloc( PROCESS_Current(), &(*file)->header, FILE_ALL_ACCESS | GENERIC_READ | @@ -106,6 +108,16 @@ HFILE32 FILE_Alloc( FILE_OBJECT **file ) return handle; } +/*********************************************************************** + * FILE_async_handler [internal] + */ +static void +FILE_async_handler(int unixfd,void *private) { + FILE_OBJECT *file = (FILE_OBJECT*)private; + + SYNC_WakeUp(&file->wait_queue,INFINITE32); +} + static BOOL32 FILE_Signaled(K32OBJ *ptr, DWORD thread_id) { fd_set fds,*readfds = NULL,*writefds = NULL; @@ -127,20 +139,23 @@ static BOOL32 FILE_Signaled(K32OBJ *ptr, DWORD thread_id) static void FILE_AddWait(K32OBJ *ptr, DWORD thread_id) { - TRACE(file,"(),stub\n"); - return; + FILE_OBJECT *file = (FILE_OBJECT*)ptr; + if (!file->wait_queue) + ASYNC_RegisterFD(file->unix_handle,FILE_async_handler,file); + THREAD_AddQueue(&file->wait_queue,thread_id); } static void FILE_RemoveWait(K32OBJ *ptr, DWORD thread_id) { - TRACE(file,"(),stub\n"); - return; + FILE_OBJECT *file = (FILE_OBJECT*)ptr; + THREAD_RemoveQueue(&file->wait_queue,thread_id); + if (!file->wait_queue) + ASYNC_UnregisterFD(file->unix_handle,FILE_async_handler); } static BOOL32 FILE_Satisfied(K32OBJ *ptr, DWORD thread_id) { - TRACE(file,"(),stub\n"); - return TRUE; + return FALSE; /* not abandoned. Hmm? */ } /* FIXME: lpOverlapped is ignored */ diff --git a/include/async.h b/include/async.h new file mode 100644 index 00000000000..52c0bbad733 --- /dev/null +++ b/include/async.h @@ -0,0 +1,6 @@ +#ifndef __WINE_ASYNC_H +#define __WINE_ASYNC_H + +extern void ASYNC_RegisterFD(int unixfd,void (*handler)(int fd,void *private),void *private); +extern void ASYNC_UnregisterFD(int unixfd,void (*handler)(int fd,void *private)); +#endif diff --git a/include/file.h b/include/file.h index b727a209ec0..e7827243ddb 100644 --- a/include/file.h +++ b/include/file.h @@ -10,6 +10,7 @@ #include #include "windows.h" #include "k32obj.h" +#include "thread.h" #define MAX_PATHNAME_LEN 1024 @@ -22,6 +23,8 @@ typedef struct char *unix_name; DWORD type; /* Type for win32 apps */ DWORD pos; /* workaround to emulate weird DOS error handling */ + + THREAD_QUEUE wait_queue; } FILE_OBJECT; /* Definition of a full DOS file name */ diff --git a/loader/signal.c b/loader/signal.c index c6267219d89..ed18a3a48bc 100644 --- a/loader/signal.c +++ b/loader/signal.c @@ -148,6 +148,7 @@ void SIGNAL_SetHandler( int sig, void (*func)(), int flags ) extern void stop_wait(int a); extern void WINSOCK_sigio(int a); +extern void ASYNC_sigio(int a); /********************************************************************** @@ -178,7 +179,8 @@ BOOL32 SIGNAL_Init(void) #endif #ifdef SIGIO sigaddset(&async_signal_set, SIGIO); - SIGNAL_SetHandler( SIGIO, (void (*)())WINSOCK_sigio, 0); +/* SIGNAL_SetHandler( SIGIO, (void (*)())WINSOCK_sigio, 0); */ + SIGNAL_SetHandler( SIGIO, (void (*)())ASYNC_sigio, 0); #endif sigaddset(&async_signal_set, SIGALRM); diff --git a/misc/winsock_dns.c b/misc/winsock_dns.c index 113c50e0d04..5408c952cc5 100644 --- a/misc/winsock_dns.c +++ b/misc/winsock_dns.c @@ -11,6 +11,7 @@ #include "config.h" +#include #include #include #include @@ -38,14 +39,11 @@ #include "heap.h" #include "ldt.h" #include "message.h" -#include "selectors.h" #include "miscemu.h" -#include "sig_context.h" +#include "async.h" #include "debug.h" -#ifndef FASYNC -#define FASYNC FIOASYNC -#endif +static void WINSOCK_async_handler(int unixfd,void *private); /* async DNS op control struct */ typedef struct @@ -67,9 +65,6 @@ extern void* __ws_memalloc( int size ); extern void __ws_memfree( void* ptr ); /* NOTE: ws_async_op list is traversed inside the SIGIO handler! */ - -static int __async_io_max_fd = 0; -static fd_set __async_io_fdset; static ws_async_op* __async_op_list = NULL; static void fixup_wshe(struct ws_hostent* p_wshe, void* base); @@ -78,20 +73,6 @@ static void fixup_wsse(struct ws_servent* p_wsse, void* base); /* ----------------------------------- async/non-blocking I/O */ -int WINSOCK_async_io(int fd, int async) -{ - int fd_flags; - -#ifndef __EMX__ - fcntl(fd, F_SETOWN, getpid()); -#endif - - fd_flags = fcntl(fd, F_GETFL, 0); - if (fcntl(fd, F_SETFL, (async)? fd_flags | FASYNC - : fd_flags & ~FASYNC ) != -1) return 0; - return -1; -} - int WINSOCK_unblock_io(int fd, int noblock) { int fd_flags; @@ -191,14 +172,12 @@ void WINSOCK_link_async_op(ws_async_op* p_aop) p = p->next; } } - else FD_ZERO(&__async_io_fdset); p_aop->next = __async_op_list; __async_op_list = p_aop; + SIGNAL_MaskAsyncEvents( FALSE ); - FD_SET(p_aop->fd[0], &__async_io_fdset); - if( p_aop->fd[0] > __async_io_max_fd ) - __async_io_max_fd = p_aop->fd[0]; + ASYNC_RegisterFD(p_aop->fd[0],WINSOCK_async_handler,p_aop); } void WINSOCK_unlink_async_op(ws_async_op* p_aop) @@ -210,9 +189,7 @@ void WINSOCK_unlink_async_op(ws_async_op* p_aop) p_aop->prev->next = p_aop->next; if( p_aop->next ) p_aop->next->prev = p_aop->prev; - FD_CLR(p_aop->fd[0], &__async_io_fdset); - if( p_aop->fd[0] == __async_io_max_fd ) - __async_io_max_fd--; + ASYNC_UnregisterFD(p_aop->fd[0],WINSOCK_async_handler); } /* ----------------------------------- SIGIO handler - @@ -223,42 +200,23 @@ void WINSOCK_unlink_async_op(ws_async_op* p_aop) * Note: pipe-based handlers must raise explicit SIGIO with kill(2). */ -HANDLER_DEF(WINSOCK_sigio) +static void WINSOCK_async_handler(int unixfd,void *private) { - struct timeval timeout; - fd_set check_set; - ws_async_op* p_aop; + ws_async_op* p_aop = (ws_async_op*)private; - HANDLER_INIT(); - - check_set = __async_io_fdset; - memset(&timeout, 0, sizeof(timeout)); - - while( select(__async_io_max_fd + 1, - &check_set, NULL, NULL, &timeout) > 0) - { - for( p_aop = __async_op_list; - p_aop ; p_aop = p_aop->next ) - if( FD_ISSET(p_aop->fd[0], &check_set) ) - if( p_aop->aop_control(p_aop, AOP_IO) == AOP_CONTROL_REMOVE ) - { - /* NOTE: memory management is signal-unsafe, therefore - * we can only set a flag to remove this p_aop later on. - */ - - p_aop->flags = WSMSG_DEAD_AOP; - close(p_aop->fd[0]); - FD_CLR(p_aop->fd[0],&__async_io_fdset); - if( p_aop->fd[0] == __async_io_max_fd ) - __async_io_max_fd = p_aop->fd[0]; - if( p_aop->pid ) - { - kill(p_aop->pid, SIGKILL); - waitpid(p_aop->pid, NULL, WNOHANG); - p_aop->pid = 0; - } - } - check_set = __async_io_fdset; + if( p_aop->aop_control(p_aop, AOP_IO) == AOP_CONTROL_REMOVE ) + { + /* NOTE: memory management is signal-unsafe, therefore + * we can only set a flag to remove this p_aop later on. + */ + p_aop->flags = WSMSG_DEAD_AOP; + close(p_aop->fd[0]); + if( p_aop->pid ) + { + kill(p_aop->pid, SIGKILL); + waitpid(p_aop->pid, NULL, WNOHANG); + p_aop->pid = 0; + } } } diff --git a/win32/console.c b/win32/console.c index 9c7d289419f..48aba956220 100644 --- a/win32/console.c +++ b/win32/console.c @@ -32,8 +32,11 @@ #include #include #include + #include "windows.h" #include "k32obj.h" +#include "thread.h" +#include "async.h" #include "file.h" #include "process.h" #include "winerror.h" @@ -53,6 +56,7 @@ typedef struct _CONSOLE { LPSTR title; /* title of console */ INPUT_RECORD *irs; /* buffered input records */ int nrofirs;/* nr of buffered input records */ + THREAD_QUEUE wait_queue; } CONSOLE; static void CONSOLE_AddWait(K32OBJ *ptr, DWORD thread_id); @@ -377,6 +381,16 @@ CONSOLE_drain_input(CONSOLE *console,int n) { } } +/*********************************************************************** + * CONSOLE_async_handler [internal] + */ +static void +CONSOLE_async_handler(int unixfd,void *private) { + CONSOLE *console = (CONSOLE*)private; + + SYNC_WakeUp(&console->wait_queue,INFINITE32); +} + /*********************************************************************** * CONSOLE_Signaled [internal] * @@ -389,7 +403,10 @@ CONSOLE_Signaled(K32OBJ *ptr,DWORD tid) { if (ptr->type!= K32OBJ_CONSOLE) return FALSE; CONSOLE_get_input(console); - return console->nrofirs!=0; + if (console->nrofirs!=0) + return TRUE; + /* addref console */ + return FALSE; } /*********************************************************************** @@ -399,19 +416,26 @@ CONSOLE_Signaled(K32OBJ *ptr,DWORD tid) { */ static void CONSOLE_AddWait(K32OBJ *ptr, DWORD thread_id) { - WARN(console,"(),stub. Expect hang.\n"); - return; + CONSOLE *console = (CONSOLE *)ptr; + + /* register our unix filedescriptors for async IO */ + if (!console->wait_queue) + ASYNC_RegisterFD(console->infd,CONSOLE_async_handler,console); + THREAD_AddQueue( &console->wait_queue, THREAD_ID_TO_THDB(thread_id) ); } /*********************************************************************** - * CONSOLE_AddWait [internal] + * CONSOLE_RemoveWait [internal] * * Remove thread from our waitqueue. */ static void CONSOLE_RemoveWait(K32OBJ *ptr, DWORD thread_id) { - TRACE(console,"(),stub\n"); - return; + CONSOLE *console = (CONSOLE *)ptr; + + THREAD_RemoveQueue( &console->wait_queue, THREAD_ID_TO_THDB(thread_id) ); + if (!console->wait_queue) + ASYNC_UnregisterFD(console->infd,CONSOLE_async_handler); } /*********************************************************************** @@ -421,8 +445,7 @@ static void CONSOLE_RemoveWait(K32OBJ *ptr, DWORD thread_id) */ static BOOL32 CONSOLE_Satisfied(K32OBJ *ptr, DWORD thread_id) { - TRACE(console,"(),stub\n"); - return TRUE; + return FALSE; } @@ -784,6 +807,7 @@ BOOL32 WINAPI AllocConsole(VOID) console->pid = -1; console->title = NULL; console->nrofirs = 0; + console->wait_queue = NULL; console->irs = HeapAlloc(GetProcessHeap(),0,1);; console->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT