- separate cleanly between async scheduling and file IO related issues.
- make the API compatible with other types of async requests (e.g. for sockets). - remove exports of async IO related functions for DLL separation.
This commit is contained in:
parent
ce73456d80
commit
2b47fb3cee
|
@ -80,6 +80,7 @@
|
|||
#include "winerror.h"
|
||||
|
||||
#include "wine/server.h"
|
||||
#include "async.h"
|
||||
#include "file.h"
|
||||
#include "heap.h"
|
||||
|
||||
|
@ -91,6 +92,52 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(comm);
|
||||
|
||||
/***********************************************************************
|
||||
* Asynchronous I/O for asynchronous wait requests *
|
||||
*/
|
||||
|
||||
static DWORD commio_get_async_status (const async_private *ovp);
|
||||
static DWORD commio_get_async_count (const async_private *ovp);
|
||||
static void commio_set_async_status (async_private *ovp, const DWORD status);
|
||||
static void CALLBACK commio_call_completion_func (ULONG_PTR data);
|
||||
|
||||
static async_ops commio_async_ops =
|
||||
{
|
||||
commio_get_async_status, /* get_status */
|
||||
commio_set_async_status, /* set_status */
|
||||
commio_get_async_count, /* get_count */
|
||||
commio_call_completion_func /* call_completion */
|
||||
};
|
||||
|
||||
typedef struct async_commio
|
||||
{
|
||||
struct async_private async;
|
||||
LPOVERLAPPED lpOverlapped;
|
||||
char *buffer;
|
||||
} async_commio;
|
||||
|
||||
static DWORD commio_get_async_status (const struct async_private *ovp)
|
||||
{
|
||||
return ((async_commio*) ovp)->lpOverlapped->Internal;
|
||||
}
|
||||
|
||||
static void commio_set_async_status (async_private *ovp, const DWORD status)
|
||||
{
|
||||
((async_commio*) ovp)->lpOverlapped->Internal = status;
|
||||
}
|
||||
|
||||
static DWORD commio_get_async_count (const struct async_private *ovp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void CALLBACK commio_call_completion_func (ULONG_PTR data)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, (void*) data);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
#if !defined(TIOCINQ) && defined(FIONREAD)
|
||||
#define TIOCINQ FIONREAD
|
||||
#endif
|
||||
|
@ -1558,12 +1605,13 @@ BOOL WINAPI GetCommModemStatus(
|
|||
*/
|
||||
static void COMM_WaitCommEventService(async_private *ovp)
|
||||
{
|
||||
LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
|
||||
async_commio *commio = (async_commio*) ovp;
|
||||
LPOVERLAPPED lpOverlapped = commio->lpOverlapped;
|
||||
|
||||
TRACE("overlapped %p\n",lpOverlapped);
|
||||
|
||||
/* FIXME: detect other events */
|
||||
*ovp->buffer = EV_RXCHAR;
|
||||
*commio->buffer = EV_RXCHAR;
|
||||
|
||||
lpOverlapped->Internal = STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -1579,8 +1627,8 @@ static BOOL COMM_WaitCommEvent(
|
|||
LPDWORD lpdwEvents, /* [out] event(s) that were detected */
|
||||
LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
|
||||
{
|
||||
int fd,ret;
|
||||
async_private *ovp;
|
||||
int fd;
|
||||
async_commio *ovp;
|
||||
|
||||
if(!lpOverlapped)
|
||||
{
|
||||
|
@ -1591,53 +1639,32 @@ static BOOL COMM_WaitCommEvent(
|
|||
if(NtResetEvent(lpOverlapped->hEvent,NULL))
|
||||
return FALSE;
|
||||
|
||||
lpOverlapped->Internal = STATUS_PENDING;
|
||||
lpOverlapped->InternalHigh = 0;
|
||||
lpOverlapped->Offset = 0;
|
||||
lpOverlapped->OffsetHigh = 0;
|
||||
|
||||
fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
|
||||
if(fd<0)
|
||||
return FALSE;
|
||||
|
||||
ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
|
||||
ovp = (async_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio));
|
||||
if(!ovp)
|
||||
{
|
||||
close(fd);
|
||||
return FALSE;
|
||||
}
|
||||
ovp->event = lpOverlapped->hEvent;
|
||||
|
||||
ovp->async.ops = &commio_async_ops;
|
||||
ovp->async.handle = hFile;
|
||||
ovp->async.fd = fd;
|
||||
ovp->async.type = ASYNC_TYPE_WAIT;
|
||||
ovp->async.func = COMM_WaitCommEventService;
|
||||
ovp->async.event = lpOverlapped->hEvent;
|
||||
ovp->lpOverlapped = lpOverlapped;
|
||||
ovp->func = COMM_WaitCommEventService;
|
||||
ovp->buffer = (char *)lpdwEvents;
|
||||
ovp->fd = fd;
|
||||
ovp->count = 0;
|
||||
ovp->completion_func = 0;
|
||||
ovp->type = ASYNC_TYPE_WAIT;
|
||||
ovp->handle = hFile;
|
||||
|
||||
ovp->next = NtCurrentTeb()->pending_list;
|
||||
ovp->prev = NULL;
|
||||
if(ovp->next)
|
||||
ovp->next->prev=ovp;
|
||||
NtCurrentTeb()->pending_list = ovp;
|
||||
|
||||
/* start an ASYNCHRONOUS WaitCommEvent */
|
||||
SERVER_START_REQ( register_async )
|
||||
{
|
||||
req->handle = hFile;
|
||||
req->overlapped = lpOverlapped;
|
||||
req->type = ASYNC_TYPE_WAIT;
|
||||
req->count = 0;
|
||||
req->func = check_async_list;
|
||||
req->status = STATUS_PENDING;
|
||||
|
||||
ret=wine_server_call_err(req);
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
lpOverlapped->InternalHigh = 0;
|
||||
lpOverlapped->Offset = 0;
|
||||
lpOverlapped->OffsetHigh = 0;
|
||||
|
||||
if (!ret)
|
||||
SetLastError(ERROR_IO_PENDING);
|
||||
if ( !register_new_async (&ovp->async) )
|
||||
SetLastError( ERROR_IO_PENDING );
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
|
197
files/file.c
197
files/file.c
|
@ -51,8 +51,11 @@
|
|||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wine/winbase16.h"
|
||||
#include "wine/server.h"
|
||||
|
||||
#include "drive.h"
|
||||
#include "file.h"
|
||||
#include "async.h"
|
||||
#include "heap.h"
|
||||
#include "msdos.h"
|
||||
#include "wincon.h"
|
||||
|
@ -60,8 +63,6 @@
|
|||
#include "smb.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "wine/server.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(file);
|
||||
|
||||
#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
|
||||
|
@ -80,6 +81,61 @@ mode_t FILE_umask;
|
|||
|
||||
extern WINAPI HANDLE FILE_SmbOpen(LPCSTR name);
|
||||
|
||||
/***********************************************************************
|
||||
* Asynchronous file I/O *
|
||||
*/
|
||||
static DWORD fileio_get_async_status (const async_private *ovp);
|
||||
static DWORD fileio_get_async_count (const async_private *ovp);
|
||||
static void fileio_set_async_status (async_private *ovp, const DWORD status);
|
||||
static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
|
||||
|
||||
static async_ops fileio_async_ops =
|
||||
{
|
||||
fileio_get_async_status, /* get_status */
|
||||
fileio_set_async_status, /* set_status */
|
||||
fileio_get_async_count, /* get_count */
|
||||
fileio_call_completion_func /* call_completion */
|
||||
};
|
||||
|
||||
typedef struct async_fileio
|
||||
{
|
||||
struct async_private async;
|
||||
LPOVERLAPPED lpOverlapped;
|
||||
LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
|
||||
char *buffer;
|
||||
int count;
|
||||
} async_fileio;
|
||||
|
||||
static DWORD fileio_get_async_status (const struct async_private *ovp)
|
||||
{
|
||||
return ((async_fileio*) ovp)->lpOverlapped->Internal;
|
||||
}
|
||||
|
||||
static void fileio_set_async_status (async_private *ovp, const DWORD status)
|
||||
{
|
||||
((async_fileio*) ovp)->lpOverlapped->Internal = status;
|
||||
}
|
||||
|
||||
static DWORD fileio_get_async_count (const struct async_private *ovp)
|
||||
{
|
||||
async_fileio *fileio = (async_fileio*) ovp;
|
||||
DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
|
||||
return (ret < 0 ? 0 : ret);
|
||||
}
|
||||
|
||||
static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
|
||||
{
|
||||
async_fileio *ovp = (async_fileio*) data;
|
||||
TRACE ("data: %p\n", ovp);
|
||||
|
||||
if (ovp->completion_func)
|
||||
ovp->completion_func(ovp->lpOverlapped->Internal,
|
||||
ovp->lpOverlapped->InternalHigh,
|
||||
ovp->lpOverlapped);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, ovp);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* FILE_ConvertOFMode
|
||||
*
|
||||
|
@ -1344,30 +1400,6 @@ BOOL WINAPI GetOverlappedResult(
|
|||
return (r==WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* FILE_StartAsync (INTERNAL)
|
||||
*
|
||||
* type==ASYNC_TYPE_NONE means cancel the indicated overlapped operation
|
||||
* lpOverlapped==NULL means all overlappeds match
|
||||
*/
|
||||
BOOL FILE_StartAsync(HANDLE hFile, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status)
|
||||
{
|
||||
BOOL ret;
|
||||
SERVER_START_REQ(register_async)
|
||||
{
|
||||
req->handle = hFile;
|
||||
req->overlapped = lpOverlapped;
|
||||
req->type = type;
|
||||
req->count = count;
|
||||
req->func = check_async_list;
|
||||
req->status = status;
|
||||
ret = wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return !ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* CancelIo (KERNEL32.@)
|
||||
*/
|
||||
|
@ -1377,16 +1409,11 @@ BOOL WINAPI CancelIo(HANDLE handle)
|
|||
|
||||
TRACE("handle = %x\n",handle);
|
||||
|
||||
ovp = NtCurrentTeb()->pending_list;
|
||||
while(ovp)
|
||||
for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
|
||||
{
|
||||
t = ovp->next;
|
||||
if(FILE_StartAsync(handle, ovp->lpOverlapped, ovp->type, 0, STATUS_CANCELLED))
|
||||
{
|
||||
TRACE("overlapped = %p\n",ovp->lpOverlapped);
|
||||
finish_async(ovp, STATUS_CANCELLED);
|
||||
}
|
||||
ovp = t;
|
||||
if ( ovp->handle == handle )
|
||||
cancel_async ( ovp );
|
||||
}
|
||||
WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
|
||||
return TRUE;
|
||||
|
@ -1400,18 +1427,19 @@ BOOL WINAPI CancelIo(HANDLE handle)
|
|||
*/
|
||||
static void FILE_AsyncReadService(async_private *ovp)
|
||||
{
|
||||
LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
|
||||
async_fileio *fileio = (async_fileio*) ovp;
|
||||
LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
|
||||
int result, r;
|
||||
int already = lpOverlapped->InternalHigh;
|
||||
|
||||
TRACE("%p %p\n", lpOverlapped, ovp->buffer );
|
||||
TRACE("%p %p\n", lpOverlapped, fileio->buffer );
|
||||
|
||||
/* check to see if the data is ready (non-blocking) */
|
||||
|
||||
result = pread (ovp->fd, &ovp->buffer[already], ovp->count - already,
|
||||
result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
|
||||
OVERLAPPED_OFFSET (lpOverlapped) + already);
|
||||
if ((result < 0) && (errno == ESPIPE))
|
||||
result = read (ovp->fd, &ovp->buffer[already], ovp->count - already);
|
||||
result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
|
||||
|
||||
if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
|
||||
{
|
||||
|
@ -1429,9 +1457,9 @@ static void FILE_AsyncReadService(async_private *ovp)
|
|||
}
|
||||
|
||||
lpOverlapped->InternalHigh += result;
|
||||
TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
|
||||
TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
|
||||
|
||||
if(lpOverlapped->InternalHigh < ovp->count)
|
||||
if(lpOverlapped->InternalHigh < fileio->count)
|
||||
r = STATUS_PENDING;
|
||||
else
|
||||
r = STATUS_SUCCESS;
|
||||
|
@ -1448,7 +1476,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||
HANDLE hEvent)
|
||||
{
|
||||
async_private *ovp;
|
||||
async_fileio *ovp;
|
||||
int fd;
|
||||
|
||||
TRACE("file %d to buf %p num %ld %p func %p\n",
|
||||
|
@ -1468,7 +1496,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
|
||||
ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
|
||||
if(!ovp)
|
||||
{
|
||||
TRACE("HeapAlloc Failed\n");
|
||||
|
@ -1476,31 +1504,19 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
close(fd);
|
||||
return FALSE;
|
||||
}
|
||||
ovp->event = hEvent;
|
||||
|
||||
ovp->async.ops = &fileio_async_ops;
|
||||
ovp->async.handle = hFile;
|
||||
ovp->async.fd = fd;
|
||||
ovp->async.type = ASYNC_TYPE_READ;
|
||||
ovp->async.func = FILE_AsyncReadService;
|
||||
ovp->async.event = hEvent;
|
||||
ovp->lpOverlapped = overlapped;
|
||||
ovp->count = bytesToRead;
|
||||
ovp->completion_func = lpCompletionRoutine;
|
||||
ovp->func = FILE_AsyncReadService;
|
||||
ovp->buffer = buffer;
|
||||
ovp->fd = fd;
|
||||
ovp->type = ASYNC_TYPE_READ;
|
||||
ovp->handle = hFile;
|
||||
|
||||
/* hook this overlap into the pending async operation list */
|
||||
ovp->next = NtCurrentTeb()->pending_list;
|
||||
ovp->prev = NULL;
|
||||
if(ovp->next)
|
||||
ovp->next->prev = ovp;
|
||||
NtCurrentTeb()->pending_list = ovp;
|
||||
|
||||
if ( !FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_READ, bytesToRead, STATUS_PENDING) )
|
||||
{
|
||||
/* FIXME: remove async_private and release memory */
|
||||
ERR("FILE_StartAsync failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return !register_new_async (&ovp->async);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -1510,7 +1526,6 @@ BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
LPOVERLAPPED overlapped,
|
||||
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
|
||||
{
|
||||
overlapped->Internal = STATUS_PENDING;
|
||||
overlapped->InternalHigh = 0;
|
||||
return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
@ -1588,7 +1603,6 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
}
|
||||
|
||||
/* at last resort, do an overlapped read */
|
||||
overlapped->Internal = STATUS_PENDING;
|
||||
overlapped->InternalHigh = result;
|
||||
|
||||
if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
|
||||
|
@ -1646,18 +1660,19 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
*/
|
||||
static void FILE_AsyncWriteService(struct async_private *ovp)
|
||||
{
|
||||
LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
|
||||
async_fileio *fileio = (async_fileio *) ovp;
|
||||
LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
|
||||
int result, r;
|
||||
int already = lpOverlapped->InternalHigh;
|
||||
|
||||
TRACE("(%p %p)\n",lpOverlapped,ovp->buffer);
|
||||
TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
|
||||
|
||||
/* write some data (non-blocking) */
|
||||
|
||||
result = pwrite(ovp->fd, &ovp->buffer[already], ovp->count - already,
|
||||
result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
|
||||
OVERLAPPED_OFFSET (lpOverlapped) + already);
|
||||
if ((result < 0) && (errno == ESPIPE))
|
||||
result = write(ovp->fd, &ovp->buffer[already], ovp->count - already);
|
||||
result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
|
||||
|
||||
if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
|
||||
{
|
||||
|
@ -1674,9 +1689,9 @@ static void FILE_AsyncWriteService(struct async_private *ovp)
|
|||
|
||||
lpOverlapped->InternalHigh += result;
|
||||
|
||||
TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
|
||||
TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
|
||||
|
||||
if(lpOverlapped->InternalHigh < ovp->count)
|
||||
if(lpOverlapped->InternalHigh < fileio->count)
|
||||
r = STATUS_PENDING;
|
||||
else
|
||||
r = STATUS_SUCCESS;
|
||||
|
@ -1693,7 +1708,8 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
|
|||
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||
HANDLE hEvent)
|
||||
{
|
||||
async_private *ovp;
|
||||
async_fileio *ovp;
|
||||
int fd;
|
||||
|
||||
TRACE("file %d to buf %p num %ld %p func %p stub\n",
|
||||
hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
|
||||
|
@ -1704,46 +1720,34 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
overlapped->Internal = STATUS_PENDING;
|
||||
overlapped->InternalHigh = 0;
|
||||
|
||||
if (!FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_WRITE, bytesToWrite, STATUS_PENDING ))
|
||||
fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
|
||||
if ( fd < 0 )
|
||||
{
|
||||
TRACE("FILE_StartAsync failed\n");
|
||||
TRACE( "Couldn't get FD\n" );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ovp = (async_private*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
|
||||
ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
|
||||
if(!ovp)
|
||||
{
|
||||
TRACE("HeapAlloc Failed\n");
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
close (fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ovp->async.ops = &fileio_async_ops;
|
||||
ovp->async.handle = hFile;
|
||||
ovp->async.fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
|
||||
ovp->async.type = ASYNC_TYPE_WRITE;
|
||||
ovp->async.func = FILE_AsyncWriteService;
|
||||
ovp->lpOverlapped = overlapped;
|
||||
ovp->event = hEvent;
|
||||
ovp->func = FILE_AsyncWriteService;
|
||||
ovp->async.event = hEvent;
|
||||
ovp->buffer = (LPVOID) buffer;
|
||||
ovp->count = bytesToWrite;
|
||||
ovp->completion_func = lpCompletionRoutine;
|
||||
ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
|
||||
ovp->type = ASYNC_TYPE_WRITE;
|
||||
ovp->handle = hFile;
|
||||
|
||||
if(ovp->fd <0)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, ovp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* hook this overlap into the pending async operation list */
|
||||
ovp->next = NtCurrentTeb()->pending_list;
|
||||
ovp->prev = NULL;
|
||||
if(ovp->next)
|
||||
ovp->next->prev = ovp;
|
||||
NtCurrentTeb()->pending_list = ovp;
|
||||
|
||||
return TRUE;
|
||||
return !register_new_async (&ovp->async);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -1753,7 +1757,6 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
|
|||
LPOVERLAPPED overlapped,
|
||||
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
|
||||
{
|
||||
overlapped->Internal = STATUS_PENDING;
|
||||
overlapped->InternalHigh = 0;
|
||||
|
||||
return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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 "wine/server.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_status)(const struct async_private *ovp);
|
||||
typedef DWORD (*async_get_count)(const struct async_private *ovp);
|
||||
typedef void (*async_set_status)(struct async_private *ovp, const DWORD status);
|
||||
|
||||
typedef struct async_ops
|
||||
{
|
||||
async_get_status get_status;
|
||||
async_set_status set_status;
|
||||
async_get_count get_count;
|
||||
async_call_completion_func call_completion;
|
||||
} async_ops;
|
||||
|
||||
typedef struct async_private
|
||||
{
|
||||
struct async_ops *ops;
|
||||
HANDLE handle;
|
||||
HANDLE event;
|
||||
int fd;
|
||||
async_handler func;
|
||||
int type;
|
||||
struct async_private *next;
|
||||
struct async_private *prev;
|
||||
} async_private;
|
||||
|
||||
/* All functions declared static for Dll separation purposes */
|
||||
|
||||
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;
|
||||
|
||||
close( ovp->fd );
|
||||
if( ovp->event != INVALID_HANDLE_VALUE )
|
||||
NtSetEvent( ovp->event, NULL );
|
||||
|
||||
QueueUserAPC( ovp->ops->call_completion, GetCurrentThread(), (ULONG_PTR)ovp );
|
||||
}
|
||||
|
||||
inline static BOOL __register_async( async_private *ovp, const DWORD status )
|
||||
{
|
||||
BOOL 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->ops->set_status ( ovp, GetLastError() );
|
||||
if ( ovp->ops->get_status (ovp) != STATUS_PENDING )
|
||||
finish_async (ovp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define register_old_async(ovp) \
|
||||
__register_async (ovp, ovp->ops->get_status( ovp ));
|
||||
|
||||
inline static BOOL register_new_async( async_private *ovp )
|
||||
{
|
||||
ovp->ops->set_status ( ovp, 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 BOOL cancel_async ( async_private *ovp )
|
||||
{
|
||||
/* avoid multiple cancellations */
|
||||
if ( ovp->ops->get_status( ovp ) != STATUS_PENDING )
|
||||
return 0;
|
||||
ovp->ops->set_status ( ovp, STATUS_CANCELLED );
|
||||
return __register_async ( ovp, STATUS_CANCELLED );
|
||||
}
|
||||
|
||||
#endif /* __WINE_ASYNC_H */
|
|
@ -46,27 +46,6 @@ typedef struct
|
|||
int flags;
|
||||
} DOS_DEVICE;
|
||||
|
||||
/* overlapped private structure */
|
||||
struct async_private;
|
||||
typedef void (*async_handler)(struct async_private *ovp);
|
||||
typedef struct async_private
|
||||
{
|
||||
LPOVERLAPPED lpOverlapped;
|
||||
HANDLE handle;
|
||||
HANDLE event;
|
||||
int fd;
|
||||
char *buffer;
|
||||
async_handler func;
|
||||
int count;
|
||||
int type;
|
||||
LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
|
||||
struct async_private *next;
|
||||
struct async_private *prev;
|
||||
} async_private;
|
||||
|
||||
extern void WINAPI check_async_list(LPOVERLAPPED ov, DWORD status);
|
||||
extern void finish_async(struct async_private *ovp, DWORD status);
|
||||
|
||||
/* locale-independent case conversion */
|
||||
inline static char FILE_tolower( char c )
|
||||
{
|
||||
|
@ -99,7 +78,6 @@ extern HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
|
|||
DWORD attributes, HANDLE template, BOOL fail_read_only,
|
||||
UINT drive_type );
|
||||
extern HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa );
|
||||
extern BOOL FILE_StartAsync(HANDLE handle, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status);
|
||||
|
||||
extern LONG WINAPI WIN16_hread(HFILE16,SEGPTR,LONG);
|
||||
|
||||
|
|
|
@ -502,7 +502,7 @@ struct get_apc_reply
|
|||
int type;
|
||||
/* VARARG(args,ptrs); */
|
||||
};
|
||||
enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC };
|
||||
enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC, APC_ASYNC_IO };
|
||||
|
||||
|
||||
|
||||
|
@ -2278,7 +2278,6 @@ struct register_async_request
|
|||
{
|
||||
struct request_header __header;
|
||||
handle_t handle;
|
||||
void* func;
|
||||
int type;
|
||||
void* overlapped;
|
||||
int count;
|
||||
|
@ -3184,6 +3183,6 @@ union generic_reply
|
|||
struct get_window_properties_reply get_window_properties_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 77
|
||||
#define SERVER_PROTOCOL_VERSION 78
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "thread.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/server.h"
|
||||
#include "async.h"
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -50,74 +51,32 @@ inline static void get_timeout( struct timeval *when, int timeout )
|
|||
}
|
||||
}
|
||||
|
||||
static void CALLBACK call_completion_routine(ULONG_PTR data)
|
||||
{
|
||||
async_private* ovp = (async_private*)data;
|
||||
|
||||
ovp->completion_func(ovp->lpOverlapped->Internal,
|
||||
ovp->lpOverlapped->InternalHigh,
|
||||
ovp->lpOverlapped);
|
||||
ovp->completion_func=NULL;
|
||||
HeapFree(GetProcessHeap(), 0, ovp);
|
||||
}
|
||||
|
||||
void finish_async(async_private *ovp, DWORD status)
|
||||
{
|
||||
ovp->lpOverlapped->Internal=status;
|
||||
|
||||
/* call ReadFileEx/WriteFileEx's overlapped completion function */
|
||||
if(ovp->completion_func)
|
||||
{
|
||||
QueueUserAPC(call_completion_routine,GetCurrentThread(),(ULONG_PTR)ovp);
|
||||
}
|
||||
|
||||
/* remove it from the active list */
|
||||
if(ovp->prev)
|
||||
ovp->prev->next = ovp->next;
|
||||
else
|
||||
NtCurrentTeb()->pending_list = ovp->next;
|
||||
|
||||
if(ovp->next)
|
||||
ovp->next->prev = ovp->prev;
|
||||
|
||||
ovp->next=NULL;
|
||||
ovp->prev=NULL;
|
||||
|
||||
close(ovp->fd);
|
||||
if(ovp->event!=INVALID_HANDLE_VALUE)
|
||||
NtSetEvent(ovp->event,NULL);
|
||||
if(!ovp->completion_func) HeapFree(GetProcessHeap(), 0, ovp);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* check_async_list
|
||||
*
|
||||
* Process a status event from the server.
|
||||
*/
|
||||
void WINAPI check_async_list(LPOVERLAPPED overlapped, DWORD status)
|
||||
static void WINAPI check_async_list(async_private *asp, DWORD status)
|
||||
{
|
||||
async_private *ovp;
|
||||
DWORD ovp_status;
|
||||
|
||||
/* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */
|
||||
|
||||
for(ovp = NtCurrentTeb()->pending_list; ovp; ovp = ovp->next)
|
||||
if(ovp->lpOverlapped == overlapped)
|
||||
break;
|
||||
for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
|
||||
|
||||
if(!ovp)
|
||||
return;
|
||||
|
||||
if(status != STATUS_ALERTED)
|
||||
ovp->lpOverlapped->Internal = status;
|
||||
if( status != STATUS_ALERTED )
|
||||
{
|
||||
ovp_status = status;
|
||||
ovp->ops->set_status (ovp, status);
|
||||
}
|
||||
else ovp_status = ovp->ops->get_status (ovp);
|
||||
|
||||
if(ovp->lpOverlapped->Internal==STATUS_PENDING)
|
||||
{
|
||||
ovp->func(ovp);
|
||||
FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal);
|
||||
}
|
||||
if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
|
||||
|
||||
if(ovp->lpOverlapped->Internal!=STATUS_PENDING)
|
||||
finish_async(ovp,ovp->lpOverlapped->Internal);
|
||||
/* This will destroy all but PENDING requests */
|
||||
register_old_async( ovp );
|
||||
}
|
||||
|
||||
|
||||
|
@ -201,6 +160,9 @@ static void call_apcs( BOOL alertable )
|
|||
DOSFS_UnixTimeToFileTime( (time_t)args[0], &ft, (DWORD)args[1] * 10 );
|
||||
proc( args[2], ft.dwLowDateTime, ft.dwHighDateTime );
|
||||
break;
|
||||
case APC_ASYNC_IO:
|
||||
check_async_list ( args[0], (DWORD) args[1]);
|
||||
break;
|
||||
default:
|
||||
server_protocol_error( "get_apc_request: bad type %d\n", type );
|
||||
break;
|
||||
|
|
|
@ -64,7 +64,7 @@ void async_notify(struct async *async, int status)
|
|||
{
|
||||
/* fprintf(stderr,"notifying %p!\n",async->overlapped); */
|
||||
async->status = status;
|
||||
thread_queue_apc(async->thread, NULL, async->func, APC_ASYNC, 1, 2, async->overlapped, status);
|
||||
thread_queue_apc(async->thread, NULL, NULL, APC_ASYNC_IO, 1, 2, async->overlapped, status);
|
||||
}
|
||||
|
||||
void destroy_async_queue( struct async_queue *q )
|
||||
|
@ -116,7 +116,7 @@ static void async_callback(void *private)
|
|||
destroy_async(async);
|
||||
}
|
||||
|
||||
struct async *create_async(struct object *obj, struct thread *thread, void *func,
|
||||
struct async *create_async(struct object *obj, struct thread *thread,
|
||||
void *overlapped)
|
||||
{
|
||||
struct async *async = (struct async *) malloc(sizeof(struct async));
|
||||
|
@ -128,7 +128,6 @@ struct async *create_async(struct object *obj, struct thread *thread, void *func
|
|||
|
||||
async->obj = obj;
|
||||
async->thread = thread;
|
||||
async->func = func;
|
||||
async->overlapped = overlapped;
|
||||
async->next = NULL;
|
||||
async->prev = NULL;
|
||||
|
@ -165,7 +164,7 @@ DECL_HANDLER(register_async)
|
|||
if(req->status==STATUS_PENDING)
|
||||
{
|
||||
if(!async)
|
||||
async = create_async(obj, current, req->func, req->overlapped);
|
||||
async = create_async(obj, current, req->overlapped);
|
||||
|
||||
if(async)
|
||||
{
|
||||
|
|
|
@ -30,7 +30,6 @@ struct async
|
|||
{
|
||||
struct object *obj;
|
||||
struct thread *thread;
|
||||
void *func;
|
||||
void *overlapped;
|
||||
unsigned int status;
|
||||
struct timeval when;
|
||||
|
@ -51,7 +50,7 @@ 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 *func, void *overlapped);
|
||||
void *overlapped);
|
||||
void async_add_timeout(struct async *async, int timeout);
|
||||
static inline void init_async_queue(struct async_queue *q)
|
||||
{
|
||||
|
|
|
@ -412,7 +412,7 @@ typedef struct
|
|||
int type; /* function type */
|
||||
VARARG(args,ptrs); /* function arguments */
|
||||
@END
|
||||
enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC };
|
||||
enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC, APC_ASYNC_IO };
|
||||
|
||||
|
||||
/* Close a handle for the current process */
|
||||
|
@ -1615,10 +1615,9 @@ enum message_type
|
|||
#define SERIALINFO_SET_ERROR 0x04
|
||||
|
||||
|
||||
/* Create/Destroy an async I/O */
|
||||
/* Create / reschedule an async I/O */
|
||||
@REQ(register_async)
|
||||
handle_t handle; /* handle to comm port, socket or file */
|
||||
void* func;
|
||||
int type;
|
||||
void* overlapped;
|
||||
int count;
|
||||
|
|
|
@ -959,8 +959,9 @@ DECL_HANDLER(get_apc)
|
|||
}
|
||||
/* Optimization: ignore APCs that have a NULL func; they are only used
|
||||
* to wake up a thread, but since we got here the thread woke up already.
|
||||
* Exception: for APC_ASYNC_IO, func == NULL is legal.
|
||||
*/
|
||||
if (apc->func) break;
|
||||
if (apc->func || apc->type == APC_ASYNC_IO) break;
|
||||
free( apc );
|
||||
}
|
||||
size = apc->nb_args * sizeof(apc->args[0]);
|
||||
|
|
|
@ -1846,7 +1846,6 @@ static void dump_set_serial_info_request( const struct set_serial_info_request *
|
|||
static void dump_register_async_request( const struct register_async_request *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%d,", req->handle );
|
||||
fprintf( stderr, " func=%p,", req->func );
|
||||
fprintf( stderr, " type=%d,", req->type );
|
||||
fprintf( stderr, " overlapped=%p,", req->overlapped );
|
||||
fprintf( stderr, " count=%d,", req->count );
|
||||
|
|
Loading…
Reference in New Issue