wine/dlls/kernel/sync.c
Alexandre Julliard 9caa71eef4 Redesign of the server communication protocol to allow arbitrary sized
data to be exchanged.
Split request and reply structures to make backwards compatibility
easier.
Moved many console functions to dlls/kernel, added code page support,
changed a few requests to behave properly with the new protocol.
2001-11-30 18:46:42 +00:00

790 lines
21 KiB
C

/*
* Kernel synchronization objects
*
* Copyright 1998 Alexandre Julliard
*/
#include "config.h"
#include <string.h>
#include "winbase.h"
#include "winerror.h"
#include "winnls.h"
#include "wine/server.h"
#include "wine/unicode.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(win32);
/*
* Events
*/
/***********************************************************************
* CreateEventA (KERNEL32.@)
*/
HANDLE WINAPI CreateEventA( SECURITY_ATTRIBUTES *sa, BOOL manual_reset,
BOOL initial_state, LPCSTR name )
{
WCHAR buffer[MAX_PATH];
if (!name) return CreateEventW( sa, manual_reset, initial_state, NULL );
if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
return CreateEventW( sa, manual_reset, initial_state, buffer );
}
/***********************************************************************
* CreateEventW (KERNEL32.@)
*/
HANDLE WINAPI CreateEventW( SECURITY_ATTRIBUTES *sa, BOOL manual_reset,
BOOL initial_state, LPCWSTR name )
{
HANDLE ret;
DWORD len = name ? strlenW(name) : 0;
if (len >= MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
/* one buggy program needs this
* ("Van Dale Groot woordenboek der Nederlandse taal")
*/
if (sa && IsBadReadPtr(sa,sizeof(SECURITY_ATTRIBUTES)))
{
ERR("Bad security attributes pointer %p\n",sa);
SetLastError( ERROR_INVALID_PARAMETER);
return 0;
}
SERVER_START_REQ( create_event )
{
req->manual_reset = manual_reset;
req->initial_state = initial_state;
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
wine_server_add_data( req, name, len * sizeof(WCHAR) );
SetLastError(0);
wine_server_call_err( req );
ret = reply->handle;
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* CreateW32Event (KERNEL.457)
*/
HANDLE WINAPI WIN16_CreateEvent( BOOL manual_reset, BOOL initial_state )
{
return CreateEventA( NULL, manual_reset, initial_state, NULL );
}
/***********************************************************************
* OpenEventA (KERNEL32.@)
*/
HANDLE WINAPI OpenEventA( DWORD access, BOOL inherit, LPCSTR name )
{
WCHAR buffer[MAX_PATH];
if (!name) return OpenEventW( access, inherit, NULL );
if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
return OpenEventW( access, inherit, buffer );
}
/***********************************************************************
* OpenEventW (KERNEL32.@)
*/
HANDLE WINAPI OpenEventW( DWORD access, BOOL inherit, LPCWSTR name )
{
HANDLE ret;
DWORD len = name ? strlenW(name) : 0;
if (len >= MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
SERVER_START_REQ( open_event )
{
req->access = access;
req->inherit = inherit;
wine_server_add_data( req, name, len * sizeof(WCHAR) );
wine_server_call_err( req );
ret = reply->handle;
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* EVENT_Operation
*
* Execute an event operation (set,reset,pulse).
*/
static BOOL EVENT_Operation( HANDLE handle, enum event_op op )
{
BOOL ret;
SERVER_START_REQ( event_op )
{
req->handle = handle;
req->op = op;
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* PulseEvent (KERNEL32.@)
*/
BOOL WINAPI PulseEvent( HANDLE handle )
{
return EVENT_Operation( handle, PULSE_EVENT );
}
/***********************************************************************
* SetW32Event (KERNEL.458)
* SetEvent (KERNEL32.@)
*/
BOOL WINAPI SetEvent( HANDLE handle )
{
return EVENT_Operation( handle, SET_EVENT );
}
/***********************************************************************
* ResetW32Event (KERNEL.459)
* ResetEvent (KERNEL32.@)
*/
BOOL WINAPI ResetEvent( HANDLE handle )
{
return EVENT_Operation( handle, RESET_EVENT );
}
/***********************************************************************
* NOTE: The Win95 VWin32_Event routines given below are really low-level
* routines implemented directly by VWin32. The user-mode libraries
* implement Win32 synchronisation routines on top of these low-level
* primitives. We do it the other way around here :-)
*/
/***********************************************************************
* VWin32_EventCreate (KERNEL.442)
*/
HANDLE WINAPI VWin32_EventCreate(VOID)
{
HANDLE hEvent = CreateEventA( NULL, FALSE, 0, NULL );
return ConvertToGlobalHandle( hEvent );
}
/***********************************************************************
* VWin32_EventDestroy (KERNEL.443)
*/
VOID WINAPI VWin32_EventDestroy(HANDLE event)
{
CloseHandle( event );
}
/***********************************************************************
* VWin32_EventWait (KERNEL.450)
*/
VOID WINAPI VWin32_EventWait(HANDLE event)
{
DWORD mutex_count;
ReleaseThunkLock( &mutex_count );
WaitForSingleObject( event, INFINITE );
RestoreThunkLock( mutex_count );
}
/***********************************************************************
* VWin32_EventSet (KERNEL.451)
* KERNEL_479 (KERNEL.479)
*/
VOID WINAPI VWin32_EventSet(HANDLE event)
{
SetEvent( event );
}
/***********************************************************************
* CreateMutexA (KERNEL32.@)
*/
HANDLE WINAPI CreateMutexA( SECURITY_ATTRIBUTES *sa, BOOL owner, LPCSTR name )
{
WCHAR buffer[MAX_PATH];
if (!name) return CreateMutexW( sa, owner, NULL );
if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
return CreateMutexW( sa, owner, buffer );
}
/***********************************************************************
* CreateMutexW (KERNEL32.@)
*/
HANDLE WINAPI CreateMutexW( SECURITY_ATTRIBUTES *sa, BOOL owner, LPCWSTR name )
{
HANDLE ret;
DWORD len = name ? strlenW(name) : 0;
if (len >= MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
SERVER_START_REQ( create_mutex )
{
req->owned = owner;
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
wine_server_add_data( req, name, len * sizeof(WCHAR) );
SetLastError(0);
wine_server_call_err( req );
ret = reply->handle;
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* OpenMutexA (KERNEL32.@)
*/
HANDLE WINAPI OpenMutexA( DWORD access, BOOL inherit, LPCSTR name )
{
WCHAR buffer[MAX_PATH];
if (!name) return OpenMutexW( access, inherit, NULL );
if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
return OpenMutexW( access, inherit, buffer );
}
/***********************************************************************
* OpenMutexW (KERNEL32.@)
*/
HANDLE WINAPI OpenMutexW( DWORD access, BOOL inherit, LPCWSTR name )
{
HANDLE ret;
DWORD len = name ? strlenW(name) : 0;
if (len >= MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
SERVER_START_REQ( open_mutex )
{
req->access = access;
req->inherit = inherit;
wine_server_add_data( req, name, len * sizeof(WCHAR) );
wine_server_call_err( req );
ret = reply->handle;
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* ReleaseMutex (KERNEL32.@)
*/
BOOL WINAPI ReleaseMutex( HANDLE handle )
{
BOOL ret;
SERVER_START_REQ( release_mutex )
{
req->handle = handle;
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
return ret;
}
/*
* Semaphores
*/
/***********************************************************************
* CreateSemaphoreA (KERNEL32.@)
*/
HANDLE WINAPI CreateSemaphoreA( SECURITY_ATTRIBUTES *sa, LONG initial, LONG max, LPCSTR name )
{
WCHAR buffer[MAX_PATH];
if (!name) return CreateSemaphoreW( sa, initial, max, NULL );
if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
return CreateSemaphoreW( sa, initial, max, buffer );
}
/***********************************************************************
* CreateSemaphoreW (KERNEL32.@)
*/
HANDLE WINAPI CreateSemaphoreW( SECURITY_ATTRIBUTES *sa, LONG initial,
LONG max, LPCWSTR name )
{
HANDLE ret;
DWORD len = name ? strlenW(name) : 0;
/* Check parameters */
if ((max <= 0) || (initial < 0) || (initial > max))
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (len >= MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
SERVER_START_REQ( create_semaphore )
{
req->initial = (unsigned int)initial;
req->max = (unsigned int)max;
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
wine_server_add_data( req, name, len * sizeof(WCHAR) );
SetLastError(0);
wine_server_call_err( req );
ret = reply->handle;
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* OpenSemaphoreA (KERNEL32.@)
*/
HANDLE WINAPI OpenSemaphoreA( DWORD access, BOOL inherit, LPCSTR name )
{
WCHAR buffer[MAX_PATH];
if (!name) return OpenSemaphoreW( access, inherit, NULL );
if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
return OpenSemaphoreW( access, inherit, buffer );
}
/***********************************************************************
* OpenSemaphoreW (KERNEL32.@)
*/
HANDLE WINAPI OpenSemaphoreW( DWORD access, BOOL inherit, LPCWSTR name )
{
HANDLE ret;
DWORD len = name ? strlenW(name) : 0;
if (len >= MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
SERVER_START_REQ( open_semaphore )
{
req->access = access;
req->inherit = inherit;
wine_server_add_data( req, name, len * sizeof(WCHAR) );
wine_server_call_err( req );
ret = reply->handle;
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* ReleaseSemaphore (KERNEL32.@)
*/
BOOL WINAPI ReleaseSemaphore( HANDLE handle, LONG count, LONG *previous )
{
NTSTATUS status = NtReleaseSemaphore( handle, count, previous );
if (status) SetLastError( RtlNtStatusToDosError(status) );
return !status;
}
/*
* Pipes
*/
/***********************************************************************
* CreateNamedPipeA (KERNEL32.@)
*/
HANDLE WINAPI CreateNamedPipeA( LPCSTR name, DWORD dwOpenMode,
DWORD dwPipeMode, DWORD nMaxInstances,
DWORD nOutBufferSize, DWORD nInBufferSize,
DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES attr )
{
WCHAR buffer[MAX_PATH];
if (!name) return CreateNamedPipeW( NULL, dwOpenMode, dwPipeMode, nMaxInstances,
nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr );
if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
return CreateNamedPipeW( buffer, dwOpenMode, dwPipeMode, nMaxInstances,
nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr );
}
/***********************************************************************
* CreateNamedPipeW (KERNEL32.@)
*/
HANDLE WINAPI CreateNamedPipeW( LPCWSTR name, DWORD dwOpenMode,
DWORD dwPipeMode, DWORD nMaxInstances,
DWORD nOutBufferSize, DWORD nInBufferSize,
DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES attr )
{
HANDLE ret;
DWORD len = name ? strlenW(name) : 0;
TRACE("(%s, %#08lx, %#08lx, %ld, %ld, %ld, %ld, %p)\n",
debugstr_w(name), dwOpenMode, dwPipeMode, nMaxInstances,
nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr );
if (len >= MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
SERVER_START_REQ( create_named_pipe )
{
req->openmode = dwOpenMode;
req->pipemode = dwPipeMode;
req->maxinstances = nMaxInstances;
req->outsize = nOutBufferSize;
req->insize = nInBufferSize;
req->timeout = nDefaultTimeOut;
wine_server_add_data( req, name, len * sizeof(WCHAR) );
SetLastError(0);
wine_server_call_err( req );
ret = reply->handle;
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* PeekNamedPipe (KERNEL32.@)
*/
BOOL WINAPI PeekNamedPipe( HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer,
LPDWORD lpcbRead, LPDWORD lpcbAvail, LPDWORD lpcbMessage )
{
FIXME("(%08x, %p, %08lx, %p, %p, %p): stub\n",
hPipe, lpvBuffer, cbBuffer, lpcbRead, lpcbAvail, lpcbMessage);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/***********************************************************************
* SYNC_CompletePipeOverlapped (Internal)
*/
static void SYNC_CompletePipeOverlapped (LPOVERLAPPED overlapped, DWORD result)
{
TRACE("for %p result %08lx\n",overlapped,result);
if(!overlapped)
return;
overlapped->Internal = result;
SetEvent(overlapped->hEvent);
}
/***********************************************************************
* WaitNamedPipeA (KERNEL32.@)
*/
BOOL WINAPI WaitNamedPipeA (LPCSTR name, DWORD nTimeOut)
{
WCHAR buffer[MAX_PATH];
if (!name) return WaitNamedPipeW( NULL, nTimeOut );
if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
return WaitNamedPipeW( buffer, nTimeOut );
}
/***********************************************************************
* WaitNamedPipeW (KERNEL32.@)
*/
BOOL WINAPI WaitNamedPipeW (LPCWSTR name, DWORD nTimeOut)
{
DWORD len = name ? strlenW(name) : 0;
BOOL ret;
OVERLAPPED ov;
if (len >= MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return FALSE;
}
TRACE("%s 0x%08lx\n",debugstr_w(name),nTimeOut);
memset(&ov,0,sizeof ov);
ov.hEvent = CreateEventA( NULL, 0, 0, NULL );
if (!ov.hEvent)
return FALSE;
SERVER_START_REQ( wait_named_pipe )
{
req->timeout = nTimeOut;
req->overlapped = &ov;
req->func = SYNC_CompletePipeOverlapped;
wine_server_add_data( req, name, len * sizeof(WCHAR) );
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
if(ret)
{
if (WAIT_OBJECT_0==WaitForSingleObject(ov.hEvent,INFINITE))
{
SetLastError(ov.Internal);
ret = (ov.Internal==STATUS_SUCCESS);
}
}
CloseHandle(ov.hEvent);
return ret;
}
/***********************************************************************
* SYNC_ConnectNamedPipe (Internal)
*/
static BOOL SYNC_ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped)
{
BOOL ret;
if(!overlapped)
return FALSE;
overlapped->Internal = STATUS_PENDING;
SERVER_START_REQ( connect_named_pipe )
{
req->handle = hPipe;
req->overlapped = overlapped;
req->func = SYNC_CompletePipeOverlapped;
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* ConnectNamedPipe (KERNEL32.@)
*/
BOOL WINAPI ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped)
{
OVERLAPPED ov;
BOOL ret;
TRACE("(%d,%p)\n",hPipe, overlapped);
if(overlapped)
return SYNC_ConnectNamedPipe(hPipe,overlapped);
memset(&ov,0,sizeof ov);
ov.hEvent = CreateEventA(NULL,0,0,NULL);
if (!ov.hEvent)
return FALSE;
ret=SYNC_ConnectNamedPipe(hPipe, &ov);
if(ret)
{
if (WAIT_OBJECT_0==WaitForSingleObject(ov.hEvent,INFINITE))
{
SetLastError(ov.Internal);
ret = (ov.Internal==STATUS_SUCCESS);
}
}
CloseHandle(ov.hEvent);
return ret;
}
/***********************************************************************
* DisconnectNamedPipe (KERNEL32.@)
*/
BOOL WINAPI DisconnectNamedPipe(HANDLE hPipe)
{
BOOL ret;
TRACE("(%d)\n",hPipe);
SERVER_START_REQ( disconnect_named_pipe )
{
req->handle = hPipe;
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* TransactNamedPipe (KERNEL32.@)
*/
BOOL WINAPI TransactNamedPipe(
HANDLE hPipe, LPVOID lpInput, DWORD dwInputSize, LPVOID lpOutput,
DWORD dwOutputSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped)
{
FIXME("%d %p %ld %p %ld %p %p\n",
hPipe, lpInput, dwInputSize, lpOutput,
dwOutputSize, lpBytesRead, lpOverlapped);
if(lpBytesRead)
*lpBytesRead=0;
return FALSE;
}
/***********************************************************************
* GetNamedPipeInfo (KERNEL32.@)
*/
BOOL WINAPI GetNamedPipeInfo(
HANDLE hNamedPipe, LPDWORD lpFlags, LPDWORD lpOutputBufferSize,
LPDWORD lpInputBufferSize, LPDWORD lpMaxInstances)
{
BOOL ret;
TRACE("%d %p %p %p %p\n", hNamedPipe, lpFlags,
lpOutputBufferSize, lpInputBufferSize, lpMaxInstances);
SERVER_START_REQ( get_named_pipe_info )
{
req->handle = hNamedPipe;
ret = !wine_server_call_err( req );
if(lpFlags) *lpFlags = reply->flags;
if(lpOutputBufferSize) *lpOutputBufferSize = reply->outsize;
if(lpInputBufferSize) *lpInputBufferSize = reply->outsize;
if(lpMaxInstances) *lpMaxInstances = reply->maxinstances;
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* GetNamedPipeHandleStateA (KERNEL32.@)
*/
BOOL WINAPI GetNamedPipeHandleStateA(
HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances,
LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout,
LPSTR lpUsername, DWORD nUsernameMaxSize)
{
FIXME("%d %p %p %p %p %p %ld\n",
hNamedPipe, lpState, lpCurInstances,
lpMaxCollectionCount, lpCollectDataTimeout,
lpUsername, nUsernameMaxSize);
return FALSE;
}
/***********************************************************************
* GetNamedPipeHandleStateW (KERNEL32.@)
*/
BOOL WINAPI GetNamedPipeHandleStateW(
HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances,
LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout,
LPWSTR lpUsername, DWORD nUsernameMaxSize)
{
FIXME("%d %p %p %p %p %p %ld\n",
hNamedPipe, lpState, lpCurInstances,
lpMaxCollectionCount, lpCollectDataTimeout,
lpUsername, nUsernameMaxSize);
return FALSE;
}
/***********************************************************************
* SetNamedPipeHandleState (KERNEL32.@)
*/
BOOL WINAPI SetNamedPipeHandleState(
HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
LPDWORD lpCollectDataTimeout)
{
FIXME("%d %p %p %p\n",
hNamedPipe, lpMode, lpMaxCollectionCount, lpCollectDataTimeout);
return FALSE;
}
/***********************************************************************
* CallNamedPipeA (KERNEL32.@)
*/
BOOL WINAPI CallNamedPipeA(
LPCSTR lpNamedPipeName, LPVOID lpInput, DWORD lpInputSize,
LPVOID lpOutput, DWORD lpOutputSize,
LPDWORD lpBytesRead, DWORD nTimeout)
{
FIXME("%s %p %ld %p %ld %p %ld\n",
debugstr_a(lpNamedPipeName), lpInput, lpInputSize,
lpOutput, lpOutputSize, lpBytesRead, nTimeout);
return FALSE;
}
/***********************************************************************
* CallNamedPipeW (KERNEL32.@)
*/
BOOL WINAPI CallNamedPipeW(
LPCWSTR lpNamedPipeName, LPVOID lpInput, DWORD lpInputSize,
LPVOID lpOutput, DWORD lpOutputSize,
LPDWORD lpBytesRead, DWORD nTimeout)
{
FIXME("%s %p %ld %p %ld %p %ld\n",
debugstr_w(lpNamedPipeName), lpInput, lpInputSize,
lpOutput, lpOutputSize, lpBytesRead, nTimeout);
return FALSE;
}