Commit 4634447d authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

- got rid of include/async.h

- fixed some overlapped issues in socket handling - moved kernel32.CancelIo implementation to ntdll
parent 3e55df39
...@@ -93,8 +93,8 @@ ...@@ -93,8 +93,8 @@
#include "winerror.h" #include "winerror.h"
#include "wine/server.h" #include "wine/server.h"
#include "async.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "thread.h"
#include "wine/debug.h" #include "wine/debug.h"
...@@ -125,32 +125,15 @@ static inline void release_comm_fd( HANDLE handle, int fd ) ...@@ -125,32 +125,15 @@ static inline void release_comm_fd( HANDLE handle, int fd )
* Asynchronous I/O for asynchronous wait requests * * Asynchronous I/O for asynchronous wait requests *
*/ */
static DWORD commio_get_async_count (const async_private *ovp);
static void commio_async_cleanup (async_private *ovp);
static async_ops commio_async_ops =
{
commio_get_async_count, /* get_count */
NULL, /* call_completion */
commio_async_cleanup /* cleanup */
};
typedef struct async_commio typedef struct async_commio
{ {
struct async_private async; HANDLE handle;
char *buffer; PIO_APC_ROUTINE apc_internal;
int type;
char* buffer;
int fd;
} async_commio; } async_commio;
static DWORD commio_get_async_count (const struct async_private *ovp)
{
return 0;
}
static void commio_async_cleanup (async_private *ovp)
{
HeapFree(GetProcessHeap(), 0, ovp );
}
/***********************************************************************/ /***********************************************************************/
#if !defined(TIOCINQ) && defined(FIONREAD) #if !defined(TIOCINQ) && defined(FIONREAD)
...@@ -1928,17 +1911,27 @@ BOOL WINAPI GetCommModemStatus( ...@@ -1928,17 +1911,27 @@ BOOL WINAPI GetCommModemStatus(
* This function is called while the client is waiting on the * This function is called while the client is waiting on the
* server, so we can't make any server calls here. * server, so we can't make any server calls here.
*/ */
static void COMM_WaitCommEventService(async_private *ovp) static void WINAPI COMM_WaitCommEventService(void* ovp, IO_STATUS_BLOCK* iosb, ULONG status)
{ {
async_commio *commio = (async_commio*) ovp; async_commio *commio = (async_commio*) ovp;
IO_STATUS_BLOCK* iosb = commio->async.iosb;
TRACE("iosb %p\n",iosb); TRACE("iosb %p\n", iosb);
/* FIXME: detect other events */ switch (status)
*commio->buffer = EV_RXCHAR; {
case STATUS_ALERTED: /* got some new stuff */
iosb->u.Status = STATUS_SUCCESS; /* FIXME: detect other events */
*commio->buffer = EV_RXCHAR;
iosb->u.Status = STATUS_SUCCESS;
break;
default:
iosb->u.Status = status;
break;
}
wine_server_release_fd( commio->handle, commio->fd );
if ( ((LPOVERLAPPED)iosb)->hEvent != INVALID_HANDLE_VALUE )
NtSetEvent( ((LPOVERLAPPED)iosb)->hEvent, NULL );
HeapFree(GetProcessHeap(), 0, commio );
} }
...@@ -1952,44 +1945,52 @@ static BOOL COMM_WaitCommEvent( ...@@ -1952,44 +1945,52 @@ static BOOL COMM_WaitCommEvent(
LPDWORD lpdwEvents, /* [out] event(s) that were detected */ LPDWORD lpdwEvents, /* [out] event(s) that were detected */
LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */ LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
{ {
int fd; int fd;
async_commio *ovp; async_commio* commio;
NTSTATUS status;
if(!lpOverlapped) if (!lpOverlapped)
{ {
SetLastError(ERROR_INVALID_PARAMETER); SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
if(NtResetEvent(lpOverlapped->hEvent,NULL)) if (NtResetEvent(lpOverlapped->hEvent,NULL))
return FALSE; return FALSE;
fd = get_comm_fd( hFile, GENERIC_WRITE ); fd = get_comm_fd( hFile, GENERIC_WRITE );
if(fd<0) if (fd < 0) return FALSE;
return FALSE;
ovp = (async_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio)); commio = (async_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio));
if(!ovp) if (!commio)
{ {
release_comm_fd( hFile, fd ); release_comm_fd( hFile, fd );
return FALSE; return FALSE;
} }
ovp->async.ops = &commio_async_ops; commio->handle = hFile;
ovp->async.handle = hFile; commio->type = ASYNC_TYPE_WAIT;
ovp->async.fd = fd; /* FIXME */ commio->apc_internal = COMM_WaitCommEventService;
ovp->async.type = ASYNC_TYPE_WAIT; commio->buffer = (char *)lpdwEvents;
ovp->async.func = COMM_WaitCommEventService; commio->fd = fd; /* FIXME */
ovp->async.event = lpOverlapped->hEvent;
ovp->async.iosb = (IO_STATUS_BLOCK*)lpOverlapped;
ovp->buffer = (char *)lpdwEvents;
lpOverlapped->InternalHigh = 0; lpOverlapped->InternalHigh = 0;
lpOverlapped->Offset = 0; lpOverlapped->Offset = 0;
lpOverlapped->OffsetHigh = 0; lpOverlapped->OffsetHigh = 0;
if ( !register_new_async (&ovp->async) ) SERVER_START_REQ( register_async )
SetLastError( ERROR_IO_PENDING ); {
req->handle = hFile;
req->io_apc = COMM_WaitCommEventService;
req->io_user = commio;
req->io_sb = (IO_STATUS_BLOCK*)lpOverlapped;
req->count = 0;
status = wine_server_call( req );
}
SERVER_END_REQ;
if ( status ) SetLastError( RtlNtStatusToDosError(status) );
else NtCurrentTeb()->num_async_io++;
return FALSE; return FALSE;
} }
......
...@@ -43,7 +43,8 @@ ...@@ -43,7 +43,8 @@
#include "excpt.h" #include "excpt.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "async.h" #include "thread.h"
#include "wine/server.h"
WINE_DEFAULT_DEBUG_CHANNEL(file); WINE_DEFAULT_DEBUG_CHANNEL(file);
...@@ -512,7 +513,7 @@ BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, ...@@ -512,7 +513,7 @@ BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped,
else else
{ {
/* busy loop */ /* busy loop */
while ( (volatile DWORD)lpOverlapped->Internal == STATUS_PENDING ) while ( ((volatile OVERLAPPED*)lpOverlapped)->Internal == STATUS_PENDING )
Sleep( 10 ); Sleep( 10 );
} }
} }
...@@ -532,7 +533,7 @@ BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, ...@@ -532,7 +533,7 @@ BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped,
} }
if ( r == WAIT_FAILED ) if ( r == WAIT_FAILED )
{ {
ERR("wait operation failed\n"); WARN("wait operation failed\n");
return FALSE; return FALSE;
} }
if (lpTransferred) *lpTransferred = lpOverlapped->InternalHigh; if (lpTransferred) *lpTransferred = lpOverlapped->InternalHigh;
...@@ -556,17 +557,14 @@ BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, ...@@ -556,17 +557,14 @@ BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped,
*/ */
BOOL WINAPI CancelIo(HANDLE handle) BOOL WINAPI CancelIo(HANDLE handle)
{ {
async_private *ovp,*t; IO_STATUS_BLOCK io_status;
TRACE("handle = %p\n",handle); NtCancelIoFile(handle, &io_status);
if (io_status.u.Status)
for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
{ {
t = ovp->next; SetLastError( RtlNtStatusToDosError( io_status.u.Status ) );
if ( ovp->handle == handle ) return FALSE;
cancel_async ( ovp );
} }
SleepEx(1,TRUE);
return TRUE; return TRUE;
} }
......
...@@ -62,7 +62,6 @@ ...@@ -62,7 +62,6 @@
#include "wine/unicode.h" #include "wine/unicode.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/server.h" #include "wine/server.h"
#include "async.h"
#include "ntdll_misc.h" #include "ntdll_misc.h"
#include "winternl.h" #include "winternl.h"
...@@ -222,59 +221,66 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB ...@@ -222,59 +221,66 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB
/*********************************************************************** /***********************************************************************
* Asynchronous file I/O * * Asynchronous file I/O *
*/ */
static DWORD fileio_get_async_count(const async_private *ovp); static void WINAPI FILE_AsyncReadService(void*, PIO_STATUS_BLOCK, ULONG);
static void CALLBACK fileio_call_completion_func(ULONG_PTR data); static void WINAPI FILE_AsyncWriteService(void*, PIO_STATUS_BLOCK, ULONG);
static void fileio_async_cleanup(async_private *ovp);
static async_ops fileio_async_ops =
{
fileio_get_async_count, /* get_count */
fileio_call_completion_func, /* call_completion */
fileio_async_cleanup /* cleanup */
};
static async_ops fileio_nocomp_async_ops =
{
fileio_get_async_count, /* get_count */
NULL, /* call_completion */
fileio_async_cleanup /* cleanup */
};
typedef struct async_fileio typedef struct async_fileio
{ {
struct async_private async; HANDLE handle;
PIO_APC_ROUTINE apc; PIO_APC_ROUTINE apc;
void* apc_user; void* apc_user;
char *buffer; char* buffer;
unsigned int count; unsigned int count;
off_t offset; off_t offset;
int queue_apc_on_error; int queue_apc_on_error;
BOOL avail_mode; BOOL avail_mode;
int fd;
HANDLE event;
} async_fileio; } async_fileio;
static DWORD fileio_get_async_count(const struct async_private *ovp) static void fileio_terminate(async_fileio *fileio, IO_STATUS_BLOCK* iosb)
{ {
const async_fileio *fileio = (const async_fileio*) ovp; TRACE("data: %p\n", fileio);
if (fileio->count < fileio->async.iosb->Information) wine_server_release_fd( fileio->handle, fileio->fd );
return 0; if ( fileio->event != INVALID_HANDLE_VALUE )
return fileio->count - fileio->async.iosb->Information; NtSetEvent( fileio->event, NULL );
}
static void CALLBACK fileio_call_completion_func(ULONG_PTR data) if (fileio->apc &&
{ (iosb->u.Status == STATUS_SUCCESS || fileio->queue_apc_on_error))
async_fileio *ovp = (async_fileio*) data; fileio->apc( fileio->apc_user, iosb, iosb->Information );
TRACE("data: %p\n", ovp);
if ((ovp->async.iosb->u.Status == STATUS_SUCCESS) || ovp->queue_apc_on_error) RtlFreeHeap( GetProcessHeap(), 0, fileio );
ovp->apc( ovp->apc_user, ovp->async.iosb, ovp->async.iosb->Information );
fileio_async_cleanup( &ovp->async );
} }
static void fileio_async_cleanup( struct async_private *ovp )
static ULONG fileio_queue_async(async_fileio* fileio, IO_STATUS_BLOCK* iosb,
BOOL do_read)
{ {
RtlFreeHeap( GetProcessHeap(), 0, ovp ); PIO_APC_ROUTINE apc = do_read ? FILE_AsyncReadService : FILE_AsyncWriteService;
NTSTATUS status;
SERVER_START_REQ( register_async )
{
req->handle = fileio->handle;
req->io_apc = apc;
req->io_sb = iosb;
req->io_user = fileio;
req->type = do_read ? ASYNC_TYPE_READ : ASYNC_TYPE_WRITE;
req->count = (fileio->count < iosb->Information) ?
0 : fileio->count - iosb->Information;
status = wine_server_call( req );
}
SERVER_END_REQ;
if ( status ) iosb->u.Status = status;
if ( iosb->u.Status != STATUS_PENDING )
{
(apc)( fileio, iosb, iosb->u.Status );
return iosb->u.Status;
}
NtCurrentTeb()->num_async_io++;
return STATUS_SUCCESS;
} }
/*********************************************************************** /***********************************************************************
...@@ -326,55 +332,75 @@ NTSTATUS FILE_GetNtStatus(void) ...@@ -326,55 +332,75 @@ NTSTATUS FILE_GetNtStatus(void)
* This function is called while the client is waiting on the * This function is called while the client is waiting on the
* server, so we can't make any server calls here. * server, so we can't make any server calls here.
*/ */
static void FILE_AsyncReadService(async_private *ovp) static void WINAPI FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, ULONG status)
{ {
async_fileio *fileio = (async_fileio*) ovp; async_fileio *fileio = (async_fileio*)user;
IO_STATUS_BLOCK* io_status = fileio->async.iosb;
int result; int result;
int already = io_status->Information; int already = iosb->Information;
TRACE("%p %p\n", io_status, fileio->buffer ); TRACE("%p %p %lu\n", iosb, fileio->buffer, status);
/* check to see if the data is ready (non-blocking) */ switch (status)
if ( fileio->avail_mode )
result = read(ovp->fd, &fileio->buffer[already], fileio->count - already);
else
{ {
result = pread(ovp->fd, &fileio->buffer[already], fileio->count - already, case STATUS_ALERTED: /* got some new data */
fileio->offset + already); if (iosb->u.Status != STATUS_PENDING) FIXME("unexpected status %08lx\n", iosb->u.Status);
if ((result < 0) && (errno == ESPIPE)) /* check to see if the data is ready (non-blocking) */
result = read(ovp->fd, &fileio->buffer[already], fileio->count - already); if ( fileio->avail_mode )
} result = read(fileio->fd, &fileio->buffer[already],
fileio->count - already);
else
{
result = pread(fileio->fd, &fileio->buffer[already],
fileio->count - already,
fileio->offset + already);
if ((result < 0) && (errno == ESPIPE))
result = read(fileio->fd, &fileio->buffer[already],
fileio->count - already);
}
if ((result < 0) && ((errno == EAGAIN) || (errno == EINTR))) if (result < 0)
{ {
TRACE("Deferred read %d\n",errno); if (errno == EAGAIN || errno == EINTR)
io_status->u.Status = STATUS_PENDING; {
return; TRACE("Deferred read %d\n", errno);
} iosb->u.Status = STATUS_PENDING;
}
else /* check to see if the transfer is complete */
iosb->u.Status = FILE_GetNtStatus();
}
else if (result == 0)
{
iosb->u.Status = iosb->Information ? STATUS_SUCCESS : STATUS_END_OF_FILE;
}
else
{
iosb->Information += result;
if (iosb->Information >= fileio->count || fileio->avail_mode)
iosb->u.Status = STATUS_SUCCESS;
else
{
/* if we only have to read the available data, and none is available,
* simply cancel the request. If data was available, it has been read
* while in by previous call (NtDelayExecution)
*/
iosb->u.Status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING;
}
/* check to see if the transfer is complete */ TRACE("read %d more bytes %ld/%d so far (%s)\n",
if (result < 0) result, iosb->Information, fileio->count,
{ (iosb->u.Status == STATUS_SUCCESS) ? "success" : "pending");
io_status->u.Status = FILE_GetNtStatus(); }
return; /* queue another async operation ? */
} if (iosb->u.Status == STATUS_PENDING)
else if (result == 0) fileio_queue_async(fileio, iosb, TRUE);
{ else
io_status->u.Status = io_status->Information ? STATUS_SUCCESS : STATUS_END_OF_FILE; fileio_terminate(fileio, iosb);
return; break;
default:
iosb->u.Status = status;
fileio_terminate(fileio, iosb);
break;
} }
TRACE("status before: %s\n", (io_status->u.Status == STATUS_SUCCESS) ? "success" : "pending");
io_status->Information += result;
if (io_status->Information >= fileio->count || fileio->avail_mode )
io_status->u.Status = STATUS_SUCCESS;
else
io_status->u.Status = STATUS_PENDING;
TRACE("read %d more bytes %ld/%d so far (%s)\n",
result, io_status->Information, fileio->count, (io_status->u.Status == STATUS_SUCCESS) ? "success" : "pending");
} }
...@@ -439,44 +465,41 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, ...@@ -439,44 +465,41 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT)) if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
{ {
async_fileio* ovp; async_fileio* fileio;
NTSTATUS ret; NTSTATUS ret;
if (!(ovp = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio)))) if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
{ {
wine_server_release_fd( hFile, unix_handle ); wine_server_release_fd( hFile, unix_handle );
if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent); if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
} }
ovp->async.ops = (apc ? &fileio_async_ops : &fileio_nocomp_async_ops ); fileio->handle = hFile;
ovp->async.handle = hFile; fileio->count = length;
ovp->async.fd = unix_handle; /* FIXME */
ovp->async.type = ASYNC_TYPE_READ;
ovp->async.func = FILE_AsyncReadService;
ovp->async.event = hEvent;
ovp->async.iosb = io_status;
ovp->count = length;
if ( offset == NULL ) if ( offset == NULL )
ovp->offset = 0; fileio->offset = 0;
else else
{ {
ovp->offset = offset->QuadPart; fileio->offset = offset->QuadPart;
if (offset->u.HighPart && ovp->offset == offset->u.LowPart) if (offset->u.HighPart && fileio->offset == offset->u.LowPart)
FIXME("High part of offset is lost\n"); FIXME("High part of offset is lost\n");
} }
ovp->apc = apc; fileio->apc = apc;
ovp->apc_user = apc_user; fileio->apc_user = apc_user;
ovp->buffer = buffer; fileio->buffer = buffer;
ovp->queue_apc_on_error = 0; fileio->queue_apc_on_error = 0;
ovp->avail_mode = (flags & FD_FLAG_AVAILABLE); fileio->avail_mode = (flags & FD_FLAG_AVAILABLE);
fileio->fd = unix_handle; /* FIXME */
fileio->event = hEvent;
NtResetEvent(hEvent, NULL); NtResetEvent(hEvent, NULL);
ret = register_new_async(&ovp->async); io_status->u.Status = STATUS_PENDING;
ret = fileio_queue_async(fileio, io_status, TRUE);
if (ret != STATUS_SUCCESS) if (ret != STATUS_SUCCESS)
{ {
wine_server_release_fd( hFile, unix_handle ); wine_server_release_fd( hFile, unix_handle );
if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent); if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
RtlFreeHeap(GetProcessHeap(), 0, ovp); RtlFreeHeap(GetProcessHeap(), 0, fileio);
return ret; return ret;
} }
if (flags & FD_FLAG_TIMEOUT) if (flags & FD_FLAG_TIMEOUT)
...@@ -484,7 +507,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, ...@@ -484,7 +507,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
ret = NtWaitForSingleObject(hEvent, TRUE, NULL); ret = NtWaitForSingleObject(hEvent, TRUE, NULL);
NtClose(hEvent); NtClose(hEvent);
if (ret != STATUS_USER_APC) if (ret != STATUS_USER_APC)
ovp->queue_apc_on_error = 1; fileio->queue_apc_on_error = 1;
} }
else else
{ {
...@@ -499,16 +522,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, ...@@ -499,16 +522,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
* returning errors because apc's are run only during alertable * returning errors because apc's are run only during alertable
* waits */ * waits */
if (ret != STATUS_USER_APC) if (ret != STATUS_USER_APC)
ovp->queue_apc_on_error = 1; fileio->queue_apc_on_error = 1;
/* if we only have to read the available data, and none is available,
* simply cancel the request. If data was available, it has been read
* while in by previous call (NtDelayExecution)
*/
if ((flags & FD_FLAG_AVAILABLE) && io_status->u.Status == STATUS_PENDING)
{
io_status->u.Status = STATUS_SUCCESS;
register_old_async(&ovp->async);
}
} }
TRACE("= 0x%08lx\n", io_status->u.Status); TRACE("= 0x%08lx\n", io_status->u.Status);
return io_status->u.Status; return io_status->u.Status;
...@@ -550,43 +564,50 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, ...@@ -550,43 +564,50 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
* This function is called while the client is waiting on the * This function is called while the client is waiting on the
* server, so we can't make any server calls here. * server, so we can't make any server calls here.
*/ */
static void FILE_AsyncWriteService(struct async_private *ovp) static void WINAPI FILE_AsyncWriteService(void *ovp, IO_STATUS_BLOCK *iosb, ULONG status)
{ {
async_fileio *fileio = (async_fileio *) ovp; async_fileio *fileio = (async_fileio *) ovp;
PIO_STATUS_BLOCK io_status = fileio->async.iosb;
int result; int result;
int already = io_status->Information; int already = iosb->Information;
TRACE("(%p %p)\n",io_status,fileio->buffer);
/* write some data (non-blocking) */
if ( fileio->avail_mode ) TRACE("(%p %p %lu)\n",iosb, fileio->buffer, status);
result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
else
{
result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
fileio->offset + already);
if ((result < 0) && (errno == ESPIPE))
result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
}
if ((result < 0) && ((errno == EAGAIN) || (errno == EINTR))) switch (status)
{ {
io_status->u.Status = STATUS_PENDING; case STATUS_ALERTED:
return; /* write some data (non-blocking) */
} if ( fileio->avail_mode )
result = write(fileio->fd, &fileio->buffer[already],
fileio->count - already);
else
{
result = pwrite(fileio->fd, &fileio->buffer[already],
fileio->count - already, fileio->offset + already);
if ((result < 0) && (errno == ESPIPE))
result = write(fileio->fd, &fileio->buffer[already],
fileio->count - already);
}
/* check to see if the transfer is complete */ if (result < 0)
if (result < 0) {
{ if (errno == EAGAIN || errno == EINTR) iosb->u.Status = STATUS_PENDING;
io_status->u.Status = FILE_GetNtStatus(); else iosb->u.Status = FILE_GetNtStatus();
return; }
else
{
iosb->Information += result;
iosb->u.Status = (iosb->Information < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
TRACE("wrote %d more bytes %ld/%d so far\n",
result, iosb->Information, fileio->count);
}
if (iosb->u.Status == STATUS_PENDING)
fileio_queue_async(fileio, iosb, FALSE);
break;
default:
iosb->u.Status = status;
fileio_terminate(fileio, iosb);
break;
} }
io_status->Information += result;
io_status->u.Status = (io_status->Information < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
TRACE("wrote %d more bytes %ld/%d so far\n",result,io_status->Information,fileio->count);
} }
/****************************************************************************** /******************************************************************************
...@@ -651,46 +672,52 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, ...@@ -651,46 +672,52 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT)) if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
{ {
async_fileio* ovp; async_fileio* fileio;
NTSTATUS ret; NTSTATUS ret;
if (!(ovp = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio)))) if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
{ {
wine_server_release_fd( hFile, unix_handle ); wine_server_release_fd( hFile, unix_handle );
if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
} }
ovp->async.ops = (apc ? &fileio_async_ops : &fileio_nocomp_async_ops ); fileio->handle = hFile;
ovp->async.handle = hFile; fileio->count = length;
ovp->async.fd = unix_handle; /* FIXME */ if (offset)
ovp->async.type = ASYNC_TYPE_WRITE; {
ovp->async.func = FILE_AsyncWriteService; fileio->offset = offset->QuadPart;
ovp->async.event = hEvent; if (offset->u.HighPart && fileio->offset == offset->u.LowPart)
ovp->async.iosb = io_status;
ovp->count = length;
if (offset) {
ovp->offset = offset->QuadPart;
if (offset->u.HighPart && ovp->offset == offset->u.LowPart)
FIXME("High part of offset is lost\n"); FIXME("High part of offset is lost\n");
} else {
ovp->offset = 0;
} }
ovp->apc = apc; else
ovp->apc_user = apc_user; {
ovp->buffer = (void*)buffer; fileio->offset = 0;
ovp->queue_apc_on_error = 0; }
ovp->avail_mode = (flags & FD_FLAG_AVAILABLE); fileio->apc = apc;
fileio->apc_user = apc_user;
fileio->buffer = (void*)buffer;
fileio->queue_apc_on_error = 0;
fileio->avail_mode = (flags & FD_FLAG_AVAILABLE);
fileio->fd = unix_handle; /* FIXME */
fileio->event = hEvent;
NtResetEvent(hEvent, NULL); NtResetEvent(hEvent, NULL);
io_status->Information = 0; io_status->Information = 0;
ret = register_new_async(&ovp->async); io_status->u.Status = STATUS_PENDING;
ret = fileio_queue_async(fileio, io_status, FALSE);
if (ret != STATUS_SUCCESS) if (ret != STATUS_SUCCESS)
{
wine_server_release_fd( hFile, unix_handle );
if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
RtlFreeHeap(GetProcessHeap(), 0, fileio);
return ret; return ret;
}
if (flags & FD_FLAG_TIMEOUT) if (flags & FD_FLAG_TIMEOUT)
{ {
ret = NtWaitForSingleObject(hEvent, TRUE, NULL); ret = NtWaitForSingleObject(hEvent, TRUE, NULL);
NtClose(hEvent); NtClose(hEvent);
if (ret != STATUS_USER_APC) if (ret != STATUS_USER_APC)
ovp->queue_apc_on_error = 1; fileio->queue_apc_on_error = 1;
} }
else else
{ {
...@@ -705,7 +732,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, ...@@ -705,7 +732,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
* returning errors because apc's are run only during alertable * returning errors because apc's are run only during alertable
* waits */ * waits */
if (ret != STATUS_USER_APC) if (ret != STATUS_USER_APC)
ovp->queue_apc_on_error = 1; fileio->queue_apc_on_error = 1;
} }
return io_status->u.Status; return io_status->u.Status;
} }
...@@ -1688,9 +1715,23 @@ NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes ) ...@@ -1688,9 +1715,23 @@ NTSTATUS WINAPI NtDeleteFile( POBJECT_ATTRIBUTES ObjectAttributes )
* *
* *
*/ */
NTSTATUS WINAPI NtCancelIoFile( HANDLE FileHandle, NTSTATUS WINAPI NtCancelIoFile( HANDLE hFile, PIO_STATUS_BLOCK io_status )
PIO_STATUS_BLOCK IoStatusBlock)
{ {
FIXME("%p %p\n", FileHandle, IoStatusBlock ); LARGE_INTEGER timeout;
return STATUS_NOT_IMPLEMENTED;
TRACE("%p %p\n", hFile, io_status );
SERVER_START_REQ( cancel_async )
{
req->handle = hFile;
wine_server_call( req );
}
SERVER_END_REQ;
/* Let some APC be run, so that we can run the remaining APCs on hFile
* either the cancelation of the pending one, but also the execution
* of the queued APC, but not yet run. This is needed to ensure proper
* clean-up of allocated data.
*/
timeout.u.LowPart = timeout.u.HighPart = 0;
return io_status->u.Status = NtDelayExecution( TRUE, &timeout );
} }
...@@ -51,7 +51,6 @@ ...@@ -51,7 +51,6 @@
#include "winbase.h" #include "winbase.h"
#include "winreg.h" #include "winreg.h"
#include "winternl.h" #include "winternl.h"
#include "async.h"
#include "thread.h" #include "thread.h"
#include "wine/server.h" #include "wine/server.h"
#include "wine/debug.h" #include "wine/debug.h"
...@@ -605,35 +604,6 @@ NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution, ...@@ -605,35 +604,6 @@ NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
/*********************************************************************** /***********************************************************************
* check_async_list
*
* Process a status event from the server.
*/
static void WINAPI check_async_list(async_private *asp, DWORD status)
{
async_private *ovp;
DWORD ovp_status;
for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
if(!ovp)
return;
if( status != STATUS_ALERTED )
{
ovp_status = status;
ovp->iosb->u.Status = status;
}
else ovp_status = ovp->iosb->u.Status;
if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
/* This will destroy all but PENDING requests */
register_old_async( ovp );
}
/***********************************************************************
* wait_reply * wait_reply
* *
* Wait for a reply on the waiting pipe of the current thread. * Wait for a reply on the waiting pipe of the current thread.
...@@ -697,7 +667,7 @@ static void call_apcs( BOOL alertable ) ...@@ -697,7 +667,7 @@ static void call_apcs( BOOL alertable )
} }
SERVER_END_REQ; SERVER_END_REQ;
switch(type) switch (type)
{ {
case APC_NONE: case APC_NONE:
return; /* no more APCs */ return; /* no more APCs */
...@@ -714,7 +684,8 @@ static void call_apcs( BOOL alertable ) ...@@ -714,7 +684,8 @@ static void call_apcs( BOOL alertable )
proc( arg3, time.u.LowPart, time.u.HighPart ); proc( arg3, time.u.LowPart, time.u.HighPart );
break; break;
case APC_ASYNC_IO: case APC_ASYNC_IO:
check_async_list( arg1, (DWORD) arg2 ); NtCurrentTeb()->num_async_io--;
proc( arg1, (IO_STATUS_BLOCK*)arg2, (ULONG)arg3 );
break; break;
default: default:
server_protocol_error( "get_apc_request: bad type %d\n", type ); server_protocol_error( "get_apc_request: bad type %d\n", type );
...@@ -810,7 +781,7 @@ NTSTATUS WINAPI NtYieldExecution(void) ...@@ -810,7 +781,7 @@ NTSTATUS WINAPI NtYieldExecution(void)
NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout ) NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
{ {
/* if alertable or async I/O in progress, we need to query the server */ /* if alertable or async I/O in progress, we need to query the server */
if (alertable || NtCurrentTeb()->pending_list) if (alertable || NtCurrentTeb()->num_async_io)
{ {
UINT flags = SELECT_INTERRUPTIBLE; UINT flags = SELECT_INTERRUPTIBLE;
if (alertable) flags |= SELECT_ALERTABLE; if (alertable) flags |= SELECT_ALERTABLE;
......
...@@ -128,6 +128,7 @@ ...@@ -128,6 +128,7 @@
#include "thread.h" #include "thread.h"
#include "wine/server.h" #include "wine/server.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "ntstatus.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#ifdef HAVE_IPX #ifdef HAVE_IPX
...@@ -161,39 +162,24 @@ inline static const char *debugstr_sockaddr( const struct WS_sockaddr *a ) ...@@ -161,39 +162,24 @@ inline static const char *debugstr_sockaddr( const struct WS_sockaddr *a )
/**************************************************************** /****************************************************************
* Async IO declarations * Async IO declarations
****************************************************************/ ****************************************************************/
#include "async.h"
static DWORD ws2_async_get_count (const struct async_private *ovp);
static void CALLBACK ws2_async_call_completion (ULONG_PTR data);
static void ws2_async_cleanup ( struct async_private *ovp );
static struct async_ops ws2_async_ops =
{
ws2_async_get_count,
ws2_async_call_completion,
ws2_async_cleanup
};
static struct async_ops ws2_nocomp_async_ops =
{
ws2_async_get_count,
NULL, /* call_completion */
ws2_async_cleanup
};
typedef struct ws2_async typedef struct ws2_async
{ {
async_private async; HANDLE hSocket;
enum ws2_mode {ws2m_read, ws2m_write, ws2m_sd_read, ws2m_sd_write} mode;
LPWSAOVERLAPPED user_overlapped; LPWSAOVERLAPPED user_overlapped;
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_func; LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_func;
struct iovec *iovec; struct iovec *iovec;
int n_iovecs; int n_iovecs;
struct WS_sockaddr *addr; struct WS_sockaddr *addr;
union { union
{
int val; /* for send operations */ int val; /* for send operations */
int *ptr; /* for recv operations */ int *ptr; /* for recv operations */
} addrlen; } addrlen;
DWORD flags; DWORD flags;
int fd;
HANDLE event;
} ws2_async; } ws2_async;
/****************************************************************/ /****************************************************************/
...@@ -290,7 +276,7 @@ static const int ws_ip_map[][2] = ...@@ -290,7 +276,7 @@ static const int ws_ip_map[][2] =
{ 0, 0 } { 0, 0 }
}; };
inline static DWORD NtStatusToWSAError ( const DWORD status ) inline static DWORD NtStatusToWSAError( const DWORD status )
{ {
/* We only need to cover the status codes set by server async request handling */ /* We only need to cover the status codes set by server async request handling */
DWORD wserr; DWORD wserr;
...@@ -311,7 +297,7 @@ inline static DWORD NtStatusToWSAError ( const DWORD status ) ...@@ -311,7 +297,7 @@ inline static DWORD NtStatusToWSAError ( const DWORD status )
else else
{ {
wserr = RtlNtStatusToDosError( status ); wserr = RtlNtStatusToDosError( status );
FIXME ( "Status code %08lx converted to DOS error code %lx\n", status, wserr ); FIXME( "Status code %08lx converted to DOS error code %lx\n", status, wserr );
} }
} }
return wserr; return wserr;
...@@ -322,7 +308,7 @@ inline static unsigned int set_error( unsigned int err ) ...@@ -322,7 +308,7 @@ inline static unsigned int set_error( unsigned int err )
{ {
if (err) if (err)
{ {
err = NtStatusToWSAError ( err ); err = NtStatusToWSAError( err );
SetLastError( err ); SetLastError( err );
} }
return err; return err;
...@@ -611,7 +597,7 @@ static void fd_set_unimport( WS_fd_set* wsfds, int lfd[] ) ...@@ -611,7 +597,7 @@ static void fd_set_unimport( WS_fd_set* wsfds, int lfd[] )
{ {
unsigned int i; unsigned int i;
for( i = 0; i < wsfds->fd_count; i++ ) for ( i = 0; i < wsfds->fd_count; i++ )
if ( lfd[i] >= 0 ) release_sock_fd( wsfds->fd_array[i], lfd[i] ); if ( lfd[i] >= 0 ) release_sock_fd( wsfds->fd_array[i], lfd[i] );
wsfds->fd_count = 0; wsfds->fd_count = 0;
} }
...@@ -818,7 +804,6 @@ static const struct sockaddr* ws_sockaddr_ws2u(const struct WS_sockaddr* wsaddr, ...@@ -818,7 +804,6 @@ static const struct sockaddr* ws_sockaddr_ws2u(const struct WS_sockaddr* wsaddr,
*uaddrlen=wsaddrlen; *uaddrlen=wsaddrlen;
return (const struct sockaddr*)wsaddr; return (const struct sockaddr*)wsaddr;
} }
return NULL;
} }
/* Allocates a Unix sockaddr structure to receive the data */ /* Allocates a Unix sockaddr structure to receive the data */
...@@ -916,138 +901,164 @@ inline void ws_sockaddr_free(const struct sockaddr* uaddr, const struct WS_socka ...@@ -916,138 +901,164 @@ inline void ws_sockaddr_free(const struct sockaddr* uaddr, const struct WS_socka
* Functions for handling overlapped I/O * Functions for handling overlapped I/O
**************************************************************************/ **************************************************************************/
static DWORD ws2_async_get_count (const struct async_private *ovp) static void CALLBACK ws2_async_terminate(ws2_async* as, IO_STATUS_BLOCK* iosb)
{ {
return ovp->iosb->Information; TRACE( "as: %p uovl %p ovl %p\n", as, as->user_overlapped, iosb );
}
static void ws2_async_cleanup ( struct async_private *ap ) wine_server_release_fd( as->hSocket, as->fd );
{ if ( as->event != INVALID_HANDLE_VALUE )
struct ws2_async *as = (struct ws2_async*) ap; NtSetEvent( as->event, NULL );
TRACE ( "as: %p uovl %p ovl %p\n", as, as->user_overlapped, as->async.iosb ); if (as->completion_func)
as->completion_func( NtStatusToWSAError (iosb->u.Status),
iosb->Information, as->user_overlapped, as->flags );
if ( !as->user_overlapped ) if ( !as->user_overlapped )
{ {
#if 0 #if 0
/* FIXME: I don't think this is really used */ /* FIXME: I don't think this is really used */
if ( as->overlapped->hEvent != INVALID_HANDLE_VALUE ) if ( as->overlapped->hEvent != INVALID_HANDLE_VALUE )
WSACloseEvent ( as->overlapped->hEvent ); WSACloseEvent( as->overlapped->hEvent );
#endif #endif
HeapFree ( GetProcessHeap(), 0, as->async.iosb ); HeapFree( GetProcessHeap(), 0, iosb );
} }
HeapFree ( GetProcessHeap(), 0, as->iovec ); HeapFree( GetProcessHeap(), 0, as->iovec );
HeapFree ( GetProcessHeap(), 0, as ); HeapFree( GetProcessHeap(), 0, as );
}
static void CALLBACK ws2_async_call_completion (ULONG_PTR data)
{
ws2_async* as = (ws2_async*) data;
TRACE ("data: %p\n", as);
as->completion_func ( NtStatusToWSAError (as->async.iosb->u.Status),
as->async.iosb->Information,
as->user_overlapped,
as->flags );
ws2_async_cleanup ( &as->async );
} }
/*********************************************************************** /***********************************************************************
* WS2_make_async (INTERNAL) * WS2_make_async (INTERNAL)
*/ */
static void WS2_async_recv (async_private *as); static void WINAPI WS2_async_recv(void*, IO_STATUS_BLOCK*, ULONG);
static void WS2_async_send (async_private *as); static void WINAPI WS2_async_send(void*, IO_STATUS_BLOCK*, ULONG);
static void WINAPI WS2_async_shutdown( void*, IO_STATUS_BLOCK*, ULONG);
inline static struct ws2_async* inline static struct ws2_async*
WS2_make_async (SOCKET s, int fd, int type, struct iovec *iovec, DWORD dwBufferCount, WS2_make_async(SOCKET s, int fd, enum ws2_mode mode, struct iovec *iovec, DWORD dwBufferCount,
LPDWORD lpFlags, struct WS_sockaddr *addr, LPDWORD lpFlags, struct WS_sockaddr *addr,
LPINT addrlen, LPWSAOVERLAPPED lpOverlapped, LPINT addrlen, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
IO_STATUS_BLOCK **piosb)
{ {
struct ws2_async *wsa = HeapAlloc ( GetProcessHeap(), 0, sizeof ( ws2_async ) ); struct ws2_async *wsa = HeapAlloc( GetProcessHeap(), 0, sizeof( ws2_async ) );
TRACE ( "wsa %p\n", wsa ); TRACE( "wsa %p\n", wsa );
if (!wsa) if (!wsa)
return NULL; return NULL;
wsa->async.ops = ( lpCompletionRoutine ? &ws2_async_ops : &ws2_nocomp_async_ops ); wsa->hSocket = (HANDLE) s;
wsa->async.handle = (HANDLE) s; wsa->mode = mode;
wsa->async.fd = fd; switch (mode)
wsa->async.type = type;
switch (type)
{ {
case ASYNC_TYPE_READ: case ws2m_read:
case ws2m_sd_read:
wsa->flags = *lpFlags; wsa->flags = *lpFlags;
wsa->async.func = WS2_async_recv;
wsa->addrlen.ptr = addrlen; wsa->addrlen.ptr = addrlen;
break; break;
case ASYNC_TYPE_WRITE: case ws2m_write:
case ws2m_sd_write:
wsa->flags = 0; wsa->flags = 0;
wsa->async.func = WS2_async_send;
wsa->addrlen.val = *addrlen; wsa->addrlen.val = *addrlen;
break; break;
default: default:
ERR ("Invalid async type: %d\n", type); ERR("Invalid async mode: %d\n", mode);
} }
wsa->user_overlapped = lpOverlapped; wsa->user_overlapped = lpOverlapped;
wsa->completion_func = lpCompletionRoutine; wsa->completion_func = lpCompletionRoutine;
wsa->iovec = iovec; wsa->iovec = iovec;
wsa->n_iovecs = dwBufferCount; wsa->n_iovecs = dwBufferCount;
wsa->addr = addr; wsa->addr = addr;
wsa->fd = fd;
wsa->event = INVALID_HANDLE_VALUE;
if ( lpOverlapped ) if ( lpOverlapped )
{ {
wsa->async.iosb = (IO_STATUS_BLOCK*)lpOverlapped; *piosb = (IO_STATUS_BLOCK*)lpOverlapped;
wsa->async.event = ( lpCompletionRoutine ? INVALID_HANDLE_VALUE : lpOverlapped->hEvent ); if (!lpCompletionRoutine)
} {
else wsa->event = lpOverlapped->hEvent;
{ NtResetEvent(wsa->event, NULL);
wsa->async.iosb = HeapAlloc ( GetProcessHeap(), 0, }
sizeof (IO_STATUS_BLOCK) );
if ( !wsa->async.iosb )
goto error;
wsa->async.event = INVALID_HANDLE_VALUE;
} }
else if (!(*piosb = HeapAlloc( GetProcessHeap(), 0, sizeof(IO_STATUS_BLOCK))))
goto error;
wsa->async.iosb->Information = 0; (*piosb)->Information = 0;
TRACE ( "wsa %p, ops %p, h %p, ev %p, fd %d, func %p, iosb %p, uov %p, cfunc %p\n", (*piosb)->u.Status = STATUS_PENDING;
wsa, wsa->async.ops, wsa->async.handle, wsa->async.event, wsa->async.fd, wsa->async.func, TRACE( "wsa %p, h %p, ev %p, fd %d, iosb %p, uov %p, cfunc %p\n",
wsa->async.iosb, wsa->user_overlapped, wsa->completion_func ); wsa, wsa->hSocket, wsa->event, wsa->fd,
*piosb, wsa->user_overlapped, wsa->completion_func );
return wsa; return wsa;
error: error:
TRACE ("Error\n"); TRACE("Error\n");
HeapFree ( GetProcessHeap(), 0, wsa ); HeapFree( GetProcessHeap(), 0, wsa );
return NULL; return NULL;
} }
static ULONG ws2_queue_async(struct ws2_async* wsa, IO_STATUS_BLOCK* iosb)
{
PIO_APC_ROUTINE apc;
int type;
NTSTATUS status;
switch (wsa->mode)
{
case ws2m_read: apc = WS2_async_recv; type = ASYNC_TYPE_READ; break;
case ws2m_write: apc = WS2_async_send; type = ASYNC_TYPE_WRITE; break;
case ws2m_sd_read: apc = WS2_async_shutdown; type = ASYNC_TYPE_READ; break;
case ws2m_sd_write: apc = WS2_async_shutdown; type = ASYNC_TYPE_WRITE; break;
default: FIXME("Unknown internal mode (%d)\n", wsa->mode); return STATUS_INVALID_PARAMETER;
}
SERVER_START_REQ( register_async )
{
req->handle = wsa->hSocket;
req->io_apc = apc;
req->io_sb = iosb;
req->io_user = wsa;
req->type = type;
req->count = iosb->Information;
status = wine_server_call( req );
}
SERVER_END_REQ;
if ( status ) iosb->u.Status = status;
if ( iosb->u.Status != STATUS_PENDING )
{
(apc)( wsa, iosb, iosb->u.Status );
return iosb->u.Status;
}
NtCurrentTeb()->num_async_io++;
return STATUS_SUCCESS;
}
/*********************************************************************** /***********************************************************************
* WS2_recv (INTERNAL) * WS2_recv (INTERNAL)
* *
* Workhorse for both synchronous and asynchronous recv() operations. * Workhorse for both synchronous and asynchronous recv() operations.
*/ */
static int WS2_recv ( int fd, struct iovec* iov, int count, static int WS2_recv( int fd, struct iovec* iov, int count,
struct WS_sockaddr *lpFrom, LPINT lpFromlen, struct WS_sockaddr *lpFrom, LPINT lpFromlen,
LPDWORD lpFlags ) LPDWORD lpFlags )
{ {
struct msghdr hdr; struct msghdr hdr;
int n; int n;
TRACE ( "fd %d, iovec %p, count %d addr %s, len %p, flags %lx\n", TRACE( "fd %d, iovec %p, count %d addr %s, len %p, flags %lx\n",
fd, iov, count, debugstr_sockaddr(lpFrom), lpFromlen, *lpFlags); fd, iov, count, debugstr_sockaddr(lpFrom), lpFromlen, *lpFlags);
hdr.msg_name = NULL; hdr.msg_name = NULL;
if ( lpFrom ) if ( lpFrom )
{ {
hdr.msg_namelen = *lpFromlen; hdr.msg_namelen = *lpFromlen;
hdr.msg_name = ws_sockaddr_alloc ( lpFrom, lpFromlen, &hdr.msg_namelen ); hdr.msg_name = ws_sockaddr_alloc( lpFrom, lpFromlen, &hdr.msg_namelen );
if ( !hdr.msg_name ) if ( !hdr.msg_name )
{ {
WSASetLastError ( WSAEFAULT ); WSASetLastError( WSAEFAULT );
n = -1; n = -1;
goto out; goto out;
} }
...@@ -1066,27 +1077,27 @@ static int WS2_recv ( int fd, struct iovec* iov, int count, ...@@ -1066,27 +1077,27 @@ static int WS2_recv ( int fd, struct iovec* iov, int count,
hdr.msg_flags = 0; hdr.msg_flags = 0;
#endif #endif
if ( (n = recvmsg (fd, &hdr, *lpFlags)) == -1 ) if ( (n = recvmsg(fd, &hdr, *lpFlags)) == -1 )
{ {
TRACE ( "recvmsg error %d\n", errno); TRACE( "recvmsg error %d\n", errno);
goto out; goto out;
} }
if ( lpFrom && if ( lpFrom &&
ws_sockaddr_u2ws ( hdr.msg_name, hdr.msg_namelen, ws_sockaddr_u2ws( hdr.msg_name, hdr.msg_namelen,
lpFrom, lpFromlen ) != 0 ) lpFrom, lpFromlen ) != 0 )
{ {
/* The from buffer was too small, but we read the data /* The from buffer was too small, but we read the data
* anyway. Is that really bad? * anyway. Is that really bad?
*/ */
WSASetLastError ( WSAEFAULT ); WSASetLastError( WSAEFAULT );
WARN ( "Address buffer too small\n" ); WARN( "Address buffer too small\n" );
} }
out: out:
ws_sockaddr_free ( hdr.msg_name, lpFrom ); ws_sockaddr_free( hdr.msg_name, lpFrom );
TRACE ("-> %d\n", n); TRACE("-> %d\n", n);
return n; return n;
} }
...@@ -1095,43 +1106,51 @@ out: ...@@ -1095,43 +1106,51 @@ out:
* *
* Handler for overlapped recv() operations. * Handler for overlapped recv() operations.
*/ */
static void WS2_async_recv ( async_private *as ) static void WINAPI WS2_async_recv( void* ovp, IO_STATUS_BLOCK* iosb, ULONG status)
{ {
ws2_async* wsa = (ws2_async*) as; ws2_async* wsa = (ws2_async*) ovp;
int result, err; int result, err;
TRACE ( "async %p\n", wsa ); TRACE( "(%p %p %lx)\n", wsa, iosb, status );
if ( wsa->async.iosb->u.Status != STATUS_PENDING ) switch (status)
{ {
TRACE ( "status: %ld\n", wsa->async.iosb->u.Status ); case STATUS_ALERTED:
return; result = WS2_recv( wsa->fd, wsa->iovec, wsa->n_iovecs,
} wsa->addr, wsa->addrlen.ptr, &wsa->flags );
if (result >= 0)
result = WS2_recv ( wsa->async.fd, wsa->iovec, wsa->n_iovecs, {
wsa->addr, wsa->addrlen.ptr, &wsa->flags ); iosb->u.Status = STATUS_SUCCESS;
iosb->Information = result;
if (result >= 0) TRACE( "received %d bytes\n", result );
{ _enable_event( wsa->hSocket, FD_READ, 0, 0 );
wsa->async.iosb->u.Status = STATUS_SUCCESS; }
wsa->async.iosb->Information = result; else
TRACE ( "received %d bytes\n", result ); {
_enable_event ( wsa->async.handle, FD_READ, 0, 0 ); err = wsaErrno();
if ( err == WSAEINTR || err == WSAEWOULDBLOCK ) /* errno: EINTR / EAGAIN */
{
iosb->u.Status = STATUS_PENDING;
_enable_event( wsa->hSocket, FD_READ, 0, 0 );
TRACE( "still pending\n" );
}
else
{
iosb->u.Status = err; /* FIXME: is this correct ???? */
TRACE( "Error: %x\n", err );
}
}
if (iosb->u.Status == STATUS_PENDING)
ws2_queue_async(wsa, iosb);
else
ws2_async_terminate(wsa, iosb);
break;
default:
FIXME( "status: %ld\n", status );
iosb->u.Status = status;
ws2_async_terminate(wsa, iosb);
return; return;
} }
err = wsaErrno ();
if ( err == WSAEINTR || err == WSAEWOULDBLOCK ) /* errno: EINTR / EAGAIN */
{
wsa->async.iosb->u.Status = STATUS_PENDING;
_enable_event ( wsa->async.handle, FD_READ, 0, 0 );
TRACE ( "still pending\n" );
}
else
{
wsa->async.iosb->u.Status = err;
TRACE ( "Error: %x\n", err );
}
} }
/*********************************************************************** /***********************************************************************
...@@ -1139,22 +1158,22 @@ static void WS2_async_recv ( async_private *as ) ...@@ -1139,22 +1158,22 @@ static void WS2_async_recv ( async_private *as )
* *
* Workhorse for both synchronous and asynchronous send() operations. * Workhorse for both synchronous and asynchronous send() operations.
*/ */
static int WS2_send ( int fd, struct iovec* iov, int count, static int WS2_send( int fd, struct iovec* iov, int count,
const struct WS_sockaddr *to, INT tolen, DWORD dwFlags ) const struct WS_sockaddr *to, INT tolen, DWORD dwFlags )
{ {
struct msghdr hdr; struct msghdr hdr;
int n = -1; int n = -1;
TRACE ( "fd %d, iovec %p, count %d addr %s, len %d, flags %lx\n", TRACE( "fd %d, iovec %p, count %d addr %s, len %d, flags %lx\n",
fd, iov, count, debugstr_sockaddr(to), tolen, dwFlags); fd, iov, count, debugstr_sockaddr(to), tolen, dwFlags);
hdr.msg_name = NULL; hdr.msg_name = NULL;
if ( to ) if ( to )
{ {
hdr.msg_name = (struct sockaddr*) ws_sockaddr_ws2u ( to, tolen, &hdr.msg_namelen ); hdr.msg_name = (struct sockaddr*) ws_sockaddr_ws2u( to, tolen, &hdr.msg_namelen );
if ( !hdr.msg_name ) if ( !hdr.msg_name )
{ {
WSASetLastError ( WSAEFAULT ); WSASetLastError( WSAEFAULT );
goto out; goto out;
} }
...@@ -1195,10 +1214,10 @@ static int WS2_send ( int fd, struct iovec* iov, int count, ...@@ -1195,10 +1214,10 @@ static int WS2_send ( int fd, struct iovec* iov, int count,
hdr.msg_flags = 0; hdr.msg_flags = 0;
#endif #endif
n = sendmsg (fd, &hdr, dwFlags); n = sendmsg(fd, &hdr, dwFlags);
out: out:
ws_sockaddr_free ( hdr.msg_name, to ); ws_sockaddr_free( hdr.msg_name, to );
return n; return n;
} }
...@@ -1207,45 +1226,57 @@ out: ...@@ -1207,45 +1226,57 @@ out:
* *
* Handler for overlapped send() operations. * Handler for overlapped send() operations.
*/ */
static void WS2_async_send ( async_private *as ) static void WINAPI WS2_async_send(void* as, IO_STATUS_BLOCK* iosb, ULONG status)
{ {
ws2_async* wsa = (ws2_async*) as; ws2_async* wsa = (ws2_async*) as;
int result, err; int result;
TRACE ( "async %p\n", wsa ); TRACE( "(%p %p %lx)\n", wsa, iosb, status );
if ( wsa->async.iosb->u.Status != STATUS_PENDING ) switch (status)
{ {
TRACE ( "status: %ld\n", wsa->async.iosb->u.Status ); case STATUS_ALERTED:
return; if (iosb->u.Status != STATUS_PENDING) FIXME("wrong %08lx\n", iosb->u.Status);
} /* check to see if the data is ready (non-blocking) */
result = WS2_send( wsa->fd, wsa->iovec, wsa->n_iovecs,
wsa->addr, wsa->addrlen.val, wsa->flags );
result = WS2_send ( wsa->async.fd, wsa->iovec, wsa->n_iovecs, if (result >= 0)
wsa->addr, wsa->addrlen.val, wsa->flags ); {
iosb->u.Status = STATUS_SUCCESS;
if (result >= 0) iosb->Information = result;
{ TRACE( "sent %d bytes\n", result );
wsa->async.iosb->u.Status = STATUS_SUCCESS; _enable_event( wsa->hSocket, FD_WRITE, 0, 0 );
wsa->async.iosb->Information = result; }
TRACE ( "sent %d bytes\n", result ); else
_enable_event ( wsa->async.handle, FD_WRITE, 0, 0 ); {
int err = wsaErrno();
if ( err == WSAEINTR )
{
iosb->u.Status = STATUS_PENDING;
_enable_event( wsa->hSocket, FD_WRITE, 0, 0 );
TRACE( "still pending\n" );
}
else
{
/* We set the status to a winsock error code and check for that
later in NtStatusToWSAError () */
iosb->u.Status = err;
TRACE( "Error: %x\n", err );
}
}
if (iosb->u.Status == STATUS_PENDING)
ws2_queue_async(wsa, iosb);
else
ws2_async_terminate(wsa, iosb);
break;
default:
FIXME( "status: %ld\n", status );
iosb->u.Status = status;
ws2_async_terminate(wsa, iosb);
return; return;
} }
err = wsaErrno ();
if ( err == WSAEINTR )
{
wsa->async.iosb->u.Status = STATUS_PENDING;
_enable_event ( wsa->async.handle, FD_WRITE, 0, 0 );
TRACE ( "still pending\n" );
}
else
{
/* We set the status to a winsock error code and check for that
later in NtStatusToWSAError () */
wsa->async.iosb->u.Status = err;
TRACE ( "Error: %x\n", err );
}
} }
/*********************************************************************** /***********************************************************************
...@@ -1253,28 +1284,33 @@ static void WS2_async_send ( async_private *as ) ...@@ -1253,28 +1284,33 @@ static void WS2_async_send ( async_private *as )
* *
* Handler for shutdown() operations on overlapped sockets. * Handler for shutdown() operations on overlapped sockets.
*/ */
static void WS2_async_shutdown ( async_private *as ) static void WINAPI WS2_async_shutdown( void* as, PIO_STATUS_BLOCK iosb, ULONG status )
{ {
ws2_async* wsa = (ws2_async*) as; ws2_async* wsa = (ws2_async*) as;
int err = 1; int err = 1;
TRACE ( "async %p %d\n", wsa, wsa->async.type ); TRACE( "async %p %d\n", wsa, wsa->mode );
switch ( wsa->async.type ) switch (status)
{ {
case ASYNC_TYPE_READ: case STATUS_ALERTED:
err = shutdown ( wsa->async.fd, 0 ); switch ( wsa->mode )
break; {
case ASYNC_TYPE_WRITE: case ws2m_sd_read: err = shutdown( wsa->fd, 0 ); break;
err = shutdown ( wsa->async.fd, 1 ); case ws2m_sd_write: err = shutdown( wsa->fd, 1 ); break;
default: ERR("invalid mode: %d\n", wsa->mode );
}
iosb->u.Status = err ? wsaErrno() : STATUS_SUCCESS;
if (iosb->u.Status == STATUS_PENDING)
ws2_queue_async(wsa, iosb);
else
ws2_async_terminate(wsa, iosb);
break; break;
default: default:
ERR ("invalid type: %d\n", wsa->async.type ); iosb->u.Status = status;
ws2_async_terminate(wsa, iosb);
break;
} }
if ( err )
wsa->async.iosb->u.Status = wsaErrno ();
else
wsa->async.iosb->u.Status = STATUS_SUCCESS;
} }
/*********************************************************************** /***********************************************************************
...@@ -1282,43 +1318,44 @@ static void WS2_async_shutdown ( async_private *as ) ...@@ -1282,43 +1318,44 @@ static void WS2_async_shutdown ( async_private *as )
* *
* Helper function for WS_shutdown() on overlapped sockets. * Helper function for WS_shutdown() on overlapped sockets.
*/ */
static int WS2_register_async_shutdown ( SOCKET s, int fd, int type ) static int WS2_register_async_shutdown( SOCKET s, int fd, enum ws2_mode mode )
{ {
struct ws2_async *wsa; struct ws2_async *wsa;
int ret, err = WSAEFAULT; int ret, err = WSAEFAULT;
DWORD dwflags = 0; DWORD dwflags = 0;
int len = 0; int len = 0;
LPWSAOVERLAPPED ovl = HeapAlloc (GetProcessHeap(), 0, sizeof ( WSAOVERLAPPED )); LPWSAOVERLAPPED ovl = HeapAlloc(GetProcessHeap(), 0, sizeof( WSAOVERLAPPED ));
IO_STATUS_BLOCK *iosb;
TRACE ("s %d fd %d type %d\n", s, fd, type); TRACE("s %d fd %d mode %d\n", s, fd, mode);
if (!ovl) if (!ovl)
goto out; goto out;
ovl->hEvent = WSACreateEvent (); ovl->hEvent = WSACreateEvent();
if ( ovl->hEvent == WSA_INVALID_EVENT ) if ( ovl->hEvent == WSA_INVALID_EVENT )
goto out_free; goto out_free;
wsa = WS2_make_async ( s, fd, type, NULL, 0, wsa = WS2_make_async( s, fd, mode, NULL, 0,
&dwflags, NULL, &len, ovl, NULL ); &dwflags, NULL, &len, ovl, NULL, &iosb );
if ( !wsa ) if ( !wsa )
goto out_close; goto out_close;
/* Hack: this will cause ws2_async_cleanup() to free the overlapped structure */ /* Hack: this will cause ws2_async_cleanup() to free the overlapped structure */
wsa->user_overlapped = NULL; wsa->user_overlapped = NULL;
wsa->async.func = WS2_async_shutdown; if ( (ret = ws2_queue_async( wsa, iosb )) )
if ( (ret = register_new_async ( &wsa->async )) )
{ {
err = NtStatusToWSAError ( ret ); err = NtStatusToWSAError( ret );
goto out; goto out;
} }
/* Try immediate completion */ /* Try immediate completion */
while ( WaitForSingleObjectEx ( ovl->hEvent, 0, TRUE ) == STATUS_USER_APC ); while ( WaitForSingleObjectEx( ovl->hEvent, 0, TRUE ) == STATUS_USER_APC );
return 0; return 0;
out_close: out_close:
WSACloseEvent ( ovl->hEvent ); WSACloseEvent( ovl->hEvent );
out_free: out_free:
HeapFree ( GetProcessHeap(), 0, ovl ); HeapFree( GetProcessHeap(), 0, iosb );
HeapFree( GetProcessHeap(), 0, ovl );
out: out:
return err; return err;
} }
...@@ -1503,13 +1540,13 @@ connect_success: ...@@ -1503,13 +1540,13 @@ connect_success:
/*********************************************************************** /***********************************************************************
* WSAConnect (WS2_32.30) * WSAConnect (WS2_32.30)
*/ */
int WINAPI WSAConnect ( SOCKET s, const struct WS_sockaddr* name, int namelen, int WINAPI WSAConnect( SOCKET s, const struct WS_sockaddr* name, int namelen,
LPWSABUF lpCallerData, LPWSABUF lpCalleeData, LPWSABUF lpCallerData, LPWSABUF lpCalleeData,
LPQOS lpSQOS, LPQOS lpGQOS ) LPQOS lpSQOS, LPQOS lpGQOS )
{ {
if ( lpCallerData || lpCalleeData || lpSQOS || lpGQOS ) if ( lpCallerData || lpCalleeData || lpSQOS || lpGQOS )
FIXME ("unsupported parameters!\n"); FIXME("unsupported parameters!\n");
return WS_connect ( s, name, namelen ); return WS_connect( s, name, namelen );
} }
...@@ -1849,15 +1886,15 @@ char* WINAPI WS_inet_ntoa(struct WS_in_addr in) ...@@ -1849,15 +1886,15 @@ char* WINAPI WS_inet_ntoa(struct WS_in_addr in)
* *
* FIXME: Only SIO_GET_INTERFACE_LIST option implemented. * FIXME: Only SIO_GET_INTERFACE_LIST option implemented.
*/ */
INT WINAPI WSAIoctl (SOCKET s, INT WINAPI WSAIoctl(SOCKET s,
DWORD dwIoControlCode, DWORD dwIoControlCode,
LPVOID lpvInBuffer, LPVOID lpvInBuffer,
DWORD cbInBuffer, DWORD cbInBuffer,
LPVOID lpbOutBuffer, LPVOID lpbOutBuffer,
DWORD cbOutBuffer, DWORD cbOutBuffer,
LPDWORD lpcbBytesReturned, LPDWORD lpcbBytesReturned,
LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{ {
int fd = get_sock_fd( s, 0, NULL ); int fd = get_sock_fd( s, 0, NULL );
...@@ -1874,7 +1911,7 @@ INT WINAPI WSAIoctl (SOCKET s, ...@@ -1874,7 +1911,7 @@ INT WINAPI WSAIoctl (SOCKET s,
INTERFACE_INFO* intArray = (INTERFACE_INFO*)lpbOutBuffer; INTERFACE_INFO* intArray = (INTERFACE_INFO*)lpbOutBuffer;
DWORD size, numInt, apiReturn; DWORD size, numInt, apiReturn;
TRACE ("-> SIO_GET_INTERFACE_LIST request\n"); TRACE("-> SIO_GET_INTERFACE_LIST request\n");
if (!lpbOutBuffer) if (!lpbOutBuffer)
{ {
...@@ -1910,7 +1947,7 @@ INT WINAPI WSAIoctl (SOCKET s, ...@@ -1910,7 +1947,7 @@ INT WINAPI WSAIoctl (SOCKET s,
HeapFree(GetProcessHeap(),0,table); HeapFree(GetProcessHeap(),0,table);
release_sock_fd( s, fd ); release_sock_fd( s, fd );
WSASetLastError(WSAEFAULT); WSASetLastError(WSAEFAULT);
return (SOCKET_ERROR); return SOCKET_ERROR;
} }
for (ptr = table, numInt = 0; ptr; for (ptr = table, numInt = 0; ptr;
ptr = ptr->Next, intArray++, numInt++) ptr = ptr->Next, intArray++, numInt++)
...@@ -1923,11 +1960,11 @@ INT WINAPI WSAIoctl (SOCKET s, ...@@ -1923,11 +1960,11 @@ INT WINAPI WSAIoctl (SOCKET s,
ifInfo.ifr_name[IFNAMSIZ-1] = '\0'; ifInfo.ifr_name[IFNAMSIZ-1] = '\0';
if (ioctl(fd, SIOCGIFFLAGS, &ifInfo) < 0) if (ioctl(fd, SIOCGIFFLAGS, &ifInfo) < 0)
{ {
ERR ("Error obtaining status flags for socket!\n"); ERR("Error obtaining status flags for socket!\n");
HeapFree(GetProcessHeap(),0,table); HeapFree(GetProcessHeap(),0,table);
release_sock_fd( s, fd ); release_sock_fd( s, fd );
WSASetLastError(WSAEINVAL); WSASetLastError(WSAEINVAL);
return (SOCKET_ERROR); return SOCKET_ERROR;
} }
else else
{ {
...@@ -1969,11 +2006,11 @@ INT WINAPI WSAIoctl (SOCKET s, ...@@ -1969,11 +2006,11 @@ INT WINAPI WSAIoctl (SOCKET s,
} }
else else
{ {
ERR ("Unable to get interface table!\n"); ERR("Unable to get interface table!\n");
release_sock_fd( s, fd ); release_sock_fd( s, fd );
HeapFree(GetProcessHeap(),0,table); HeapFree(GetProcessHeap(),0,table);
WSASetLastError(WSAEINVAL); WSASetLastError(WSAEINVAL);
return (SOCKET_ERROR); return SOCKET_ERROR;
} }
HeapFree(GetProcessHeap(),0,table); HeapFree(GetProcessHeap(),0,table);
} }
...@@ -1981,15 +2018,15 @@ INT WINAPI WSAIoctl (SOCKET s, ...@@ -1981,15 +2018,15 @@ INT WINAPI WSAIoctl (SOCKET s,
{ {
release_sock_fd( s, fd ); release_sock_fd( s, fd );
WSASetLastError(WSAEINVAL); WSASetLastError(WSAEINVAL);
return (SOCKET_ERROR); return SOCKET_ERROR;
} }
} }
else else
{ {
ERR ("Unable to get interface table!\n"); ERR("Unable to get interface table!\n");
release_sock_fd( s, fd ); release_sock_fd( s, fd );
WSASetLastError(WSAEINVAL); WSASetLastError(WSAEINVAL);
return (SOCKET_ERROR); return SOCKET_ERROR;
} }
/* Calculate the size of the array being returned */ /* Calculate the size of the array being returned */
*lpcbBytesReturned = sizeof(INTERFACE_INFO) * numInt; *lpcbBytesReturned = sizeof(INTERFACE_INFO) * numInt;
...@@ -2006,12 +2043,12 @@ INT WINAPI WSAIoctl (SOCKET s, ...@@ -2006,12 +2043,12 @@ INT WINAPI WSAIoctl (SOCKET s,
WARN("\tunsupported WS_IOCTL cmd (%08lx)\n", dwIoControlCode); WARN("\tunsupported WS_IOCTL cmd (%08lx)\n", dwIoControlCode);
release_sock_fd( s, fd ); release_sock_fd( s, fd );
WSASetLastError(WSAEOPNOTSUPP); WSASetLastError(WSAEOPNOTSUPP);
return (SOCKET_ERROR); return SOCKET_ERROR;
} }
/* Function executed with no errors */ /* Function executed with no errors */
release_sock_fd( s, fd ); release_sock_fd( s, fd );
return (0); return 0;
} }
...@@ -2130,7 +2167,7 @@ int WINAPI WS_recv(SOCKET s, char *buf, int len, int flags) ...@@ -2130,7 +2167,7 @@ int WINAPI WS_recv(SOCKET s, char *buf, int len, int flags)
wsabuf.len = len; wsabuf.len = len;
wsabuf.buf = buf; wsabuf.buf = buf;
if ( WSARecvFrom (s, &wsabuf, 1, &n, &dwFlags, NULL, NULL, NULL, NULL) == SOCKET_ERROR ) if ( WSARecvFrom(s, &wsabuf, 1, &n, &dwFlags, NULL, NULL, NULL, NULL) == SOCKET_ERROR )
return SOCKET_ERROR; return SOCKET_ERROR;
else else
return n; return n;
...@@ -2140,7 +2177,7 @@ int WINAPI WS_recv(SOCKET s, char *buf, int len, int flags) ...@@ -2140,7 +2177,7 @@ int WINAPI WS_recv(SOCKET s, char *buf, int len, int flags)
* recvfrom (WS2_32.17) * recvfrom (WS2_32.17)
*/ */
int WINAPI WS_recvfrom(SOCKET s, char *buf, INT len, int flags, int WINAPI WS_recvfrom(SOCKET s, char *buf, INT len, int flags,
struct WS_sockaddr *from, int *fromlen) struct WS_sockaddr *from, int *fromlen)
{ {
DWORD n, dwFlags = flags; DWORD n, dwFlags = flags;
WSABUF wsabuf; WSABUF wsabuf;
...@@ -2148,7 +2185,7 @@ int WINAPI WS_recvfrom(SOCKET s, char *buf, INT len, int flags, ...@@ -2148,7 +2185,7 @@ int WINAPI WS_recvfrom(SOCKET s, char *buf, INT len, int flags,
wsabuf.len = len; wsabuf.len = len;
wsabuf.buf = buf; wsabuf.buf = buf;
if ( WSARecvFrom (s, &wsabuf, 1, &n, &dwFlags, from, fromlen, NULL, NULL) == SOCKET_ERROR ) if ( WSARecvFrom(s, &wsabuf, 1, &n, &dwFlags, from, fromlen, NULL, NULL) == SOCKET_ERROR )
return SOCKET_ERROR; return SOCKET_ERROR;
else else
return n; return n;
...@@ -2222,7 +2259,7 @@ int WINAPI WS_send(SOCKET s, const char *buf, int len, int flags) ...@@ -2222,7 +2259,7 @@ int WINAPI WS_send(SOCKET s, const char *buf, int len, int flags)
wsabuf.len = len; wsabuf.len = len;
wsabuf.buf = (char*) buf; wsabuf.buf = (char*) buf;
if ( WSASendTo ( s, &wsabuf, 1, &n, flags, NULL, 0, NULL, NULL) == SOCKET_ERROR ) if ( WSASendTo( s, &wsabuf, 1, &n, flags, NULL, 0, NULL, NULL) == SOCKET_ERROR )
return SOCKET_ERROR; return SOCKET_ERROR;
else else
return n; return n;
...@@ -2236,8 +2273,8 @@ INT WINAPI WSASend( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -2236,8 +2273,8 @@ INT WINAPI WSASend( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ) LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{ {
return WSASendTo ( s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, return WSASendTo( s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags,
NULL, 0, lpOverlapped, lpCompletionRoutine ); NULL, 0, lpOverlapped, lpCompletionRoutine );
} }
/*********************************************************************** /***********************************************************************
...@@ -2245,7 +2282,7 @@ INT WINAPI WSASend( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -2245,7 +2282,7 @@ INT WINAPI WSASend( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
*/ */
INT WINAPI WSASendDisconnect( SOCKET s, LPWSABUF lpBuffers ) INT WINAPI WSASendDisconnect( SOCKET s, LPWSABUF lpBuffers )
{ {
return WS_shutdown ( s, SD_SEND ); return WS_shutdown( s, SD_SEND );
} }
...@@ -2262,19 +2299,20 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -2262,19 +2299,20 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
int n, fd, err = WSAENOTSOCK, flags, ret; int n, fd, err = WSAENOTSOCK, flags, ret;
struct iovec* iovec; struct iovec* iovec;
struct ws2_async *wsa; struct ws2_async *wsa;
IO_STATUS_BLOCK* iosb;
TRACE ("socket %04x, wsabuf %p, nbufs %ld, flags %ld, to %p, tolen %d, ovl %p, func %p\n", TRACE("socket %04x, wsabuf %p, nbufs %ld, flags %ld, to %p, tolen %d, ovl %p, func %p\n",
s, lpBuffers, dwBufferCount, dwFlags, s, lpBuffers, dwBufferCount, dwFlags,
to, tolen, lpOverlapped, lpCompletionRoutine); to, tolen, lpOverlapped, lpCompletionRoutine);
fd = get_sock_fd( s, GENERIC_WRITE, &flags ); fd = get_sock_fd( s, GENERIC_WRITE, &flags );
TRACE ( "fd=%d, flags=%x\n", fd, flags ); TRACE( "fd=%d, flags=%x\n", fd, flags );
if ( fd == -1 ) return SOCKET_ERROR; if ( fd == -1 ) return SOCKET_ERROR;
if (flags & FD_FLAG_SEND_SHUTDOWN) if (flags & FD_FLAG_SEND_SHUTDOWN)
{ {
WSASetLastError ( WSAESHUTDOWN ); WSASetLastError( WSAESHUTDOWN );
goto err_close; goto err_close;
} }
...@@ -2284,7 +2322,7 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -2284,7 +2322,7 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
goto err_close; goto err_close;
} }
iovec = HeapAlloc (GetProcessHeap(), 0, dwBufferCount * sizeof (struct iovec) ); iovec = HeapAlloc(GetProcessHeap(), 0, dwBufferCount * sizeof(struct iovec) );
if ( !iovec ) if ( !iovec )
{ {
...@@ -2300,37 +2338,37 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -2300,37 +2338,37 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
if ( (lpOverlapped || lpCompletionRoutine) && flags & FD_FLAG_OVERLAPPED ) if ( (lpOverlapped || lpCompletionRoutine) && flags & FD_FLAG_OVERLAPPED )
{ {
wsa = WS2_make_async ( s, fd, ASYNC_TYPE_WRITE, iovec, dwBufferCount, wsa = WS2_make_async( s, fd, ws2m_write, iovec, dwBufferCount,
&dwFlags, (struct WS_sockaddr*) to, &tolen, &dwFlags, (struct WS_sockaddr*) to, &tolen,
lpOverlapped, lpCompletionRoutine ); lpOverlapped, lpCompletionRoutine, &iosb );
if ( !wsa ) if ( !wsa )
{ {
err = WSAEFAULT; err = WSAEFAULT;
goto err_free; goto err_free;
} }
if ( ( ret = register_new_async ( &wsa->async )) ) if ( ( ret = ws2_queue_async( wsa, iosb ) ) )
{ {
err = NtStatusToWSAError ( ret ); err = NtStatusToWSAError( ret );
if ( !lpOverlapped ) if ( !lpOverlapped )
HeapFree ( GetProcessHeap(), 0, wsa->async.iosb ); HeapFree( GetProcessHeap(), 0, iosb );
HeapFree ( GetProcessHeap(), 0, wsa ); HeapFree( GetProcessHeap(), 0, wsa );
goto err_free; goto err_free;
} }
/* Try immediate completion */ /* Try immediate completion */
if ( lpOverlapped && !NtResetEvent( lpOverlapped->hEvent, NULL ) ) if ( lpOverlapped )
{ {
if ( WSAGetOverlappedResult ( s, lpOverlapped, if ( WSAGetOverlappedResult( s, lpOverlapped,
lpNumberOfBytesSent, FALSE, &dwFlags) ) lpNumberOfBytesSent, FALSE, &dwFlags) )
return 0; return 0;
if ( (err = WSAGetLastError ()) != WSA_IO_INCOMPLETE ) if ( (err = WSAGetLastError()) != WSA_IO_INCOMPLETE )
goto error; goto error;
} }
WSASetLastError ( WSA_IO_PENDING ); WSASetLastError( WSA_IO_PENDING );
return SOCKET_ERROR; return SOCKET_ERROR;
} }
...@@ -2344,31 +2382,31 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -2344,31 +2382,31 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
} }
} }
n = WS2_send ( fd, iovec, dwBufferCount, to, tolen, dwFlags ); n = WS2_send( fd, iovec, dwBufferCount, to, tolen, dwFlags );
if ( n == -1 ) if ( n == -1 )
{ {
err = wsaErrno(); err = wsaErrno();
if ( err == WSAEWOULDBLOCK ) if ( err == WSAEWOULDBLOCK )
_enable_event (SOCKET2HANDLE(s), FD_WRITE, 0, 0); _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
goto err_free; goto err_free;
} }
TRACE(" -> %i bytes\n", n); TRACE(" -> %i bytes\n", n);
*lpNumberOfBytesSent = n; *lpNumberOfBytesSent = n;
HeapFree ( GetProcessHeap(), 0, iovec ); HeapFree( GetProcessHeap(), 0, iovec );
release_sock_fd( s, fd ); release_sock_fd( s, fd );
return 0; return 0;
err_free: err_free:
HeapFree ( GetProcessHeap(), 0, iovec ); HeapFree( GetProcessHeap(), 0, iovec );
err_close: err_close:
release_sock_fd( s, fd ); release_sock_fd( s, fd );
error: error:
WARN (" -> ERROR %d\n", err); WARN(" -> ERROR %d\n", err);
WSASetLastError (err); WSASetLastError(err);
return SOCKET_ERROR; return SOCKET_ERROR;
} }
...@@ -2384,7 +2422,7 @@ int WINAPI WS_sendto(SOCKET s, const char *buf, int len, int flags, ...@@ -2384,7 +2422,7 @@ int WINAPI WS_sendto(SOCKET s, const char *buf, int len, int flags,
wsabuf.len = len; wsabuf.len = len;
wsabuf.buf = (char*) buf; wsabuf.buf = (char*) buf;
if ( WSASendTo (s, &wsabuf, 1, &n, flags, to, tolen, NULL, NULL) == SOCKET_ERROR ) if ( WSASendTo(s, &wsabuf, 1, &n, flags, to, tolen, NULL, NULL) == SOCKET_ERROR )
return SOCKET_ERROR; return SOCKET_ERROR;
else else
return n; return n;
...@@ -2460,7 +2498,6 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname, ...@@ -2460,7 +2498,6 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
/* Returning 0 is better for now than returning a SOCKET_ERROR */ /* Returning 0 is better for now than returning a SOCKET_ERROR */
return 0; return 0;
break;
default: default:
FIXME("opt_name:%x\n", optname); FIXME("opt_name:%x\n", optname);
return SOCKET_ERROR; return SOCKET_ERROR;
...@@ -2587,13 +2624,13 @@ int WINAPI WS_shutdown(SOCKET s, int how) ...@@ -2587,13 +2624,13 @@ int WINAPI WS_shutdown(SOCKET s, int how)
case SD_BOTH: case SD_BOTH:
default: default:
fd0 = fd; fd0 = fd;
fd1 = get_sock_fd ( s, 0, NULL ); fd1 = get_sock_fd( s, 0, NULL );
break; break;
} }
if ( fd0 != -1 ) if ( fd0 != -1 )
{ {
err = WS2_register_async_shutdown ( s, fd0, ASYNC_TYPE_READ ); err = WS2_register_async_shutdown( s, fd0, ws2m_sd_read );
if ( err ) if ( err )
{ {
release_sock_fd( s, fd0 ); release_sock_fd( s, fd0 );
...@@ -2602,7 +2639,7 @@ int WINAPI WS_shutdown(SOCKET s, int how) ...@@ -2602,7 +2639,7 @@ int WINAPI WS_shutdown(SOCKET s, int how)
} }
if ( fd1 != -1 ) if ( fd1 != -1 )
{ {
err = WS2_register_async_shutdown ( s, fd1, ASYNC_TYPE_WRITE ); err = WS2_register_async_shutdown( s, fd1, ws2m_sd_write );
if ( err ) if ( err )
{ {
release_sock_fd( s, fd1 ); release_sock_fd( s, fd1 );
...@@ -2614,7 +2651,7 @@ int WINAPI WS_shutdown(SOCKET s, int how) ...@@ -2614,7 +2651,7 @@ int WINAPI WS_shutdown(SOCKET s, int how)
{ {
if ( shutdown( fd, how ) ) if ( shutdown( fd, how ) )
{ {
err = wsaErrno (); err = wsaErrno();
release_sock_fd( s, fd ); release_sock_fd( s, fd );
goto error; goto error;
} }
...@@ -2627,7 +2664,7 @@ int WINAPI WS_shutdown(SOCKET s, int how) ...@@ -2627,7 +2664,7 @@ int WINAPI WS_shutdown(SOCKET s, int how)
error: error:
_enable_event( SOCKET2HANDLE(s), 0, 0, clear_flags ); _enable_event( SOCKET2HANDLE(s), 0, 0, clear_flags );
WSASetLastError ( err ); WSASetLastError( err );
return SOCKET_ERROR; return SOCKET_ERROR;
} }
...@@ -2638,8 +2675,8 @@ SOCKET WINAPI WS_socket(int af, int type, int protocol) ...@@ -2638,8 +2675,8 @@ SOCKET WINAPI WS_socket(int af, int type, int protocol)
{ {
TRACE("af=%d type=%d protocol=%d\n", af, type, protocol); TRACE("af=%d type=%d protocol=%d\n", af, type, protocol);
return WSASocketA ( af, type, protocol, NULL, 0, return WSASocketA( af, type, protocol, NULL, 0,
get_per_thread_data()->opentype ? 0 : WSA_FLAG_OVERLAPPED ); get_per_thread_data()->opentype ? 0 : WSA_FLAG_OVERLAPPED );
} }
...@@ -2913,34 +2950,40 @@ int WINAPI WSAEventSelect(SOCKET s, WSAEVENT hEvent, long lEvent) ...@@ -2913,34 +2950,40 @@ int WINAPI WSAEventSelect(SOCKET s, WSAEVENT hEvent, long lEvent)
/********************************************************************** /**********************************************************************
* WSAGetOverlappedResult (WS2_32.40) * WSAGetOverlappedResult (WS2_32.40)
*/ */
BOOL WINAPI WSAGetOverlappedResult ( SOCKET s, LPWSAOVERLAPPED lpOverlapped, BOOL WINAPI WSAGetOverlappedResult( SOCKET s, LPWSAOVERLAPPED lpOverlapped,
LPDWORD lpcbTransfer, BOOL fWait, LPDWORD lpcbTransfer, BOOL fWait,
LPDWORD lpdwFlags ) LPDWORD lpdwFlags )
{ {
DWORD r; DWORD r;
TRACE ( "socket %04x ovl %p trans %p, wait %d flags %p\n", TRACE( "socket %04x ovl %p trans %p, wait %d flags %p\n",
s, lpOverlapped, lpcbTransfer, fWait, lpdwFlags ); s, lpOverlapped, lpcbTransfer, fWait, lpdwFlags );
if ( !(lpOverlapped && lpOverlapped->hEvent) ) if ( lpOverlapped == NULL )
{ {
ERR ( "Invalid pointer\n" ); ERR( "Invalid pointer\n" );
WSASetLastError (WSA_INVALID_PARAMETER); WSASetLastError(WSA_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
if ( fWait ) if ( fWait )
{ {
while ( WaitForSingleObjectEx (lpOverlapped->hEvent, INFINITE, TRUE) == STATUS_USER_APC ); if (lpOverlapped->hEvent)
while ( WaitForSingleObjectEx(lpOverlapped->hEvent,
INFINITE, TRUE) == STATUS_USER_APC );
else /* busy loop */
while ( ((volatile OVERLAPPED*)lpOverlapped)->Internal == STATUS_PENDING )
Sleep( 10 );
} }
else if ( lpOverlapped->Internal == STATUS_PENDING ) else if ( lpOverlapped->Internal == STATUS_PENDING )
{ {
/* Wait in order to give APCs a chance to run. */ /* Wait in order to give APCs a chance to run. */
/* This is cheating, so we must set the event again in case of success - /* This is cheating, so we must set the event again in case of success -
it may be a non-manual reset event. */ it may be a non-manual reset event. */
while ( (r = WaitForSingleObjectEx (lpOverlapped->hEvent, 0, TRUE)) == STATUS_USER_APC ); while ( (r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE)) == STATUS_USER_APC );
if ( r == WAIT_OBJECT_0 ) if ( r == WAIT_OBJECT_0 && lpOverlapped->hEvent )
NtSetEvent ( lpOverlapped->hEvent, NULL ); NtSetEvent( lpOverlapped->hEvent, NULL );
} }
if ( lpcbTransfer ) if ( lpcbTransfer )
...@@ -2954,11 +2997,11 @@ BOOL WINAPI WSAGetOverlappedResult ( SOCKET s, LPWSAOVERLAPPED lpOverlapped, ...@@ -2954,11 +2997,11 @@ BOOL WINAPI WSAGetOverlappedResult ( SOCKET s, LPWSAOVERLAPPED lpOverlapped,
case STATUS_SUCCESS: case STATUS_SUCCESS:
return TRUE; return TRUE;
case STATUS_PENDING: case STATUS_PENDING:
WSASetLastError ( WSA_IO_INCOMPLETE ); WSASetLastError( WSA_IO_INCOMPLETE );
if (fWait) ERR ("PENDING status after waiting!\n"); if (fWait) ERR("PENDING status after waiting!\n");
return FALSE; return FALSE;
default: default:
WSASetLastError ( NtStatusToWSAError ( lpOverlapped->Internal )); WSASetLastError( NtStatusToWSAError( lpOverlapped->Internal ));
return FALSE; return FALSE;
} }
} }
...@@ -3267,7 +3310,7 @@ static int list_dup(char** l_src, char** l_to, int item_size) ...@@ -3267,7 +3310,7 @@ static int list_dup(char** l_src, char** l_to, int item_size)
p += count; p += count;
} }
l_to[i] = NULL; l_to[i] = NULL;
return (p - (char *)l_to); return p - (char *)l_to;
} }
/* ----- hostent */ /* ----- hostent */
...@@ -3453,13 +3496,13 @@ UINT wsaHerrno(int loc_errno) ...@@ -3453,13 +3496,13 @@ UINT wsaHerrno(int loc_errno)
/*********************************************************************** /***********************************************************************
* WSARecv (WS2_32.67) * WSARecv (WS2_32.67)
*/ */
int WINAPI WSARecv (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, int WINAPI WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPDWORD NumberOfBytesReceived, LPDWORD lpFlags, LPDWORD NumberOfBytesReceived, LPDWORD lpFlags,
LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{ {
return WSARecvFrom (s, lpBuffers, dwBufferCount, NumberOfBytesReceived, lpFlags, return WSARecvFrom(s, lpBuffers, dwBufferCount, NumberOfBytesReceived, lpFlags,
NULL, NULL, lpOverlapped, lpCompletionRoutine); NULL, NULL, lpOverlapped, lpCompletionRoutine);
} }
/*********************************************************************** /***********************************************************************
...@@ -3475,6 +3518,7 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -3475,6 +3518,7 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
int n, fd, err = WSAENOTSOCK, flags, ret; int n, fd, err = WSAENOTSOCK, flags, ret;
struct iovec* iovec; struct iovec* iovec;
struct ws2_async *wsa; struct ws2_async *wsa;
IO_STATUS_BLOCK* iosb;
TRACE("socket %04x, wsabuf %p, nbufs %ld, flags %ld, from %p, fromlen %ld, ovl %p, func %p\n", TRACE("socket %04x, wsabuf %p, nbufs %ld, flags %ld, from %p, fromlen %ld, ovl %p, func %p\n",
s, lpBuffers, dwBufferCount, *lpFlags, lpFrom, s, lpBuffers, dwBufferCount, *lpFlags, lpFrom,
...@@ -3482,17 +3526,17 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -3482,17 +3526,17 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
lpOverlapped, lpCompletionRoutine); lpOverlapped, lpCompletionRoutine);
fd = get_sock_fd( s, GENERIC_READ, &flags ); fd = get_sock_fd( s, GENERIC_READ, &flags );
TRACE ( "fd=%d, flags=%x\n", fd, flags ); TRACE( "fd=%d, flags=%x\n", fd, flags );
if (fd == -1) return SOCKET_ERROR; if (fd == -1) return SOCKET_ERROR;
if (flags & FD_FLAG_RECV_SHUTDOWN) if (flags & FD_FLAG_RECV_SHUTDOWN)
{ {
WSASetLastError ( WSAESHUTDOWN ); WSASetLastError( WSAESHUTDOWN );
goto err_close; goto err_close;
} }
iovec = HeapAlloc ( GetProcessHeap(), 0, dwBufferCount * sizeof (struct iovec) ); iovec = HeapAlloc( GetProcessHeap(), 0, dwBufferCount * sizeof (struct iovec) );
if ( !iovec ) if ( !iovec )
{ {
err = WSAEFAULT; err = WSAEFAULT;
...@@ -3507,9 +3551,9 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -3507,9 +3551,9 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
if ( (lpOverlapped || lpCompletionRoutine) && flags & FD_FLAG_OVERLAPPED ) if ( (lpOverlapped || lpCompletionRoutine) && flags & FD_FLAG_OVERLAPPED )
{ {
wsa = WS2_make_async ( s, fd, ASYNC_TYPE_READ, iovec, dwBufferCount, wsa = WS2_make_async( s, fd, ws2m_read, iovec, dwBufferCount,
lpFlags, lpFrom, lpFromlen, lpFlags, lpFrom, lpFromlen,
lpOverlapped, lpCompletionRoutine ); lpOverlapped, lpCompletionRoutine, &iosb );
if ( !wsa ) if ( !wsa )
{ {
...@@ -3517,28 +3561,28 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -3517,28 +3561,28 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
goto err_free; goto err_free;
} }
if ( ( ret = register_new_async ( &wsa->async )) ) if ( ( ret = ws2_queue_async( wsa, iosb )) )
{ {
err = NtStatusToWSAError ( ret ); err = NtStatusToWSAError( ret );
if ( !lpOverlapped ) if ( !lpOverlapped )
HeapFree ( GetProcessHeap(), 0, wsa->async.iosb ); HeapFree( GetProcessHeap(), 0, iosb );
HeapFree ( GetProcessHeap(), 0, wsa ); HeapFree( GetProcessHeap(), 0, wsa );
goto err_free; goto err_free;
} }
/* Try immediate completion */ /* Try immediate completion */
if ( lpOverlapped && !NtResetEvent( lpOverlapped->hEvent, NULL ) ) if ( lpOverlapped )
{ {
if ( WSAGetOverlappedResult ( s, lpOverlapped, if ( WSAGetOverlappedResult( s, lpOverlapped,
lpNumberOfBytesRecvd, FALSE, lpFlags) ) lpNumberOfBytesRecvd, FALSE, lpFlags) )
return 0; return 0;
if ( (err = WSAGetLastError ()) != WSA_IO_INCOMPLETE ) if ( (err = WSAGetLastError()) != WSA_IO_INCOMPLETE )
goto error; goto error;
} }
WSASetLastError ( WSA_IO_PENDING ); WSASetLastError( WSA_IO_PENDING );
return SOCKET_ERROR; return SOCKET_ERROR;
} }
...@@ -3555,7 +3599,7 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -3555,7 +3599,7 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
} }
} }
n = WS2_recv ( fd, iovec, dwBufferCount, lpFrom, lpFromlen, lpFlags ); n = WS2_recv( fd, iovec, dwBufferCount, lpFrom, lpFromlen, lpFlags );
if ( n == -1 ) if ( n == -1 )
{ {
err = wsaErrno(); err = wsaErrno();
...@@ -3565,21 +3609,21 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, ...@@ -3565,21 +3609,21 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
TRACE(" -> %i bytes\n", n); TRACE(" -> %i bytes\n", n);
*lpNumberOfBytesRecvd = n; *lpNumberOfBytesRecvd = n;
HeapFree (GetProcessHeap(), 0, iovec); HeapFree(GetProcessHeap(), 0, iovec);
release_sock_fd( s, fd ); release_sock_fd( s, fd );
_enable_event(SOCKET2HANDLE(s), FD_READ, 0, 0); _enable_event(SOCKET2HANDLE(s), FD_READ, 0, 0);
return 0; return 0;
err_free: err_free:
HeapFree (GetProcessHeap(), 0, iovec); HeapFree(GetProcessHeap(), 0, iovec);
err_close: err_close:
release_sock_fd( s, fd ); release_sock_fd( s, fd );
error: error:
WARN(" -> ERROR %d\n", err); WARN(" -> ERROR %d\n", err);
WSASetLastError ( err ); WSASetLastError( err );
return SOCKET_ERROR; return SOCKET_ERROR;
} }
...@@ -3656,14 +3700,14 @@ SOCKET WINAPI WSAAccept( SOCKET s, struct WS_sockaddr *addr, LPINT addrlen, ...@@ -3656,14 +3700,14 @@ SOCKET WINAPI WSAAccept( SOCKET s, struct WS_sockaddr *addr, LPINT addrlen,
addr = memcpy(addr, &src_addr, (*addrlen > size) ? size : *addrlen ); addr = memcpy(addr, &src_addr, (*addrlen > size) ? size : *addrlen );
return cs; return cs;
case CF_DEFER: case CF_DEFER:
SERVER_START_REQ ( set_socket_deferred ) SERVER_START_REQ( set_socket_deferred )
{ {
req->handle = SOCKET2HANDLE (s); req->handle = SOCKET2HANDLE(s);
req->deferred = SOCKET2HANDLE (cs); req->deferred = SOCKET2HANDLE(cs);
if ( !wine_server_call_err ( req ) ) if ( !wine_server_call_err ( req ) )
{ {
SetLastError ( WSATRY_AGAIN ); SetLastError( WSATRY_AGAIN );
WS_closesocket ( cs ); WS_closesocket( cs );
} }
} }
SERVER_END_REQ; SERVER_END_REQ;
......
/*
* Structures and static functions for handling asynchronous I/O.
*
* Copyright (C) 2002 Mike McCormack, Martin Wilck
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* This file declares static functions.
* It should only be included by those source files that implement async I/O requests.
*/
#ifndef __WINE_ASYNC_H
#define __WINE_ASYNC_H
#include <thread.h>
#include <ntstatus.h>
#include <wine/server.h>
#include <winternl.h>
struct async_private;
typedef void (*async_handler)(struct async_private *ovp);
typedef void (CALLBACK *async_call_completion_func)(ULONG_PTR data);
typedef DWORD (*async_get_count)(const struct async_private *ovp);
typedef void (*async_cleanup)(struct async_private *ovp);
typedef struct async_ops
{
async_get_count get_count;
async_call_completion_func call_completion;
async_cleanup cleanup;
} async_ops;
typedef struct async_private
{
struct async_ops* ops;
HANDLE handle;
HANDLE event;
int fd;
async_handler func;
int type;
IO_STATUS_BLOCK* iosb;
struct async_private* next;
struct async_private* prev;
} async_private;
/* All functions declared static for Dll separation purposes */
static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
{
PAPCFUNC func = (PAPCFUNC)arg1;
func( arg2 );
}
inline static void finish_async( async_private *ovp )
{
if (ovp->prev)
ovp->prev->next = ovp->next;
else
NtCurrentTeb()->pending_list = ovp->next;
if (ovp->next)
ovp->next->prev = ovp->prev;
ovp->next = ovp->prev = NULL;
wine_server_release_fd( ovp->handle, ovp->fd );
if ( ovp->event != INVALID_HANDLE_VALUE )
NtSetEvent( ovp->event, NULL );
if ( ovp->ops->call_completion )
NtQueueApcThread( GetCurrentThread(), call_user_apc,
(ULONG_PTR)ovp->ops->call_completion, (ULONG_PTR)ovp, 0 );
else
ovp->ops->cleanup( ovp );
}
inline static NTSTATUS __register_async( async_private *ovp, const DWORD status )
{
NTSTATUS ret;
SERVER_START_REQ( register_async )
{
req->handle = ovp->handle;
req->overlapped = ovp;
req->type = ovp->type;
req->count = ovp->ops->get_count( ovp );
req->status = status;
ret = wine_server_call( req );
}
SERVER_END_REQ;
if (ret) ovp->iosb->u.Status = ret;
if ( ovp->iosb->u.Status != STATUS_PENDING )
finish_async(ovp);
return ret;
}
inline static NTSTATUS register_old_async( async_private *ovp )
{
return __register_async(ovp, ovp->iosb->u.Status);
}
inline static NTSTATUS register_new_async( async_private *ovp )
{
ovp->iosb->u.Status = STATUS_PENDING;
ovp->next = NtCurrentTeb()->pending_list;
ovp->prev = NULL;
if ( ovp->next ) ovp->next->prev = ovp;
NtCurrentTeb()->pending_list = ovp;
return __register_async( ovp, STATUS_PENDING );
}
inline static NTSTATUS cancel_async( async_private *ovp )
{
/* avoid multiple cancellations */
if ( ovp->iosb->u.Status != STATUS_PENDING )
return STATUS_SUCCESS;
ovp->iosb->u.Status = STATUS_CANCELLED;
return __register_async( ovp, STATUS_CANCELLED );
}
#endif /* __WINE_ASYNC_H */
...@@ -112,7 +112,7 @@ typedef struct _TEB ...@@ -112,7 +112,7 @@ typedef struct _TEB
int wait_fd[2]; /* --3 214 fd for sleeping server requests */ int wait_fd[2]; /* --3 214 fd for sleeping server requests */
struct debug_info *debug_info; /* --3 21c Info for debugstr functions */ struct debug_info *debug_info; /* --3 21c Info for debugstr functions */
void *pthread_data; /* --3 220 Data for pthread emulation */ void *pthread_data; /* --3 220 Data for pthread emulation */
struct async_private *pending_list; /* --3 224 list of pending async operations */ DWORD num_async_io; /* --3 224 number of pending async I/O in the server */
void *driver_data; /* --3 228 Graphics driver private data */ void *driver_data; /* --3 228 Graphics driver private data */
DWORD dpmi_vif; /* --3 22c Protected mode virtual interrupt flag */ DWORD dpmi_vif; /* --3 22c Protected mode virtual interrupt flag */
DWORD vm86_pending; /* --3 230 Data for vm86 mode */ DWORD vm86_pending; /* --3 230 Data for vm86 mode */
......
...@@ -2282,21 +2282,33 @@ struct register_async_request ...@@ -2282,21 +2282,33 @@ struct register_async_request
struct request_header __header; struct request_header __header;
obj_handle_t handle; obj_handle_t handle;
int type; int type;
void* overlapped; void* io_apc;
void* io_sb;
void* io_user;
int count; int count;
unsigned int status;
}; };
struct register_async_reply struct register_async_reply
{ {
struct reply_header __header; struct reply_header __header;
}; };
#define ASYNC_TYPE_NONE 0x00
#define ASYNC_TYPE_READ 0x01 #define ASYNC_TYPE_READ 0x01
#define ASYNC_TYPE_WRITE 0x02 #define ASYNC_TYPE_WRITE 0x02
#define ASYNC_TYPE_WAIT 0x03 #define ASYNC_TYPE_WAIT 0x03
struct cancel_async_request
{
struct request_header __header;
obj_handle_t handle;
};
struct cancel_async_reply
{
struct reply_header __header;
};
struct create_named_pipe_request struct create_named_pipe_request
{ {
struct request_header __header; struct request_header __header;
...@@ -3274,6 +3286,7 @@ enum request ...@@ -3274,6 +3286,7 @@ enum request
REQ_get_serial_info, REQ_get_serial_info,
REQ_set_serial_info, REQ_set_serial_info,
REQ_register_async, REQ_register_async,
REQ_cancel_async,
REQ_create_named_pipe, REQ_create_named_pipe,
REQ_open_named_pipe, REQ_open_named_pipe,
REQ_connect_named_pipe, REQ_connect_named_pipe,
...@@ -3460,6 +3473,7 @@ union generic_request ...@@ -3460,6 +3473,7 @@ union generic_request
struct get_serial_info_request get_serial_info_request; struct get_serial_info_request get_serial_info_request;
struct set_serial_info_request set_serial_info_request; struct set_serial_info_request set_serial_info_request;
struct register_async_request register_async_request; struct register_async_request register_async_request;
struct cancel_async_request cancel_async_request;
struct create_named_pipe_request create_named_pipe_request; struct create_named_pipe_request create_named_pipe_request;
struct open_named_pipe_request open_named_pipe_request; struct open_named_pipe_request open_named_pipe_request;
struct connect_named_pipe_request connect_named_pipe_request; struct connect_named_pipe_request connect_named_pipe_request;
...@@ -3644,6 +3658,7 @@ union generic_reply ...@@ -3644,6 +3658,7 @@ union generic_reply
struct get_serial_info_reply get_serial_info_reply; struct get_serial_info_reply get_serial_info_reply;
struct set_serial_info_reply set_serial_info_reply; struct set_serial_info_reply set_serial_info_reply;
struct register_async_reply register_async_reply; struct register_async_reply register_async_reply;
struct cancel_async_reply cancel_async_reply;
struct create_named_pipe_reply create_named_pipe_reply; struct create_named_pipe_reply create_named_pipe_reply;
struct open_named_pipe_reply open_named_pipe_reply; struct open_named_pipe_reply open_named_pipe_reply;
struct connect_named_pipe_reply connect_named_pipe_reply; struct connect_named_pipe_reply connect_named_pipe_reply;
...@@ -3697,6 +3712,6 @@ union generic_reply ...@@ -3697,6 +3712,6 @@ union generic_reply
struct set_global_windows_reply set_global_windows_reply; struct set_global_windows_reply set_global_windows_reply;
}; };
#define SERVER_PROTOCOL_VERSION 153 #define SERVER_PROTOCOL_VERSION 154
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -6,7 +6,6 @@ VPATH = @srcdir@ ...@@ -6,7 +6,6 @@ VPATH = @srcdir@
MODULE = none MODULE = none
C_SRCS = \ C_SRCS = \
async.c \
atom.c \ atom.c \
change.c \ change.c \
class.c \ class.c \
......
/*
* Server-side support for async i/o operations
*
* Copyright (C) 1998 Alexandre Julliard
* Copyright (C) 2000 Mike McCormack
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include "handle.h"
#include "file.h"
#include "thread.h"
#include "request.h"
#include "async.h"
void destroy_async( struct async *async )
{
struct async_queue *aq = async->q;
/*fprintf(stderr,"destroyed async %p\n",async->overlapped); */
if(async->timeout)
remove_timeout_user(async->timeout);
async->timeout = NULL;
if(async->prev)
async->prev->next = async->next;
else
aq->head = async->next;
if(async->next)
async->next->prev = async->prev;
else
aq->tail = async->prev;
async->q = NULL;
async->next = NULL;
async->prev = NULL;
release_object( async->thread );
free(async);
}
void async_notify(struct async *async, int status)
{
/* fprintf(stderr,"notifying %p!\n",async->overlapped); */
async->status = status;
thread_queue_apc(async->thread, NULL, NULL, APC_ASYNC_IO, 1,
async->overlapped, (void *)status, NULL );
}
void destroy_async_queue( struct async_queue *q )
{
while(q->head)
{
async_notify(q->head, STATUS_CANCELLED);
destroy_async(q->head);
}
}
struct async *find_async(struct async_queue *q, struct thread *thread, void *overlapped)
{
struct async *async;
/* fprintf(stderr,"find_async: %p\n",overlapped); */
if(!q)
return NULL;
for(async = q->head; async; async = async->next)
if((async->overlapped==overlapped) && (async->thread == thread))
return async;
return NULL;
}
void async_insert(struct async_queue *q, struct async *async)
{
async->q = q;
async->prev = q->tail;
async->next = NULL;
if(q->tail)
q->tail->next = async;
else
q->head = async;
q->tail = async;
}
static void async_callback(void *private)
{
struct async *async = (struct async *)private;
/* fprintf(stderr,"%p timeout out\n",async->overlapped); */
async->timeout = NULL;
async_notify(async, STATUS_TIMEOUT);
destroy_async(async);
}
struct async *create_async(struct object *obj, struct thread *thread,
void *overlapped)
{
struct async *async = (struct async *) malloc(sizeof(struct async));
if(!async)
{
set_error(STATUS_NO_MEMORY);
return NULL;
}
async->obj = obj;
async->thread = (struct thread *)grab_object(thread);
async->overlapped = overlapped;
async->next = NULL;
async->prev = NULL;
async->q = NULL;
async->status = STATUS_PENDING;
async->timeout = NULL;
return async;
}
void async_add_timeout(struct async *async, int timeout)
{
if(timeout)
{
gettimeofday( &async->when, 0 );
add_timeout( &async->when, timeout );
async->timeout = add_timeout_user( &async->when, async_callback, async );
}
}
/*
* Async i/o definitions
*
* Copyright (C) 2000 Mike McCormack
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SERVER_ASYNC_
#define _SERVER_ASYNC_
#include <sys/time.h>
#include "object.h"
struct async_queue;
struct async
{
struct object *obj;
struct thread *thread;
void *overlapped;
unsigned int status;
struct timeval when;
struct timeout_user *timeout;
struct async *next,*prev;
struct async_queue *q;
};
struct async_queue
{
struct async *head;
struct async *tail;
};
void destroy_async( struct async *async );
void destroy_async_queue( struct async_queue *q );
void async_notify(struct async *async, int status);
struct async *find_async(struct async_queue *q, struct thread *thread, void *overlapped);
void async_insert(struct async_queue *q, struct async *async);
struct async *create_async(struct object *obj, struct thread *thread,
void *overlapped);
void async_add_timeout(struct async *async, int timeout);
static inline void init_async_queue(struct async_queue *q)
{
q->head = q->tail = NULL;
}
#define IS_READY(q) (((q).head) && ((q).head->status==STATUS_PENDING))
#endif /* _SERVER_ASYNC_ */
...@@ -980,6 +980,89 @@ void unlock_fd( struct fd *fd, file_pos_t start, file_pos_t count ) ...@@ -980,6 +980,89 @@ void unlock_fd( struct fd *fd, file_pos_t start, file_pos_t count )
/****************************************************************/ /****************************************************************/
/* asynchronous operations support */
struct async
{
struct fd *fd;
struct thread *thread;
void *apc;
void *user;
void *sb;
struct timeval when;
struct timeout_user *timeout;
struct async *next;
struct async **head;
};
/* cb for timeout on an async request */
static void async_callback(void *private)
{
struct async *async = (struct async *)private;
/* fprintf(stderr, "async timeout out %p\n", async); */
async->timeout = NULL;
async_terminate( async, STATUS_TIMEOUT );
}
/* create an async on a given queue of a fd */
struct async *create_async(struct fd *fd, struct thread *thread,
int timeout, struct async **head,
void *io_apc, void *io_user, void* io_sb)
{
struct async *async = mem_alloc( sizeof(struct async) );
struct async **p;
if (!async) return NULL;
async->fd = fd;
async->thread = (struct thread *)grab_object(thread);
async->apc = io_apc;
async->user = io_user;
async->sb = io_sb;
async->head = head;
async->next = NULL;
for (p = head; *p; p = &(*p)->next);
*p = async;
if (timeout)
{
gettimeofday( &async->when, 0 );
add_timeout( &async->when, timeout );
async->timeout = add_timeout_user( &async->when, async_callback, async );
}
else async->timeout = NULL;
return async;
}
/* notifies client thread of new status of its async request */
/* destroys the server side of it */
void async_terminate( struct async *async, int status )
{
struct async** p;
thread_queue_apc( async->thread, NULL, async->apc, APC_ASYNC_IO,
1, async->user, async->sb, (void *)status );
if (async->timeout) remove_timeout_user( async->timeout );
async->timeout = NULL;
for (p = async->head; *p; p = &(*p)->next)
{
if (*p == async)
{
*p = async->next;
break;
}
}
release_object( async->thread );
free( async );
}
/****************************************************************/
/* file descriptor functions */ /* file descriptor functions */
static void fd_dump( struct object *obj, int verbose ) static void fd_dump( struct object *obj, int verbose )
...@@ -1309,7 +1392,14 @@ int no_get_file_info( struct fd *fd ) ...@@ -1309,7 +1392,14 @@ int no_get_file_info( struct fd *fd )
} }
/* default queue_async() routine */ /* default queue_async() routine */
void no_queue_async( struct fd *fd, void* ptr, unsigned int status, int type, int count ) void no_queue_async( struct fd *fd, void* apc, void* user, void* io_sb,
int type, int count)
{
set_error( STATUS_OBJECT_TYPE_MISMATCH );
}
/* default cancel_async() routine */
void no_cancel_async( struct fd *fd )
{ {
set_error( STATUS_OBJECT_TYPE_MISMATCH ); set_error( STATUS_OBJECT_TYPE_MISMATCH );
} }
...@@ -1338,7 +1428,7 @@ DECL_HANDLER(flush_file) ...@@ -1338,7 +1428,7 @@ DECL_HANDLER(flush_file)
if (fd) if (fd)
{ {
fd->fd_ops->flush( fd, &event ); fd->fd_ops->flush( fd, &event );
if( event ) if ( event )
{ {
reply->event = alloc_handle( current->process, event, SYNCHRONIZE, 0 ); reply->event = alloc_handle( current->process, event, SYNCHRONIZE, 0 );
} }
...@@ -1372,26 +1462,41 @@ DECL_HANDLER(register_async) ...@@ -1372,26 +1462,41 @@ DECL_HANDLER(register_async)
{ {
struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 ); struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
/* /*
* The queue_async method must do the following: * The queue_async method must do the following:
* *
* 1. Get the async_queue for the request of given type. * 1. Get the async_queue for the request of given type.
* 2. Call find_async() to look for the specific client request in the queue (=> NULL if not found). * 2. Create a new asynchronous request for the selected queue
* 3. If status is STATUS_PENDING: * 3. Carry out any operations necessary to adjust the object's poll events
* a) If no async request found in step 2 (new request): call create_async() to initialize one. * Usually: set_elect_events (obj, obj->ops->get_poll_events()).
* b) Set request's status to STATUS_PENDING. * 4. When the async request is triggered, then send back (with a proper APC)
* c) If the "queue" field of the async request is NULL: call async_insert() to put it into the queue. * the trigger (STATUS_ALERTED) to the thread that posted the request.
* Otherwise: * async_destroy() is to be called: it will both notify the sender about
* If the async request was found in step 2, destroy it by calling destroy_async(). * the trigger and destroy the request by itself
* 4. Carry out any operations necessary to adjust the object's poll events * See also the implementations in file.c, serial.c, and sock.c.
* Usually: set_elect_events (obj, obj->ops->get_poll_events()). */
*
* See also the implementations in file.c, serial.c, and sock.c.
*/
if (fd) if (fd)
{ {
fd->fd_ops->queue_async( fd, req->overlapped, req->status, req->type, req->count ); fd->fd_ops->queue_async( fd, req->io_apc, req->io_user, req->io_sb,
req->type, req->count );
release_object( fd ); release_object( fd );
} }
} }
/* cancels all async I/O */
DECL_HANDLER(cancel_async)
{
struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
if (fd)
{
/* Note: we don't kill the queued APC_ASYNC_IO on this thread because
* NtCancelIoFile() will force the pending APC to be run. Since,
* Windows only guarantees that the current thread will have no async
* operation on the current fd when NtCancelIoFile returns, this shall
* do the work.
*/
fd->fd_ops->cancel_async( fd );
release_object( fd );
}
}
...@@ -50,7 +50,6 @@ ...@@ -50,7 +50,6 @@
#include "handle.h" #include "handle.h"
#include "thread.h" #include "thread.h"
#include "request.h" #include "request.h"
#include "async.h"
struct file struct file
{ {
...@@ -58,8 +57,8 @@ struct file ...@@ -58,8 +57,8 @@ struct file
struct fd *fd; /* file descriptor for this file */ struct fd *fd; /* file descriptor for this file */
unsigned int access; /* file access (GENERIC_READ/WRITE) */ unsigned int access; /* file access (GENERIC_READ/WRITE) */
unsigned int options; /* file options (FILE_DELETE_ON_CLOSE, FILE_SYNCHRONOUS...) */ unsigned int options; /* file options (FILE_DELETE_ON_CLOSE, FILE_SYNCHRONOUS...) */
struct async_queue read_q; struct async *read_q;
struct async_queue write_q; struct async *write_q;
}; };
static void file_dump( struct object *obj, int verbose ); static void file_dump( struct object *obj, int verbose );
...@@ -70,7 +69,8 @@ static int file_get_poll_events( struct fd *fd ); ...@@ -70,7 +69,8 @@ static int file_get_poll_events( struct fd *fd );
static void file_poll_event( struct fd *fd, int event ); static void file_poll_event( struct fd *fd, int event );
static int file_flush( struct fd *fd, struct event **event ); static int file_flush( struct fd *fd, struct event **event );
static int file_get_info( struct fd *fd ); static int file_get_info( struct fd *fd );
static void file_queue_async( struct fd *fd, void *ptr, unsigned int status, int type, int count ); static void file_queue_async( struct fd *fd, void *apc, void *user, void* iosb, int type, int count );
static void file_cancel_async( struct fd *fd );
static const struct object_ops file_ops = static const struct object_ops file_ops =
{ {
...@@ -90,7 +90,8 @@ static const struct fd_ops file_fd_ops = ...@@ -90,7 +90,8 @@ static const struct fd_ops file_fd_ops =
file_poll_event, /* poll_event */ file_poll_event, /* poll_event */
file_flush, /* flush */ file_flush, /* flush */
file_get_info, /* get_file_info */ file_get_info, /* get_file_info */
file_queue_async /* queue_async */ file_queue_async, /* queue_async */
file_cancel_async /* cancel_async */
}; };
static inline int is_overlapped( const struct file *file ) static inline int is_overlapped( const struct file *file )
...@@ -141,6 +142,7 @@ static struct object *create_file( const char *nameptr, size_t len, unsigned int ...@@ -141,6 +142,7 @@ static struct object *create_file( const char *nameptr, size_t len, unsigned int
case FILE_OVERWRITE: flags = O_TRUNC; break; case FILE_OVERWRITE: flags = O_TRUNC; break;
default: set_error( STATUS_INVALID_PARAMETER ); goto error; default: set_error( STATUS_INVALID_PARAMETER ); goto error;
} }
switch(access & (GENERIC_READ | GENERIC_WRITE)) switch(access & (GENERIC_READ | GENERIC_WRITE))
{ {
case 0: break; case 0: break;
...@@ -160,8 +162,7 @@ static struct object *create_file( const char *nameptr, size_t len, unsigned int ...@@ -160,8 +162,7 @@ static struct object *create_file( const char *nameptr, size_t len, unsigned int
file->options = options; file->options = options;
if (is_overlapped( file )) if (is_overlapped( file ))
{ {
init_async_queue (&file->read_q); file->read_q = file->write_q = NULL;
init_async_queue (&file->write_q);
} }
/* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */ /* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */
...@@ -236,14 +237,14 @@ static void file_poll_event( struct fd *fd, int event ) ...@@ -236,14 +237,14 @@ static void file_poll_event( struct fd *fd, int event )
assert( file->obj.ops == &file_ops ); assert( file->obj.ops == &file_ops );
if (is_overlapped( file )) if (is_overlapped( file ))
{ {
if( IS_READY(file->read_q) && (POLLIN & event) ) if ( file->read_q && (POLLIN & event) )
{ {
async_notify(file->read_q.head, STATUS_ALERTED); async_terminate( file->read_q, STATUS_ALERTED );
return; return;
} }
if( IS_READY(file->write_q) && (POLLOUT & event) ) if ( file->write_q && (POLLOUT & event) )
{ {
async_notify(file->write_q.head, STATUS_ALERTED); async_terminate( file->write_q, STATUS_ALERTED );
return; return;
} }
} }
...@@ -266,56 +267,51 @@ static int file_get_info( struct fd *fd ) ...@@ -266,56 +267,51 @@ static int file_get_info( struct fd *fd )
else return 0; else return 0;
} }
static void file_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count) static void file_queue_async( struct fd *fd, void *apc, void *user, void *iosb,
int type, int count )
{ {
struct file *file = get_fd_user( fd ); struct file *file = get_fd_user( fd );
struct async *async; struct async **head;
struct async_queue *q; int events;
assert( file->obj.ops == &file_ops ); assert( file->obj.ops == &file_ops );
if (!is_overlapped( file )) if (!is_overlapped( file ))
{ {
set_error ( STATUS_INVALID_HANDLE ); set_error( STATUS_INVALID_HANDLE );
return; return;
} }
switch(type) switch (type)
{ {
case ASYNC_TYPE_READ: case ASYNC_TYPE_READ:
q = &file->read_q; head = &file->read_q;
break; break;
case ASYNC_TYPE_WRITE: case ASYNC_TYPE_WRITE:
q = &file->write_q; head = &file->write_q;
break; break;
default: default:
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
return; return;
} }
async = find_async ( q, current, ptr ); if (!create_async( fd, current, 0, head, apc, user, iosb ))
return;
if ( status == STATUS_PENDING )
{
int events;
if ( !async ) /* Check if the new pending request can be served immediately */
async = create_async ( &file->obj, current, ptr ); events = check_fd_events( fd, file_get_poll_events( fd ) );
if ( !async ) if (events) file_poll_event( fd, events );
return;
async->status = STATUS_PENDING; set_fd_events( fd, file_get_poll_events( fd ));
if ( !async->q ) }
async_insert( q, async );
/* Check if the new pending request can be served immediately */ static void file_cancel_async( struct fd *fd )
events = check_fd_events( fd, file_get_poll_events( fd ) ); {
if (events) file_poll_event ( fd, events ); struct file *file = get_fd_user( fd );
} assert( file->obj.ops == &file_ops );
else if ( async ) destroy_async ( async );
else set_error ( STATUS_INVALID_PARAMETER );
set_fd_events( fd, file_get_poll_events( fd )); async_terminate_queue( &file->read_q, STATUS_CANCELLED );
async_terminate_queue( &file->write_q, STATUS_CANCELLED );
} }
static struct fd *file_get_fd( struct object *obj ) static struct fd *file_get_fd( struct object *obj )
...@@ -332,8 +328,8 @@ static void file_destroy( struct object *obj ) ...@@ -332,8 +328,8 @@ static void file_destroy( struct object *obj )
if (is_overlapped( file )) if (is_overlapped( file ))
{ {
destroy_async_queue (&file->read_q); async_terminate_queue( &file->read_q, STATUS_CANCELLED );
destroy_async_queue (&file->write_q); async_terminate_queue( &file->write_q, STATUS_CANCELLED );
} }
if (file->fd) release_object( file->fd ); if (file->fd) release_object( file->fd );
} }
......
...@@ -38,8 +38,10 @@ struct fd_ops ...@@ -38,8 +38,10 @@ struct fd_ops
int (*flush)(struct fd *, struct event **); int (*flush)(struct fd *, struct event **);
/* get file information */ /* get file information */
int (*get_file_info)(struct fd *); int (*get_file_info)(struct fd *);
/* queue an async operation - see register_async handler in async.c*/ /* queue an async operation */
void (*queue_async)(struct fd *, void* ptr, unsigned int status, int type, int count); void (*queue_async)(struct fd *, void* apc, void* user, void* io_sb, int type, int count);
/* cancel an async operation */
void (*cancel_async)(struct fd *);
}; };
/* file descriptor functions */ /* file descriptor functions */
...@@ -65,7 +67,8 @@ extern int default_fd_signaled( struct object *obj, struct thread *thread ); ...@@ -65,7 +67,8 @@ extern int default_fd_signaled( struct object *obj, struct thread *thread );
extern void default_poll_event( struct fd *fd, int event ); extern void default_poll_event( struct fd *fd, int event );
extern int no_flush( struct fd *fd, struct event **event ); extern int no_flush( struct fd *fd, struct event **event );
extern int no_get_file_info( struct fd *fd ); extern int no_get_file_info( struct fd *fd );
extern void no_queue_async( struct fd *fd, void* ptr, unsigned int status, int type, int count ); extern void no_queue_async( struct fd *fd, void* apc, void* user, void* io_sb, int type, int count);
extern void no_cancel_async( struct fd *fd );
extern void main_loop(void); extern void main_loop(void);
inline static struct fd *get_obj_fd( struct object *obj ) { return obj->ops->get_fd( obj ); } inline static struct fd *get_obj_fd( struct object *obj ) { return obj->ops->get_fd( obj ); }
...@@ -107,4 +110,14 @@ extern void sigio_callback(void); ...@@ -107,4 +110,14 @@ extern void sigio_callback(void);
extern int is_serial_fd( struct fd *fd ); extern int is_serial_fd( struct fd *fd );
extern struct object *create_serial( struct fd *fd, unsigned int options ); extern struct object *create_serial( struct fd *fd, unsigned int options );
/* async I/O functions */
extern struct async *create_async( struct fd *fd, struct thread *thread, int timeout,
struct async **head, void *, void *, void *);
extern void async_terminate( struct async *async, int status );
static inline void async_terminate_queue( struct async **head, int status )
{
while (*head) async_terminate( *head, status );
}
#endif /* __WINE_SERVER_FILE_H */ #endif /* __WINE_SERVER_FILE_H */
...@@ -151,7 +151,8 @@ static const struct fd_ops pipe_server_fd_ops = ...@@ -151,7 +151,8 @@ static const struct fd_ops pipe_server_fd_ops =
default_poll_event, /* poll_event */ default_poll_event, /* poll_event */
pipe_server_flush, /* flush */ pipe_server_flush, /* flush */
pipe_end_get_info, /* get_file_info */ pipe_end_get_info, /* get_file_info */
no_queue_async /* queue_async */ no_queue_async, /* queue_async */
no_cancel_async, /* cancel_async */
}; };
/* client end functions */ /* client end functions */
...@@ -178,7 +179,8 @@ static const struct fd_ops pipe_client_fd_ops = ...@@ -178,7 +179,8 @@ static const struct fd_ops pipe_client_fd_ops =
default_poll_event, /* poll_event */ default_poll_event, /* poll_event */
pipe_client_flush, /* flush */ pipe_client_flush, /* flush */
pipe_end_get_info, /* get_file_info */ pipe_end_get_info, /* get_file_info */
no_queue_async /* queue_async */ no_queue_async, /* queue_async */
no_cancel_async /* cancel_async */
}; };
static void named_pipe_dump( struct object *obj, int verbose ) static void named_pipe_dump( struct object *obj, int verbose )
......
...@@ -76,7 +76,8 @@ static const struct fd_ops process_fd_ops = ...@@ -76,7 +76,8 @@ static const struct fd_ops process_fd_ops =
process_poll_event, /* poll_event */ process_poll_event, /* poll_event */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
no_queue_async /* queue_async */ no_queue_async, /* queue_async */
no_cancel_async /* cancel async */
}; };
/* process startup info */ /* process startup info */
......
...@@ -1615,20 +1615,26 @@ enum message_type ...@@ -1615,20 +1615,26 @@ enum message_type
#define SERIALINFO_SET_ERROR 0x04 #define SERIALINFO_SET_ERROR 0x04
/* Create / reschedule an async I/O */ /* Create an async I/O */
@REQ(register_async) @REQ(register_async)
obj_handle_t handle; /* handle to comm port, socket or file */ obj_handle_t handle; /* handle to comm port, socket or file */
int type; int type; /* type of queue to look after */
void* overlapped; void* io_apc; /* APC routine to queue upon end of async */
int count; void* io_sb; /* I/O status block (unique across all async on this handle) */
unsigned int status; void* io_user; /* data to pass back to caller */
int count; /* count - usually # of bytes to be read/written */
@END @END
#define ASYNC_TYPE_NONE 0x00
#define ASYNC_TYPE_READ 0x01 #define ASYNC_TYPE_READ 0x01
#define ASYNC_TYPE_WRITE 0x02 #define ASYNC_TYPE_WRITE 0x02
#define ASYNC_TYPE_WAIT 0x03 #define ASYNC_TYPE_WAIT 0x03
/* Cancel all async op on a fd */
@REQ(cancel_async)
obj_handle_t handle; /* handle to comm port, socket or file */
@END
/* Create a named pipe */ /* Create a named pipe */
@REQ(create_named_pipe) @REQ(create_named_pipe)
unsigned int openmode; unsigned int openmode;
......
...@@ -100,7 +100,8 @@ static const struct fd_ops master_socket_fd_ops = ...@@ -100,7 +100,8 @@ static const struct fd_ops master_socket_fd_ops =
master_socket_poll_event, /* poll_event */ master_socket_poll_event, /* poll_event */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
no_queue_async /* queue_async */ no_queue_async, /* queue_async */
no_cancel_async /* cancel_async */
}; };
......
...@@ -231,6 +231,7 @@ DECL_HANDLER(kill_win_timer); ...@@ -231,6 +231,7 @@ DECL_HANDLER(kill_win_timer);
DECL_HANDLER(get_serial_info); DECL_HANDLER(get_serial_info);
DECL_HANDLER(set_serial_info); DECL_HANDLER(set_serial_info);
DECL_HANDLER(register_async); DECL_HANDLER(register_async);
DECL_HANDLER(cancel_async);
DECL_HANDLER(create_named_pipe); DECL_HANDLER(create_named_pipe);
DECL_HANDLER(open_named_pipe); DECL_HANDLER(open_named_pipe);
DECL_HANDLER(connect_named_pipe); DECL_HANDLER(connect_named_pipe);
...@@ -416,6 +417,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = ...@@ -416,6 +417,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_get_serial_info, (req_handler)req_get_serial_info,
(req_handler)req_set_serial_info, (req_handler)req_set_serial_info,
(req_handler)req_register_async, (req_handler)req_register_async,
(req_handler)req_cancel_async,
(req_handler)req_create_named_pipe, (req_handler)req_create_named_pipe,
(req_handler)req_open_named_pipe, (req_handler)req_open_named_pipe,
(req_handler)req_connect_named_pipe, (req_handler)req_connect_named_pipe,
......
...@@ -53,7 +53,6 @@ ...@@ -53,7 +53,6 @@
#include "handle.h" #include "handle.h"
#include "thread.h" #include "thread.h"
#include "request.h" #include "request.h"
#include "async.h"
static void serial_dump( struct object *obj, int verbose ); static void serial_dump( struct object *obj, int verbose );
static struct fd *serial_get_fd( struct object *obj ); static struct fd *serial_get_fd( struct object *obj );
...@@ -63,7 +62,8 @@ static int serial_get_poll_events( struct fd *fd ); ...@@ -63,7 +62,8 @@ static int serial_get_poll_events( struct fd *fd );
static void serial_poll_event( struct fd *fd, int event ); static void serial_poll_event( struct fd *fd, int event );
static int serial_get_info( struct fd *fd ); static int serial_get_info( struct fd *fd );
static int serial_flush( struct fd *fd, struct event **event ); static int serial_flush( struct fd *fd, struct event **event );
static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count); static void serial_queue_async( struct fd *fd, void *apc, void *user, void *iosb, int type, int count );
static void serial_cancel_async( struct fd *fd );
struct serial struct serial
{ {
...@@ -83,9 +83,9 @@ struct serial ...@@ -83,9 +83,9 @@ struct serial
struct termios original; struct termios original;
struct async_queue read_q; struct async *read_q;
struct async_queue write_q; struct async *write_q;
struct async_queue wait_q; struct async *wait_q;
/* FIXME: add dcb, comm status, handler module, sharing */ /* FIXME: add dcb, comm status, handler module, sharing */
}; };
...@@ -108,7 +108,8 @@ static const struct fd_ops serial_fd_ops = ...@@ -108,7 +108,8 @@ static const struct fd_ops serial_fd_ops =
serial_poll_event, /* poll_event */ serial_poll_event, /* poll_event */
serial_flush, /* flush */ serial_flush, /* flush */
serial_get_info, /* get_file_info */ serial_get_info, /* get_file_info */
serial_queue_async /* queue_async */ serial_queue_async, /* queue_async */
serial_cancel_async /* cancel_async */
}; };
/* check if the given fd is a serial port */ /* check if the given fd is a serial port */
...@@ -144,9 +145,7 @@ struct object *create_serial( struct fd *fd, unsigned int options ) ...@@ -144,9 +145,7 @@ struct object *create_serial( struct fd *fd, unsigned int options )
serial->writeconst = 0; serial->writeconst = 0;
serial->eventmask = 0; serial->eventmask = 0;
serial->commerror = 0; serial->commerror = 0;
init_async_queue(&serial->read_q); serial->read_q = serial->write_q = serial->wait_q = NULL;
init_async_queue(&serial->write_q);
init_async_queue(&serial->wait_q);
if (!(serial->fd = create_anonymous_fd( &serial_fd_ops, unix_fd, &serial->obj ))) if (!(serial->fd = create_anonymous_fd( &serial_fd_ops, unix_fd, &serial->obj )))
{ {
release_object( serial ); release_object( serial );
...@@ -165,9 +164,9 @@ static void serial_destroy( struct object *obj) ...@@ -165,9 +164,9 @@ static void serial_destroy( struct object *obj)
{ {
struct serial *serial = (struct serial *)obj; struct serial *serial = (struct serial *)obj;
destroy_async_queue(&serial->read_q); async_terminate_queue( &serial->read_q, STATUS_CANCELLED );
destroy_async_queue(&serial->write_q); async_terminate_queue( &serial->write_q, STATUS_CANCELLED );
destroy_async_queue(&serial->wait_q); async_terminate_queue( &serial->wait_q, STATUS_CANCELLED );
if (serial->fd) release_object( serial->fd ); if (serial->fd) release_object( serial->fd );
} }
...@@ -189,12 +188,9 @@ static int serial_get_poll_events( struct fd *fd ) ...@@ -189,12 +188,9 @@ static int serial_get_poll_events( struct fd *fd )
int events = 0; int events = 0;
assert( serial->obj.ops == &serial_ops ); assert( serial->obj.ops == &serial_ops );
if(IS_READY(serial->read_q)) if (serial->read_q) events |= POLLIN;
events |= POLLIN; if (serial->write_q) events |= POLLOUT;
if(IS_READY(serial->write_q)) if (serial->wait_q) events |= POLLIN;
events |= POLLOUT;
if(IS_READY(serial->wait_q))
events |= POLLIN;
/* fprintf(stderr,"poll events are %04x\n",events); */ /* fprintf(stderr,"poll events are %04x\n",events); */
...@@ -225,39 +221,40 @@ static void serial_poll_event(struct fd *fd, int event) ...@@ -225,39 +221,40 @@ static void serial_poll_event(struct fd *fd, int event)
/* fprintf(stderr,"Poll event %02x\n",event); */ /* fprintf(stderr,"Poll event %02x\n",event); */
if(IS_READY(serial->read_q) && (POLLIN & event) ) if (serial->read_q && (POLLIN & event) )
async_notify(serial->read_q.head,STATUS_ALERTED); async_terminate( serial->read_q, STATUS_ALERTED );
if(IS_READY(serial->write_q) && (POLLOUT & event) ) if (serial->write_q && (POLLOUT & event) )
async_notify(serial->write_q.head,STATUS_ALERTED); async_terminate( serial->write_q, STATUS_ALERTED );
if(IS_READY(serial->wait_q) && (POLLIN & event) ) if (serial->wait_q && (POLLIN & event) )
async_notify(serial->wait_q.head,STATUS_ALERTED); async_terminate( serial->wait_q, STATUS_ALERTED );
set_fd_events( fd, serial_get_poll_events(fd) ); set_fd_events( fd, serial_get_poll_events(fd) );
} }
static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count) static void serial_queue_async( struct fd *fd, void *apc, void *user, void *iosb,
int type, int count )
{ {
struct serial *serial = get_fd_user( fd ); struct serial *serial = get_fd_user( fd );
struct async_queue *q; struct async **head;
struct async *async;
int timeout; int timeout;
int events;
assert(serial->obj.ops == &serial_ops); assert(serial->obj.ops == &serial_ops);
switch(type) switch (type)
{ {
case ASYNC_TYPE_READ: case ASYNC_TYPE_READ:
q = &serial->read_q; head = &serial->read_q;
timeout = serial->readconst + serial->readmult*count; timeout = serial->readconst + serial->readmult*count;
break; break;
case ASYNC_TYPE_WAIT: case ASYNC_TYPE_WAIT:
q = &serial->wait_q; head = &serial->wait_q;
timeout = 0; timeout = 0;
break; break;
case ASYNC_TYPE_WRITE: case ASYNC_TYPE_WRITE:
q = &serial->write_q; head = &serial->write_q;
timeout = serial->writeconst + serial->writemult*count; timeout = serial->writeconst + serial->writemult*count;
break; break;
default: default:
...@@ -265,37 +262,29 @@ static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, in ...@@ -265,37 +262,29 @@ static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, in
return; return;
} }
async = find_async ( q, current, ptr ); if (!create_async( fd, current, timeout, head, apc, user, iosb ))
return;
if ( status == STATUS_PENDING ) /* Check if the new pending request can be served immediately */
events = check_fd_events( fd, serial_get_poll_events( fd ) );
if (events)
{ {
int events; /* serial_poll_event() calls set_select_events() */
serial_poll_event( fd, events );
if ( !async ) return;
async = create_async ( &serial->obj, current, ptr ); }
if ( !async )
return;
async->status = STATUS_PENDING; set_fd_events( fd, serial_get_poll_events( fd ) );
if(!async->q) }
{
async_add_timeout(async,timeout);
async_insert(q, async);
}
/* Check if the new pending request can be served immediately */ static void serial_cancel_async( struct fd *fd )
events = check_fd_events( fd, serial_get_poll_events( fd ) ); {
if (events) struct serial *serial = get_fd_user( fd );
{ assert(serial->obj.ops == &serial_ops);
/* serial_poll_event() calls set_select_events() */
serial_poll_event( fd, events );
return;
}
}
else if ( async ) destroy_async ( async );
else set_error ( STATUS_INVALID_PARAMETER );
set_fd_events ( fd, serial_get_poll_events( fd ) ); async_terminate_queue( &serial->read_q, STATUS_CANCELLED );
async_terminate_queue( &serial->write_q, STATUS_CANCELLED );
async_terminate_queue( &serial->wait_q, STATUS_CANCELLED );
} }
static int serial_flush( struct fd *fd, struct event **event ) static int serial_flush( struct fd *fd, struct event **event )
...@@ -338,7 +327,7 @@ DECL_HANDLER(set_serial_info) ...@@ -338,7 +327,7 @@ DECL_HANDLER(set_serial_info)
if ((serial = get_serial_obj( current->process, req->handle, 0 ))) if ((serial = get_serial_obj( current->process, req->handle, 0 )))
{ {
/* timeouts */ /* timeouts */
if(req->flags & SERIALINFO_SET_TIMEOUTS) if (req->flags & SERIALINFO_SET_TIMEOUTS)
{ {
serial->readinterval = req->readinterval; serial->readinterval = req->readinterval;
serial->readconst = req->readconst; serial->readconst = req->readconst;
...@@ -348,21 +337,17 @@ DECL_HANDLER(set_serial_info) ...@@ -348,21 +337,17 @@ DECL_HANDLER(set_serial_info)
} }
/* event mask */ /* event mask */
if(req->flags & SERIALINFO_SET_MASK) if (req->flags & SERIALINFO_SET_MASK)
{ {
serial->eventmask = req->eventmask; serial->eventmask = req->eventmask;
if(!serial->eventmask) if (!serial->eventmask)
{ {
while(serial->wait_q.head) async_terminate_queue( &serial->wait_q, STATUS_SUCCESS );
{
async_notify(serial->wait_q.head, STATUS_SUCCESS);
destroy_async(serial->wait_q.head);
}
} }
} }
/* comm port error status */ /* comm port error status */
if(req->flags & SERIALINFO_SET_ERROR) if (req->flags & SERIALINFO_SET_ERROR)
{ {
serial->commerror = req->commerror; serial->commerror = req->commerror;
} }
......
...@@ -71,7 +71,8 @@ static const struct fd_ops handler_fd_ops = ...@@ -71,7 +71,8 @@ static const struct fd_ops handler_fd_ops =
handler_poll_event, /* poll_event */ handler_poll_event, /* poll_event */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
no_queue_async /* queue_async */ no_queue_async, /* queue_async */
no_cancel_async /* cancel_async */
}; };
static struct handler *handler_sighup; static struct handler *handler_sighup;
......
...@@ -56,7 +56,6 @@ ...@@ -56,7 +56,6 @@
#include "thread.h" #include "thread.h"
#include "request.h" #include "request.h"
#include "user.h" #include "user.h"
#include "async.h"
/* To avoid conflicts with the Unix socket headers. Plus we only need a few /* To avoid conflicts with the Unix socket headers. Plus we only need a few
* macros anyway. * macros anyway.
...@@ -81,9 +80,9 @@ struct sock ...@@ -81,9 +80,9 @@ struct sock
unsigned int message; /* message to send */ unsigned int message; /* message to send */
obj_handle_t wparam; /* message wparam (socket handle) */ obj_handle_t wparam; /* message wparam (socket handle) */
int errors[FD_MAX_EVENTS]; /* event errors */ int errors[FD_MAX_EVENTS]; /* event errors */
struct sock* deferred; /* socket that waits for a deferred accept */ struct sock *deferred; /* socket that waits for a deferred accept */
struct async_queue read_q; /* Queue for asynchronous reads */ struct async *read_q; /* Queue for asynchronous reads */
struct async_queue write_q; /* Queue for asynchronous writes */ struct async *write_q; /* Queue for asynchronous writes */
}; };
static void sock_dump( struct object *obj, int verbose ); static void sock_dump( struct object *obj, int verbose );
...@@ -94,7 +93,8 @@ static void sock_destroy( struct object *obj ); ...@@ -94,7 +93,8 @@ static void sock_destroy( struct object *obj );
static int sock_get_poll_events( struct fd *fd ); static int sock_get_poll_events( struct fd *fd );
static void sock_poll_event( struct fd *fd, int event ); static void sock_poll_event( struct fd *fd, int event );
static int sock_get_info( struct fd *fd ); static int sock_get_info( struct fd *fd );
static void sock_queue_async( struct fd *fd, void *ptr, unsigned int status, int type, int count ); static void sock_queue_async( struct fd *fd, void *apc, void *user, void *iosb, int type, int count );
static void sock_cancel_async( struct fd *fd );
static int sock_get_error( int err ); static int sock_get_error( int err );
static void sock_set_error(void); static void sock_set_error(void);
...@@ -117,7 +117,8 @@ static const struct fd_ops sock_fd_ops = ...@@ -117,7 +117,8 @@ static const struct fd_ops sock_fd_ops =
sock_poll_event, /* poll_event */ sock_poll_event, /* poll_event */
no_flush, /* flush */ no_flush, /* flush */
sock_get_info, /* get_file_info */ sock_get_info, /* get_file_info */
sock_queue_async /* queue_async */ sock_queue_async, /* queue_async */
sock_cancel_async /* cancel_async */
}; };
...@@ -150,48 +151,48 @@ typedef enum { ...@@ -150,48 +151,48 @@ typedef enum {
static sock_shutdown_t sock_shutdown_type = SOCK_SHUTDOWN_ERROR; static sock_shutdown_t sock_shutdown_type = SOCK_SHUTDOWN_ERROR;
static sock_shutdown_t sock_check_pollhup (void) static sock_shutdown_t sock_check_pollhup(void)
{ {
sock_shutdown_t ret = SOCK_SHUTDOWN_ERROR; sock_shutdown_t ret = SOCK_SHUTDOWN_ERROR;
int fd[2], n; int fd[2], n;
struct pollfd pfd; struct pollfd pfd;
char dummy; char dummy;
if ( socketpair ( AF_UNIX, SOCK_STREAM, 0, fd ) ) goto out; if ( socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) ) goto out;
if ( shutdown ( fd[0], 1 ) ) goto out; if ( shutdown( fd[0], 1 ) ) goto out;
pfd.fd = fd[1]; pfd.fd = fd[1];
pfd.events = POLLIN; pfd.events = POLLIN;
pfd.revents = 0; pfd.revents = 0;
n = poll ( &pfd, 1, 0 ); n = poll( &pfd, 1, 0 );
if ( n != 1 ) goto out; /* error or timeout */ if ( n != 1 ) goto out; /* error or timeout */
if ( pfd.revents & POLLHUP ) if ( pfd.revents & POLLHUP )
ret = SOCK_SHUTDOWN_POLLHUP; ret = SOCK_SHUTDOWN_POLLHUP;
else if ( pfd.revents & POLLIN && else if ( pfd.revents & POLLIN &&
read ( fd[1], &dummy, 1 ) == 0 ) read( fd[1], &dummy, 1 ) == 0 )
ret = SOCK_SHUTDOWN_EOF; ret = SOCK_SHUTDOWN_EOF;
out: out:
close ( fd[0] ); close( fd[0] );
close ( fd[1] ); close( fd[1] );
return ret; return ret;
} }
void sock_init(void) void sock_init(void)
{ {
sock_shutdown_type = sock_check_pollhup (); sock_shutdown_type = sock_check_pollhup();
switch ( sock_shutdown_type ) switch ( sock_shutdown_type )
{ {
case SOCK_SHUTDOWN_EOF: case SOCK_SHUTDOWN_EOF:
if (debug_level) fprintf ( stderr, "sock_init: shutdown() causes EOF\n" ); if (debug_level) fprintf( stderr, "sock_init: shutdown() causes EOF\n" );
break; break;
case SOCK_SHUTDOWN_POLLHUP: case SOCK_SHUTDOWN_POLLHUP:
if (debug_level) fprintf ( stderr, "sock_init: shutdown() causes POLLHUP\n" ); if (debug_level) fprintf( stderr, "sock_init: shutdown() causes POLLHUP\n" );
break; break;
default: default:
fprintf ( stderr, "sock_init: ERROR in sock_check_pollhup()\n" ); fprintf( stderr, "sock_init: ERROR in sock_check_pollhup()\n" );
sock_shutdown_type = SOCK_SHUTDOWN_EOF; sock_shutdown_type = SOCK_SHUTDOWN_EOF;
} }
} }
...@@ -217,13 +218,13 @@ static int sock_reselect( struct sock *sock ) ...@@ -217,13 +218,13 @@ static int sock_reselect( struct sock *sock )
/* After POLLHUP is received, the socket will no longer be in the main select loop. /* After POLLHUP is received, the socket will no longer be in the main select loop.
This function is used to signal pending events nevertheless */ This function is used to signal pending events nevertheless */
static void sock_try_event ( struct sock *sock, int event ) static void sock_try_event( struct sock *sock, int event )
{ {
event = check_fd_events( sock->fd, event ); event = check_fd_events( sock->fd, event );
if (event) if (event)
{ {
if ( debug_level ) fprintf ( stderr, "sock_try_event: %x\n", event ); if ( debug_level ) fprintf( stderr, "sock_try_event: %x\n", event );
sock_poll_event ( sock->fd, event ); sock_poll_event( sock->fd, event );
} }
} }
...@@ -236,16 +237,16 @@ static void sock_wake_up( struct sock *sock, int pollev ) ...@@ -236,16 +237,16 @@ static void sock_wake_up( struct sock *sock, int pollev )
if ( sock->flags & WSA_FLAG_OVERLAPPED ) if ( sock->flags & WSA_FLAG_OVERLAPPED )
{ {
if( pollev & (POLLIN|POLLPRI) && IS_READY( sock->read_q ) ) if ( pollev & (POLLIN|POLLPRI) && sock->read_q )
{ {
if (debug_level) fprintf ( stderr, "activating read queue for socket %p\n", sock ); if (debug_level) fprintf( stderr, "activating read queue for socket %p\n", sock );
async_notify( sock->read_q.head, STATUS_ALERTED ); async_terminate( sock->read_q, STATUS_ALERTED );
async_active = 1; async_active = 1;
} }
if( pollev & POLLOUT && IS_READY( sock->write_q ) ) if ( pollev & POLLOUT && sock->write_q )
{ {
if (debug_level) fprintf ( stderr, "activating write queue for socket %p\n", sock ); if (debug_level) fprintf( stderr, "activating write queue for socket %p\n", sock );
async_notify( sock->write_q.head, STATUS_ALERTED ); async_terminate( sock->write_q, STATUS_ALERTED );
async_active = 1; async_active = 1;
} }
} }
...@@ -315,8 +316,8 @@ static void sock_poll_event( struct fd *fd, int event ) ...@@ -315,8 +316,8 @@ static void sock_poll_event( struct fd *fd, int event )
if (debug_level) if (debug_level)
fprintf(stderr, "socket %p connection failure\n", sock); fprintf(stderr, "socket %p connection failure\n", sock);
} }
} else }
if (sock->state & FD_WINE_LISTENING) else if (sock->state & FD_WINE_LISTENING)
{ {
/* listening */ /* listening */
if (event & POLLIN) if (event & POLLIN)
...@@ -333,7 +334,8 @@ static void sock_poll_event( struct fd *fd, int event ) ...@@ -333,7 +334,8 @@ static void sock_poll_event( struct fd *fd, int event )
sock->errors[FD_ACCEPT_BIT] = sock_error( fd ); sock->errors[FD_ACCEPT_BIT] = sock_error( fd );
sock->hmask |= FD_ACCEPT; sock->hmask |= FD_ACCEPT;
} }
} else }
else
{ {
/* normal data flow */ /* normal data flow */
if ( sock->type == SOCK_STREAM && ( event & POLLIN ) ) if ( sock->type == SOCK_STREAM && ( event & POLLIN ) )
...@@ -364,7 +366,7 @@ static void sock_poll_event( struct fd *fd, int event ) ...@@ -364,7 +366,7 @@ static void sock_poll_event( struct fd *fd, int event )
else else
{ {
if ( debug_level ) if ( debug_level )
fprintf ( stderr, "recv error on socket %p: %d\n", sock, errno ); fprintf( stderr, "recv error on socket %p: %d\n", sock, errno );
event = POLLERR; event = POLLERR;
} }
} }
...@@ -418,7 +420,7 @@ static void sock_poll_event( struct fd *fd, int event ) ...@@ -418,7 +420,7 @@ static void sock_poll_event( struct fd *fd, int event )
if ( sock->pmask & FD_CLOSE || event & (POLLERR|POLLHUP) ) if ( sock->pmask & FD_CLOSE || event & (POLLERR|POLLHUP) )
{ {
if ( debug_level ) if ( debug_level )
fprintf ( stderr, "removing socket %p from select loop\n", sock ); fprintf( stderr, "removing socket %p from select loop\n", sock );
set_fd_events( sock->fd, -1 ); set_fd_events( sock->fd, -1 );
} }
else else
...@@ -464,9 +466,9 @@ static int sock_get_poll_events( struct fd *fd ) ...@@ -464,9 +466,9 @@ static int sock_get_poll_events( struct fd *fd )
/* listening, wait for readable */ /* listening, wait for readable */
return (sock->hmask & FD_ACCEPT) ? 0 : POLLIN; return (sock->hmask & FD_ACCEPT) ? 0 : POLLIN;
if (mask & (FD_READ) || (sock->flags & WSA_FLAG_OVERLAPPED && IS_READY (sock->read_q))) if (mask & (FD_READ) || (sock->flags & WSA_FLAG_OVERLAPPED && sock->read_q))
ev |= POLLIN | POLLPRI; ev |= POLLIN | POLLPRI;
if (mask & FD_WRITE || (sock->flags & WSA_FLAG_OVERLAPPED && IS_READY (sock->write_q))) if (mask & FD_WRITE || (sock->flags & WSA_FLAG_OVERLAPPED && sock->write_q))
ev |= POLLOUT; ev |= POLLOUT;
/* We use POLLIN with 0 bytes recv() as FD_CLOSE indication for stream sockets. */ /* We use POLLIN with 0 bytes recv() as FD_CLOSE indication for stream sockets. */
if ( sock->type == SOCK_STREAM && ( sock->mask & ~sock->hmask & FD_CLOSE) ) if ( sock->type == SOCK_STREAM && ( sock->mask & ~sock->hmask & FD_CLOSE) )
...@@ -479,7 +481,7 @@ static int sock_get_info( struct fd *fd ) ...@@ -479,7 +481,7 @@ static int sock_get_info( struct fd *fd )
{ {
int flags = FD_FLAG_AVAILABLE; int flags = FD_FLAG_AVAILABLE;
struct sock *sock = get_fd_user( fd ); struct sock *sock = get_fd_user( fd );
assert ( sock->obj.ops == &sock_ops ); assert( sock->obj.ops == &sock_ops );
if (sock->flags & WSA_FLAG_OVERLAPPED) flags |= FD_FLAG_OVERLAPPED; if (sock->flags & WSA_FLAG_OVERLAPPED) flags |= FD_FLAG_OVERLAPPED;
if ( sock->type != SOCK_STREAM || sock->state & FD_WINE_CONNECTED ) if ( sock->type != SOCK_STREAM || sock->state & FD_WINE_CONNECTED )
...@@ -490,62 +492,57 @@ static int sock_get_info( struct fd *fd ) ...@@ -490,62 +492,57 @@ static int sock_get_info( struct fd *fd )
return flags; return flags;
} }
static void sock_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count) static void sock_queue_async( struct fd *fd, void *apc, void *user, void *iosb,
int type, int count )
{ {
struct sock *sock = get_fd_user( fd ); struct sock *sock = get_fd_user( fd );
struct async_queue *q; struct async **head;
struct async *async;
int pollev; int pollev;
assert( sock->obj.ops == &sock_ops ); assert( sock->obj.ops == &sock_ops );
if ( !(sock->flags & WSA_FLAG_OVERLAPPED) ) if ( !(sock->flags & WSA_FLAG_OVERLAPPED) )
{ {
set_error ( STATUS_INVALID_HANDLE ); set_error( STATUS_INVALID_HANDLE );
return; return;
} }
switch( type ) switch (type)
{ {
case ASYNC_TYPE_READ: case ASYNC_TYPE_READ:
q = &sock->read_q; head = &sock->read_q;
sock->hmask &= ~FD_CLOSE; sock->hmask &= ~FD_CLOSE;
break; break;
case ASYNC_TYPE_WRITE: case ASYNC_TYPE_WRITE:
q = &sock->write_q; head = &sock->write_q;
break; break;
default: default:
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
return; return;
} }
async = find_async ( q, current, ptr ); if ( ( !( sock->state & FD_READ ) && type == ASYNC_TYPE_READ ) ||
( !( sock->state & FD_WRITE ) && type == ASYNC_TYPE_WRITE ) )
if ( status == STATUS_PENDING )
{ {
if ( ( !( sock->state & FD_READ ) && type == ASYNC_TYPE_READ ) || set_error( STATUS_PIPE_DISCONNECTED );
( !( sock->state & FD_WRITE ) && type == ASYNC_TYPE_WRITE ) ) }
{ else
set_error ( STATUS_PIPE_DISCONNECTED ); {
if ( async ) destroy_async ( async ); if (!create_async( fd, current, 0, head, apc, user, iosb ))
} return;
else
{
if ( !async )
async = create_async ( &sock->obj, current, ptr );
if ( !async )
return;
async->status = STATUS_PENDING;
if ( !async->q )
async_insert ( q, async );
}
} }
else if ( async ) destroy_async ( async );
else set_error ( STATUS_INVALID_PARAMETER );
pollev = sock_reselect ( sock ); pollev = sock_reselect( sock );
if ( pollev ) sock_try_event ( sock, pollev ); if ( pollev ) sock_try_event( sock, pollev );
}
static void sock_cancel_async( struct fd *fd )
{
struct sock *sock = get_fd_user( fd );
assert( sock->obj.ops == &sock_ops );
async_terminate_queue( &sock->read_q, STATUS_CANCELLED );
async_terminate_queue( &sock->write_q, STATUS_CANCELLED );
} }
static struct fd *sock_get_fd( struct object *obj ) static struct fd *sock_get_fd( struct object *obj )
...@@ -562,12 +559,12 @@ static void sock_destroy( struct object *obj ) ...@@ -562,12 +559,12 @@ static void sock_destroy( struct object *obj )
/* FIXME: special socket shutdown stuff? */ /* FIXME: special socket shutdown stuff? */
if ( sock->deferred ) if ( sock->deferred )
release_object ( sock->deferred ); release_object( sock->deferred );
if ( sock->flags & WSA_FLAG_OVERLAPPED ) if ( sock->flags & WSA_FLAG_OVERLAPPED )
{ {
destroy_async_queue ( &sock->read_q ); async_terminate_queue( &sock->read_q, STATUS_CANCELLED );
destroy_async_queue ( &sock->write_q ); async_terminate_queue( &sock->write_q, STATUS_CANCELLED );
} }
if (sock->event) release_object( sock->event ); if (sock->event) release_object( sock->event );
if (sock->fd) release_object( sock->fd ); if (sock->fd) release_object( sock->fd );
...@@ -582,7 +579,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne ...@@ -582,7 +579,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne
sockfd = socket( family, type, protocol ); sockfd = socket( family, type, protocol );
if (debug_level) if (debug_level)
fprintf(stderr,"socket(%d,%d,%d)=%d\n",family,type,protocol,sockfd); fprintf(stderr,"socket(%d,%d,%d)=%d\n",family,type,protocol,sockfd);
if (sockfd == -1) { if (sockfd == -1)
{
sock_set_error(); sock_set_error();
return NULL; return NULL;
} }
...@@ -612,8 +610,7 @@ static struct object *create_socket( int family, int type, int protocol, unsigne ...@@ -612,8 +610,7 @@ static struct object *create_socket( int family, int type, int protocol, unsigne
} }
if (sock->flags & WSA_FLAG_OVERLAPPED) if (sock->flags & WSA_FLAG_OVERLAPPED)
{ {
init_async_queue (&sock->read_q); sock->read_q = sock->write_q = NULL;
init_async_queue (&sock->write_q);
} }
sock_reselect( sock ); sock_reselect( sock );
clear_error(); clear_error();
...@@ -634,10 +631,13 @@ static struct sock *accept_socket( obj_handle_t handle ) ...@@ -634,10 +631,13 @@ static struct sock *accept_socket( obj_handle_t handle )
if (!sock) if (!sock)
return NULL; return NULL;
if ( sock->deferred ) { if ( sock->deferred )
{
acceptsock = sock->deferred; acceptsock = sock->deferred;
sock->deferred = NULL; sock->deferred = NULL;
} else { }
else
{
/* Try to accept(2). We can't be safe that this an already connected socket /* Try to accept(2). We can't be safe that this an already connected socket
* or that accept() is allowed on it. In those cases we will get -1/errno * or that accept() is allowed on it. In those cases we will get -1/errno
...@@ -645,7 +645,8 @@ static struct sock *accept_socket( obj_handle_t handle ) ...@@ -645,7 +645,8 @@ static struct sock *accept_socket( obj_handle_t handle )
*/ */
slen = sizeof(saddr); slen = sizeof(saddr);
acceptfd = accept( get_unix_fd(sock->fd), &saddr, &slen); acceptfd = accept( get_unix_fd(sock->fd), &saddr, &slen);
if (acceptfd==-1) { if (acceptfd==-1)
{
sock_set_error(); sock_set_error();
release_object( sock ); release_object( sock );
return NULL; return NULL;
...@@ -683,8 +684,7 @@ static struct sock *accept_socket( obj_handle_t handle ) ...@@ -683,8 +684,7 @@ static struct sock *accept_socket( obj_handle_t handle )
} }
if ( acceptsock->flags & WSA_FLAG_OVERLAPPED ) if ( acceptsock->flags & WSA_FLAG_OVERLAPPED )
{ {
init_async_queue ( &acceptsock->read_q ); acceptsock->read_q = acceptsock->write_q = NULL;
init_async_queue ( &acceptsock->write_q );
} }
} }
clear_error(); clear_error();
...@@ -700,62 +700,62 @@ static int sock_get_error( int err ) ...@@ -700,62 +700,62 @@ static int sock_get_error( int err )
{ {
switch (err) switch (err)
{ {
case EINTR: return WSAEINTR; break; case EINTR: return WSAEINTR;
case EBADF: return WSAEBADF; break; case EBADF: return WSAEBADF;
case EPERM: case EPERM:
case EACCES: return WSAEACCES; break; case EACCES: return WSAEACCES;
case EFAULT: return WSAEFAULT; break; case EFAULT: return WSAEFAULT;
case EINVAL: return WSAEINVAL; break; case EINVAL: return WSAEINVAL;
case EMFILE: return WSAEMFILE; break; case EMFILE: return WSAEMFILE;
case EWOULDBLOCK: return WSAEWOULDBLOCK; break; case EWOULDBLOCK: return WSAEWOULDBLOCK;
case EINPROGRESS: return WSAEINPROGRESS; break; case EINPROGRESS: return WSAEINPROGRESS;
case EALREADY: return WSAEALREADY; break; case EALREADY: return WSAEALREADY;
case ENOTSOCK: return WSAENOTSOCK; break; case ENOTSOCK: return WSAENOTSOCK;
case EDESTADDRREQ: return WSAEDESTADDRREQ; break; case EDESTADDRREQ: return WSAEDESTADDRREQ;
case EMSGSIZE: return WSAEMSGSIZE; break; case EMSGSIZE: return WSAEMSGSIZE;
case EPROTOTYPE: return WSAEPROTOTYPE; break; case EPROTOTYPE: return WSAEPROTOTYPE;
case ENOPROTOOPT: return WSAENOPROTOOPT; break; case ENOPROTOOPT: return WSAENOPROTOOPT;
case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT; break; case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT; break; case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
case EOPNOTSUPP: return WSAEOPNOTSUPP; break; case EOPNOTSUPP: return WSAEOPNOTSUPP;
case EPFNOSUPPORT: return WSAEPFNOSUPPORT; break; case EPFNOSUPPORT: return WSAEPFNOSUPPORT;
case EAFNOSUPPORT: return WSAEAFNOSUPPORT; break; case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
case EADDRINUSE: return WSAEADDRINUSE; break; case EADDRINUSE: return WSAEADDRINUSE;
case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL; break; case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
case ENETDOWN: return WSAENETDOWN; break; case ENETDOWN: return WSAENETDOWN;
case ENETUNREACH: return WSAENETUNREACH; break; case ENETUNREACH: return WSAENETUNREACH;
case ENETRESET: return WSAENETRESET; break; case ENETRESET: return WSAENETRESET;
case ECONNABORTED: return WSAECONNABORTED; break; case ECONNABORTED: return WSAECONNABORTED;
case EPIPE: case EPIPE:
case ECONNRESET: return WSAECONNRESET; break; case ECONNRESET: return WSAECONNRESET;
case ENOBUFS: return WSAENOBUFS; break; case ENOBUFS: return WSAENOBUFS;
case EISCONN: return WSAEISCONN; break; case EISCONN: return WSAEISCONN;
case ENOTCONN: return WSAENOTCONN; break; case ENOTCONN: return WSAENOTCONN;
case ESHUTDOWN: return WSAESHUTDOWN; break; case ESHUTDOWN: return WSAESHUTDOWN;
case ETOOMANYREFS: return WSAETOOMANYREFS; break; case ETOOMANYREFS: return WSAETOOMANYREFS;
case ETIMEDOUT: return WSAETIMEDOUT; break; case ETIMEDOUT: return WSAETIMEDOUT;
case ECONNREFUSED: return WSAECONNREFUSED; break; case ECONNREFUSED: return WSAECONNREFUSED;
case ELOOP: return WSAELOOP; break; case ELOOP: return WSAELOOP;
case ENAMETOOLONG: return WSAENAMETOOLONG; break; case ENAMETOOLONG: return WSAENAMETOOLONG;
case EHOSTDOWN: return WSAEHOSTDOWN; break; case EHOSTDOWN: return WSAEHOSTDOWN;
case EHOSTUNREACH: return WSAEHOSTUNREACH; break; case EHOSTUNREACH: return WSAEHOSTUNREACH;
case ENOTEMPTY: return WSAENOTEMPTY; break; case ENOTEMPTY: return WSAENOTEMPTY;
#ifdef EPROCLIM #ifdef EPROCLIM
case EPROCLIM: return WSAEPROCLIM; break; case EPROCLIM: return WSAEPROCLIM;
#endif #endif
#ifdef EUSERS #ifdef EUSERS
case EUSERS: return WSAEUSERS; break; case EUSERS: return WSAEUSERS;
#endif #endif
#ifdef EDQUOT #ifdef EDQUOT
case EDQUOT: return WSAEDQUOT; break; case EDQUOT: return WSAEDQUOT;
#endif #endif
#ifdef ESTALE #ifdef ESTALE
case ESTALE: return WSAESTALE; break; case ESTALE: return WSAESTALE;
#endif #endif
#ifdef EREMOTE #ifdef EREMOTE
case EREMOTE: return WSAEREMOTE; break; case EREMOTE: return WSAEREMOTE;
#endif #endif
default: errno=err; perror("sock_set_error"); return WSAEFAULT; break; default: errno=err; perror("sock_set_error"); return WSAEFAULT;
} }
} }
...@@ -814,7 +814,7 @@ DECL_HANDLER(set_socket_event) ...@@ -814,7 +814,7 @@ DECL_HANDLER(set_socket_event)
if (debug_level && sock->event) fprintf(stderr, "event ptr: %p\n", sock->event); if (debug_level && sock->event) fprintf(stderr, "event ptr: %p\n", sock->event);
pollev = sock_reselect( sock ); pollev = sock_reselect( sock );
if ( pollev ) sock_try_event ( sock, pollev ); if ( pollev ) sock_try_event( sock, pollev );
if (sock->mask) if (sock->mask)
sock->state |= FD_WINE_NONBLOCKING; sock->state |= FD_WINE_NONBLOCKING;
...@@ -885,7 +885,7 @@ DECL_HANDLER(enable_socket_event) ...@@ -885,7 +885,7 @@ DECL_HANDLER(enable_socket_event)
if ( sock->type != SOCK_STREAM ) sock->state &= ~STREAM_FLAG_MASK; if ( sock->type != SOCK_STREAM ) sock->state &= ~STREAM_FLAG_MASK;
pollev = sock_reselect( sock ); pollev = sock_reselect( sock );
if ( pollev ) sock_try_event ( sock, pollev ); if ( pollev ) sock_try_event( sock, pollev );
release_object( &sock->obj ); release_object( &sock->obj );
} }
...@@ -898,17 +898,17 @@ DECL_HANDLER(set_socket_deferred) ...@@ -898,17 +898,17 @@ DECL_HANDLER(set_socket_deferred)
GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops ); GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops );
if ( !sock ) if ( !sock )
{ {
set_error ( WSAENOTSOCK ); set_error( WSAENOTSOCK );
return; return;
} }
acceptsock = (struct sock*)get_handle_obj( current->process,req->deferred, acceptsock = (struct sock*)get_handle_obj( current->process,req->deferred,
GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops ); GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops );
if ( !acceptsock ) if ( !acceptsock )
{ {
release_object ( sock ); release_object( sock );
set_error ( WSAENOTSOCK ); set_error( WSAENOTSOCK );
return; return;
} }
sock->deferred = acceptsock; sock->deferred = acceptsock;
release_object ( sock ); release_object( sock );
} }
...@@ -100,7 +100,8 @@ static const struct fd_ops thread_fd_ops = ...@@ -100,7 +100,8 @@ static const struct fd_ops thread_fd_ops =
thread_poll_event, /* poll_event */ thread_poll_event, /* poll_event */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
no_queue_async /* queue_async */ no_queue_async, /* queue_async */
no_cancel_async /* cancel_async */
}; };
static struct thread *first_thread; static struct thread *first_thread;
......
...@@ -1948,9 +1948,15 @@ static void dump_register_async_request( const struct register_async_request *re ...@@ -1948,9 +1948,15 @@ static void dump_register_async_request( const struct register_async_request *re
{ {
fprintf( stderr, " handle=%p,", req->handle ); fprintf( stderr, " handle=%p,", req->handle );
fprintf( stderr, " type=%d,", req->type ); fprintf( stderr, " type=%d,", req->type );
fprintf( stderr, " overlapped=%p,", req->overlapped ); fprintf( stderr, " io_apc=%p,", req->io_apc );
fprintf( stderr, " count=%d,", req->count ); fprintf( stderr, " io_sb=%p,", req->io_sb );
fprintf( stderr, " status=%08x", req->status ); fprintf( stderr, " io_user=%p,", req->io_user );
fprintf( stderr, " count=%d", req->count );
}
static void dump_cancel_async_request( const struct cancel_async_request *req )
{
fprintf( stderr, " handle=%p", req->handle );
} }
static void dump_create_named_pipe_request( const struct create_named_pipe_request *req ) static void dump_create_named_pipe_request( const struct create_named_pipe_request *req )
...@@ -2730,6 +2736,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { ...@@ -2730,6 +2736,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_serial_info_request, (dump_func)dump_get_serial_info_request,
(dump_func)dump_set_serial_info_request, (dump_func)dump_set_serial_info_request,
(dump_func)dump_register_async_request, (dump_func)dump_register_async_request,
(dump_func)dump_cancel_async_request,
(dump_func)dump_create_named_pipe_request, (dump_func)dump_create_named_pipe_request,
(dump_func)dump_open_named_pipe_request, (dump_func)dump_open_named_pipe_request,
(dump_func)dump_connect_named_pipe_request, (dump_func)dump_connect_named_pipe_request,
...@@ -2912,6 +2919,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { ...@@ -2912,6 +2919,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_serial_info_reply, (dump_func)dump_get_serial_info_reply,
(dump_func)0, (dump_func)0,
(dump_func)0, (dump_func)0,
(dump_func)0,
(dump_func)dump_create_named_pipe_reply, (dump_func)dump_create_named_pipe_reply,
(dump_func)dump_open_named_pipe_reply, (dump_func)dump_open_named_pipe_reply,
(dump_func)0, (dump_func)0,
...@@ -3094,6 +3102,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { ...@@ -3094,6 +3102,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"get_serial_info", "get_serial_info",
"set_serial_info", "set_serial_info",
"register_async", "register_async",
"cancel_async",
"create_named_pipe", "create_named_pipe",
"open_named_pipe", "open_named_pipe",
"connect_named_pipe", "connect_named_pipe",
......
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