[KERNEL32_WINETEST]
[reactos.git] / rostests / winetests / kernel32 / sync.c
index ea36fc6..e875c79 100755 (executable)
@@ -18,7 +18,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define _WIN32_WINNT 0x500
+#define _WIN32_WINNT 0x502
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -35,14 +35,15 @@ static HANDLE (WINAPI *pCreateWaitableTimerA)(SECURITY_ATTRIBUTES*,BOOL,LPCSTR);
 static BOOL   (WINAPI *pDeleteTimerQueueEx)(HANDLE, HANDLE);
 static BOOL   (WINAPI *pDeleteTimerQueueTimer)(HANDLE, HANDLE, HANDLE);
 static HANDLE (WINAPI *pOpenWaitableTimerA)(DWORD,BOOL,LPCSTR);
+static HANDLE (WINAPI *pCreateMemoryResourceNotification)(MEMORY_RESOURCE_NOTIFICATION_TYPE);
+static BOOL   (WINAPI *pQueryMemoryResourceNotification)(HANDLE, PBOOL);
 
 static void test_signalandwait(void)
 {
     DWORD (WINAPI *pSignalObjectAndWait)(HANDLE, HANDLE, DWORD, BOOL);
     HMODULE kernel32;
     DWORD r;
-    int i;
-    HANDLE event[2], maxevents[MAXIMUM_WAIT_OBJECTS], semaphore[2], file;
+    HANDLE event[2], semaphore[2], file;
 
     kernel32 = GetModuleHandle("kernel32");
     pSignalObjectAndWait = (void*) GetProcAddress(kernel32, "SignalObjectAndWait");
@@ -94,19 +95,6 @@ static void test_signalandwait(void)
     CloseHandle(event[0]);
     CloseHandle(event[1]);
 
-    /* create the maximum number of events and make sure 
-     * we can wait on that many */
-    for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
-    {
-        maxevents[i] = CreateEvent(NULL, 1, 1, NULL);
-        ok( maxevents[i] != 0, "should create enough events\n");
-    }
-    r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
-    ok( r != WAIT_FAILED && r != WAIT_TIMEOUT, "should succeed\n");
-
-    for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
-        if (maxevents[i]) CloseHandle(maxevents[i]);
-
     /* semaphores */
     semaphore[0] = CreateSemaphore( NULL, 0, 1, NULL );
     semaphore[1] = CreateSemaphore( NULL, 1, 1, NULL );
@@ -142,20 +130,73 @@ static void test_mutex(void)
     BOOL ret;
     HANDLE hCreated;
     HANDLE hOpened;
+    int i;
+    DWORD failed = 0;
 
+    SetLastError(0xdeadbeef);
+    hOpened = OpenMutex(0, FALSE, "WineTestMutex");
+    ok(hOpened == NULL, "OpenMutex succeeded\n");
+    ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
     hCreated = CreateMutex(NULL, FALSE, "WineTestMutex");
     ok(hCreated != NULL, "CreateMutex failed with error %d\n", GetLastError());
-    wait_ret = WaitForSingleObject(hCreated, INFINITE);
-    ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error 0x%08x\n", wait_ret);
 
-    /* yes, opening with just READ_CONTROL access allows us to successfully
-     * call ReleaseMutex */
-    hOpened = OpenMutex(READ_CONTROL, FALSE, "WineTestMutex");
+    SetLastError(0xdeadbeef);
+    hOpened = OpenMutex(0, FALSE, "WineTestMutex");
+todo_wine
+    ok(hOpened == NULL, "OpenMutex succeeded\n");
+todo_wine
+    ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    hOpened = OpenMutex(GENERIC_EXECUTE, FALSE, "WineTestMutex");
+    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);
+    }
+
+    SetLastError(0xdeadbeef);
+    hOpened = OpenMutex(GENERIC_READ | GENERIC_WRITE, FALSE, "WineTestMutex");
     ok(hOpened != NULL, "OpenMutex failed with error %d\n", GetLastError());
-    ret = ReleaseMutex(hOpened);
-    todo_wine ok(ret, "ReleaseMutex failed with error %d\n", GetLastError());
+    wait_ret = WaitForSingleObject(hOpened, INFINITE);
+    ok(wait_ret == WAIT_FAILED, "WaitForSingleObject succeeded\n");
+    CloseHandle(hOpened);
+
+    for (i = 0; i < 32; i++)
+    {
+        SetLastError(0xdeadbeef);
+        hOpened = OpenMutex(0x1 << i, FALSE, "WineTestMutex");
+        if(hOpened != NULL)
+        {
+            SetLastError(0xdeadbeef);
+            ret = ReleaseMutex(hOpened);
+            ok(ret, "ReleaseMutex failed with error %d, access %x\n", GetLastError(), 1 << i);
+            CloseHandle(hOpened);
+        }
+        else
+        {
+            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);
+            ReleaseMutex(hCreated);
+            failed |=0x1 << i;
+        }
+    }
+
+todo_wine
+    ok( failed == 0x0de0fffe, "open succeeded when it shouldn't: %x\n", failed);
+
+    SetLastError(0xdeadbeef);
     ret = ReleaseMutex(hCreated);
-    todo_wine ok(!ret && (GetLastError() == ERROR_NOT_OWNER),
+    ok(!ret && (GetLastError() == ERROR_NOT_OWNER),
         "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %d\n", GetLastError());
 
     /* test case sensitivity */
@@ -163,16 +204,12 @@ static void test_mutex(void)
     SetLastError(0xdeadbeef);
     hOpened = OpenMutex(READ_CONTROL, FALSE, "WINETESTMUTEX");
     ok(!hOpened, "OpenMutex succeeded\n");
-    ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
-       GetLastError() == ERROR_INVALID_NAME, /* win9x */
-       "wrong error %u\n", GetLastError());
+    ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
 
     SetLastError(0xdeadbeef);
     hOpened = OpenMutex(READ_CONTROL, FALSE, "winetestmutex");
     ok(!hOpened, "OpenMutex succeeded\n");
-    ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
-       GetLastError() == ERROR_INVALID_NAME, /* win9x */
-       "wrong error %u\n", GetLastError());
+    ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
 
     SetLastError(0xdeadbeef);
     hOpened = CreateMutex(NULL, FALSE, "WineTestMutex");
@@ -285,6 +322,8 @@ static void test_event(void)
     SECURITY_ATTRIBUTES sa;
     SECURITY_DESCRIPTOR sd;
     ACL acl;
+    DWORD ret;
+    BOOL val;
 
     /* no sd */
     handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
@@ -342,10 +381,41 @@ static void test_event(void)
     SetLastError(0xdeadbeef);
     handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": TEST EVENT");
     ok( !handle2, "OpenEvent succeeded\n");
-    ok( GetLastError() == ERROR_FILE_NOT_FOUND ||
-        GetLastError() == ERROR_INVALID_NAME, /* win9x */
-        "wrong error %u\n", GetLastError());
+    ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
+
+    CloseHandle( handle );
+
+    /* 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 );
 }
 
@@ -380,9 +450,7 @@ static void test_semaphore(void)
     SetLastError(0xdeadbeef);
     handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": TEST SEMAPHORE");
     ok( !handle2, "OpenSemaphore succeeded\n");
-    ok( GetLastError() == ERROR_FILE_NOT_FOUND ||
-        GetLastError() == ERROR_INVALID_NAME, /* win9x */
-        "wrong error %u\n", GetLastError());
+    ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
 
     CloseHandle( handle );
 }
@@ -939,6 +1007,120 @@ static void test_timer_queue(void)
        GetLastError());
 }
 
+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;
+    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());
+
+    CloseHandle(signaled);
+    CloseHandle(nonsignaled);
+}
+
+static void test_WaitForMultipleObjects(void)
+{
+    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++)
+    {
+        maxevents[i] = CreateEvent(NULL, i==0, TRUE, NULL);
+        ok( maxevents[i] != 0, "should create enough events\n");
+    }
+
+    /* a manual-reset event remains signaled, an auto-reset event is cleared */
+    r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
+    ok( r == WAIT_OBJECT_0, "should signal lowest handle first, got %d\n", r);
+    r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
+    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 */
+        r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
+        ok( r == WAIT_OBJECT_0+i, "should signal handle #%d first, got %d\n", i, r);
+    }
+
+    for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
+        if (maxevents[i]) CloseHandle(maxevents[i]);
+}
+
 START_TEST(sync)
 {
     HMODULE hdll = GetModuleHandle("kernel32");
@@ -949,6 +1131,8 @@ START_TEST(sync)
     pDeleteTimerQueueEx = (void*)GetProcAddress(hdll, "DeleteTimerQueueEx");
     pDeleteTimerQueueTimer = (void*)GetProcAddress(hdll, "DeleteTimerQueueTimer");
     pOpenWaitableTimerA = (void*)GetProcAddress(hdll, "OpenWaitableTimerA");
+    pCreateMemoryResourceNotification = (void *)GetProcAddress(hdll, "CreateMemoryResourceNotification");
+    pQueryMemoryResourceNotification = (void *)GetProcAddress(hdll, "QueryMemoryResourceNotification");
 
     test_signalandwait();
     test_mutex();
@@ -958,4 +1142,6 @@ START_TEST(sync)
     test_waitable_timer();
     test_iocp_callback();
     test_timer_queue();
+    test_WaitForSingleObject();
+    test_WaitForMultipleObjects();
 }