Made async IO (SIGIO) stuff from WINSOCK generic useable.
Added async IO support to FILE and CONSOLE objects.
diff --git a/files/Makefile.in b/files/Makefile.in
index eb37b89..b1937e1 100644
--- a/files/Makefile.in
+++ b/files/Makefile.in
@@ -8,6 +8,7 @@
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 0000000..7f1c69f
--- /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 <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+#ifdef __svr4__
+# include <sys/file.h>
+#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<asyncfds[i].unixfd)
+ maxfd=asyncfds[i].unixfd;
+ }
+ /* select() with timeout values set to 0 is nonblocking. */
+ memset(&timeout,0,sizeof(timeout));
+ if (select(maxfd+1,&rset,&wset,NULL,&timeout)<=0)
+ return; /* Can't be. hmm */
+ for (i=nrofasyncfds;i--;)
+ if ( (FD_ISSET(asyncfds[i].unixfd,&rset)) ||
+ (FD_ISSET(asyncfds[i].unixfd,&wset))
+ )
+ asyncfds[i].handler(asyncfds[i].unixfd,asyncfds[i].private);
+}
+
+/***************************************************************************
+ * ASYNC_MakeFDAsync [internal]
+ *
+ * Makes the passed filedescriptor async (or not) depending on flag.
+ */
+static BOOL32 ASYNC_MakeFDAsync(int unixfd,int async) {
+ int flags;
+
+#if !defined(FASYNC) && defined(FIOASYNC)
+#define FASYNC FIOASYNC
+#endif
+
+#ifdef F_SETOWN
+ if (-1==fcntl(unixfd,F_SETOWN,getpid()))
+ perror("fcntl F_SETOWN <pid>");
+#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;i<nrofasyncfds;i++) {
+ if (asyncfds[i].unixfd==unixfd) {
+ /* Might be a leftover entry. Make fd async anyway... */
+ if (asyncfds[i].handler==handler) {
+ ASYNC_MakeFDAsync(unixfd,1);
+ SIGNAL_MaskAsyncEvents( FALSE );
+ return;
+ }
+ }
+ }
+ for (i=0;i<nrofasyncfds;i++)
+ if (asyncfds[i].unixfd == -1)
+ break;
+ if (i==nrofasyncfds) {
+ if (nrofasyncfds)
+ asyncfds=(ASYNC_FD*)xrealloc(asyncfds,sizeof(ASYNC_FD)*(nrofasyncfds+1));
+ else
+ asyncfds=(ASYNC_FD*)xmalloc(sizeof(ASYNC_FD)*1);
+ nrofasyncfds++;
+ }
+ asyncfds[i].unixfd = unixfd;
+ asyncfds[i].handler = handler;
+ asyncfds[i].private = private;
+ ASYNC_MakeFDAsync(unixfd,1);
+ SIGNAL_MaskAsyncEvents( FALSE );
+}
+
+/***************************************************************************
+ * ASYNC_UnregisterFD [internal]
+ *
+ * Unregister a UNIX filedescriptor with handler. This function is basically
+ * signal safe, but try to not call it in the signal handler anyway.
+ */
+void ASYNC_UnregisterFD(int unixfd,void (*handler)(int fd,void *private)) {
+ int i;
+
+ for (i=nrofasyncfds;i--;)
+ if ((asyncfds[i].unixfd==unixfd)||(asyncfds[i].handler==handler))
+ break;
+ if (i==nrofasyncfds)
+ return;
+ asyncfds[i].unixfd = -1;
+ asyncfds[i].handler = NULL;
+ asyncfds[i].private = NULL;
+ return;
+}
diff --git a/files/file.c b/files/file.c
index c4ddb55..6a5cac0 100644
--- a/files/file.c
+++ b/files/file.c
@@ -35,6 +35,7 @@
#include "ldt.h"
#include "process.h"
#include "task.h"
+#include "async.h"
#include "debug.h"
#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
@@ -97,6 +98,7 @@
(*file)->type = 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 @@
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 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 0000000..52c0bba
--- /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 b727a20..e782724 100644
--- a/include/file.h
+++ b/include/file.h
@@ -10,6 +10,7 @@
#include <time.h>
#include "windows.h"
#include "k32obj.h"
+#include "thread.h"
#define MAX_PATHNAME_LEN 1024
@@ -22,6 +23,8 @@
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 c626721..ed18a3a 100644
--- a/loader/signal.c
+++ b/loader/signal.c
@@ -148,6 +148,7 @@
extern void stop_wait(int a);
extern void WINSOCK_sigio(int a);
+extern void ASYNC_sigio(int a);
/**********************************************************************
@@ -178,7 +179,8 @@
#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 113c50e..5408c95 100644
--- a/misc/winsock_dns.c
+++ b/misc/winsock_dns.c
@@ -11,6 +11,7 @@
#include "config.h"
+#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
@@ -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_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 @@
/* ----------------------------------- 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 @@
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 @@
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 @@
* 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 9c7d289..48aba95 100644
--- a/win32/console.c
+++ b/win32/console.c
@@ -32,8 +32,11 @@
#include <sys/errno.h>
#include <signal.h>
#include <assert.h>
+
#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 @@
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);
@@ -378,6 +382,16 @@
}
/***********************************************************************
+ * 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]
*
* Checks if we can read something. (Hmm, what about writing ?)
@@ -389,7 +403,10 @@
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 @@
*/
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 BOOL32 CONSOLE_Satisfied(K32OBJ *ptr, DWORD thread_id)
{
- TRACE(console,"(),stub\n");
- return TRUE;
+ return FALSE;
}
@@ -784,6 +807,7 @@
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