2007-03-06 11:59:18 +00:00
/*
* Synchronization tests
*
* Copyright 2005 Mike McCormack for CodeWeavers
*
* 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
2008-05-09 17:35:45 +00:00
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
2007-03-06 11:59:18 +00:00
*/
2018-04-03 12:39:42 +00:00
# include <stdarg.h>
# include <stdlib.h>
# include <stdio.h>
# include <windef.h>
# include <winbase.h>
# include <winternl.h>
# include "wine/test.h"
# ifdef __REACTOS__
2016-03-08 15:49:46 +00:00
# define QueryDepthSList(x) RtlQueryDepthSList(x)
# define InterlockedPushEntrySList(x,y) RtlInterlockedPushEntrySList(x,y)
# define InterlockedPopEntrySList(x) RtlInterlockedPopEntrySList(x)
# define InterlockedFlushSList(x) RtlInterlockedFlushSList(x)
2018-04-03 12:39:42 +00:00
# endif
2016-03-08 15:49:46 +00:00
# undef __fastcall
# define __fastcall __stdcall
2012-05-12 19:33:11 +00:00
static HANDLE ( WINAPI * pCreateMemoryResourceNotification ) ( MEMORY_RESOURCE_NOTIFICATION_TYPE ) ;
static BOOL ( WINAPI * pQueryMemoryResourceNotification ) ( HANDLE , PBOOL ) ;
2012-12-09 20:39:13 +00:00
static VOID ( WINAPI * pInitOnceInitialize ) ( PINIT_ONCE ) ;
static BOOL ( WINAPI * pInitOnceExecuteOnce ) ( PINIT_ONCE , PINIT_ONCE_FN , PVOID , LPVOID * ) ;
static BOOL ( WINAPI * pInitOnceBeginInitialize ) ( PINIT_ONCE , DWORD , BOOL * , LPVOID * ) ;
static BOOL ( WINAPI * pInitOnceComplete ) ( PINIT_ONCE , DWORD , LPVOID ) ;
static VOID ( WINAPI * pInitializeConditionVariable ) ( PCONDITION_VARIABLE ) ;
static BOOL ( WINAPI * pSleepConditionVariableCS ) ( PCONDITION_VARIABLE , PCRITICAL_SECTION , DWORD ) ;
2014-04-18 22:50:27 +00:00
static BOOL ( WINAPI * pSleepConditionVariableSRW ) ( PCONDITION_VARIABLE , PSRWLOCK , DWORD , ULONG ) ;
2012-12-09 20:39:13 +00:00
static VOID ( WINAPI * pWakeAllConditionVariable ) ( PCONDITION_VARIABLE ) ;
static VOID ( WINAPI * pWakeConditionVariable ) ( PCONDITION_VARIABLE ) ;
2008-12-23 20:02:47 +00:00
2014-04-18 22:50:27 +00:00
static VOID ( WINAPI * pInitializeSRWLock ) ( PSRWLOCK ) ;
static VOID ( WINAPI * pAcquireSRWLockExclusive ) ( PSRWLOCK ) ;
static VOID ( WINAPI * pAcquireSRWLockShared ) ( PSRWLOCK ) ;
static VOID ( WINAPI * pReleaseSRWLockExclusive ) ( PSRWLOCK ) ;
static VOID ( WINAPI * pReleaseSRWLockShared ) ( PSRWLOCK ) ;
static BOOLEAN ( WINAPI * pTryAcquireSRWLockExclusive ) ( PSRWLOCK ) ;
static BOOLEAN ( WINAPI * pTryAcquireSRWLockShared ) ( PSRWLOCK ) ;
2015-11-23 16:10:53 +00:00
static NTSTATUS ( WINAPI * pNtAllocateVirtualMemory ) ( HANDLE , PVOID * , ULONG , SIZE_T * , ULONG , ULONG ) ;
static NTSTATUS ( WINAPI * pNtFreeVirtualMemory ) ( HANDLE , PVOID * , SIZE_T * , ULONG ) ;
2016-03-08 15:49:46 +00:00
static NTSTATUS ( WINAPI * pNtWaitForSingleObject ) ( HANDLE , BOOLEAN , const LARGE_INTEGER * ) ;
2014-09-20 19:35:24 +00:00
static NTSTATUS ( WINAPI * pNtWaitForMultipleObjects ) ( ULONG , const HANDLE * , BOOLEAN , BOOLEAN , const LARGE_INTEGER * ) ;
2016-03-08 15:49:46 +00:00
static PSLIST_ENTRY ( __fastcall * pRtlInterlockedPushListSList ) ( PSLIST_HEADER list , PSLIST_ENTRY first ,
PSLIST_ENTRY last , ULONG count ) ;
static PSLIST_ENTRY ( WINAPI * pRtlInterlockedPushListSListEx ) ( PSLIST_HEADER list , PSLIST_ENTRY first ,
PSLIST_ENTRY last , ULONG count ) ;
# ifdef __i386__
# include "pshpack1.h"
struct fastcall_thunk
{
BYTE pop_edx ; /* popl %edx (ret addr) */
BYTE pop_eax ; /* popl %eax (func) */
BYTE pop_ecx ; /* popl %ecx (param 1) */
BYTE xchg [ 3 ] ; /* xchgl (%esp),%edx (param 2) */
WORD jmp_eax ; /* jmp *%eax */
} ;
# include "poppack.h"
static void * ( WINAPI * call_fastcall_func4 ) ( void * func , const void * a , const void * b , const void * c , const void * d ) ;
static void init_fastcall_thunk ( void )
{
struct fastcall_thunk * thunk = VirtualAlloc ( NULL , sizeof ( * thunk ) , MEM_COMMIT , PAGE_EXECUTE_READWRITE ) ;
thunk - > pop_edx = 0x5a ; /* popl %edx */
thunk - > pop_eax = 0x58 ; /* popl %eax */
thunk - > pop_ecx = 0x59 ; /* popl %ecx */
thunk - > xchg [ 0 ] = 0x87 ; /* xchgl (%esp),%edx */
thunk - > xchg [ 1 ] = 0x14 ;
thunk - > xchg [ 2 ] = 0x24 ;
thunk - > jmp_eax = 0xe0ff ; /* jmp *%eax */
call_fastcall_func4 = ( void * ) thunk ;
}
# define call_func4(func, a, b, c, d) call_fastcall_func4(func, (const void *)(a), \
( const void * ) ( b ) , ( const void * ) ( c ) , ( const void * ) ( d ) )
# else /* __i386__ */
# define init_fastcall_thunk() do { } while(0)
# define call_func4(func, a, b, c, d) func(a, b, c, d)
# endif /* __i386__ */
2014-04-18 22:50:27 +00:00
2007-03-06 11:59:18 +00:00
static void test_signalandwait ( void )
{
DWORD r ;
2011-10-03 17:58:01 +00:00
HANDLE event [ 2 ] , semaphore [ 2 ] , file ;
2015-03-09 17:15:16 +00:00
int i ;
2007-03-06 11:59:18 +00:00
/* invalid parameters */
2018-04-03 12:39:42 +00:00
r = SignalObjectAndWait ( NULL , NULL , 0 , 0 ) ;
2007-03-06 11:59:18 +00:00
ok ( r = = WAIT_FAILED , " should fail \n " ) ;
2014-04-18 22:50:27 +00:00
event [ 0 ] = CreateEventW ( NULL , 0 , 0 , NULL ) ;
event [ 1 ] = CreateEventW ( NULL , 1 , 1 , NULL ) ;
2007-03-06 11:59:18 +00:00
ok ( event [ 0 ] & & event [ 1 ] , " failed to create event flags \n " ) ;
2018-04-03 12:39:42 +00:00
r = SignalObjectAndWait ( event [ 0 ] , NULL , 0 , FALSE ) ;
2007-03-06 11:59:18 +00:00
ok ( r = = WAIT_FAILED , " should fail \n " ) ;
2018-04-03 12:39:42 +00:00
r = SignalObjectAndWait ( NULL , event [ 0 ] , 0 , FALSE ) ;
2007-03-06 11:59:18 +00:00
ok ( r = = WAIT_FAILED , " should fail \n " ) ;
/* valid parameters */
2018-04-03 12:39:42 +00:00
r = SignalObjectAndWait ( event [ 0 ] , event [ 1 ] , 0 , FALSE ) ;
2007-03-06 11:59:18 +00:00
ok ( r = = WAIT_OBJECT_0 , " should succeed \n " ) ;
2015-03-09 17:15:16 +00:00
/* event[0] is now signalled - we repeat this test multiple times
* to ensure that the wineserver handles this situation properly . */
for ( i = 0 ; i < 10000 ; i + + )
{
2018-04-03 12:39:42 +00:00
r = SignalObjectAndWait ( event [ 0 ] , event [ 0 ] , 0 , FALSE ) ;
2015-11-23 16:10:53 +00:00
ok ( r = = WAIT_OBJECT_0 , " should succeed \n " ) ;
2015-03-09 17:15:16 +00:00
}
2007-03-06 11:59:18 +00:00
/* event[0] is not signalled */
r = WaitForSingleObject ( event [ 0 ] , 0 ) ;
ok ( r = = WAIT_TIMEOUT , " event was signalled \n " ) ;
2018-04-03 12:39:42 +00:00
r = SignalObjectAndWait ( event [ 0 ] , event [ 0 ] , 0 , FALSE ) ;
2007-03-06 11:59:18 +00:00
ok ( r = = WAIT_OBJECT_0 , " should succeed \n " ) ;
/* clear event[1] and check for a timeout */
ok ( ResetEvent ( event [ 1 ] ) , " failed to clear event[1] \n " ) ;
2018-04-03 12:39:42 +00:00
r = SignalObjectAndWait ( event [ 0 ] , event [ 1 ] , 0 , FALSE ) ;
2007-03-06 11:59:18 +00:00
ok ( r = = WAIT_TIMEOUT , " should timeout \n " ) ;
CloseHandle ( event [ 0 ] ) ;
CloseHandle ( event [ 1 ] ) ;
/* semaphores */
2014-04-18 22:50:27 +00:00
semaphore [ 0 ] = CreateSemaphoreW ( NULL , 0 , 1 , NULL ) ;
semaphore [ 1 ] = CreateSemaphoreW ( NULL , 1 , 1 , NULL ) ;
2007-03-06 11:59:18 +00:00
ok ( semaphore [ 0 ] & & semaphore [ 1 ] , " failed to create semaphore \n " ) ;
2018-04-03 12:39:42 +00:00
r = SignalObjectAndWait ( semaphore [ 0 ] , semaphore [ 1 ] , 0 , FALSE ) ;
2007-03-06 11:59:18 +00:00
ok ( r = = WAIT_OBJECT_0 , " should succeed \n " ) ;
2018-04-03 12:39:42 +00:00
r = SignalObjectAndWait ( semaphore [ 0 ] , semaphore [ 1 ] , 0 , FALSE ) ;
2007-03-06 11:59:18 +00:00
ok ( r = = WAIT_FAILED , " should fail \n " ) ;
r = ReleaseSemaphore ( semaphore [ 0 ] , 1 , NULL ) ;
ok ( r = = FALSE , " should fail \n " ) ;
r = ReleaseSemaphore ( semaphore [ 1 ] , 1 , NULL ) ;
ok ( r = = TRUE , " should succeed \n " ) ;
CloseHandle ( semaphore [ 0 ] ) ;
CloseHandle ( semaphore [ 1 ] ) ;
/* try a registry key */
2014-04-18 22:50:27 +00:00
file = CreateFileA ( " x " , GENERIC_READ | GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS ,
2007-03-06 11:59:18 +00:00
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE , NULL ) ;
2018-04-03 12:39:42 +00:00
r = SignalObjectAndWait ( file , file , 0 , FALSE ) ;
2007-03-06 11:59:18 +00:00
ok ( r = = WAIT_FAILED , " should fail \n " ) ;
ok ( ERROR_INVALID_HANDLE = = GetLastError ( ) , " should return invalid handle error \n " ) ;
CloseHandle ( file ) ;
}
2008-05-09 17:35:45 +00:00
static void test_mutex ( void )
{
DWORD wait_ret ;
BOOL ret ;
HANDLE hCreated ;
HANDLE hOpened ;
2011-10-03 17:58:01 +00:00
int i ;
DWORD failed = 0 ;
2008-05-09 17:35:45 +00:00
2012-05-12 19:33:11 +00:00
SetLastError ( 0xdeadbeef ) ;
2014-04-18 22:50:27 +00:00
hOpened = OpenMutexA ( 0 , FALSE , " WineTestMutex " ) ;
2012-05-12 19:33:11 +00:00
ok ( hOpened = = NULL , " OpenMutex succeeded \n " ) ;
ok ( GetLastError ( ) = = ERROR_FILE_NOT_FOUND , " wrong error %u \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
2014-04-18 22:50:27 +00:00
hCreated = CreateMutexA ( NULL , FALSE , " WineTestMutex " ) ;
2008-05-09 17:35:45 +00:00
ok ( hCreated ! = NULL , " CreateMutex failed with error %d \n " , GetLastError ( ) ) ;
2012-05-12 19:33:11 +00:00
SetLastError ( 0xdeadbeef ) ;
2014-04-18 22:50:27 +00:00
hOpened = OpenMutexA ( 0 , FALSE , " WineTestMutex " ) ;
2012-05-12 19:33:11 +00:00
todo_wine
ok ( hOpened = = NULL , " OpenMutex succeeded \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_ACCESS_DENIED , " wrong error %u \n " , GetLastError ( ) ) ;
2011-10-03 17:58:01 +00:00
2012-05-12 19:33:11 +00:00
SetLastError ( 0xdeadbeef ) ;
2014-04-18 22:50:27 +00:00
hOpened = OpenMutexA ( GENERIC_EXECUTE , FALSE , " WineTestMutex " ) ;
2011-10-03 17:58:01 +00:00
ok ( hOpened ! = NULL , " OpenMutex failed with error %d \n " , GetLastError ( ) ) ;
wait_ret = WaitForSingleObject ( hOpened , INFINITE ) ;
ok ( wait_ret = = WAIT_OBJECT_0 , " WaitForSingleObject failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( hOpened ) ;
for ( i = 0 ; i < 31 ; i + + )
{
wait_ret = WaitForSingleObject ( hCreated , INFINITE ) ;
ok ( wait_ret = = WAIT_OBJECT_0 , " WaitForSingleObject failed with error 0x%08x \n " , wait_ret ) ;
}
2012-05-12 19:33:11 +00:00
SetLastError ( 0xdeadbeef ) ;
2014-04-18 22:50:27 +00:00
hOpened = OpenMutexA ( GENERIC_READ | GENERIC_WRITE , FALSE , " WineTestMutex " ) ;
2008-05-09 17:35:45 +00:00
ok ( hOpened ! = NULL , " OpenMutex failed with error %d \n " , GetLastError ( ) ) ;
2011-10-03 17:58:01 +00:00
wait_ret = WaitForSingleObject ( hOpened , INFINITE ) ;
ok ( wait_ret = = WAIT_FAILED , " WaitForSingleObject succeeded \n " ) ;
CloseHandle ( hOpened ) ;
for ( i = 0 ; i < 32 ; i + + )
{
2012-05-12 19:33:11 +00:00
SetLastError ( 0xdeadbeef ) ;
2014-04-18 22:50:27 +00:00
hOpened = OpenMutexA ( 0x1 < < i , FALSE , " WineTestMutex " ) ;
2011-10-03 17:58:01 +00:00
if ( hOpened ! = NULL )
{
2012-05-12 19:33:11 +00:00
SetLastError ( 0xdeadbeef ) ;
2011-10-03 17:58:01 +00:00
ret = ReleaseMutex ( hOpened ) ;
ok ( ret , " ReleaseMutex failed with error %d, access %x \n " , GetLastError ( ) , 1 < < i ) ;
CloseHandle ( hOpened ) ;
}
else
{
2012-05-12 19:33:11 +00:00
if ( ( 1 < < i ) = = ACCESS_SYSTEM_SECURITY )
todo_wine ok ( GetLastError ( ) = = ERROR_PRIVILEGE_NOT_HELD , " wrong error %u, access %x \n " , GetLastError ( ) , 1 < < i ) ;
else
todo_wine ok ( GetLastError ( ) = = ERROR_ACCESS_DENIED , " wrong error %u, , access %x \n " , GetLastError ( ) , 1 < < i ) ;
2011-10-03 17:58:01 +00:00
ReleaseMutex ( hCreated ) ;
failed | = 0x1 < < i ;
}
}
2012-05-12 19:33:11 +00:00
todo_wine
ok ( failed = = 0x0de0fffe , " open succeeded when it shouldn't: %x \n " , failed ) ;
2011-10-03 17:58:01 +00:00
2012-05-12 19:33:11 +00:00
SetLastError ( 0xdeadbeef ) ;
2008-05-09 17:35:45 +00:00
ret = ReleaseMutex ( hCreated ) ;
2011-10-03 17:58:01 +00:00
ok ( ! ret & & ( GetLastError ( ) = = ERROR_NOT_OWNER ) ,
2008-05-09 17:35:45 +00:00
" ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %d \n " , GetLastError ( ) ) ;
2008-12-23 20:02:47 +00:00
/* test case sensitivity */
SetLastError ( 0xdeadbeef ) ;
2014-04-18 22:50:27 +00:00
hOpened = OpenMutexA ( READ_CONTROL , FALSE , " WINETESTMUTEX " ) ;
2008-12-23 20:02:47 +00:00
ok ( ! hOpened , " OpenMutex succeeded \n " ) ;
2011-10-03 17:58:01 +00:00
ok ( GetLastError ( ) = = ERROR_FILE_NOT_FOUND , " wrong error %u \n " , GetLastError ( ) ) ;
2008-12-23 20:02:47 +00:00
SetLastError ( 0xdeadbeef ) ;
2014-04-18 22:50:27 +00:00
hOpened = OpenMutexA ( READ_CONTROL , FALSE , " winetestmutex " ) ;
2008-12-23 20:02:47 +00:00
ok ( ! hOpened , " OpenMutex succeeded \n " ) ;
2011-10-03 17:58:01 +00:00
ok ( GetLastError ( ) = = ERROR_FILE_NOT_FOUND , " wrong error %u \n " , GetLastError ( ) ) ;
2008-12-23 20:02:47 +00:00
2018-04-03 12:39:42 +00:00
SetLastError ( 0xdeadbeef ) ;
hOpened = OpenMutexA ( READ_CONTROL , FALSE , NULL ) ;
ok ( ! hOpened , " OpenMutex succeeded \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong error %u \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
hOpened = OpenMutexW ( READ_CONTROL , FALSE , NULL ) ;
ok ( ! hOpened , " OpenMutex succeeded \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong error %u \n " , GetLastError ( ) ) ;
2008-12-23 20:02:47 +00:00
SetLastError ( 0xdeadbeef ) ;
2014-04-18 22:50:27 +00:00
hOpened = CreateMutexA ( NULL , FALSE , " WineTestMutex " ) ;
2008-12-23 20:02:47 +00:00
ok ( hOpened ! = NULL , " CreateMutex failed with error %d \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = ERROR_ALREADY_EXISTS , " wrong error %u \n " , GetLastError ( ) ) ;
CloseHandle ( hOpened ) ;
SetLastError ( 0xdeadbeef ) ;
2014-04-18 22:50:27 +00:00
hOpened = CreateMutexA ( NULL , FALSE , " WINETESTMUTEX " ) ;
2008-12-23 20:02:47 +00:00
ok ( hOpened ! = NULL , " CreateMutex failed with error %d \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = 0 , " wrong error %u \n " , GetLastError ( ) ) ;
2008-05-09 17:35:45 +00:00
CloseHandle ( hOpened ) ;
2008-12-23 20:02:47 +00:00
2008-05-09 17:35:45 +00:00
CloseHandle ( hCreated ) ;
}
static void test_slist ( void )
{
struct item
{
SLIST_ENTRY entry ;
int value ;
2016-03-08 15:49:46 +00:00
} item1 , item2 , item3 , * item ;
2009-05-17 07:05:22 +00:00
SLIST_HEADER slist_header ;
2016-03-08 15:49:46 +00:00
SLIST_ENTRY * entry ;
2008-05-09 17:35:45 +00:00
USHORT size ;
2014-04-18 22:50:27 +00:00
int i ;
2008-05-09 17:35:45 +00:00
item1 . value = 1 ;
item2 . value = 2 ;
item3 . value = 3 ;
2016-03-08 15:49:46 +00:00
memset ( & slist_header , 0xff , sizeof ( slist_header ) ) ;
InitializeSListHead ( & slist_header ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 0 , " Expected size == 0, got %u \n " , size ) ;
/* test PushEntry, PopEntry and Flush */
entry = InterlockedPushEntrySList ( & slist_header , & item1 . entry ) ;
ok ( entry = = NULL , " Expected entry == NULL, got %p \n " , entry ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 1 , " Expected size == 1, got %u \n " , size ) ;
entry = InterlockedPushEntrySList ( & slist_header , & item2 . entry ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 1 , " Expected item->value == 1, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 2 , " Expected size == 2, got %u \n " , size ) ;
entry = InterlockedPushEntrySList ( & slist_header , & item3 . entry ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 2 , " Expected item->value == 2, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 3 , " Expected size == 3, got %u \n " , size ) ;
entry = InterlockedPopEntrySList ( & slist_header ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 3 , " Expected item->value == 3, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 2 , " Expected size == 2, got %u \n " , size ) ;
entry = InterlockedFlushSList ( & slist_header ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 2 , " Expected item->value == 2, got %u \n " , item - > value ) ;
item = CONTAINING_RECORD ( item - > entry . Next , struct item , entry ) ;
ok ( item - > value = = 1 , " Expected item->value == 1, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 0 , " Expected size == 0, got %u \n " , size ) ;
entry = InterlockedPopEntrySList ( & slist_header ) ;
ok ( entry = = NULL , " Expected entry == NULL, got %p \n " , entry ) ;
/* test RtlInterlockedPushListSList */
entry = InterlockedPushEntrySList ( & slist_header , & item3 . entry ) ;
ok ( entry = = NULL , " Expected entry == NULL, got %p \n " , entry ) ;
entry = call_func4 ( pRtlInterlockedPushListSList , & slist_header , & item2 . entry , & item1 . entry , 42 ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 3 , " Expected item->value == 3, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 43 , " Expected size == 43, got %u \n " , size ) ;
entry = InterlockedPopEntrySList ( & slist_header ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 2 , " Expected item->value == 2, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 42 , " Expected size == 42, got %u \n " , size ) ;
entry = InterlockedPopEntrySList ( & slist_header ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 1 , " Expected item->value == 1, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 41 , " Expected size == 41, got %u \n " , size ) ;
entry = InterlockedPopEntrySList ( & slist_header ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 3 , " Expected item->value == 3, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 40 , " Expected size == 40, got %u \n " , size ) ;
entry = InterlockedPopEntrySList ( & slist_header ) ;
ok ( entry = = NULL , " Expected entry == NULL, got %p \n " , entry ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 40 , " Expected size == 40, got %u \n " , size ) ;
entry = InterlockedFlushSList ( & slist_header ) ;
ok ( entry = = NULL , " Expected entry == NULL, got %p \n " , entry ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 40 | | broken ( size = = 0 ) /* >= Win 8 */ , " Expected size == 40, got %u \n " , size ) ;
entry = InterlockedPushEntrySList ( & slist_header , & item1 . entry ) ;
ok ( entry = = NULL , " Expected entry == NULL, got %p \n " , entry ) ;
entry = InterlockedFlushSList ( & slist_header ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 1 , " Expected item->value == 1, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 0 , " Expected size == 0, got %u \n " , size ) ;
/* test RtlInterlockedPushListSListEx */
if ( pRtlInterlockedPushListSListEx )
2008-05-09 17:35:45 +00:00
{
2016-03-08 15:49:46 +00:00
entry = InterlockedPushEntrySList ( & slist_header , & item3 . entry ) ;
ok ( entry = = NULL , " Expected entry == NULL, got %p \n " , entry ) ;
entry = pRtlInterlockedPushListSListEx ( & slist_header , & item2 . entry , & item1 . entry , 42 ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 3 , " Expected item->value == 3, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 43 , " Expected size == 43, got %u \n " , size ) ;
entry = InterlockedFlushSList ( & slist_header ) ;
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = 2 , " Expected item->value == 2, got %u \n " , item - > value ) ;
item = CONTAINING_RECORD ( item - > entry . Next , struct item , entry ) ;
ok ( item - > value = = 1 , " Expected item->value == 1, got %u \n " , item - > value ) ;
item = CONTAINING_RECORD ( item - > entry . Next , struct item , entry ) ;
ok ( item - > value = = 3 , " Expected item->value == 3, got %u \n " , item - > value ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 0 , " Expected size == 0, got %u \n " , size ) ;
2008-05-09 17:35:45 +00:00
}
2016-03-08 15:49:46 +00:00
else
win_skip ( " RtlInterlockedPushListSListEx not available, skipping tests \n " ) ;
2014-04-18 22:50:27 +00:00
2016-03-08 15:49:46 +00:00
/* test with a lot of items */
2014-04-18 22:50:27 +00:00
for ( i = 0 ; i < 65536 ; i + + )
{
2016-03-08 15:49:46 +00:00
item = HeapAlloc ( GetProcessHeap ( ) , 0 , sizeof ( * item ) ) ;
item - > value = i + 1 ;
entry = InterlockedPushEntrySList ( & slist_header , & item - > entry ) ;
if ( i )
{
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = i , " Expected item->value == %u, got %u \n " , i , item - > value ) ;
}
else
{
ok ( entry = = NULL , " Expected entry == NULL, got %p \n " , entry ) ;
}
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = ( ( i + 1 ) & 0xffff ) , " Expected size == %u, got %u \n " , ( i + 1 ) & 0xffff , size ) ;
2014-04-18 22:50:27 +00:00
}
2016-03-08 15:49:46 +00:00
entry = InterlockedFlushSList ( & slist_header ) ;
for ( i = 65536 ; i > 0 ; i - - )
2014-04-18 22:50:27 +00:00
{
2016-03-08 15:49:46 +00:00
ok ( entry ! = NULL , " Expected entry != NULL, got %p \n " , entry ) ;
item = CONTAINING_RECORD ( entry , struct item , entry ) ;
ok ( item - > value = = i , " Expected item->value == %u, got %u \n " , i , item - > value ) ;
entry = item - > entry . Next ;
HeapFree ( GetProcessHeap ( ) , 0 , item ) ;
2014-04-18 22:50:27 +00:00
}
2016-03-08 15:49:46 +00:00
ok ( entry = = NULL , " Expected entry == NULL, got %p \n " , entry ) ;
size = QueryDepthSList ( & slist_header ) ;
ok ( size = = 0 , " Expected size == 0, got %u \n " , size ) ;
entry = InterlockedPopEntrySList ( & slist_header ) ;
ok ( entry = = NULL , " Expected entry == NULL, got %p \n " , entry ) ;
2008-05-09 17:35:45 +00:00
}
2008-12-23 20:02:47 +00:00
static void test_event ( void )
2008-05-09 17:35:45 +00:00
{
2008-12-23 20:02:47 +00:00
HANDLE handle , handle2 ;
2008-05-09 17:35:45 +00:00
SECURITY_ATTRIBUTES sa ;
SECURITY_DESCRIPTOR sd ;
ACL acl ;
2012-05-12 19:33:11 +00:00
DWORD ret ;
BOOL val ;
2008-05-09 17:35:45 +00:00
/* no sd */
handle = CreateEventA ( NULL , FALSE , FALSE , __FILE__ " : Test Event " ) ;
ok ( handle ! = NULL , " CreateEventW with blank sd failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( handle ) ;
sa . nLength = sizeof ( sa ) ;
sa . lpSecurityDescriptor = & sd ;
sa . bInheritHandle = FALSE ;
InitializeSecurityDescriptor ( & sd , SECURITY_DESCRIPTOR_REVISION ) ;
/* blank sd */
handle = CreateEventA ( & sa , FALSE , FALSE , __FILE__ " : Test Event " ) ;
ok ( handle ! = NULL , " CreateEventW with blank sd failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( handle ) ;
/* sd with NULL dacl */
SetSecurityDescriptorDacl ( & sd , TRUE , NULL , FALSE ) ;
handle = CreateEventA ( & sa , FALSE , FALSE , __FILE__ " : Test Event " ) ;
ok ( handle ! = NULL , " CreateEventW with blank sd failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( handle ) ;
/* sd with empty dacl */
InitializeAcl ( & acl , sizeof ( acl ) , ACL_REVISION ) ;
SetSecurityDescriptorDacl ( & sd , TRUE , & acl , FALSE ) ;
handle = CreateEventA ( & sa , FALSE , FALSE , __FILE__ " : Test Event " ) ;
ok ( handle ! = NULL , " CreateEventW with blank sd failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( handle ) ;
2008-12-23 20:02:47 +00:00
/* test case sensitivity */
SetLastError ( 0xdeadbeef ) ;
handle = CreateEventA ( NULL , FALSE , FALSE , __FILE__ " : Test Event " ) ;
ok ( handle ! = NULL , " CreateEvent failed with error %u \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = 0 , " wrong error %u \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = CreateEventA ( NULL , FALSE , FALSE , __FILE__ " : Test Event " ) ;
ok ( handle2 ! = NULL , " CreateEvent failed with error %d \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = ERROR_ALREADY_EXISTS , " wrong error %u \n " , GetLastError ( ) ) ;
CloseHandle ( handle2 ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = CreateEventA ( NULL , FALSE , FALSE , __FILE__ " : TEST EVENT " ) ;
ok ( handle2 ! = NULL , " CreateEvent failed with error %d \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = 0 , " wrong error %u \n " , GetLastError ( ) ) ;
CloseHandle ( handle2 ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = OpenEventA ( EVENT_ALL_ACCESS , FALSE , __FILE__ " : Test Event " ) ;
ok ( handle2 ! = NULL , " OpenEvent failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( handle2 ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = OpenEventA ( EVENT_ALL_ACCESS , FALSE , __FILE__ " : TEST EVENT " ) ;
ok ( ! handle2 , " OpenEvent succeeded \n " ) ;
2011-10-03 17:58:01 +00:00
ok ( GetLastError ( ) = = ERROR_FILE_NOT_FOUND , " wrong error %u \n " , GetLastError ( ) ) ;
2008-12-23 20:02:47 +00:00
2018-04-03 12:39:42 +00:00
SetLastError ( 0xdeadbeef ) ;
handle2 = OpenEventA ( EVENT_ALL_ACCESS , FALSE , NULL ) ;
ok ( ! handle2 , " OpenEvent succeeded \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong error %u \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = OpenEventW ( EVENT_ALL_ACCESS , FALSE , NULL ) ;
ok ( ! handle2 , " OpenEvent succeeded \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong error %u \n " , GetLastError ( ) ) ;
2008-12-23 20:02:47 +00:00
CloseHandle ( handle ) ;
2012-05-12 19:33:11 +00:00
/* resource notifications are events too */
if ( ! pCreateMemoryResourceNotification | | ! pQueryMemoryResourceNotification )
{
trace ( " memory resource notifications not supported \n " ) ;
return ;
}
handle = pCreateMemoryResourceNotification ( HighMemoryResourceNotification + 1 ) ;
ok ( ! handle , " CreateMemoryResourceNotification succeeded \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong error %u \n " , GetLastError ( ) ) ;
ret = pQueryMemoryResourceNotification ( handle , & val ) ;
ok ( ! ret , " QueryMemoryResourceNotification succeeded \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong error %u \n " , GetLastError ( ) ) ;
handle = pCreateMemoryResourceNotification ( LowMemoryResourceNotification ) ;
ok ( handle ! = 0 , " CreateMemoryResourceNotification failed err %u \n " , GetLastError ( ) ) ;
ret = WaitForSingleObject ( handle , 10 ) ;
ok ( ret = = WAIT_OBJECT_0 | | ret = = WAIT_TIMEOUT , " WaitForSingleObject wrong ret %u \n " , ret ) ;
val = ~ 0 ;
ret = pQueryMemoryResourceNotification ( handle , & val ) ;
ok ( ret , " QueryMemoryResourceNotification failed err %u \n " , GetLastError ( ) ) ;
ok ( val = = FALSE | | val = = TRUE , " wrong value %u \n " , val ) ;
ret = CloseHandle ( handle ) ;
ok ( ret , " CloseHandle failed err %u \n " , GetLastError ( ) ) ;
handle = CreateEventA ( NULL , FALSE , FALSE , __FILE__ " : Test Event " ) ;
val = ~ 0 ;
ret = pQueryMemoryResourceNotification ( handle , & val ) ;
ok ( ret , " QueryMemoryResourceNotification failed err %u \n " , GetLastError ( ) ) ;
ok ( val = = FALSE | | val = = TRUE , " wrong value %u \n " , val ) ;
CloseHandle ( handle ) ;
2008-12-23 20:02:47 +00:00
}
static void test_semaphore ( void )
{
HANDLE handle , handle2 ;
/* test case sensitivity */
SetLastError ( 0xdeadbeef ) ;
handle = CreateSemaphoreA ( NULL , 0 , 1 , __FILE__ " : Test Semaphore " ) ;
ok ( handle ! = NULL , " CreateSemaphore failed with error %u \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = 0 , " wrong error %u \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = CreateSemaphoreA ( NULL , 0 , 1 , __FILE__ " : Test Semaphore " ) ;
ok ( handle2 ! = NULL , " CreateSemaphore failed with error %d \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = ERROR_ALREADY_EXISTS , " wrong error %u \n " , GetLastError ( ) ) ;
CloseHandle ( handle2 ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = CreateSemaphoreA ( NULL , 0 , 1 , __FILE__ " : TEST SEMAPHORE " ) ;
ok ( handle2 ! = NULL , " CreateSemaphore failed with error %d \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = 0 , " wrong error %u \n " , GetLastError ( ) ) ;
CloseHandle ( handle2 ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = OpenSemaphoreA ( SEMAPHORE_ALL_ACCESS , FALSE , __FILE__ " : Test Semaphore " ) ;
ok ( handle2 ! = NULL , " OpenSemaphore failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( handle2 ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = OpenSemaphoreA ( SEMAPHORE_ALL_ACCESS , FALSE , __FILE__ " : TEST SEMAPHORE " ) ;
ok ( ! handle2 , " OpenSemaphore succeeded \n " ) ;
2011-10-03 17:58:01 +00:00
ok ( GetLastError ( ) = = ERROR_FILE_NOT_FOUND , " wrong error %u \n " , GetLastError ( ) ) ;
2008-12-23 20:02:47 +00:00
2018-04-03 12:39:42 +00:00
SetLastError ( 0xdeadbeef ) ;
handle2 = OpenSemaphoreA ( SEMAPHORE_ALL_ACCESS , FALSE , NULL ) ;
ok ( ! handle2 , " OpenSemaphore succeeded \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong error %u \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = OpenSemaphoreW ( SEMAPHORE_ALL_ACCESS , FALSE , NULL ) ;
ok ( ! handle2 , " OpenSemaphore succeeded \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong error %u \n " , GetLastError ( ) ) ;
2008-12-23 20:02:47 +00:00
CloseHandle ( handle ) ;
}
static void test_waitable_timer ( void )
{
HANDLE handle , handle2 ;
/* test case sensitivity */
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
handle = CreateWaitableTimerA ( NULL , FALSE , __FILE__ " : Test WaitableTimer " ) ;
2008-12-23 20:02:47 +00:00
ok ( handle ! = NULL , " CreateWaitableTimer failed with error %u \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = 0 , " wrong error %u \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
handle2 = CreateWaitableTimerA ( NULL , FALSE , __FILE__ " : Test WaitableTimer " ) ;
2008-12-23 20:02:47 +00:00
ok ( handle2 ! = NULL , " CreateWaitableTimer failed with error %d \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = ERROR_ALREADY_EXISTS , " wrong error %u \n " , GetLastError ( ) ) ;
CloseHandle ( handle2 ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
handle2 = CreateWaitableTimerA ( NULL , FALSE , __FILE__ " : TEST WAITABLETIMER " ) ;
2008-12-23 20:02:47 +00:00
ok ( handle2 ! = NULL , " CreateWaitableTimer failed with error %d \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = 0 , " wrong error %u \n " , GetLastError ( ) ) ;
CloseHandle ( handle2 ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
handle2 = OpenWaitableTimerA ( TIMER_ALL_ACCESS , FALSE , __FILE__ " : Test WaitableTimer " ) ;
2008-12-23 20:02:47 +00:00
ok ( handle2 ! = NULL , " OpenWaitableTimer failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( handle2 ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
handle2 = OpenWaitableTimerA ( TIMER_ALL_ACCESS , FALSE , __FILE__ " : TEST WAITABLETIMER " ) ;
2008-12-23 20:02:47 +00:00
ok ( ! handle2 , " OpenWaitableTimer succeeded \n " ) ;
2018-04-03 12:39:42 +00:00
ok ( GetLastError ( ) = = ERROR_FILE_NOT_FOUND , " wrong error %u \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = OpenWaitableTimerA ( TIMER_ALL_ACCESS , FALSE , NULL ) ;
ok ( ! handle2 , " OpenWaitableTimer failed with error %d \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong error %u \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
handle2 = OpenWaitableTimerW ( TIMER_ALL_ACCESS , FALSE , NULL ) ;
ok ( ! handle2 , " OpenWaitableTimer failed with error %d \n " , GetLastError ( ) ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong error %u \n " , GetLastError ( ) ) ;
2008-12-23 20:02:47 +00:00
CloseHandle ( handle ) ;
2008-05-09 17:35:45 +00:00
}
static HANDLE sem = 0 ;
static void CALLBACK iocp_callback ( DWORD dwErrorCode , DWORD dwNumberOfBytesTransferred , LPOVERLAPPED lpOverlapped )
{
ReleaseSemaphore ( sem , 1 , NULL ) ;
}
2008-12-23 20:02:47 +00:00
static BOOL ( WINAPI * p_BindIoCompletionCallback ) ( HANDLE FileHandle , LPOVERLAPPED_COMPLETION_ROUTINE Function , ULONG Flags ) = NULL ;
2008-05-09 17:35:45 +00:00
static void test_iocp_callback ( void )
{
char temp_path [ MAX_PATH ] ;
char filename [ MAX_PATH ] ;
DWORD ret ;
BOOL retb ;
static const char prefix [ ] = " pfx " ;
HANDLE hFile ;
HMODULE hmod = GetModuleHandleA ( " kernel32.dll " ) ;
DWORD bytesWritten ;
const char * buffer = " 12345678123456781234567812345678 " ;
OVERLAPPED overlapped ;
p_BindIoCompletionCallback = ( void * ) GetProcAddress ( hmod , " BindIoCompletionCallback " ) ;
if ( ! p_BindIoCompletionCallback ) {
2009-05-17 07:05:22 +00:00
win_skip ( " BindIoCompletionCallback not found in this DLL \n " ) ;
2008-05-09 17:35:45 +00:00
return ;
}
2014-04-18 22:50:27 +00:00
sem = CreateSemaphoreW ( NULL , 0 , 1 , NULL ) ;
2008-05-09 17:35:45 +00:00
ok ( sem ! = INVALID_HANDLE_VALUE , " Creating a semaphore failed \n " ) ;
ret = GetTempPathA ( MAX_PATH , temp_path ) ;
ok ( ret ! = 0 , " GetTempPathA error %d \n " , GetLastError ( ) ) ;
ok ( ret < MAX_PATH , " temp path should fit into MAX_PATH \n " ) ;
ret = GetTempFileNameA ( temp_path , prefix , 0 , filename ) ;
ok ( ret ! = 0 , " GetTempFileNameA error %d \n " , GetLastError ( ) ) ;
hFile = CreateFileA ( filename , GENERIC_READ | GENERIC_WRITE , 0 , NULL ,
CREATE_ALWAYS , FILE_FLAG_RANDOM_ACCESS , 0 ) ;
ok ( hFile ! = INVALID_HANDLE_VALUE , " CreateFileA: error %d \n " , GetLastError ( ) ) ;
retb = p_BindIoCompletionCallback ( hFile , iocp_callback , 0 ) ;
ok ( retb = = FALSE , " BindIoCompletionCallback succeeded on a file that wasn't created with FILE_FLAG_OVERLAPPED \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " Last error is %d \n " , GetLastError ( ) ) ;
ret = CloseHandle ( hFile ) ;
ok ( ret , " CloseHandle: error %d \n " , GetLastError ( ) ) ;
ret = DeleteFileA ( filename ) ;
ok ( ret , " DeleteFileA: error %d \n " , GetLastError ( ) ) ;
hFile = CreateFileA ( filename , GENERIC_READ | GENERIC_WRITE , 0 , NULL ,
CREATE_ALWAYS , FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED , 0 ) ;
ok ( hFile ! = INVALID_HANDLE_VALUE , " CreateFileA: error %d \n " , GetLastError ( ) ) ;
retb = p_BindIoCompletionCallback ( hFile , iocp_callback , 0 ) ;
ok ( retb = = TRUE , " BindIoCompletionCallback failed \n " ) ;
memset ( & overlapped , 0 , sizeof ( overlapped ) ) ;
2009-05-17 07:05:22 +00:00
retb = WriteFile ( hFile , buffer , 4 , & bytesWritten , & overlapped ) ;
2008-05-09 17:35:45 +00:00
ok ( retb = = TRUE | | GetLastError ( ) = = ERROR_IO_PENDING , " WriteFile failed, lastError = %d \n " , GetLastError ( ) ) ;
ret = WaitForSingleObject ( sem , 5000 ) ;
ok ( ret = = WAIT_OBJECT_0 , " Wait for the IO completion callback failed \n " ) ;
CloseHandle ( sem ) ;
retb = p_BindIoCompletionCallback ( hFile , iocp_callback , 0 ) ;
ok ( retb = = FALSE , " BindIoCompletionCallback succeeded when setting the same callback on the file again \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " Last error is %d \n " , GetLastError ( ) ) ;
retb = p_BindIoCompletionCallback ( hFile , NULL , 0 ) ;
ok ( retb = = FALSE , " BindIoCompletionCallback succeeded when setting the callback to NULL \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER , " Last error is %d \n " , GetLastError ( ) ) ;
ret = CloseHandle ( hFile ) ;
ok ( ret , " CloseHandle: error %d \n " , GetLastError ( ) ) ;
ret = DeleteFileA ( filename ) ;
ok ( ret , " DeleteFileA: error %d \n " , GetLastError ( ) ) ;
/* win2k3 requires the Flags parameter to be zero */
SetLastError ( 0xdeadbeef ) ;
hFile = CreateFileA ( filename , GENERIC_READ | GENERIC_WRITE , 0 , NULL ,
CREATE_ALWAYS , FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED , 0 ) ;
ok ( hFile ! = INVALID_HANDLE_VALUE , " CreateFileA: error %d \n " , GetLastError ( ) ) ;
retb = p_BindIoCompletionCallback ( hFile , iocp_callback , 12345 ) ;
if ( ! retb )
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER ,
" Expected ERROR_INVALID_PARAMETER, got %d \n " , GetLastError ( ) ) ;
else
ok ( retb = = TRUE , " BindIoCompletionCallback failed with Flags != 0 \n " ) ;
ret = CloseHandle ( hFile ) ;
ok ( ret , " CloseHandle: error %d \n " , GetLastError ( ) ) ;
ret = DeleteFileA ( filename ) ;
ok ( ret , " DeleteFileA: error %d \n " , GetLastError ( ) ) ;
retb = p_BindIoCompletionCallback ( NULL , iocp_callback , 0 ) ;
ok ( retb = = FALSE , " BindIoCompletionCallback succeeded on a NULL file \n " ) ;
2008-12-23 20:02:47 +00:00
ok ( GetLastError ( ) = = ERROR_INVALID_HANDLE | |
GetLastError ( ) = = ERROR_INVALID_PARAMETER , /* vista */
" Last error is %d \n " , GetLastError ( ) ) ;
}
static void CALLBACK timer_queue_cb1 ( PVOID p , BOOLEAN timedOut )
{
2009-05-17 07:05:22 +00:00
int * pn = p ;
2019-09-15 13:07:32 +00:00
disable_success_count
2008-12-23 20:02:47 +00:00
ok ( timedOut , " Timer callbacks should always time out \n " ) ;
+ + * pn ;
}
struct timer_queue_data1
{
int num_calls ;
int max_calls ;
HANDLE q , t ;
} ;
static void CALLBACK timer_queue_cb2 ( PVOID p , BOOLEAN timedOut )
{
struct timer_queue_data1 * d = p ;
ok ( timedOut , " Timer callbacks should always time out \n " ) ;
if ( d - > t & & + + d - > num_calls = = d - > max_calls )
{
BOOL ret ;
SetLastError ( 0xdeadbeef ) ;
/* Note, XP SP2 does *not* do any deadlock checking, so passing
INVALID_HANDLE_VALUE here will just hang . */
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( d - > q , d - > t , NULL ) ;
2008-12-23 20:02:47 +00:00
ok ( ! ret , " DeleteTimerQueueTimer \n " ) ;
ok ( GetLastError ( ) = = ERROR_IO_PENDING , " DeleteTimerQueueTimer \n " ) ;
}
}
static void CALLBACK timer_queue_cb3 ( PVOID p , BOOLEAN timedOut )
{
struct timer_queue_data1 * d = p ;
ok ( timedOut , " Timer callbacks should always time out \n " ) ;
if ( d - > t & & + + d - > num_calls = = d - > max_calls )
{
/* Basically kill the timer since it won't have time to run
again . */
2018-04-03 12:39:42 +00:00
BOOL ret = ChangeTimerQueueTimer ( d - > q , d - > t , 10000 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " ChangeTimerQueueTimer \n " ) ;
}
}
static void CALLBACK timer_queue_cb4 ( PVOID p , BOOLEAN timedOut )
{
struct timer_queue_data1 * d = p ;
ok ( timedOut , " Timer callbacks should always time out \n " ) ;
if ( d - > t )
{
/* This tests whether a timer gets flagged for deletion before
or after the callback runs . If we start this timer with a
period of zero ( run once ) , then ChangeTimerQueueTimer will
fail if the timer is already flagged . Hence we really run
only once . Otherwise we will run multiple times . */
2018-04-03 12:39:42 +00:00
BOOL ret = ChangeTimerQueueTimer ( d - > q , d - > t , 50 , 50 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " ChangeTimerQueueTimer \n " ) ;
+ + d - > num_calls ;
}
}
static void CALLBACK timer_queue_cb5 ( PVOID p , BOOLEAN timedOut )
{
2009-05-17 07:05:22 +00:00
DWORD_PTR delay = ( DWORD_PTR ) p ;
2008-12-23 20:02:47 +00:00
ok ( timedOut , " Timer callbacks should always time out \n " ) ;
if ( delay )
Sleep ( delay ) ;
}
static void CALLBACK timer_queue_cb6 ( PVOID p , BOOLEAN timedOut )
{
struct timer_queue_data1 * d = p ;
ok ( timedOut , " Timer callbacks should always time out \n " ) ;
/* This tests an original implementation bug where a deleted timer may get
to run , but it is tricky to set up . */
if ( d - > q & & d - > num_calls + + = = 0 )
{
/* First run: delete ourselves, then insert and remove a timer
that goes in front of us in the sorted timeout list . Once
removed , we will still timeout at the faster timer ' s due time ,
but this should be a no - op if we are bug - free . There should
not be a second run . We can test the value of num_calls later . */
BOOL ret ;
HANDLE t ;
/* The delete will pend while we are in this callback. */
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( d - > q , d - > t , NULL ) ;
2008-12-23 20:02:47 +00:00
ok ( ! ret , " DeleteTimerQueueTimer \n " ) ;
ok ( GetLastError ( ) = = ERROR_IO_PENDING , " DeleteTimerQueueTimer \n " ) ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t , d - > q , timer_queue_cb1 , NULL , 100 , 0 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t ! = NULL , " CreateTimerQueueTimer \n " ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( d - > q , t , INVALID_HANDLE_VALUE ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " DeleteTimerQueueTimer \n " ) ;
/* Now we stay alive by hanging around in the callback. */
Sleep ( 500 ) ;
}
}
static void test_timer_queue ( void )
{
2012-12-09 20:39:13 +00:00
HANDLE q , t0 , t1 , t2 , t3 , t4 , t5 ;
int n0 , n1 , n2 , n3 , n4 , n5 ;
2008-12-23 20:02:47 +00:00
struct timer_queue_data1 d1 , d2 , d3 , d4 ;
HANDLE e , et1 , et2 ;
2012-12-09 20:39:13 +00:00
BOOL ret , ret0 ;
2008-12-23 20:02:47 +00:00
/* Test asynchronous deletion of the queue. */
2018-04-03 12:39:42 +00:00
q = CreateTimerQueue ( ) ;
2008-12-23 20:02:47 +00:00
ok ( q ! = NULL , " CreateTimerQueue \n " ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueEx ( q , NULL ) ;
2008-12-23 20:02:47 +00:00
ok ( ret /* vista */ | | GetLastError ( ) = = ERROR_IO_PENDING ,
" DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d \n " ,
GetLastError ( ) ) ;
/* Test synchronous deletion of the queue and running timers. */
2018-04-03 12:39:42 +00:00
q = CreateTimerQueue ( ) ;
2008-12-23 20:02:47 +00:00
ok ( q ! = NULL , " CreateTimerQueue \n " ) ;
2012-12-09 20:39:13 +00:00
/* Not called. */
t0 = NULL ;
n0 = 0 ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t0 , q , timer_queue_cb1 , & n0 , 0 , 300 , 0 ) ;
2012-12-09 20:39:13 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t0 ! = NULL , " CreateTimerQueueTimer \n " ) ;
2018-04-03 12:39:42 +00:00
ret0 = DeleteTimerQueueTimer ( q , t0 , NULL ) ;
2012-12-09 20:39:13 +00:00
ok ( ( ! ret0 & & GetLastError ( ) = = ERROR_IO_PENDING ) | |
broken ( ret0 ) , /* Win 2000 & XP & 2003 */
" DeleteTimerQueueTimer ret=%d le=%u \n " , ret0 , GetLastError ( ) ) ;
2008-12-23 20:02:47 +00:00
/* Called once. */
t1 = NULL ;
n1 = 0 ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t1 , q , timer_queue_cb1 , & n1 , 0 , 0 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t1 ! = NULL , " CreateTimerQueueTimer \n " ) ;
/* A slow one. */
t2 = NULL ;
n2 = 0 ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t2 , q , timer_queue_cb1 , & n2 , 0 , 100 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t2 ! = NULL , " CreateTimerQueueTimer \n " ) ;
/* A fast one. */
t3 = NULL ;
n3 = 0 ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t3 , q , timer_queue_cb1 , & n3 , 0 , 10 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t3 ! = NULL , " CreateTimerQueueTimer \n " ) ;
/* Start really late (it won't start). */
t4 = NULL ;
n4 = 0 ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t4 , q , timer_queue_cb1 , & n4 , 10000 , 10 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t4 ! = NULL , " CreateTimerQueueTimer \n " ) ;
/* Start soon, but delay so long it won't run again. */
t5 = NULL ;
n5 = 0 ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t5 , q , timer_queue_cb1 , & n5 , 0 , 10000 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t5 ! = NULL , " CreateTimerQueueTimer \n " ) ;
/* Give them a chance to do some work. */
Sleep ( 500 ) ;
/* Test deleting a once-only timer. */
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( q , t1 , INVALID_HANDLE_VALUE ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " DeleteTimerQueueTimer \n " ) ;
/* A periodic timer. */
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( q , t2 , INVALID_HANDLE_VALUE ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " DeleteTimerQueueTimer \n " ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueEx ( q , INVALID_HANDLE_VALUE ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " DeleteTimerQueueEx \n " ) ;
2012-12-09 20:39:13 +00:00
todo_wine
ok ( n0 = = 1 | | broken ( ret0 & & n0 = = 0 ) , " Timer callback 0 expected 1 got %d \n " , n0 ) ;
ok ( n1 = = 1 , " Timer callback 1 expected 1 got %d \n " , n1 ) ;
ok ( n2 < n3 , " Timer callback 2 & 3 expected %d < %d \n " , n2 , n3 ) ;
ok ( n4 = = 0 , " Timer callback 4 expected 0 got %d \n " , n4 ) ;
ok ( n5 = = 1 , " Timer callback 5 expected 1 got %d \n " , n5 ) ;
2008-12-23 20:02:47 +00:00
/* Test synchronous deletion of the timer/queue with event trigger. */
2014-04-18 22:50:27 +00:00
e = CreateEventW ( NULL , TRUE , FALSE , NULL ) ;
et1 = CreateEventW ( NULL , TRUE , FALSE , NULL ) ;
et2 = CreateEventW ( NULL , TRUE , FALSE , NULL ) ;
2008-12-23 20:02:47 +00:00
if ( ! e | | ! et1 | | ! et2 )
{
skip ( " Failed to create timer queue descruction event \n " ) ;
return ;
}
2018-04-03 12:39:42 +00:00
q = CreateTimerQueue ( ) ;
2008-12-23 20:02:47 +00:00
ok ( q ! = NULL , " CreateTimerQueue \n " ) ;
/* Run once and finish quickly (should be done when we delete it). */
t1 = NULL ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t1 , q , timer_queue_cb5 , NULL , 0 , 0 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t1 ! = NULL , " CreateTimerQueueTimer \n " ) ;
/* Run once and finish slowly (shouldn't be done when we delete it). */
t2 = NULL ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t2 , q , timer_queue_cb5 , ( PVOID ) 1000 , 0 , 0 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t2 ! = NULL , " CreateTimerQueueTimer \n " ) ;
/* Run once and finish quickly (should be done when we delete it). */
t3 = NULL ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t3 , q , timer_queue_cb5 , NULL , 0 , 0 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t3 ! = NULL , " CreateTimerQueueTimer \n " ) ;
/* Run once and finish slowly (shouldn't be done when we delete it). */
t4 = NULL ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t4 , q , timer_queue_cb5 , ( PVOID ) 1000 , 0 , 0 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t4 ! = NULL , " CreateTimerQueueTimer \n " ) ;
/* Give them a chance to start. */
Sleep ( 400 ) ;
/* DeleteTimerQueueTimer always returns PENDING with a NULL event,
even if the timer is finished . */
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( q , t1 , NULL ) ;
2008-12-23 20:02:47 +00:00
ok ( ret /* vista */ | | GetLastError ( ) = = ERROR_IO_PENDING ,
" DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d \n " ,
GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( q , t2 , NULL ) ;
2008-12-23 20:02:47 +00:00
ok ( ! ret , " DeleteTimerQueueTimer call was expected to fail \n " ) ;
ok ( GetLastError ( ) = = ERROR_IO_PENDING ,
" DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d \n " ,
GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( q , t3 , et1 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " DeleteTimerQueueTimer call was expected to fail \n " ) ;
ok ( GetLastError ( ) = = 0xdeadbeef ,
" DeleteTimerQueueTimer, GetLastError: expected 0xdeadbeef, got %d \n " ,
GetLastError ( ) ) ;
ok ( WaitForSingleObject ( et1 , 250 ) = = WAIT_OBJECT_0 ,
" Timer destruction event not triggered \n " ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( q , t4 , et2 ) ;
2008-12-23 20:02:47 +00:00
ok ( ! ret , " DeleteTimerQueueTimer call was expected to fail \n " ) ;
ok ( GetLastError ( ) = = ERROR_IO_PENDING ,
" DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d \n " ,
GetLastError ( ) ) ;
ok ( WaitForSingleObject ( et2 , 1000 ) = = WAIT_OBJECT_0 ,
" Timer destruction event not triggered \n " ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueEx ( q , e ) ;
2008-12-23 20:02:47 +00:00
ok ( ret /* vista */ | | GetLastError ( ) = = ERROR_IO_PENDING ,
" DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d \n " ,
GetLastError ( ) ) ;
ok ( WaitForSingleObject ( e , 250 ) = = WAIT_OBJECT_0 ,
" Queue destruction event not triggered \n " ) ;
CloseHandle ( e ) ;
/* Test deleting/changing a timer in execution. */
2018-04-03 12:39:42 +00:00
q = CreateTimerQueue ( ) ;
2008-12-23 20:02:47 +00:00
ok ( q ! = NULL , " CreateTimerQueue \n " ) ;
/* Test changing a once-only timer before it fires (this is allowed,
whereas after it fires you cannot ) . */
n1 = 0 ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t1 , q , timer_queue_cb1 , & n1 , 10000 , 0 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t1 ! = NULL , " CreateTimerQueueTimer \n " ) ;
2018-04-03 12:39:42 +00:00
ret = ChangeTimerQueueTimer ( q , t1 , 0 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " ChangeTimerQueueTimer \n " ) ;
d2 . t = t2 = NULL ;
d2 . num_calls = 0 ;
d2 . max_calls = 3 ;
d2 . q = q ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t2 , q , timer_queue_cb2 , & d2 , 10 , 10 , 0 ) ;
2008-12-23 20:02:47 +00:00
d2 . t = t2 ;
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t2 ! = NULL , " CreateTimerQueueTimer \n " ) ;
d3 . t = t3 = NULL ;
d3 . num_calls = 0 ;
d3 . max_calls = 4 ;
d3 . q = q ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t3 , q , timer_queue_cb3 , & d3 , 10 , 10 , 0 ) ;
2008-12-23 20:02:47 +00:00
d3 . t = t3 ;
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t3 ! = NULL , " CreateTimerQueueTimer \n " ) ;
d4 . t = t4 = NULL ;
d4 . num_calls = 0 ;
d4 . q = q ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t4 , q , timer_queue_cb4 , & d4 , 10 , 0 , 0 ) ;
2008-12-23 20:02:47 +00:00
d4 . t = t4 ;
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t4 ! = NULL , " CreateTimerQueueTimer \n " ) ;
Sleep ( 500 ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueEx ( q , INVALID_HANDLE_VALUE ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " DeleteTimerQueueEx \n " ) ;
ok ( n1 = = 1 , " ChangeTimerQueueTimer \n " ) ;
ok ( d2 . num_calls = = d2 . max_calls , " DeleteTimerQueueTimer \n " ) ;
ok ( d3 . num_calls = = d3 . max_calls , " ChangeTimerQueueTimer \n " ) ;
ok ( d4 . num_calls = = 1 , " Timer flagged for deletion incorrectly \n " ) ;
/* Test an obscure bug that was in the original implementation. */
2018-04-03 12:39:42 +00:00
q = CreateTimerQueue ( ) ;
2008-12-23 20:02:47 +00:00
ok ( q ! = NULL , " CreateTimerQueue \n " ) ;
/* All the work is done in the callback. */
d1 . t = t1 = NULL ;
d1 . num_calls = 0 ;
d1 . q = q ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t1 , q , timer_queue_cb6 , & d1 , 100 , 100 , WT_EXECUTELONGFUNCTION ) ;
2008-12-23 20:02:47 +00:00
d1 . t = t1 ;
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t1 ! = NULL , " CreateTimerQueueTimer \n " ) ;
Sleep ( 750 ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueEx ( q , NULL ) ;
2008-12-23 20:02:47 +00:00
ok ( ret /* vista */ | | GetLastError ( ) = = ERROR_IO_PENDING ,
" DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d \n " ,
GetLastError ( ) ) ;
ok ( d1 . num_calls = = 1 , " DeleteTimerQueueTimer \n " ) ;
/* Test functions on the default timer queue. */
t1 = NULL ;
n1 = 0 ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t1 , NULL , timer_queue_cb1 , & n1 , 1000 , 1000 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer, default queue \n " ) ;
ok ( t1 ! = NULL , " CreateTimerQueueTimer, default queue \n " ) ;
2018-04-03 12:39:42 +00:00
ret = ChangeTimerQueueTimer ( NULL , t1 , 2000 , 2000 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " ChangeTimerQueueTimer, default queue \n " ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( NULL , t1 , INVALID_HANDLE_VALUE ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " DeleteTimerQueueTimer, default queue \n " ) ;
/* Try mixing default and non-default queues. Apparently this works. */
2018-04-03 12:39:42 +00:00
q = CreateTimerQueue ( ) ;
2008-12-23 20:02:47 +00:00
ok ( q ! = NULL , " CreateTimerQueue \n " ) ;
t1 = NULL ;
n1 = 0 ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t1 , q , timer_queue_cb1 , & n1 , 1000 , 1000 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t1 ! = NULL , " CreateTimerQueueTimer \n " ) ;
t2 = NULL ;
n2 = 0 ;
2018-04-03 12:39:42 +00:00
ret = CreateTimerQueueTimer ( & t2 , NULL , timer_queue_cb1 , & n2 , 1000 , 1000 , 0 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " CreateTimerQueueTimer \n " ) ;
ok ( t2 ! = NULL , " CreateTimerQueueTimer \n " ) ;
2018-04-03 12:39:42 +00:00
ret = ChangeTimerQueueTimer ( NULL , t1 , 2000 , 2000 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " ChangeTimerQueueTimer \n " ) ;
2018-04-03 12:39:42 +00:00
ret = ChangeTimerQueueTimer ( q , t2 , 2000 , 2000 ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " ChangeTimerQueueTimer \n " ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( NULL , t1 , INVALID_HANDLE_VALUE ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " DeleteTimerQueueTimer \n " ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueTimer ( q , t2 , INVALID_HANDLE_VALUE ) ;
2008-12-23 20:02:47 +00:00
ok ( ret , " DeleteTimerQueueTimer \n " ) ;
/* Try to delete the default queue? In any case: not allowed. */
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueEx ( NULL , NULL ) ;
2008-12-23 20:02:47 +00:00
ok ( ! ret , " DeleteTimerQueueEx call was expected to fail \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_HANDLE ,
" DeleteTimerQueueEx, GetLastError: expected ERROR_INVALID_HANDLE, got %d \n " ,
GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
2018-04-03 12:39:42 +00:00
ret = DeleteTimerQueueEx ( q , NULL ) ;
2008-12-23 20:02:47 +00:00
ok ( ret /* vista */ | | GetLastError ( ) = = ERROR_IO_PENDING ,
" DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d \n " ,
GetLastError ( ) ) ;
2008-05-09 17:35:45 +00:00
}
2011-10-03 17:58:01 +00:00
static HANDLE modify_handle ( HANDLE handle , DWORD modify )
{
DWORD tmp = HandleToULong ( handle ) ;
tmp | = modify ;
return ULongToHandle ( tmp ) ;
}
static void test_WaitForSingleObject ( void )
{
HANDLE signaled , nonsignaled , invalid ;
2016-03-08 15:49:46 +00:00
LARGE_INTEGER timeout ;
NTSTATUS status ;
2011-10-03 17:58:01 +00:00
DWORD ret ;
signaled = CreateEventW ( NULL , TRUE , TRUE , NULL ) ;
nonsignaled = CreateEventW ( NULL , TRUE , FALSE , NULL ) ;
invalid = ( HANDLE ) 0xdeadbee0 ;
/* invalid handle with different values for lower 2 bits */
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( invalid , 0 ) ;
ok ( ret = = WAIT_FAILED , " expected WAIT_FAILED, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_HANDLE , " expected ERROR_INVALID_HANDLE, got %d \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( modify_handle ( invalid , 1 ) , 0 ) ;
ok ( ret = = WAIT_FAILED , " expected WAIT_FAILED, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_HANDLE , " expected ERROR_INVALID_HANDLE, got %d \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( modify_handle ( invalid , 2 ) , 0 ) ;
ok ( ret = = WAIT_FAILED , " expected WAIT_FAILED, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_HANDLE , " expected ERROR_INVALID_HANDLE, got %d \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( modify_handle ( invalid , 3 ) , 0 ) ;
ok ( ret = = WAIT_FAILED , " expected WAIT_FAILED, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_HANDLE , " expected ERROR_INVALID_HANDLE, got %d \n " , GetLastError ( ) ) ;
/* valid handle with different values for lower 2 bits */
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( nonsignaled , 0 ) ;
ok ( ret = = WAIT_TIMEOUT , " expected WAIT_TIMEOUT, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = 0xdeadbeef , " expected 0xdeadbeef, got %d \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( modify_handle ( nonsignaled , 1 ) , 0 ) ;
ok ( ret = = WAIT_TIMEOUT , " expected WAIT_TIMEOUT, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = 0xdeadbeef , " expected 0xdeadbeef, got %d \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( modify_handle ( nonsignaled , 2 ) , 0 ) ;
ok ( ret = = WAIT_TIMEOUT , " expected WAIT_TIMEOUT, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = 0xdeadbeef , " expected 0xdeadbeef, got %d \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( modify_handle ( nonsignaled , 3 ) , 0 ) ;
ok ( ret = = WAIT_TIMEOUT , " expected WAIT_TIMEOUT, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = 0xdeadbeef , " expected 0xdeadbeef, got %d \n " , GetLastError ( ) ) ;
/* valid handle with different values for lower 2 bits */
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( signaled , 0 ) ;
ok ( ret = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = 0xdeadbeef , " expected 0xdeadbeef, got %d \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( modify_handle ( signaled , 1 ) , 0 ) ;
ok ( ret = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = 0xdeadbeef , " expected 0xdeadbeef, got %d \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( modify_handle ( signaled , 2 ) , 0 ) ;
ok ( ret = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = 0xdeadbeef , " expected 0xdeadbeef, got %d \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = WaitForSingleObject ( modify_handle ( signaled , 3 ) , 0 ) ;
ok ( ret = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %d \n " , ret ) ;
ok ( GetLastError ( ) = = 0xdeadbeef , " expected 0xdeadbeef, got %d \n " , GetLastError ( ) ) ;
2016-03-08 15:49:46 +00:00
/* pseudo handles are allowed in WaitForSingleObject and NtWaitForSingleObject */
ret = WaitForSingleObject ( GetCurrentProcess ( ) , 100 ) ;
ok ( ret = = WAIT_TIMEOUT , " expected WAIT_TIMEOUT, got %u \n " , ret ) ;
ret = WaitForSingleObject ( GetCurrentThread ( ) , 100 ) ;
ok ( ret = = WAIT_TIMEOUT , " expected WAIT_TIMEOUT, got %u \n " , ret ) ;
timeout . QuadPart = - 1000000 ;
status = pNtWaitForSingleObject ( GetCurrentProcess ( ) , FALSE , & timeout ) ;
ok ( status = = STATUS_TIMEOUT , " expected STATUS_TIMEOUT, got %08x \n " , status ) ;
timeout . QuadPart = - 1000000 ;
status = pNtWaitForSingleObject ( GetCurrentThread ( ) , FALSE , & timeout ) ;
ok ( status = = STATUS_TIMEOUT , " expected STATUS_TIMEOUT, got %08x \n " , status ) ;
2011-10-03 17:58:01 +00:00
CloseHandle ( signaled ) ;
CloseHandle ( nonsignaled ) ;
}
static void test_WaitForMultipleObjects ( void )
{
2016-03-08 15:49:46 +00:00
LARGE_INTEGER timeout ;
NTSTATUS status ;
2011-10-03 17:58:01 +00:00
DWORD r ;
int i ;
HANDLE maxevents [ MAXIMUM_WAIT_OBJECTS ] ;
/* create the maximum number of events and make sure
* we can wait on that many */
for ( i = 0 ; i < MAXIMUM_WAIT_OBJECTS ; i + + )
{
2014-04-18 22:50:27 +00:00
maxevents [ i ] = CreateEventW ( NULL , i = = 0 , TRUE , NULL ) ;
2011-10-03 17:58:01 +00:00
ok ( maxevents [ i ] ! = 0 , " should create enough events \n " ) ;
}
/* a manual-reset event remains signaled, an auto-reset event is cleared */
2014-09-20 19:35:24 +00:00
r = WaitForMultipleObjects ( MAXIMUM_WAIT_OBJECTS , maxevents , FALSE , 0 ) ;
2011-10-03 17:58:01 +00:00
ok ( r = = WAIT_OBJECT_0 , " should signal lowest handle first, got %d \n " , r ) ;
2014-09-20 19:35:24 +00:00
r = WaitForMultipleObjects ( MAXIMUM_WAIT_OBJECTS , maxevents , FALSE , 0 ) ;
2011-10-03 17:58:01 +00:00
ok ( r = = WAIT_OBJECT_0 , " should signal handle #0 first, got %d \n " , r ) ;
ok ( ResetEvent ( maxevents [ 0 ] ) , " ResetEvent \n " ) ;
for ( i = 1 ; i < MAXIMUM_WAIT_OBJECTS ; i + + )
{
/* the lowest index is checked first and remaining events are untouched */
2014-09-20 19:35:24 +00:00
r = WaitForMultipleObjects ( MAXIMUM_WAIT_OBJECTS , maxevents , FALSE , 0 ) ;
ok ( r = = WAIT_OBJECT_0 + i , " should signal handle #%d first, got %d \n " , i , r ) ;
}
/* run same test with Nt* call */
for ( i = 0 ; i < MAXIMUM_WAIT_OBJECTS ; i + + )
SetEvent ( maxevents [ i ] ) ;
/* a manual-reset event remains signaled, an auto-reset event is cleared */
2016-03-08 15:49:46 +00:00
status = pNtWaitForMultipleObjects ( MAXIMUM_WAIT_OBJECTS , maxevents , TRUE , FALSE , NULL ) ;
ok ( status = = STATUS_WAIT_0 , " should signal lowest handle first, got %08x \n " , status ) ;
status = pNtWaitForMultipleObjects ( MAXIMUM_WAIT_OBJECTS , maxevents , TRUE , FALSE , NULL ) ;
ok ( status = = STATUS_WAIT_0 , " should signal handle #0 first, got %08x \n " , status ) ;
2014-09-20 19:35:24 +00:00
ok ( ResetEvent ( maxevents [ 0 ] ) , " ResetEvent \n " ) ;
for ( i = 1 ; i < MAXIMUM_WAIT_OBJECTS ; i + + )
{
/* the lowest index is checked first and remaining events are untouched */
2016-03-08 15:49:46 +00:00
status = pNtWaitForMultipleObjects ( MAXIMUM_WAIT_OBJECTS , maxevents , TRUE , FALSE , NULL ) ;
ok ( status = = STATUS_WAIT_0 + i , " should signal handle #%d first, got %08x \n " , i , status ) ;
2011-10-03 17:58:01 +00:00
}
for ( i = 0 ; i < MAXIMUM_WAIT_OBJECTS ; i + + )
if ( maxevents [ i ] ) CloseHandle ( maxevents [ i ] ) ;
2016-03-08 15:49:46 +00:00
/* in contrast to WaitForSingleObject, pseudo handles are not allowed in
* WaitForMultipleObjects and NtWaitForMultipleObjects */
maxevents [ 0 ] = GetCurrentProcess ( ) ;
SetLastError ( 0xdeadbeef ) ;
r = WaitForMultipleObjects ( 1 , maxevents , FALSE , 100 ) ;
todo_wine ok ( r = = WAIT_FAILED , " expected WAIT_FAILED, got %u \n " , r ) ;
todo_wine ok ( GetLastError ( ) = = ERROR_INVALID_HANDLE ,
" expected ERROR_INVALID_HANDLE, got %u \n " , GetLastError ( ) ) ;
maxevents [ 0 ] = GetCurrentThread ( ) ;
SetLastError ( 0xdeadbeef ) ;
r = WaitForMultipleObjects ( 1 , maxevents , FALSE , 100 ) ;
todo_wine ok ( r = = WAIT_FAILED , " expected WAIT_FAILED, got %u \n " , r ) ;
todo_wine ok ( GetLastError ( ) = = ERROR_INVALID_HANDLE ,
" expected ERROR_INVALID_HANDLE, got %u \n " , GetLastError ( ) ) ;
timeout . QuadPart = - 1000000 ;
maxevents [ 0 ] = GetCurrentProcess ( ) ;
status = pNtWaitForMultipleObjects ( 1 , maxevents , TRUE , FALSE , & timeout ) ;
todo_wine ok ( status = = STATUS_INVALID_HANDLE , " expected STATUS_INVALID_HANDLE, got %08x \n " , status ) ;
timeout . QuadPart = - 1000000 ;
maxevents [ 0 ] = GetCurrentThread ( ) ;
status = pNtWaitForMultipleObjects ( 1 , maxevents , TRUE , FALSE , & timeout ) ;
todo_wine ok ( status = = STATUS_INVALID_HANDLE , " expected STATUS_INVALID_HANDLE, got %08x \n " , status ) ;
2011-10-03 17:58:01 +00:00
}
2012-12-09 20:39:13 +00:00
static BOOL g_initcallback_ret , g_initcallback_called ;
static void * g_initctxt ;
static BOOL CALLBACK initonce_callback ( INIT_ONCE * initonce , void * parameter , void * * ctxt )
{
g_initcallback_called = TRUE ;
/* zero bit set means here that initialization is taking place - initialization locked */
ok ( g_initctxt = = * ctxt , " got wrong context value %p, expected %p \n " , * ctxt , g_initctxt ) ;
ok ( initonce - > Ptr = = ( void * ) 0x1 , " got %p \n " , initonce - > Ptr ) ;
ok ( parameter = = ( void * ) 0xdeadbeef , " got wrong parameter \n " ) ;
return g_initcallback_ret ;
}
static void test_initonce ( void )
{
INIT_ONCE initonce ;
BOOL ret , pending ;
if ( ! pInitOnceInitialize | | ! pInitOnceExecuteOnce )
{
2013-09-11 11:32:57 +00:00
win_skip ( " one-time initialization API not supported \n " ) ;
2012-12-09 20:39:13 +00:00
return ;
}
/* blocking initialization with callback */
initonce . Ptr = ( void * ) 0xdeadbeef ;
pInitOnceInitialize ( & initonce ) ;
ok ( initonce . Ptr = = NULL , " got %p \n " , initonce . Ptr ) ;
/* initialisation completed successfully */
g_initcallback_ret = TRUE ;
g_initctxt = NULL ;
ret = pInitOnceExecuteOnce ( & initonce , initonce_callback , ( void * ) 0xdeadbeef , & g_initctxt ) ;
2013-09-11 11:32:57 +00:00
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
2012-12-09 20:39:13 +00:00
ok ( initonce . Ptr = = ( void * ) 0x2 , " got %p \n " , initonce . Ptr ) ;
ok ( g_initctxt = = NULL , " got %p \n " , g_initctxt ) ;
ok ( g_initcallback_called , " got %d \n " , g_initcallback_called ) ;
/* so it's been called already so won't be called again */
g_initctxt = NULL ;
g_initcallback_called = FALSE ;
ret = pInitOnceExecuteOnce ( & initonce , initonce_callback , ( void * ) 0xdeadbeef , & g_initctxt ) ;
2013-09-11 11:32:57 +00:00
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
2012-12-09 20:39:13 +00:00
ok ( initonce . Ptr = = ( void * ) 0x2 , " got %p \n " , initonce . Ptr ) ;
ok ( g_initctxt = = NULL , " got %p \n " , g_initctxt ) ;
ok ( ! g_initcallback_called , " got %d \n " , g_initcallback_called ) ;
pInitOnceInitialize ( & initonce ) ;
g_initcallback_called = FALSE ;
/* 2 lower order bits should never be used, you'll get a crash in result */
g_initctxt = ( void * ) 0xFFFFFFF0 ;
ret = pInitOnceExecuteOnce ( & initonce , initonce_callback , ( void * ) 0xdeadbeef , & g_initctxt ) ;
2013-09-11 11:32:57 +00:00
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
2012-12-09 20:39:13 +00:00
ok ( initonce . Ptr = = ( void * ) 0xFFFFFFF2 , " got %p \n " , initonce . Ptr ) ;
ok ( g_initctxt = = ( void * ) 0xFFFFFFF0 , " got %p \n " , g_initctxt ) ;
ok ( g_initcallback_called , " got %d \n " , g_initcallback_called ) ;
/* callback failed */
g_initcallback_ret = FALSE ;
g_initcallback_called = FALSE ;
g_initctxt = NULL ;
pInitOnceInitialize ( & initonce ) ;
2013-09-11 11:32:57 +00:00
SetLastError ( 0xdeadbeef ) ;
2012-12-09 20:39:13 +00:00
ret = pInitOnceExecuteOnce ( & initonce , initonce_callback , ( void * ) 0xdeadbeef , & g_initctxt ) ;
2013-09-11 11:32:57 +00:00
ok ( ! ret & & GetLastError ( ) = = 0xdeadbeef , " got wrong ret value %d err %u \n " , ret , GetLastError ( ) ) ;
2012-12-09 20:39:13 +00:00
ok ( initonce . Ptr = = NULL , " got %p \n " , initonce . Ptr ) ;
ok ( g_initctxt = = NULL , " got %p \n " , g_initctxt ) ;
ok ( g_initcallback_called , " got %d \n " , g_initcallback_called ) ;
2013-09-11 11:32:57 +00:00
/* blocking initialization without a callback */
2012-12-09 20:39:13 +00:00
pInitOnceInitialize ( & initonce ) ;
g_initctxt = NULL ;
pending = FALSE ;
ret = pInitOnceBeginInitialize ( & initonce , 0 , & pending , & g_initctxt ) ;
2013-09-11 11:32:57 +00:00
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
2012-12-09 20:39:13 +00:00
ok ( pending , " got %d \n " , pending ) ;
ok ( initonce . Ptr = = ( void * ) 1 , " got %p \n " , initonce . Ptr ) ;
ok ( g_initctxt = = NULL , " got %p \n " , g_initctxt ) ;
/* another attempt to begin initialization with block a single thread */
g_initctxt = NULL ;
pending = 0xf ;
2013-09-11 11:32:57 +00:00
SetLastError ( 0xdeadbeef ) ;
2012-12-09 20:39:13 +00:00
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY , & pending , & g_initctxt ) ;
2013-09-11 11:32:57 +00:00
ok ( ! ret & & GetLastError ( ) = = ERROR_GEN_FAILURE , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
2012-12-09 20:39:13 +00:00
ok ( pending = = 0xf , " got %d \n " , pending ) ;
ok ( initonce . Ptr = = ( void * ) 1 , " got %p \n " , initonce . Ptr ) ;
ok ( g_initctxt = = NULL , " got %p \n " , g_initctxt ) ;
g_initctxt = ( void * ) 0xdeadbee0 ;
2013-09-11 11:32:57 +00:00
SetLastError ( 0xdeadbeef ) ;
2012-12-09 20:39:13 +00:00
ret = pInitOnceComplete ( & initonce , INIT_ONCE_INIT_FAILED , g_initctxt ) ;
2013-09-11 11:32:57 +00:00
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
2012-12-09 20:39:13 +00:00
ok ( initonce . Ptr = = ( void * ) 1 , " got %p \n " , initonce . Ptr ) ;
/* once failed already */
g_initctxt = ( void * ) 0xdeadbee0 ;
ret = pInitOnceComplete ( & initonce , 0 , g_initctxt ) ;
2013-09-11 11:32:57 +00:00
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
2012-12-09 20:39:13 +00:00
ok ( initonce . Ptr = = ( void * ) 0xdeadbee2 , " got %p \n " , initonce . Ptr ) ;
2013-09-11 11:32:57 +00:00
pInitOnceInitialize ( & initonce ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceComplete ( & initonce , INIT_ONCE_INIT_FAILED , NULL ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_GEN_FAILURE , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = NULL , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceComplete ( & initonce , INIT_ONCE_INIT_FAILED | INIT_ONCE_ASYNC , NULL ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = NULL , " got %p \n " , initonce . Ptr ) ;
ret = pInitOnceBeginInitialize ( & initonce , 0 , & pending , & g_initctxt ) ;
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( pending , " got %d \n " , pending ) ;
ok ( initonce . Ptr = = ( void * ) 1 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_ASYNC , & pending , & g_initctxt ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceComplete ( & initonce , INIT_ONCE_INIT_FAILED | INIT_ONCE_ASYNC , NULL ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = ( void * ) 1 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceComplete ( & initonce , 0 , ( void * ) 0xdeadbeef ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = ( void * ) 1 , " got %p \n " , initonce . Ptr ) ;
ret = pInitOnceComplete ( & initonce , INIT_ONCE_INIT_FAILED , NULL ) ;
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = NULL , " got %p \n " , initonce . Ptr ) ;
pInitOnceInitialize ( & initonce ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_ASYNC , & pending , & g_initctxt ) ;
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( pending , " got %d \n " , pending ) ;
ok ( initonce . Ptr = = ( void * ) 3 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceBeginInitialize ( & initonce , 0 , & pending , & g_initctxt ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_ASYNC , & pending , & g_initctxt ) ;
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( pending , " got %d \n " , pending ) ;
ok ( initonce . Ptr = = ( void * ) 3 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceComplete ( & initonce , INIT_ONCE_INIT_FAILED , NULL ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = ( void * ) 3 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceComplete ( & initonce , INIT_ONCE_INIT_FAILED | INIT_ONCE_ASYNC , NULL ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = ( void * ) 3 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceComplete ( & initonce , INIT_ONCE_ASYNC , ( void * ) 0xdeadbeef ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = ( void * ) 3 , " got %p \n " , initonce . Ptr ) ;
ret = pInitOnceComplete ( & initonce , INIT_ONCE_ASYNC , ( void * ) 0xdeadbee0 ) ;
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = ( void * ) 0xdeadbee2 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceComplete ( & initonce , INIT_ONCE_INIT_FAILED | INIT_ONCE_ASYNC , NULL ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = ( void * ) 0xdeadbee2 , " got %p \n " , initonce . Ptr ) ;
pInitOnceInitialize ( & initonce ) ;
ret = pInitOnceBeginInitialize ( & initonce , 0 , & pending , & g_initctxt ) ;
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( pending , " got %d \n " , pending ) ;
ok ( initonce . Ptr = = ( void * ) 1 , " got %p \n " , initonce . Ptr ) ;
/* test INIT_ONCE_CHECK_ONLY */
pInitOnceInitialize ( & initonce ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY , & pending , & g_initctxt ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_GEN_FAILURE , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY | INIT_ONCE_ASYNC , & pending , & g_initctxt ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ret = pInitOnceBeginInitialize ( & initonce , 0 , & pending , & g_initctxt ) ;
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( pending , " got %d \n " , pending ) ;
ok ( initonce . Ptr = = ( void * ) 1 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY , & pending , & g_initctxt ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_GEN_FAILURE , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY | INIT_ONCE_ASYNC , & pending , & g_initctxt ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ret = pInitOnceComplete ( & initonce , 0 , ( void * ) 0xdeadbee0 ) ;
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = ( void * ) 0xdeadbee2 , " got %p \n " , initonce . Ptr ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY , & pending , & g_initctxt ) ;
ok ( ret , " got wrong ret value %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( ! pending , " got %d \n " , pending ) ;
ok ( initonce . Ptr = = ( void * ) 0xdeadbee2 , " got %p \n " , initonce . Ptr ) ;
ok ( g_initctxt = = ( void * ) 0xdeadbee0 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY | INIT_ONCE_ASYNC , & pending , & g_initctxt ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
pInitOnceInitialize ( & initonce ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_ASYNC , & pending , & g_initctxt ) ;
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( pending , " got %d \n " , pending ) ;
ok ( initonce . Ptr = = ( void * ) 3 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY , & pending , & g_initctxt ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_GEN_FAILURE , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY | INIT_ONCE_ASYNC , & pending , & g_initctxt ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ret = pInitOnceComplete ( & initonce , INIT_ONCE_ASYNC , ( void * ) 0xdeadbee0 ) ;
ok ( ret , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( initonce . Ptr = = ( void * ) 0xdeadbee2 , " got %p \n " , initonce . Ptr ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY , & pending , & g_initctxt ) ;
ok ( ret , " got wrong ret value %d err %u \n " , ret , GetLastError ( ) ) ;
ok ( ! pending , " got %d \n " , pending ) ;
ok ( initonce . Ptr = = ( void * ) 0xdeadbee2 , " got %p \n " , initonce . Ptr ) ;
ok ( g_initctxt = = ( void * ) 0xdeadbee0 , " got %p \n " , initonce . Ptr ) ;
SetLastError ( 0xdeadbeef ) ;
ret = pInitOnceBeginInitialize ( & initonce , INIT_ONCE_CHECK_ONLY | INIT_ONCE_ASYNC , & pending , & g_initctxt ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER , " wrong ret %d err %u \n " , ret , GetLastError ( ) ) ;
2012-12-09 20:39:13 +00:00
}
2013-09-11 11:32:57 +00:00
static CONDITION_VARIABLE buffernotempty = CONDITION_VARIABLE_INIT ;
static CONDITION_VARIABLE buffernotfull = CONDITION_VARIABLE_INIT ;
2012-12-09 20:39:13 +00:00
static CRITICAL_SECTION buffercrit ;
static BOOL condvar_stop = FALSE , condvar_sleeperr = FALSE ;
static LONG bufferlen , totalproduced , totalconsumed ;
static LONG condvar_producer_sleepcnt , condvar_consumer_sleepcnt ;
2013-09-11 11:32:57 +00:00
# define BUFFER_SIZE 5
2012-12-09 20:39:13 +00:00
static DWORD WINAPI condvar_producer ( LPVOID x ) {
2013-09-11 11:32:57 +00:00
DWORD sleepinterval = 5 ;
2012-12-09 20:39:13 +00:00
while ( 1 ) {
2013-09-11 11:32:57 +00:00
Sleep ( sleepinterval ) ;
if ( sleepinterval > 1 )
sleepinterval - = 1 ;
2012-12-09 20:39:13 +00:00
EnterCriticalSection ( & buffercrit ) ;
while ( ( bufferlen = = BUFFER_SIZE ) & & ! condvar_stop ) {
condvar_producer_sleepcnt + + ;
2013-09-11 11:32:57 +00:00
if ( ! pSleepConditionVariableCS ( & buffernotfull , & buffercrit , sleepinterval ) ) {
if ( GetLastError ( ) ! = ERROR_TIMEOUT )
condvar_sleeperr = TRUE ;
}
2012-12-09 20:39:13 +00:00
}
if ( condvar_stop ) {
LeaveCriticalSection ( & buffercrit ) ;
break ;
}
bufferlen + + ;
totalproduced + + ;
LeaveCriticalSection ( & buffercrit ) ;
pWakeConditionVariable ( & buffernotempty ) ;
}
return 0 ;
}
static DWORD WINAPI condvar_consumer ( LPVOID x ) {
DWORD * cnt = ( DWORD * ) x ;
2013-09-11 11:32:57 +00:00
DWORD sleepinterval = 1 ;
2012-12-09 20:39:13 +00:00
while ( 1 ) {
EnterCriticalSection ( & buffercrit ) ;
while ( ( bufferlen = = 0 ) & & ! condvar_stop ) {
condvar_consumer_sleepcnt + + ;
2013-09-11 11:32:57 +00:00
if ( ! pSleepConditionVariableCS ( & buffernotempty , & buffercrit , sleepinterval ) ) {
if ( GetLastError ( ) ! = ERROR_TIMEOUT )
condvar_sleeperr = TRUE ;
}
2012-12-09 20:39:13 +00:00
}
if ( condvar_stop & & ( bufferlen = = 0 ) ) {
LeaveCriticalSection ( & buffercrit ) ;
break ;
}
bufferlen - - ;
totalconsumed + + ;
( * cnt ) + + ;
LeaveCriticalSection ( & buffercrit ) ;
pWakeConditionVariable ( & buffernotfull ) ;
2013-09-11 11:32:57 +00:00
Sleep ( sleepinterval ) ;
if ( sleepinterval < 5 ) sleepinterval + = 1 ;
2012-12-09 20:39:13 +00:00
}
return 0 ;
}
2013-09-11 11:32:57 +00:00
static void test_condvars_consumer_producer ( void )
2012-12-09 20:39:13 +00:00
{
2013-09-11 11:32:57 +00:00
HANDLE hp1 , hp2 , hp3 , hc1 , hc2 , hc3 ;
2012-12-09 20:39:13 +00:00
DWORD dummy ;
2013-09-11 11:32:57 +00:00
DWORD cnt1 , cnt2 , cnt3 ;
2012-12-09 20:39:13 +00:00
if ( ! pInitializeConditionVariable ) {
/* function is not yet in XP, only in newer Windows */
2014-04-18 22:50:27 +00:00
win_skip ( " no condition variable support. \n " ) ;
2012-12-09 20:39:13 +00:00
return ;
}
/* Implement a producer / consumer scheme with non-full / non-empty triggers */
2013-09-11 11:32:57 +00:00
/* If we have static initialized condition variables, InitializeConditionVariable
* is not strictly necessary .
* pInitializeConditionVariable ( & buffernotfull ) ;
*/
2012-12-09 20:39:13 +00:00
pInitializeConditionVariable ( & buffernotempty ) ;
InitializeCriticalSection ( & buffercrit ) ;
2013-09-11 11:32:57 +00:00
/* Larger Test: consumer/producer example */
bufferlen = totalproduced = totalconsumed = cnt1 = cnt2 = cnt3 = 0 ;
2012-12-09 20:39:13 +00:00
hp1 = CreateThread ( NULL , 0 , condvar_producer , NULL , 0 , & dummy ) ;
hp2 = CreateThread ( NULL , 0 , condvar_producer , NULL , 0 , & dummy ) ;
2013-09-11 11:32:57 +00:00
hp3 = CreateThread ( NULL , 0 , condvar_producer , NULL , 0 , & dummy ) ;
2012-12-09 20:39:13 +00:00
hc1 = CreateThread ( NULL , 0 , condvar_consumer , ( PVOID ) & cnt1 , 0 , & dummy ) ;
hc2 = CreateThread ( NULL , 0 , condvar_consumer , ( PVOID ) & cnt2 , 0 , & dummy ) ;
2013-09-11 11:32:57 +00:00
hc3 = CreateThread ( NULL , 0 , condvar_consumer , ( PVOID ) & cnt3 , 0 , & dummy ) ;
2012-12-09 20:39:13 +00:00
/* Limit run to 0.5 seconds. */
Sleep ( 500 ) ;
/* tear down start */
condvar_stop = TRUE ;
/* final wake up call */
pWakeAllConditionVariable ( & buffernotfull ) ;
pWakeAllConditionVariable ( & buffernotempty ) ;
2013-09-11 11:32:57 +00:00
/* (mostly an implementation detail)
* ok ( buffernotfull . Ptr = = NULL , " buffernotfull.Ptr is %p \n " , buffernotfull . Ptr ) ;
*/
2012-12-09 20:39:13 +00:00
WaitForSingleObject ( hp1 , 1000 ) ;
WaitForSingleObject ( hp2 , 1000 ) ;
2013-09-11 11:32:57 +00:00
WaitForSingleObject ( hp3 , 1000 ) ;
2012-12-09 20:39:13 +00:00
WaitForSingleObject ( hc1 , 1000 ) ;
WaitForSingleObject ( hc2 , 1000 ) ;
2013-09-11 11:32:57 +00:00
WaitForSingleObject ( hc3 , 1000 ) ;
2012-12-09 20:39:13 +00:00
ok ( totalconsumed = = totalproduced ,
" consumed %d != produced %d \n " , totalconsumed , totalproduced ) ;
ok ( ! condvar_sleeperr , " error occurred during SleepConditionVariableCS \n " ) ;
/* Checking cnt1 - cnt2 for non-0 would be not good, the case where
* one consumer does not get anything to do is possible . */
2013-09-11 11:32:57 +00:00
trace ( " produced %d, c1 %d, c2 %d, c3 %d \n " , totalproduced , cnt1 , cnt2 , cnt3 ) ;
2012-12-09 20:39:13 +00:00
/* The sleeps of the producer or consumer should not go above 100* produced count,
* otherwise the implementation does not sleep correctly . But yet again , this is
* not hard defined . */
trace ( " producer sleep %d, consumer sleep %d \n " , condvar_producer_sleepcnt , condvar_consumer_sleepcnt ) ;
}
2013-09-11 11:32:57 +00:00
/* Sample test for some sequence of events happening, sequenced using "condvar_seq" */
static DWORD condvar_seq = 0 ;
static CONDITION_VARIABLE condvar_base = CONDITION_VARIABLE_INIT ;
static CRITICAL_SECTION condvar_crit ;
2014-04-18 22:50:27 +00:00
static SRWLOCK condvar_srwlock ;
2013-09-11 11:32:57 +00:00
/* Sequence of wake/sleep to check boundary conditions:
* 0 : init
2016-07-12 21:10:24 +00:00
* 1 : producer emits a WakeConditionVariable without consumer waiting .
2013-09-11 11:32:57 +00:00
* 2 : consumer sleeps without a wake expecting timeout
2016-07-12 21:10:24 +00:00
* 3 : producer emits a WakeAllConditionVariable without consumer waiting .
2013-09-11 11:32:57 +00:00
* 4 : consumer sleeps without a wake expecting timeout
* 5 : a wake is handed to a SleepConditionVariableCS
* 6 : a wakeall is handed to a SleepConditionVariableCS
* 7 : sleep after above should timeout
* 8 : wake with crit section locked into the sleep timeout
2014-04-18 22:50:27 +00:00
*
* the following tests will only be executed if InitializeSRWLock is available
*
* 9 : producer ( exclusive ) wakes up consumer ( exclusive )
* 10 : producer ( exclusive ) wakes up consumer ( shared )
* 11 : producer ( shared ) wakes up consumer ( exclusive )
* 12 : producer ( shared ) wakes up consumer ( shared )
* 13 : end
2013-09-11 11:32:57 +00:00
*/
static DWORD WINAPI condvar_base_producer ( LPVOID x ) {
while ( condvar_seq < 1 ) Sleep ( 1 ) ;
pWakeConditionVariable ( & condvar_base ) ;
condvar_seq = 2 ;
while ( condvar_seq < 3 ) Sleep ( 1 ) ;
pWakeAllConditionVariable ( & condvar_base ) ;
condvar_seq = 4 ;
while ( condvar_seq < 5 ) Sleep ( 1 ) ;
EnterCriticalSection ( & condvar_crit ) ;
pWakeConditionVariable ( & condvar_base ) ;
LeaveCriticalSection ( & condvar_crit ) ;
while ( condvar_seq < 6 ) Sleep ( 1 ) ;
EnterCriticalSection ( & condvar_crit ) ;
pWakeAllConditionVariable ( & condvar_base ) ;
LeaveCriticalSection ( & condvar_crit ) ;
while ( condvar_seq < 8 ) Sleep ( 1 ) ;
EnterCriticalSection ( & condvar_crit ) ;
pWakeConditionVariable ( & condvar_base ) ;
Sleep ( 50 ) ;
LeaveCriticalSection ( & condvar_crit ) ;
2014-04-18 22:50:27 +00:00
/* skip over remaining tests if InitializeSRWLock is not available */
if ( ! pInitializeSRWLock )
return 0 ;
while ( condvar_seq < 9 ) Sleep ( 1 ) ;
pAcquireSRWLockExclusive ( & condvar_srwlock ) ;
pWakeConditionVariable ( & condvar_base ) ;
pReleaseSRWLockExclusive ( & condvar_srwlock ) ;
while ( condvar_seq < 10 ) Sleep ( 1 ) ;
pAcquireSRWLockExclusive ( & condvar_srwlock ) ;
pWakeConditionVariable ( & condvar_base ) ;
pReleaseSRWLockExclusive ( & condvar_srwlock ) ;
while ( condvar_seq < 11 ) Sleep ( 1 ) ;
pAcquireSRWLockShared ( & condvar_srwlock ) ;
pWakeConditionVariable ( & condvar_base ) ;
pReleaseSRWLockShared ( & condvar_srwlock ) ;
while ( condvar_seq < 12 ) Sleep ( 1 ) ;
Sleep ( 50 ) ; /* ensure that consumer waits for cond variable */
pAcquireSRWLockShared ( & condvar_srwlock ) ;
pWakeConditionVariable ( & condvar_base ) ;
pReleaseSRWLockShared ( & condvar_srwlock ) ;
2013-09-11 11:32:57 +00:00
return 0 ;
}
static DWORD WINAPI condvar_base_consumer ( LPVOID x ) {
BOOL ret ;
while ( condvar_seq < 2 ) Sleep ( 1 ) ;
/* wake was emitted, but we were not sleeping */
EnterCriticalSection ( & condvar_crit ) ;
ret = pSleepConditionVariableCS ( & condvar_base , & condvar_crit , 10 ) ;
LeaveCriticalSection ( & condvar_crit ) ;
ok ( ! ret , " SleepConditionVariableCS should return FALSE on out of band wake \n " ) ;
ok ( GetLastError ( ) = = ERROR_TIMEOUT , " SleepConditionVariableCS should return ERROR_TIMEOUT on out of band wake, not %d \n " , GetLastError ( ) ) ;
condvar_seq = 3 ;
while ( condvar_seq < 4 ) Sleep ( 1 ) ;
/* wake all was emitted, but we were not sleeping */
EnterCriticalSection ( & condvar_crit ) ;
ret = pSleepConditionVariableCS ( & condvar_base , & condvar_crit , 10 ) ;
LeaveCriticalSection ( & condvar_crit ) ;
ok ( ! ret , " SleepConditionVariableCS should return FALSE on out of band wake \n " ) ;
ok ( GetLastError ( ) = = ERROR_TIMEOUT , " SleepConditionVariableCS should return ERROR_TIMEOUT on out of band wake, not %d \n " , GetLastError ( ) ) ;
EnterCriticalSection ( & condvar_crit ) ;
condvar_seq = 5 ;
ret = pSleepConditionVariableCS ( & condvar_base , & condvar_crit , 200 ) ;
LeaveCriticalSection ( & condvar_crit ) ;
ok ( ret , " SleepConditionVariableCS should return TRUE on good wake \n " ) ;
EnterCriticalSection ( & condvar_crit ) ;
condvar_seq = 6 ;
ret = pSleepConditionVariableCS ( & condvar_base , & condvar_crit , 200 ) ;
LeaveCriticalSection ( & condvar_crit ) ;
ok ( ret , " SleepConditionVariableCS should return TRUE on good wakeall \n " ) ;
condvar_seq = 7 ;
EnterCriticalSection ( & condvar_crit ) ;
ret = pSleepConditionVariableCS ( & condvar_base , & condvar_crit , 10 ) ;
LeaveCriticalSection ( & condvar_crit ) ;
ok ( ! ret , " SleepConditionVariableCS should return FALSE on out of band wake \n " ) ;
ok ( GetLastError ( ) = = ERROR_TIMEOUT , " SleepConditionVariableCS should return ERROR_TIMEOUT on out of band wake, not %d \n " , GetLastError ( ) ) ;
EnterCriticalSection ( & condvar_crit ) ;
condvar_seq = 8 ;
ret = pSleepConditionVariableCS ( & condvar_base , & condvar_crit , 20 ) ;
LeaveCriticalSection ( & condvar_crit ) ;
ok ( ret , " SleepConditionVariableCS should still return TRUE on crit unlock delay \n " ) ;
2014-04-18 22:50:27 +00:00
/* skip over remaining tests if InitializeSRWLock is not available */
if ( ! pInitializeSRWLock )
{
win_skip ( " no srw lock support. \n " ) ;
condvar_seq = 13 ; /* end */
return 0 ;
}
pAcquireSRWLockExclusive ( & condvar_srwlock ) ;
condvar_seq = 9 ;
ret = pSleepConditionVariableSRW ( & condvar_base , & condvar_srwlock , 200 , 0 ) ;
pReleaseSRWLockExclusive ( & condvar_srwlock ) ;
ok ( ret , " pSleepConditionVariableSRW should return TRUE on good wake \n " ) ;
pAcquireSRWLockShared ( & condvar_srwlock ) ;
condvar_seq = 10 ;
ret = pSleepConditionVariableSRW ( & condvar_base , & condvar_srwlock , 200 , CONDITION_VARIABLE_LOCKMODE_SHARED ) ;
pReleaseSRWLockShared ( & condvar_srwlock ) ;
ok ( ret , " pSleepConditionVariableSRW should return TRUE on good wake \n " ) ;
pAcquireSRWLockExclusive ( & condvar_srwlock ) ;
condvar_seq = 11 ;
ret = pSleepConditionVariableSRW ( & condvar_base , & condvar_srwlock , 200 , 0 ) ;
pReleaseSRWLockExclusive ( & condvar_srwlock ) ;
ok ( ret , " pSleepConditionVariableSRW should return TRUE on good wake \n " ) ;
pAcquireSRWLockShared ( & condvar_srwlock ) ;
condvar_seq = 12 ;
ret = pSleepConditionVariableSRW ( & condvar_base , & condvar_srwlock , 200 , CONDITION_VARIABLE_LOCKMODE_SHARED ) ;
pReleaseSRWLockShared ( & condvar_srwlock ) ;
ok ( ret , " pSleepConditionVariableSRW should return TRUE on good wake \n " ) ;
condvar_seq = 13 ;
2013-09-11 11:32:57 +00:00
return 0 ;
}
static void test_condvars_base ( void ) {
HANDLE hp , hc ;
DWORD dummy ;
BOOL ret ;
if ( ! pInitializeConditionVariable ) {
/* function is not yet in XP, only in newer Windows */
2014-04-18 22:50:27 +00:00
win_skip ( " no condition variable support. \n " ) ;
2013-09-11 11:32:57 +00:00
return ;
}
InitializeCriticalSection ( & condvar_crit ) ;
2014-04-18 22:50:27 +00:00
if ( pInitializeSRWLock )
pInitializeSRWLock ( & condvar_srwlock ) ;
2013-09-11 11:32:57 +00:00
EnterCriticalSection ( & condvar_crit ) ;
ret = pSleepConditionVariableCS ( & condvar_base , & condvar_crit , 10 ) ;
LeaveCriticalSection ( & condvar_crit ) ;
ok ( ! ret , " SleepConditionVariableCS should return FALSE on untriggered condvar \n " ) ;
ok ( GetLastError ( ) = = ERROR_TIMEOUT , " SleepConditionVariableCS should return ERROR_TIMEOUT on untriggered condvar, not %d \n " , GetLastError ( ) ) ;
2014-04-18 22:50:27 +00:00
if ( pInitializeSRWLock )
{
pAcquireSRWLockExclusive ( & condvar_srwlock ) ;
ret = pSleepConditionVariableSRW ( & condvar_base , & condvar_srwlock , 10 , 0 ) ;
pReleaseSRWLockExclusive ( & condvar_srwlock ) ;
ok ( ! ret , " SleepConditionVariableSRW should return FALSE on untriggered condvar \n " ) ;
ok ( GetLastError ( ) = = ERROR_TIMEOUT , " SleepConditionVariableSRW should return ERROR_TIMEOUT on untriggered condvar, not %d \n " , GetLastError ( ) ) ;
pAcquireSRWLockShared ( & condvar_srwlock ) ;
ret = pSleepConditionVariableSRW ( & condvar_base , & condvar_srwlock , 10 , CONDITION_VARIABLE_LOCKMODE_SHARED ) ;
pReleaseSRWLockShared ( & condvar_srwlock ) ;
ok ( ! ret , " SleepConditionVariableSRW should return FALSE on untriggered condvar \n " ) ;
ok ( GetLastError ( ) = = ERROR_TIMEOUT , " SleepConditionVariableSRW should return ERROR_TIMEOUT on untriggered condvar, not %d \n " , GetLastError ( ) ) ;
}
2013-09-11 11:32:57 +00:00
hp = CreateThread ( NULL , 0 , condvar_base_producer , NULL , 0 , & dummy ) ;
hc = CreateThread ( NULL , 0 , condvar_base_consumer , NULL , 0 , & dummy ) ;
condvar_seq = 1 ; /* go */
while ( condvar_seq < 9 )
Sleep ( 5 ) ;
WaitForSingleObject ( hp , 100 ) ;
WaitForSingleObject ( hc , 100 ) ;
}
2014-04-18 22:50:27 +00:00
static LONG srwlock_seq = 0 ;
static SRWLOCK srwlock_base ;
static struct
{
LONG wrong_execution_order ;
LONG samethread_excl_excl ;
LONG samethread_excl_shared ;
LONG samethread_shared_excl ;
LONG multithread_excl_excl ;
LONG excl_not_preferred ;
LONG trylock_excl ;
LONG trylock_shared ;
} srwlock_base_errors ;
/* Sequence of acquire/release to check boundary conditions:
* 0 : init
*
* 1 : thread2 acquires an exclusive lock and tries to acquire a second exclusive lock
* 2 : thread1 expects a deadlock and releases the waiting lock
* thread2 releases the lock again
*
* 3 : thread2 acquires an exclusive lock and tries to acquire a shared lock
* 4 : thread1 expects a deadlock and releases the waiting lock
* thread2 releases the lock again
*
* 5 : thread2 acquires a shared lock and tries to acquire an exclusive lock
* 6 : thread1 expects a deadlock and releases the waiting lock
* thread2 releases the lock again
*
* 7 : thread2 acquires and releases two nested shared locks
*
* 8 : thread1 acquires an exclusive lock
* 9 : thread2 tries to acquire the exclusive lock , too
* thread1 releases the exclusive lock again
* 10 : thread2 enters the exclusive lock and leaves it immediately again
*
* 11 : thread1 acquires a shared lock
* 12 : thread2 acquires and releases a shared lock
* thread1 releases the lock again
*
* 13 : thread1 acquires a shared lock
* 14 : thread2 tries to acquire an exclusive lock
* 15 : thread3 tries to acquire a shared lock
* 16 : thread1 releases the shared lock
* 17 : thread2 wakes up and releases the exclusive lock
* 18 : thread3 wakes up and releases the shared lock
*
* the following tests will only be executed if TryAcquireSRWLock * is available
*
* 19 : thread1 calls TryAcquireSRWLockExclusive which should return TRUE
* thread1 checks the result of recursive calls to TryAcquireSRWLock *
* thread1 releases the exclusive lock
*
* thread1 calls TryAcquireSRWLockShared which should return TRUE
* thread1 checks the result of recursive calls to TryAcquireSRWLock *
* thread1 releases the shared lock
*
* thread1 acquires an exclusive lock
* 20 : thread2 calls TryAcquireSRWLockShared which should return FALSE
* thread2 calls TryAcquireSRWLockExclusive which should return FALSE
* 21 : thread1 releases the exclusive lock
*
* thread1 acquires an shared lock
* 22 : thread2 calls TryAcquireSRWLockShared which should return TRUE
* thread2 calls TryAcquireSRWLockExclusive which should return FALSE
* 23 : thread1 releases the shared lock
*
* thread1 acquires a shared lock and tries to acquire an exclusive lock
* 24 : thread2 calls TryAcquireSRWLockShared which should return FALSE
* thread2 calls TryAcquireSRWLockExclusive which should return FALSE
* 25 : thread1 releases the exclusive lock
*
* thread1 acquires two shared locks
* 26 : thread2 calls TryAcquireSRWLockShared which should return TRUE
* thread2 calls TryAcquireSRWLockExclusive which should return FALSE
* 27 : thread1 releases one shared lock
* 28 : thread2 calls TryAcquireSRWLockShared which should return TRUE
* thread2 calls TryAcquireSRWLockExclusive which should return FALSE
* 29 : thread1 releases the second shared lock
* 30 : thread2 calls TryAcquireSRWLockShared which should return TRUE
* thread2 calls TryAcquireSRWLockExclusive which should return TRUE
*
* 31 : end
*/
static DWORD WINAPI srwlock_base_thread1 ( LPVOID x )
{
/* seq 2 */
while ( srwlock_seq < 2 ) Sleep ( 1 ) ;
Sleep ( 100 ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 3 )
InterlockedIncrement ( & srwlock_base_errors . samethread_excl_excl ) ;
pReleaseSRWLockExclusive ( & srwlock_base ) ;
/* seq 4 */
while ( srwlock_seq < 4 ) Sleep ( 1 ) ;
Sleep ( 100 ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 5 )
InterlockedIncrement ( & srwlock_base_errors . samethread_excl_shared ) ;
pReleaseSRWLockExclusive ( & srwlock_base ) ;
/* seq 6 */
while ( srwlock_seq < 6 ) Sleep ( 1 ) ;
Sleep ( 100 ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 7 )
InterlockedIncrement ( & srwlock_base_errors . samethread_shared_excl ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
/* seq 8 */
while ( srwlock_seq < 8 ) Sleep ( 1 ) ;
pAcquireSRWLockExclusive ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 9 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
Sleep ( 100 ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 10 )
InterlockedIncrement ( & srwlock_base_errors . multithread_excl_excl ) ;
pReleaseSRWLockExclusive ( & srwlock_base ) ;
/* seq 11 */
while ( srwlock_seq < 11 ) Sleep ( 1 ) ;
pAcquireSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 12 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 13 */
while ( srwlock_seq < 13 ) Sleep ( 1 ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
pAcquireSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 14 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 16 */
while ( srwlock_seq < 16 ) Sleep ( 1 ) ;
Sleep ( 50 ) ; /* ensure that both the exclusive and shared access thread are queued */
if ( InterlockedIncrement ( & srwlock_seq ) ! = 17 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
/* skip over remaining tests if TryAcquireSRWLock* is not available */
if ( ! pTryAcquireSRWLockExclusive )
return 0 ;
/* seq 19 */
while ( srwlock_seq < 19 ) Sleep ( 1 ) ;
if ( pTryAcquireSRWLockExclusive ( & srwlock_base ) )
{
if ( pTryAcquireSRWLockShared ( & srwlock_base ) )
InterlockedIncrement ( & srwlock_base_errors . trylock_shared ) ;
if ( pTryAcquireSRWLockExclusive ( & srwlock_base ) )
InterlockedIncrement ( & srwlock_base_errors . trylock_excl ) ;
pReleaseSRWLockExclusive ( & srwlock_base ) ;
}
else
InterlockedIncrement ( & srwlock_base_errors . trylock_excl ) ;
if ( pTryAcquireSRWLockShared ( & srwlock_base ) )
{
if ( pTryAcquireSRWLockShared ( & srwlock_base ) )
pReleaseSRWLockShared ( & srwlock_base ) ;
else
InterlockedIncrement ( & srwlock_base_errors . trylock_shared ) ;
if ( pTryAcquireSRWLockExclusive ( & srwlock_base ) )
InterlockedIncrement ( & srwlock_base_errors . trylock_excl ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
}
else
InterlockedIncrement ( & srwlock_base_errors . trylock_shared ) ;
pAcquireSRWLockExclusive ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 20 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 21 */
while ( srwlock_seq < 21 ) Sleep ( 1 ) ;
pReleaseSRWLockExclusive ( & srwlock_base ) ;
pAcquireSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 22 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 23 */
while ( srwlock_seq < 23 ) Sleep ( 1 ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
pAcquireSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 24 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 25 */
pAcquireSRWLockExclusive ( & srwlock_base ) ;
if ( srwlock_seq ! = 25 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
pReleaseSRWLockExclusive ( & srwlock_base ) ;
pAcquireSRWLockShared ( & srwlock_base ) ;
pAcquireSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 26 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 27 */
while ( srwlock_seq < 27 ) Sleep ( 1 ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 28 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 29 */
while ( srwlock_seq < 29 ) Sleep ( 1 ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 30 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
return 0 ;
}
static DWORD WINAPI srwlock_base_thread2 ( LPVOID x )
{
/* seq 1 */
while ( srwlock_seq < 1 ) Sleep ( 1 ) ;
pAcquireSRWLockExclusive ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 2 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 3 */
pAcquireSRWLockExclusive ( & srwlock_base ) ;
if ( srwlock_seq ! = 3 )
InterlockedIncrement ( & srwlock_base_errors . samethread_excl_excl ) ;
pReleaseSRWLockExclusive ( & srwlock_base ) ;
pAcquireSRWLockExclusive ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 4 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 5 */
pAcquireSRWLockShared ( & srwlock_base ) ;
if ( srwlock_seq ! = 5 )
InterlockedIncrement ( & srwlock_base_errors . samethread_excl_shared ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
pAcquireSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 6 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 7 */
pAcquireSRWLockExclusive ( & srwlock_base ) ;
if ( srwlock_seq ! = 7 )
InterlockedIncrement ( & srwlock_base_errors . samethread_shared_excl ) ;
pReleaseSRWLockExclusive ( & srwlock_base ) ;
pAcquireSRWLockShared ( & srwlock_base ) ;
pAcquireSRWLockShared ( & srwlock_base ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 8 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 9, 10 */
while ( srwlock_seq < 9 ) Sleep ( 1 ) ;
pAcquireSRWLockExclusive ( & srwlock_base ) ;
if ( srwlock_seq ! = 10 )
InterlockedIncrement ( & srwlock_base_errors . multithread_excl_excl ) ;
pReleaseSRWLockExclusive ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 11 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 12 */
while ( srwlock_seq < 12 ) Sleep ( 1 ) ;
pAcquireSRWLockShared ( & srwlock_base ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 13 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 14 */
while ( srwlock_seq < 14 ) Sleep ( 1 ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 15 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 17 */
pAcquireSRWLockExclusive ( & srwlock_base ) ;
if ( srwlock_seq ! = 17 )
InterlockedIncrement ( & srwlock_base_errors . excl_not_preferred ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 18 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
pReleaseSRWLockExclusive ( & srwlock_base ) ;
/* skip over remaining tests if TryAcquireSRWLock* is not available */
if ( ! pTryAcquireSRWLockExclusive )
return 0 ;
/* seq 20 */
while ( srwlock_seq < 20 ) Sleep ( 1 ) ;
if ( pTryAcquireSRWLockShared ( & srwlock_base ) )
InterlockedIncrement ( & srwlock_base_errors . trylock_shared ) ;
if ( pTryAcquireSRWLockExclusive ( & srwlock_base ) )
InterlockedIncrement ( & srwlock_base_errors . trylock_excl ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 21 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 22 */
while ( srwlock_seq < 22 ) Sleep ( 1 ) ;
if ( pTryAcquireSRWLockShared ( & srwlock_base ) )
pReleaseSRWLockShared ( & srwlock_base ) ;
else
InterlockedIncrement ( & srwlock_base_errors . trylock_shared ) ;
if ( pTryAcquireSRWLockExclusive ( & srwlock_base ) )
InterlockedIncrement ( & srwlock_base_errors . trylock_excl ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 23 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 24 */
while ( srwlock_seq < 24 ) Sleep ( 1 ) ;
Sleep ( 50 ) ; /* ensure that exclusive access request is queued */
if ( pTryAcquireSRWLockShared ( & srwlock_base ) )
{
pReleaseSRWLockShared ( & srwlock_base ) ;
InterlockedIncrement ( & srwlock_base_errors . excl_not_preferred ) ;
}
if ( pTryAcquireSRWLockExclusive ( & srwlock_base ) )
InterlockedIncrement ( & srwlock_base_errors . trylock_excl ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 25 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
/* seq 26 */
while ( srwlock_seq < 26 ) Sleep ( 1 ) ;
if ( pTryAcquireSRWLockShared ( & srwlock_base ) )
pReleaseSRWLockShared ( & srwlock_base ) ;
else
InterlockedIncrement ( & srwlock_base_errors . trylock_shared ) ;
if ( pTryAcquireSRWLockExclusive ( & srwlock_base ) )
InterlockedIncrement ( & srwlock_base_errors . trylock_excl ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 27 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 28 */
while ( srwlock_seq < 28 ) Sleep ( 1 ) ;
if ( pTryAcquireSRWLockShared ( & srwlock_base ) )
pReleaseSRWLockShared ( & srwlock_base ) ;
else
InterlockedIncrement ( & srwlock_base_errors . trylock_shared ) ;
if ( pTryAcquireSRWLockExclusive ( & srwlock_base ) )
InterlockedIncrement ( & srwlock_base_errors . trylock_excl ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 29 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 30 */
while ( srwlock_seq < 30 ) Sleep ( 1 ) ;
if ( pTryAcquireSRWLockShared ( & srwlock_base ) )
pReleaseSRWLockShared ( & srwlock_base ) ;
else
InterlockedIncrement ( & srwlock_base_errors . trylock_shared ) ;
if ( pTryAcquireSRWLockExclusive ( & srwlock_base ) )
pReleaseSRWLockExclusive ( & srwlock_base ) ;
else
InterlockedIncrement ( & srwlock_base_errors . trylock_excl ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 31 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
return 0 ;
}
static DWORD WINAPI srwlock_base_thread3 ( LPVOID x )
{
/* seq 15 */
while ( srwlock_seq < 15 ) Sleep ( 1 ) ;
2014-09-20 19:35:24 +00:00
Sleep ( 50 ) ; /* some delay, so that thread2 can try to acquire a second exclusive lock */
2014-04-18 22:50:27 +00:00
if ( InterlockedIncrement ( & srwlock_seq ) ! = 16 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* seq 18 */
pAcquireSRWLockShared ( & srwlock_base ) ;
if ( srwlock_seq ! = 18 )
InterlockedIncrement ( & srwlock_base_errors . excl_not_preferred ) ;
pReleaseSRWLockShared ( & srwlock_base ) ;
if ( InterlockedIncrement ( & srwlock_seq ) ! = 19 )
InterlockedIncrement ( & srwlock_base_errors . wrong_execution_order ) ;
/* skip over remaining tests if TryAcquireSRWLock* is not available */
if ( ! pTryAcquireSRWLockExclusive )
{
/* function is only in Windows 7 and newer */
win_skip ( " no srw trylock support. \n " ) ;
srwlock_seq = 31 ; /* end */
return 0 ;
}
return 0 ;
}
static void test_srwlock_base ( void )
{
HANDLE h1 , h2 , h3 ;
DWORD dummy ;
if ( ! pInitializeSRWLock )
{
/* function is not yet in XP, only in newer Windows */
win_skip ( " no srw lock support. \n " ) ;
return ;
}
pInitializeSRWLock ( & srwlock_base ) ;
memset ( & srwlock_base_errors , 0 , sizeof ( srwlock_base_errors ) ) ;
h1 = CreateThread ( NULL , 0 , srwlock_base_thread1 , NULL , 0 , & dummy ) ;
h2 = CreateThread ( NULL , 0 , srwlock_base_thread2 , NULL , 0 , & dummy ) ;
h3 = CreateThread ( NULL , 0 , srwlock_base_thread3 , NULL , 0 , & dummy ) ;
srwlock_seq = 1 ; /* go */
while ( srwlock_seq < 31 )
Sleep ( 5 ) ;
WaitForSingleObject ( h1 , 100 ) ;
WaitForSingleObject ( h2 , 100 ) ;
WaitForSingleObject ( h3 , 100 ) ;
ok ( ! srwlock_base_errors . wrong_execution_order ,
" thread commands were executed in the wrong order (occurred %d times). \n " ,
srwlock_base_errors . wrong_execution_order ) ;
ok ( ! srwlock_base_errors . samethread_excl_excl ,
" AcquireSRWLockExclusive didn't block when called multiple times from the same thread (occurred %d times). \n " ,
srwlock_base_errors . samethread_excl_excl ) ;
ok ( ! srwlock_base_errors . samethread_excl_shared ,
" AcquireSRWLockShared didn't block when the same thread holds an exclusive lock (occurred %d times). \n " ,
srwlock_base_errors . samethread_excl_shared ) ;
ok ( ! srwlock_base_errors . samethread_shared_excl ,
" AcquireSRWLockExclusive didn't block when the same thread holds a shared lock (occurred %d times). \n " ,
srwlock_base_errors . samethread_shared_excl ) ;
ok ( ! srwlock_base_errors . multithread_excl_excl ,
" AcquireSRWLockExclusive didn't block when a second thread holds the exclusive lock (occurred %d times). \n " ,
srwlock_base_errors . multithread_excl_excl ) ;
ok ( ! srwlock_base_errors . excl_not_preferred ,
" thread waiting for exclusive access to the SHMLock was not preferred (occurred %d times). \n " ,
srwlock_base_errors . excl_not_preferred ) ;
ok ( ! srwlock_base_errors . trylock_excl ,
" TryAcquireSRWLockExclusive didn't behave as expected (occurred %d times). \n " ,
srwlock_base_errors . trylock_excl ) ;
ok ( ! srwlock_base_errors . trylock_shared ,
" TryAcquireSRWLockShared didn't behave as expected (occurred %d times). \n " ,
srwlock_base_errors . trylock_shared ) ;
}
static SRWLOCK srwlock_example ;
static LONG srwlock_protected_value = 0 ;
static LONG srwlock_example_errors = 0 , srwlock_inside = 0 , srwlock_cnt = 0 ;
static BOOL srwlock_stop = FALSE ;
static DWORD WINAPI srwlock_example_thread ( LPVOID x ) {
DWORD * cnt = x ;
LONG old ;
while ( ! srwlock_stop )
{
/* periodically request exclusive access */
if ( InterlockedIncrement ( & srwlock_cnt ) % 13 = = 0 )
{
pAcquireSRWLockExclusive ( & srwlock_example ) ;
if ( InterlockedIncrement ( & srwlock_inside ) ! = 1 )
InterlockedIncrement ( & srwlock_example_errors ) ;
InterlockedIncrement ( & srwlock_protected_value ) ;
Sleep ( 1 ) ;
if ( InterlockedDecrement ( & srwlock_inside ) ! = 0 )
InterlockedIncrement ( & srwlock_example_errors ) ;
pReleaseSRWLockExclusive ( & srwlock_example ) ;
}
/* request shared access */
pAcquireSRWLockShared ( & srwlock_example ) ;
InterlockedIncrement ( & srwlock_inside ) ;
old = srwlock_protected_value ;
( * cnt ) + + ;
Sleep ( 1 ) ;
if ( old ! = srwlock_protected_value )
InterlockedIncrement ( & srwlock_example_errors ) ;
InterlockedDecrement ( & srwlock_inside ) ;
pReleaseSRWLockShared ( & srwlock_example ) ;
}
return 0 ;
}
static void test_srwlock_example ( void )
{
HANDLE h1 , h2 , h3 ;
DWORD dummy ;
DWORD cnt1 , cnt2 , cnt3 ;
if ( ! pInitializeSRWLock ) {
/* function is not yet in XP, only in newer Windows */
win_skip ( " no srw lock support. \n " ) ;
return ;
}
pInitializeSRWLock ( & srwlock_example ) ;
cnt1 = cnt2 = cnt3 = 0 ;
h1 = CreateThread ( NULL , 0 , srwlock_example_thread , & cnt1 , 0 , & dummy ) ;
h2 = CreateThread ( NULL , 0 , srwlock_example_thread , & cnt2 , 0 , & dummy ) ;
h3 = CreateThread ( NULL , 0 , srwlock_example_thread , & cnt3 , 0 , & dummy ) ;
/* limit run to 1 second. */
Sleep ( 1000 ) ;
/* tear down start */
srwlock_stop = TRUE ;
WaitForSingleObject ( h1 , 1000 ) ;
WaitForSingleObject ( h2 , 1000 ) ;
WaitForSingleObject ( h3 , 1000 ) ;
ok ( ! srwlock_inside , " threads didn't terminate properly, srwlock_inside is %d. \n " , srwlock_inside ) ;
ok ( ! srwlock_example_errors , " errors occurred while running SRWLock example test (number of errors: %d) \n " ,
srwlock_example_errors ) ;
trace ( " number of shared accesses per thread are c1 %d, c2 %d, c3 %d \n " , cnt1 , cnt2 , cnt3 ) ;
trace ( " number of total exclusive accesses is %d \n " , srwlock_protected_value ) ;
}
2013-09-11 11:32:57 +00:00
2015-11-23 16:10:53 +00:00
static DWORD WINAPI alertable_wait_thread ( void * param )
{
HANDLE * semaphores = param ;
LARGE_INTEGER timeout ;
NTSTATUS status ;
DWORD result ;
ReleaseSemaphore ( semaphores [ 0 ] , 1 , NULL ) ;
result = WaitForMultipleObjectsEx ( 1 , & semaphores [ 1 ] , TRUE , 1000 , TRUE ) ;
ok ( result = = WAIT_IO_COMPLETION , " expected WAIT_IO_COMPLETION, got %u \n " , result ) ;
result = WaitForMultipleObjectsEx ( 1 , & semaphores [ 1 ] , TRUE , 200 , TRUE ) ;
ok ( result = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %u \n " , result ) ;
ReleaseSemaphore ( semaphores [ 0 ] , 1 , NULL ) ;
timeout . QuadPart = - 10000000 ;
status = pNtWaitForMultipleObjects ( 1 , & semaphores [ 1 ] , FALSE , TRUE , & timeout ) ;
ok ( status = = STATUS_USER_APC , " expected STATUS_USER_APC, got %08x \n " , status ) ;
timeout . QuadPart = - 2000000 ;
status = pNtWaitForMultipleObjects ( 1 , & semaphores [ 1 ] , FALSE , TRUE , & timeout ) ;
ok ( status = = STATUS_WAIT_0 , " expected STATUS_WAIT_0, got %08x \n " , status ) ;
ReleaseSemaphore ( semaphores [ 0 ] , 1 , NULL ) ;
timeout . QuadPart = - 10000000 ;
status = pNtWaitForMultipleObjects ( 1 , & semaphores [ 1 ] , FALSE , TRUE , & timeout ) ;
ok ( status = = STATUS_USER_APC , " expected STATUS_USER_APC, got %08x \n " , status ) ;
result = WaitForSingleObject ( semaphores [ 0 ] , 0 ) ;
ok ( result = = WAIT_TIMEOUT , " expected WAIT_TIMEOUT, got %u \n " , result ) ;
return 0 ;
}
static void CALLBACK alertable_wait_apc ( ULONG_PTR userdata )
{
HANDLE * semaphores = ( void * ) userdata ;
ReleaseSemaphore ( semaphores [ 1 ] , 1 , NULL ) ;
}
static void CALLBACK alertable_wait_apc2 ( ULONG_PTR userdata )
{
HANDLE * semaphores = ( void * ) userdata ;
DWORD result ;
result = WaitForSingleObject ( semaphores [ 0 ] , 1000 ) ;
ok ( result = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %u \n " , result ) ;
}
static void test_alertable_wait ( void )
{
HANDLE thread , semaphores [ 2 ] ;
DWORD result ;
semaphores [ 0 ] = CreateSemaphoreW ( NULL , 0 , 2 , NULL ) ;
ok ( semaphores [ 0 ] ! = NULL , " CreateSemaphore failed with %u \n " , GetLastError ( ) ) ;
semaphores [ 1 ] = CreateSemaphoreW ( NULL , 0 , 1 , NULL ) ;
ok ( semaphores [ 1 ] ! = NULL , " CreateSemaphore failed with %u \n " , GetLastError ( ) ) ;
thread = CreateThread ( NULL , 0 , alertable_wait_thread , semaphores , 0 , NULL ) ;
ok ( thread ! = NULL , " CreateThread failed with %u \n " , GetLastError ( ) ) ;
result = WaitForSingleObject ( semaphores [ 0 ] , 1000 ) ;
ok ( result = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %u \n " , result ) ;
Sleep ( 100 ) ; /* ensure the thread is blocking in WaitForMultipleObjectsEx */
result = QueueUserAPC ( alertable_wait_apc , thread , ( ULONG_PTR ) semaphores ) ;
ok ( result ! = 0 , " QueueUserAPC failed with %u \n " , GetLastError ( ) ) ;
result = WaitForSingleObject ( semaphores [ 0 ] , 1000 ) ;
ok ( result = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %u \n " , result ) ;
Sleep ( 100 ) ; /* ensure the thread is blocking in NtWaitForMultipleObjects */
result = QueueUserAPC ( alertable_wait_apc , thread , ( ULONG_PTR ) semaphores ) ;
ok ( result ! = 0 , " QueueUserAPC failed with %u \n " , GetLastError ( ) ) ;
result = WaitForSingleObject ( semaphores [ 0 ] , 1000 ) ;
ok ( result = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %u \n " , result ) ;
Sleep ( 100 ) ; /* ensure the thread is blocking in NtWaitForMultipleObjects */
result = QueueUserAPC ( alertable_wait_apc2 , thread , ( ULONG_PTR ) semaphores ) ;
ok ( result ! = 0 , " QueueUserAPC failed with %u \n " , GetLastError ( ) ) ;
result = QueueUserAPC ( alertable_wait_apc2 , thread , ( ULONG_PTR ) semaphores ) ;
ok ( result ! = 0 , " QueueUserAPC failed with %u \n " , GetLastError ( ) ) ;
ReleaseSemaphore ( semaphores [ 0 ] , 2 , NULL ) ;
result = WaitForSingleObject ( thread , 1000 ) ;
ok ( result = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %u \n " , result ) ;
CloseHandle ( thread ) ;
CloseHandle ( semaphores [ 0 ] ) ;
CloseHandle ( semaphores [ 1 ] ) ;
}
struct apc_deadlock_info
{
PROCESS_INFORMATION * pi ;
HANDLE event ;
BOOL running ;
} ;
static DWORD WINAPI apc_deadlock_thread ( void * param )
{
struct apc_deadlock_info * info = param ;
PROCESS_INFORMATION * pi = info - > pi ;
NTSTATUS status ;
SIZE_T size ;
void * base ;
while ( info - > running )
{
base = NULL ;
size = 0x1000 ;
status = pNtAllocateVirtualMemory ( pi - > hProcess , & base , 0 , & size ,
MEM_RESERVE | MEM_COMMIT , PAGE_READWRITE ) ;
2019-09-15 13:07:32 +00:00
disable_success_count
2015-11-23 16:10:53 +00:00
ok ( ! status , " expected STATUS_SUCCESS, got %08x \n " , status ) ;
ok ( base ! = NULL , " expected base != NULL, got %p \n " , base ) ;
SetEvent ( info - > event ) ;
size = 0 ;
status = pNtFreeVirtualMemory ( pi - > hProcess , & base , & size , MEM_RELEASE ) ;
2019-09-15 13:07:32 +00:00
disable_success_count
2015-11-23 16:10:53 +00:00
ok ( ! status , " expected STATUS_SUCCESS, got %08x \n " , status ) ;
SetEvent ( info - > event ) ;
}
return 0 ;
}
static void test_apc_deadlock ( void )
{
struct apc_deadlock_info info ;
PROCESS_INFORMATION pi ;
STARTUPINFOA si = { sizeof ( si ) } ;
char cmdline [ MAX_PATH ] ;
HANDLE event , thread ;
DWORD result ;
BOOL success ;
char * * argv ;
int i ;
2021-07-02 16:12:24 +00:00
# if defined(__REACTOS__) && defined(_M_AMD64)
if ( ! winetest_interactive )
{
skip ( " ROSTESTS-371: Skipping kernel32_winetest:sync test_apc_deadlock because it fails on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway. \n " ) ;
return ;
}
# endif
2015-11-23 16:10:53 +00:00
winetest_get_mainargs ( & argv ) ;
sprintf ( cmdline , " \" %s \" sync apc_deadlock " , argv [ 0 ] ) ;
success = CreateProcessA ( argv [ 0 ] , cmdline , NULL , NULL , FALSE , 0 , NULL , NULL , & si , & pi ) ;
ok ( success , " CreateProcess failed with %u \n " , GetLastError ( ) ) ;
event = CreateEventA ( NULL , FALSE , FALSE , NULL ) ;
ok ( event ! = NULL , " CreateEvent failed with %u \n " , GetLastError ( ) ) ;
info . pi = & pi ;
info . event = event ;
info . running = TRUE ;
thread = CreateThread ( NULL , 0 , apc_deadlock_thread , & info , 0 , NULL ) ;
ok ( thread ! = NULL , " CreateThread failed with %u \n " , GetLastError ( ) ) ;
result = WaitForSingleObject ( event , 1000 ) ;
ok ( result = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %u \n " , result ) ;
2019-09-15 13:07:32 +00:00
disable_success_count
2015-11-23 16:10:53 +00:00
for ( i = 0 ; i < 1000 ; i + + )
{
result = SuspendThread ( pi . hThread ) ;
ok ( result = = 0 , " expected 0, got %u \n " , result ) ;
WaitForSingleObject ( event , 0 ) ; /* reset event */
result = WaitForSingleObject ( event , 1000 ) ;
ok ( result = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %u \n " , result ) ;
result = ResumeThread ( pi . hThread ) ;
ok ( result = = 1 , " expected 1, got %u \n " , result ) ;
Sleep ( 1 ) ;
}
info . running = FALSE ;
result = WaitForSingleObject ( thread , 1000 ) ;
ok ( result = = WAIT_OBJECT_0 , " expected WAIT_OBJECT_0, got %u \n " , result ) ;
CloseHandle ( thread ) ;
CloseHandle ( event ) ;
TerminateProcess ( pi . hProcess , 0 ) ;
CloseHandle ( pi . hThread ) ;
CloseHandle ( pi . hProcess ) ;
}
2007-03-06 11:59:18 +00:00
START_TEST ( sync )
{
2015-11-23 16:10:53 +00:00
char * * argv ;
int argc ;
2014-04-18 22:50:27 +00:00
HMODULE hdll = GetModuleHandleA ( " kernel32.dll " ) ;
2014-09-20 19:35:24 +00:00
HMODULE hntdll = GetModuleHandleA ( " ntdll.dll " ) ;
2018-09-16 10:03:08 +00:00
# ifdef __REACTOS__
HMODULE hdll_vista = GetModuleHandleA ( " kernel32_vista.dll " ) ;
# endif
2014-09-20 19:35:24 +00:00
2012-12-09 20:39:13 +00:00
pInitOnceInitialize = ( void * ) GetProcAddress ( hdll , " InitOnceInitialize " ) ;
pInitOnceExecuteOnce = ( void * ) GetProcAddress ( hdll , " InitOnceExecuteOnce " ) ;
pInitOnceBeginInitialize = ( void * ) GetProcAddress ( hdll , " InitOnceBeginInitialize " ) ;
pInitOnceComplete = ( void * ) GetProcAddress ( hdll , " InitOnceComplete " ) ;
pInitializeConditionVariable = ( void * ) GetProcAddress ( hdll , " InitializeConditionVariable " ) ;
pSleepConditionVariableCS = ( void * ) GetProcAddress ( hdll , " SleepConditionVariableCS " ) ;
2014-04-18 22:50:27 +00:00
pSleepConditionVariableSRW = ( void * ) GetProcAddress ( hdll , " SleepConditionVariableSRW " ) ;
2012-12-09 20:39:13 +00:00
pWakeAllConditionVariable = ( void * ) GetProcAddress ( hdll , " WakeAllConditionVariable " ) ;
pWakeConditionVariable = ( void * ) GetProcAddress ( hdll , " WakeConditionVariable " ) ;
2014-04-18 22:50:27 +00:00
pInitializeSRWLock = ( void * ) GetProcAddress ( hdll , " InitializeSRWLock " ) ;
pAcquireSRWLockExclusive = ( void * ) GetProcAddress ( hdll , " AcquireSRWLockExclusive " ) ;
pAcquireSRWLockShared = ( void * ) GetProcAddress ( hdll , " AcquireSRWLockShared " ) ;
pReleaseSRWLockExclusive = ( void * ) GetProcAddress ( hdll , " ReleaseSRWLockExclusive " ) ;
pReleaseSRWLockShared = ( void * ) GetProcAddress ( hdll , " ReleaseSRWLockShared " ) ;
pTryAcquireSRWLockExclusive = ( void * ) GetProcAddress ( hdll , " TryAcquireSRWLockExclusive " ) ;
pTryAcquireSRWLockShared = ( void * ) GetProcAddress ( hdll , " TryAcquireSRWLockShared " ) ;
2015-11-23 16:10:53 +00:00
pNtAllocateVirtualMemory = ( void * ) GetProcAddress ( hntdll , " NtAllocateVirtualMemory " ) ;
pNtFreeVirtualMemory = ( void * ) GetProcAddress ( hntdll , " NtFreeVirtualMemory " ) ;
2016-03-08 15:49:46 +00:00
pNtWaitForSingleObject = ( void * ) GetProcAddress ( hntdll , " NtWaitForSingleObject " ) ;
2014-09-20 19:35:24 +00:00
pNtWaitForMultipleObjects = ( void * ) GetProcAddress ( hntdll , " NtWaitForMultipleObjects " ) ;
2016-03-08 15:49:46 +00:00
pRtlInterlockedPushListSList = ( void * ) GetProcAddress ( hntdll , " RtlInterlockedPushListSList " ) ;
pRtlInterlockedPushListSListEx = ( void * ) GetProcAddress ( hntdll , " RtlInterlockedPushListSListEx " ) ;
2008-12-23 20:02:47 +00:00
2018-09-16 10:03:08 +00:00
# ifdef __REACTOS__
if ( ! pInitializeConditionVariable )
{
pInitializeConditionVariable = ( void * ) GetProcAddress ( hdll_vista , " InitializeConditionVariable " ) ;
pSleepConditionVariableCS = ( void * ) GetProcAddress ( hdll_vista , " SleepConditionVariableCS " ) ;
pSleepConditionVariableSRW = ( void * ) GetProcAddress ( hdll_vista , " SleepConditionVariableSRW " ) ;
pWakeAllConditionVariable = ( void * ) GetProcAddress ( hdll_vista , " WakeAllConditionVariable " ) ;
pWakeConditionVariable = ( void * ) GetProcAddress ( hdll_vista , " WakeConditionVariable " ) ;
}
if ( ! pInitializeSRWLock )
{
pInitializeSRWLock = ( void * ) GetProcAddress ( hdll_vista , " InitializeSRWLock " ) ;
pAcquireSRWLockExclusive = ( void * ) GetProcAddress ( hdll_vista , " AcquireSRWLockExclusive " ) ;
pAcquireSRWLockShared = ( void * ) GetProcAddress ( hdll_vista , " AcquireSRWLockShared " ) ;
pReleaseSRWLockExclusive = ( void * ) GetProcAddress ( hdll_vista , " ReleaseSRWLockExclusive " ) ;
pReleaseSRWLockShared = ( void * ) GetProcAddress ( hdll_vista , " ReleaseSRWLockShared " ) ;
pTryAcquireSRWLockExclusive = ( void * ) GetProcAddress ( hdll_vista , " TryAcquireSRWLockExclusive " ) ;
pTryAcquireSRWLockShared = ( void * ) GetProcAddress ( hdll_vista , " TryAcquireSRWLockShared " ) ;
}
# endif
2015-11-23 16:10:53 +00:00
argc = winetest_get_mainargs ( & argv ) ;
if ( argc > = 3 )
{
if ( ! strcmp ( argv [ 2 ] , " apc_deadlock " ) )
{
2015-11-24 19:38:03 +00:00
for ( ; ; ) SleepEx ( INFINITE , TRUE ) ;
2015-11-23 16:10:53 +00:00
}
return ;
}
2016-03-08 15:49:46 +00:00
init_fastcall_thunk ( ) ;
2007-03-06 11:59:18 +00:00
test_signalandwait ( ) ;
2008-05-09 17:35:45 +00:00
test_mutex ( ) ;
test_slist ( ) ;
2008-12-23 20:02:47 +00:00
test_event ( ) ;
test_semaphore ( ) ;
test_waitable_timer ( ) ;
2008-05-09 17:35:45 +00:00
test_iocp_callback ( ) ;
2008-12-23 20:02:47 +00:00
test_timer_queue ( ) ;
2011-10-03 17:58:01 +00:00
test_WaitForSingleObject ( ) ;
test_WaitForMultipleObjects ( ) ;
2012-12-09 20:39:13 +00:00
test_initonce ( ) ;
2013-09-11 11:32:57 +00:00
test_condvars_base ( ) ;
test_condvars_consumer_producer ( ) ;
2014-04-18 22:50:27 +00:00
test_srwlock_base ( ) ;
test_srwlock_example ( ) ;
2015-11-23 16:10:53 +00:00
test_alertable_wait ( ) ;
test_apc_deadlock ( ) ;
2007-03-06 11:59:18 +00:00
}