blob: 275294ae3b0a6956006c84503462b3dff3c276c9 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2013-2014 Google, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Google, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* kernel32.dll and kernelbase.dll synchronization redirection routines */
#include "kernel32_redir.h" /* must be included first */
#include "../../globals.h"
#include "ntdll_redir.h"
#include "drwinapi_private.h"
VOID
WINAPI
redirect_InitializeCriticalSection(
__out LPCRITICAL_SECTION lpCriticalSection
)
{
NTSTATUS res = redirect_RtlInitializeCriticalSection(lpCriticalSection);
/* The man page for RtlInitializeCriticalSection implies it doesn't set
* any error codes, but it seems reasonable to do so, esp on NULL being
* passed in or sthg.
*/
if (!NT_SUCCESS(res))
set_last_error(ntstatus_to_last_error(res));
}
BOOL
WINAPI
redirect_InitializeCriticalSectionAndSpinCount(
__out LPCRITICAL_SECTION lpCriticalSection,
__in DWORD dwSpinCount
)
{
NTSTATUS res = redirect_RtlInitializeCriticalSectionAndSpinCount
(lpCriticalSection, dwSpinCount);
if (!NT_SUCCESS(res)) {
set_last_error(ntstatus_to_last_error(res));
return FALSE;
}
return TRUE;
}
BOOL
WINAPI
redirect_InitializeCriticalSectionEx(
__out LPCRITICAL_SECTION lpCriticalSection,
__in DWORD dwSpinCount,
__in DWORD Flags
)
{
NTSTATUS res = redirect_RtlInitializeCriticalSectionEx
(lpCriticalSection, dwSpinCount, Flags);
if (!NT_SUCCESS(res)) {
set_last_error(ntstatus_to_last_error(res));
return FALSE;
}
return TRUE;
}
VOID
WINAPI
redirect_DeleteCriticalSection(
__inout LPCRITICAL_SECTION lpCriticalSection
)
{
redirect_RtlDeleteCriticalSection(lpCriticalSection);
}
VOID
WINAPI
redirect_EnterCriticalSection(
__inout LPCRITICAL_SECTION lpCriticalSection
)
{
/* XXX: invoking ntdll routine b/c DR is already doing so.
* We've seen some alloc/free mismatches in Initialize and Delete
* though (DrMem i#333, DR i#963) so be on the lookout.
*/
RtlEnterCriticalSection(lpCriticalSection);
}
VOID
WINAPI
redirect_LeaveCriticalSection(
__inout LPCRITICAL_SECTION lpCriticalSection
)
{
/* XXX: invoking ntdll routine b/c DR is already doing so.
* We've seen some alloc/free mismatches in Initialize and Delete
* though (DrMem i#333, DR i#963) so be on the lookout.
*/
RtlLeaveCriticalSection(lpCriticalSection);
}
LONG
WINAPI
redirect_InterlockedCompareExchange (
__inout __drv_interlocked LONG volatile *Destination,
__in LONG ExChange,
__in LONG Comperand
)
{
return _InterlockedCompareExchange(Destination, ExChange, Comperand);
}
LONG
WINAPI
redirect_InterlockedDecrement(
__inout __drv_interlocked LONG volatile *Addend
)
{
return _InterlockedDecrement(Addend);
}
LONG
WINAPI
redirect_InterlockedExchange(
__inout __drv_interlocked LONG volatile *Target,
__in LONG Value
)
{
return _InterlockedExchange(Target, Value);
}
LONG
WINAPI
redirect_InterlockedIncrement(
__inout __drv_interlocked LONG volatile *Addend
)
{
return _InterlockedIncrement(Addend);
}
DWORD
WINAPI
redirect_WaitForSingleObject(
__in HANDLE hHandle,
__in DWORD dwMilliseconds
)
{
NTSTATUS res;
LARGE_INTEGER li;
LARGE_INTEGER *timeout;
if (dwMilliseconds == INFINITE)
timeout = NULL;
else {
li.QuadPart = -((int)dwMilliseconds * TIMER_UNITS_PER_MILLISECOND);
timeout = &li;
}
/* XXX: are there special handles we need to convert to real handles? */
res = NtWaitForSingleObject(hHandle, FALSE/*!alertable*/, timeout);
if (!NT_SUCCESS(res)) {
set_last_error(ntstatus_to_last_error(res));
return WAIT_FAILED;
}
if (res == STATUS_TIMEOUT)
return WAIT_TIMEOUT;
else if (res == STATUS_WAIT_0)
return WAIT_OBJECT_0;
else if (res == STATUS_ABANDONED_WAIT_0)
return WAIT_ABANDONED;
else
return res; /* WAIT_ success codes tend to match STATUS_ values */
}
#ifdef STANDALONE_UNIT_TEST
void
unit_test_drwinapi_kernel32_sync(void)
{
CRITICAL_SECTION sec;
BOOL ok;
LONG volatile vol;
LONG val1, val2, res;
HANDLE e;
DWORD dw;
LARGE_INTEGER li;
print_file(STDERR, "testing drwinapi kernel32 sync-related routines\n");
/* We just ensure everything runs */
redirect_InitializeCriticalSection(&sec);
redirect_DeleteCriticalSection(&sec);
ok = redirect_InitializeCriticalSectionAndSpinCount(&sec, 0);
EXPECT(ok, TRUE);
redirect_DeleteCriticalSection(&sec);
ok = redirect_InitializeCriticalSectionEx(&sec, 0,
RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO);
EXPECT(ok, TRUE);
redirect_EnterCriticalSection(&sec);
redirect_LeaveCriticalSection(&sec);
redirect_DeleteCriticalSection(&sec);
vol = 4;
val1 = 5;
val2 = 6;
res = redirect_InterlockedCompareExchange (&vol, val1, val2);
EXPECT(res == vol && res == 4, true);
vol = 4;
val1 = 5;
val2 = 4;
res = redirect_InterlockedCompareExchange (&vol, val1, val2);
EXPECT(res == 4 && vol == val1, true);
vol = 42;
res = redirect_InterlockedDecrement(&vol);
EXPECT(res == 41 && vol == 41, true);
vol = 42;
val1 = 37;
res = redirect_InterlockedExchange(&vol, val1);
EXPECT(res == 42 && vol == val1, true);
vol = 42;
res = redirect_InterlockedIncrement(&vol);
EXPECT(res == 43 && vol == 43, true);
e = CreateEvent(NULL, TRUE, FALSE, "myevent");
EXPECT(e != NULL, true);
dw = redirect_WaitForSingleObject(e, 50);
EXPECT(dw == WAIT_TIMEOUT, true);
ok = SetEvent(e);
EXPECT(ok, true);
dw = redirect_WaitForSingleObject(e, 50);
EXPECT(dw == WAIT_OBJECT_0, true);
ok = redirect_CloseHandle(e);
EXPECT(ok, true);
/* Test INFINITE wait (i#1467) */
e = CreateWaitableTimer(NULL, TRUE, "mytimer");
EXPECT(e != NULL, true);
li.QuadPart = -(50 * TIMER_UNITS_PER_MILLISECOND);
ok = SetWaitableTimer(e, &li, 0, NULL, NULL, FALSE);
EXPECT(ok, true);
dw = redirect_WaitForSingleObject(e, INFINITE);
EXPECT(dw == WAIT_OBJECT_0, true);
ok = redirect_CloseHandle(e);
EXPECT(ok, true);
}
#endif