Skip to content
Snippets Groups Projects
Commit ad7538bf authored by Marcus Meissner's avatar Marcus Meissner Committed by Alexandre Julliard
Browse files

Made async IO (SIGIO) stuff from WINSOCK generic useable.

Added async IO support to FILE and CONSOLE objects.
parent 0875d6e9
No related branches found
No related tags found
No related merge requests found
...@@ -8,6 +8,7 @@ VPATH = @srcdir@ ...@@ -8,6 +8,7 @@ VPATH = @srcdir@
MODULE = files MODULE = files
C_SRCS = \ C_SRCS = \
async.c \
change.c \ change.c \
directory.c \ directory.c \
dos_fs.c \ dos_fs.c \
......
/*
* 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;
}
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "ldt.h" #include "ldt.h"
#include "process.h" #include "process.h"
#include "task.h" #include "task.h"
#include "async.h"
#include "debug.h" #include "debug.h"
#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON) #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
...@@ -97,6 +98,7 @@ HFILE32 FILE_Alloc( FILE_OBJECT **file ) ...@@ -97,6 +98,7 @@ HFILE32 FILE_Alloc( FILE_OBJECT **file )
(*file)->type = FILE_TYPE_DISK; (*file)->type = FILE_TYPE_DISK;
(*file)->pos = 0; (*file)->pos = 0;
(*file)->mode = 0; (*file)->mode = 0;
(*file)->wait_queue = NULL;
handle = HANDLE_Alloc( PROCESS_Current(), &(*file)->header, handle = HANDLE_Alloc( PROCESS_Current(), &(*file)->header,
FILE_ALL_ACCESS | GENERIC_READ | FILE_ALL_ACCESS | GENERIC_READ |
...@@ -106,6 +108,16 @@ HFILE32 FILE_Alloc( FILE_OBJECT **file ) ...@@ -106,6 +108,16 @@ HFILE32 FILE_Alloc( FILE_OBJECT **file )
return handle; 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) static BOOL32 FILE_Signaled(K32OBJ *ptr, DWORD thread_id)
{ {
fd_set fds,*readfds = NULL,*writefds = NULL; fd_set fds,*readfds = NULL,*writefds = NULL;
...@@ -127,20 +139,23 @@ static BOOL32 FILE_Signaled(K32OBJ *ptr, DWORD thread_id) ...@@ -127,20 +139,23 @@ static BOOL32 FILE_Signaled(K32OBJ *ptr, DWORD thread_id)
static void FILE_AddWait(K32OBJ *ptr, DWORD thread_id) static void FILE_AddWait(K32OBJ *ptr, DWORD thread_id)
{ {
TRACE(file,"(),stub\n"); FILE_OBJECT *file = (FILE_OBJECT*)ptr;
return; 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) static void FILE_RemoveWait(K32OBJ *ptr, DWORD thread_id)
{ {
TRACE(file,"(),stub\n"); FILE_OBJECT *file = (FILE_OBJECT*)ptr;
return; 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) static BOOL32 FILE_Satisfied(K32OBJ *ptr, DWORD thread_id)
{ {
TRACE(file,"(),stub\n"); return FALSE; /* not abandoned. Hmm? */
return TRUE;
} }
/* FIXME: lpOverlapped is ignored */ /* FIXME: lpOverlapped is ignored */
......
#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
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <time.h> #include <time.h>
#include "windows.h" #include "windows.h"
#include "k32obj.h" #include "k32obj.h"
#include "thread.h"
#define MAX_PATHNAME_LEN 1024 #define MAX_PATHNAME_LEN 1024
...@@ -22,6 +23,8 @@ typedef struct ...@@ -22,6 +23,8 @@ typedef struct
char *unix_name; char *unix_name;
DWORD type; /* Type for win32 apps */ DWORD type; /* Type for win32 apps */
DWORD pos; /* workaround to emulate weird DOS error handling */ DWORD pos; /* workaround to emulate weird DOS error handling */
THREAD_QUEUE wait_queue;
} FILE_OBJECT; } FILE_OBJECT;
/* Definition of a full DOS file name */ /* Definition of a full DOS file name */
......
...@@ -148,6 +148,7 @@ void SIGNAL_SetHandler( int sig, void (*func)(), int flags ) ...@@ -148,6 +148,7 @@ void SIGNAL_SetHandler( int sig, void (*func)(), int flags )
extern void stop_wait(int a); extern void stop_wait(int a);
extern void WINSOCK_sigio(int a); extern void WINSOCK_sigio(int a);
extern void ASYNC_sigio(int a);
/********************************************************************** /**********************************************************************
...@@ -178,7 +179,8 @@ BOOL32 SIGNAL_Init(void) ...@@ -178,7 +179,8 @@ BOOL32 SIGNAL_Init(void)
#endif #endif
#ifdef SIGIO #ifdef SIGIO
sigaddset(&async_signal_set, 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 #endif
sigaddset(&async_signal_set, SIGALRM); sigaddset(&async_signal_set, SIGALRM);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "config.h" #include "config.h"
#include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
...@@ -38,14 +39,11 @@ ...@@ -38,14 +39,11 @@
#include "heap.h" #include "heap.h"
#include "ldt.h" #include "ldt.h"
#include "message.h" #include "message.h"
#include "selectors.h"
#include "miscemu.h" #include "miscemu.h"
#include "sig_context.h" #include "async.h"
#include "debug.h" #include "debug.h"
#ifndef FASYNC static void WINSOCK_async_handler(int unixfd,void *private);
#define FASYNC FIOASYNC
#endif
/* async DNS op control struct */ /* async DNS op control struct */
typedef struct typedef struct
...@@ -67,9 +65,6 @@ extern void* __ws_memalloc( int size ); ...@@ -67,9 +65,6 @@ extern void* __ws_memalloc( int size );
extern void __ws_memfree( void* ptr ); extern void __ws_memfree( void* ptr );
/* NOTE: ws_async_op list is traversed inside the SIGIO handler! */ /* 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 ws_async_op* __async_op_list = NULL;
static void fixup_wshe(struct ws_hostent* p_wshe, void* base); 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); ...@@ -78,20 +73,6 @@ static void fixup_wsse(struct ws_servent* p_wsse, void* base);
/* ----------------------------------- async/non-blocking I/O */ /* ----------------------------------- 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 WINSOCK_unblock_io(int fd, int noblock)
{ {
int fd_flags; int fd_flags;
...@@ -191,14 +172,12 @@ void WINSOCK_link_async_op(ws_async_op* p_aop) ...@@ -191,14 +172,12 @@ void WINSOCK_link_async_op(ws_async_op* p_aop)
p = p->next; p = p->next;
} }
} }
else FD_ZERO(&__async_io_fdset);
p_aop->next = __async_op_list; p_aop->next = __async_op_list;
__async_op_list = p_aop; __async_op_list = p_aop;
SIGNAL_MaskAsyncEvents( FALSE ); SIGNAL_MaskAsyncEvents( FALSE );
FD_SET(p_aop->fd[0], &__async_io_fdset); ASYNC_RegisterFD(p_aop->fd[0],WINSOCK_async_handler,p_aop);
if( p_aop->fd[0] > __async_io_max_fd )
__async_io_max_fd = p_aop->fd[0];
} }
void WINSOCK_unlink_async_op(ws_async_op* 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) ...@@ -210,9 +189,7 @@ void WINSOCK_unlink_async_op(ws_async_op* p_aop)
p_aop->prev->next = p_aop->next; p_aop->prev->next = p_aop->next;
if( p_aop->next ) p_aop->next->prev = p_aop->prev; if( p_aop->next ) p_aop->next->prev = p_aop->prev;
FD_CLR(p_aop->fd[0], &__async_io_fdset); ASYNC_UnregisterFD(p_aop->fd[0],WINSOCK_async_handler);
if( p_aop->fd[0] == __async_io_max_fd )
__async_io_max_fd--;
} }
/* ----------------------------------- SIGIO handler - /* ----------------------------------- SIGIO handler -
...@@ -223,42 +200,23 @@ void WINSOCK_unlink_async_op(ws_async_op* p_aop) ...@@ -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). * 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; ws_async_op* p_aop = (ws_async_op*)private;
fd_set check_set;
ws_async_op* p_aop; if( p_aop->aop_control(p_aop, AOP_IO) == AOP_CONTROL_REMOVE )
{
HANDLER_INIT(); /* NOTE: memory management is signal-unsafe, therefore
* we can only set a flag to remove this p_aop later on.
check_set = __async_io_fdset; */
memset(&timeout, 0, sizeof(timeout)); p_aop->flags = WSMSG_DEAD_AOP;
close(p_aop->fd[0]);
while( select(__async_io_max_fd + 1, if( p_aop->pid )
&check_set, NULL, NULL, &timeout) > 0) {
{ kill(p_aop->pid, SIGKILL);
for( p_aop = __async_op_list; waitpid(p_aop->pid, NULL, WNOHANG);
p_aop ; p_aop = p_aop->next ) p_aop->pid = 0;
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;
} }
} }
......
...@@ -32,8 +32,11 @@ ...@@ -32,8 +32,11 @@
#include <sys/errno.h> #include <sys/errno.h>
#include <signal.h> #include <signal.h>
#include <assert.h> #include <assert.h>
#include "windows.h" #include "windows.h"
#include "k32obj.h" #include "k32obj.h"
#include "thread.h"
#include "async.h"
#include "file.h" #include "file.h"
#include "process.h" #include "process.h"
#include "winerror.h" #include "winerror.h"
...@@ -53,6 +56,7 @@ typedef struct _CONSOLE { ...@@ -53,6 +56,7 @@ typedef struct _CONSOLE {
LPSTR title; /* title of console */ LPSTR title; /* title of console */
INPUT_RECORD *irs; /* buffered input records */ INPUT_RECORD *irs; /* buffered input records */
int nrofirs;/* nr of buffered input records */ int nrofirs;/* nr of buffered input records */
THREAD_QUEUE wait_queue;
} CONSOLE; } CONSOLE;
static void CONSOLE_AddWait(K32OBJ *ptr, DWORD thread_id); static void CONSOLE_AddWait(K32OBJ *ptr, DWORD thread_id);
...@@ -377,6 +381,16 @@ CONSOLE_drain_input(CONSOLE *console,int n) { ...@@ -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] * CONSOLE_Signaled [internal]
* *
...@@ -389,7 +403,10 @@ CONSOLE_Signaled(K32OBJ *ptr,DWORD tid) { ...@@ -389,7 +403,10 @@ CONSOLE_Signaled(K32OBJ *ptr,DWORD tid) {
if (ptr->type!= K32OBJ_CONSOLE) if (ptr->type!= K32OBJ_CONSOLE)
return FALSE; return FALSE;
CONSOLE_get_input(console); 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) { ...@@ -399,19 +416,26 @@ CONSOLE_Signaled(K32OBJ *ptr,DWORD tid) {
*/ */
static void CONSOLE_AddWait(K32OBJ *ptr, DWORD thread_id) static void CONSOLE_AddWait(K32OBJ *ptr, DWORD thread_id)
{ {
WARN(console,"(),stub. Expect hang.\n"); CONSOLE *console = (CONSOLE *)ptr;
return;
/* 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. * Remove thread from our waitqueue.
*/ */
static void CONSOLE_RemoveWait(K32OBJ *ptr, DWORD thread_id) static void CONSOLE_RemoveWait(K32OBJ *ptr, DWORD thread_id)
{ {
TRACE(console,"(),stub\n"); CONSOLE *console = (CONSOLE *)ptr;
return;
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) ...@@ -421,8 +445,7 @@ static void CONSOLE_RemoveWait(K32OBJ *ptr, DWORD thread_id)
*/ */
static BOOL32 CONSOLE_Satisfied(K32OBJ *ptr, DWORD thread_id) static BOOL32 CONSOLE_Satisfied(K32OBJ *ptr, DWORD thread_id)
{ {
TRACE(console,"(),stub\n"); return FALSE;
return TRUE;
} }
...@@ -784,6 +807,7 @@ BOOL32 WINAPI AllocConsole(VOID) ...@@ -784,6 +807,7 @@ BOOL32 WINAPI AllocConsole(VOID)
console->pid = -1; console->pid = -1;
console->title = NULL; console->title = NULL;
console->nrofirs = 0; console->nrofirs = 0;
console->wait_queue = NULL;
console->irs = HeapAlloc(GetProcessHeap(),0,1);; console->irs = HeapAlloc(GetProcessHeap(),0,1);;
console->mode = ENABLE_PROCESSED_INPUT console->mode = ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT | ENABLE_LINE_INPUT
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment