Commit ad7538bf authored by Marcus Meissner's avatar Marcus Meissner Committed by Alexandre Julliard

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

Added async IO support to FILE and CONSOLE objects.
parent 0875d6e9
......@@ -8,6 +8,7 @@ VPATH = @srcdir@
MODULE = files
C_SRCS = \
async.c \
change.c \
directory.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 @@
#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 @@ HFILE32 FILE_Alloc( FILE_OBJECT **file )
(*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 @@ 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 */
......
#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 @@
#include <time.h>
#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 */
......
......@@ -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);
......
......@@ -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_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;
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;
ws_async_op* p_aop = (ws_async_op*)private;
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;
}
}
}
......
......@@ -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 @@ 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);
......@@ -378,6 +382,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]
*
* Checks if we can read something. (Hmm, what about writing ?)
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment