[KERNEL32]
[reactos.git] / rostests / winetests / kernel32 / thread.c
index 0030422..4c4e764 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Unit test suite for directory functions.
+ * Unit test suite for thread functions.
  *
  * Copyright 2002 Geoffrey Hausheer
  *
@@ -18,6 +18,9 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+/* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */
+#define _WIN32_WINNT 0x0500
+
 #include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
 # endif
 #endif
 
-typedef BOOL (WINAPI *GetThreadPriorityBoost_t)(HANDLE,PBOOL);
-static GetThreadPriorityBoost_t pGetThreadPriorityBoost=NULL;
-
-typedef HANDLE (WINAPI *OpenThread_t)(DWORD,BOOL,DWORD);
-static OpenThread_t pOpenThread=NULL;
-
-typedef BOOL (WINAPI *QueueUserWorkItem_t)(LPTHREAD_START_ROUTINE,PVOID,ULONG);
-static QueueUserWorkItem_t pQueueUserWorkItem=NULL;
-
-typedef DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD);
-static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL;
-
-typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL);
-static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL;
-
-typedef BOOL (WINAPI *RegisterWaitForSingleObject_t)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG);
-static RegisterWaitForSingleObject_t pRegisterWaitForSingleObject=NULL;
-
-typedef BOOL (WINAPI *UnregisterWait_t)(HANDLE);
-static UnregisterWait_t pUnregisterWait=NULL;
+static BOOL (WINAPI *pGetThreadPriorityBoost)(HANDLE,PBOOL);
+static HANDLE (WINAPI *pOpenThread)(DWORD,BOOL,DWORD);
+static BOOL (WINAPI *pQueueUserWorkItem)(LPTHREAD_START_ROUTINE,PVOID,ULONG);
+static DWORD (WINAPI *pSetThreadIdealProcessor)(HANDLE,DWORD);
+static BOOL (WINAPI *pSetThreadPriorityBoost)(HANDLE,BOOL);
+static BOOL (WINAPI *pRegisterWaitForSingleObject)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG);
+static BOOL (WINAPI *pUnregisterWait)(HANDLE);
+static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
+static BOOL (WINAPI *pSetThreadErrorMode)(DWORD,PDWORD);
+static DWORD (WINAPI *pGetThreadErrorMode)(void);
+static DWORD (WINAPI *pRtlGetThreadErrorMode)(void);
 
 static HANDLE create_target_process(const char *arg)
 {
@@ -180,11 +174,11 @@ INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
 */
 static DWORD WINAPI threadFunc1(LPVOID p)
 {
-    t1Struct *tstruct = (t1Struct *)p;
+   t1Struct *tstruct = p;
    int i;
 /* write our thread # into shared memory */
    tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
-   ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
+   ok(TlsSetValue(tlsIndex,(LPVOID)(INT_PTR)(tstruct->threadnum+1))!=0,
       "TlsSetValue failed\n");
 /* The threads synchronize before terminating.  This is done by
    Signaling an event, and waiting for all events to occur
@@ -202,7 +196,7 @@ static DWORD WINAPI threadFunc1(LPVOID p)
    ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
 
 /* Check that no one changed our tls memory */
-   ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
+   ok((INT_PTR)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
       "TlsGetValue failed\n");
    return NUM_THREADS+tstruct->threadnum;
 }
@@ -222,7 +216,7 @@ static DWORD WINAPI threadFunc3(LPVOID p)
 
 static DWORD WINAPI threadFunc4(LPVOID p)
 {
-    HANDLE event = (HANDLE)p;
+   HANDLE event = p;
    if(event != NULL) {
      SetEvent(event);
    }
@@ -233,7 +227,7 @@ static DWORD WINAPI threadFunc4(LPVOID p)
 #if CHECK_STACK
 static DWORD WINAPI threadFunc5(LPVOID p)
 {
-  DWORD *exitCode = (DWORD *)p;
+  DWORD *exitCode = p;
   SYSTEM_INFO sysInfo;
   sysInfo.dwPageSize=0;
   GetSystemInfo(&sysInfo);
@@ -252,13 +246,13 @@ static DWORD WINAPI threadFunc5(LPVOID p)
 
 static DWORD WINAPI threadFunc_SetEvent(LPVOID p)
 {
-    SetEvent((HANDLE) p);
+    SetEvent(p);
     return 0;
 }
 
 static DWORD WINAPI threadFunc_CloseHandle(LPVOID p)
 {
-    CloseHandle((HANDLE) p);
+    CloseHandle(p);
     return 0;
 }
 
@@ -305,7 +299,7 @@ static VOID test_CreateRemoteThread(void)
                                  hRemoteEvent, CREATE_SUSPENDED, &tid);
     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
     {
-        skip("CreateRemoteThread is not implemented\n");
+        win_skip("CreateRemoteThread is not implemented\n");
         goto cleanup;
     }
     ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
@@ -427,7 +421,17 @@ static VOID test_CreateThread_basic(void)
          "Thread did not execute successfully\n");
     ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
   }
-  ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
+
+  SetLastError(0xCAFEF00D);
+  ok(TlsFree(tlsIndex)!=0,"TlsFree failed: %08x\n", GetLastError());
+  ok(GetLastError()==0xCAFEF00D,
+     "GetLastError: expected 0xCAFEF00D, got %08x\n", GetLastError());
+
+  /* Test freeing an already freed TLS index */
+  SetLastError(0xCAFEF00D);
+  ok(TlsFree(tlsIndex)==0,"TlsFree succeeded\n");
+  ok(GetLastError()==ERROR_INVALID_PARAMETER,
+     "GetLastError: expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
 
   /* Test how passing NULL as a pointer to threadid works */
   SetLastError(0xFACEaBAD);
@@ -547,8 +551,7 @@ static VOID test_TerminateThread(void)
   HANDLE thread,access_thread,event;
   DWORD threadId,exitCode;
   event=CreateEventA(NULL,TRUE,FALSE,NULL);
-  thread = CreateThread(NULL,0,threadFunc4,
-                        (LPVOID)event, 0,&threadId);
+  thread = CreateThread(NULL,0,threadFunc4,event,0,&threadId);
   ok(thread!=NULL,"Create Thread failed\n");
 /* TerminateThread has a race condition in Wine.  If the thread is terminated
    before it starts, it leaves a process behind.  Therefore, we wait for the
@@ -691,10 +694,12 @@ static VOID test_thread_priority(void)
    SetLastError(0xdeadbeef);
    rc=pGetThreadPriorityBoost(curthread,&disabled);
    if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
-     return; /* WinME */
+   {
+      win_skip("GetThreadPriorityBoost is not implemented on WinME\n");
+      return;
+   }
 
-   todo_wine
-     ok(rc!=0,"error=%d\n",GetLastError());
+   ok(rc!=0,"error=%d\n",GetLastError());
 
    if (pOpenThread) {
 /* check that access control is obeyed */
@@ -704,7 +709,7 @@ static VOID test_thread_priority(void)
      ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
      if (access_thread!=NULL) {
        obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
-       obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
+       todo_wine obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
        ok(CloseHandle(access_thread),"Error Closing thread handle\n");
      }
    }
@@ -718,10 +723,10 @@ static VOID test_thread_priority(void)
 
      rc = pSetThreadPriorityBoost(curthread,0);
      ok( rc != 0, "error=%d\n",GetLastError());
-     rc=pGetThreadPriorityBoost(curthread,&disabled);
-     ok(rc!=0 && disabled==0,
-        "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
    }
+   rc=pGetThreadPriorityBoost(curthread,&disabled);
+   ok(rc!=0 && disabled==0,
+      "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
 }
 
 /* check the GetThreadTimes function */
@@ -753,7 +758,10 @@ static VOID test_GetThreadTimes(void)
 /* GetThreadTimes should set all of the parameters passed to it */
      error=GetThreadTimes(thread,&creationTime,&exitTime,
                           &kernelTime,&userTime);
-     if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
+
+     if (error == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+       win_skip("GetThreadTimes is not implemented\n");
+     else {
        ok(error!=0,"GetThreadTimes failed\n");
        ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
           "creationTime was invalid\n");
@@ -782,9 +790,12 @@ static VOID test_GetThreadTimes(void)
 static VOID test_thread_processor(void)
 {
    HANDLE curthread,curproc;
-   DWORD_PTR processMask,systemMask;
+   DWORD_PTR processMask,systemMask,retMask;
    SYSTEM_INFO sysInfo;
    int error=0;
+   BOOL is_wow64;
+
+   if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
 
    sysInfo.dwNumberOfProcessors=0;
    GetSystemInfo(&sysInfo);
@@ -802,24 +813,55 @@ static VOID test_thread_processor(void)
       "SetThreadAffinityMask failed\n");
    ok(SetThreadAffinityMask(curthread,processMask+1)==0,
       "SetThreadAffinityMask passed for an illegal processor\n");
+/* NOTE: Pre-Vista does not recognize the "all processors" flag (all bits set) */
+   retMask = SetThreadAffinityMask(curthread,~0);
+   ok(broken(retMask==0) || retMask==processMask,
+      "SetThreadAffinityMask(thread,-1) failed to request all processors.\n");
+   if (retMask == processMask && sizeof(ULONG_PTR) > sizeof(ULONG))
+   {
+       /* only the low 32-bits matter */
+       retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0);
+       ok(retMask == processMask, "SetThreadAffinityMask failed\n");
+       retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0 >> 3);
+       ok(retMask == processMask, "SetThreadAffinityMask failed\n");
+       retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)1);
+       ok(retMask == 0, "SetThreadAffinityMask succeeded\n");
+   }
 /* NOTE: This only works on WinNT/2000/XP) */
    if (pSetThreadIdealProcessor) {
-     todo_wine {
-       SetLastError(0);
-       error=pSetThreadIdealProcessor(curthread,0);
-       if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
-         ok(error!=-1, "SetThreadIdealProcessor failed\n");
-       }
+     SetLastError(0xdeadbeef);
+     error=pSetThreadIdealProcessor(curthread,0);
+     if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+     {
+       win_skip("SetThreadIdealProcessor is not implemented\n");
+       return;
      }
-     if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
-       error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
-       ok(error==-1,
-          "SetThreadIdealProcessor succeeded with an illegal processor #\n");
-       todo_wine {
-         error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
-         ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
-       }
+     ok(error!=-1, "SetThreadIdealProcessor failed\n");
+
+     if (is_wow64)
+     {
+         SetLastError(0xdeadbeef);
+         error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
+         todo_wine
+         ok(error!=-1, "SetThreadIdealProcessor failed for %u on Wow64\n", MAXIMUM_PROCESSORS+1);
+
+         SetLastError(0xdeadbeef);
+         error=pSetThreadIdealProcessor(curthread,65);
+         ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
+         ok(GetLastError()==ERROR_INVALID_PARAMETER,
+            "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+     }
+     else
+     {
+         SetLastError(0xdeadbeef);
+         error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
+         ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
+         ok(GetLastError()==ERROR_INVALID_PARAMETER,
+            "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
      }
+
+     error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
+     ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
    }
 }
 
@@ -926,7 +968,7 @@ static DWORD CALLBACK work_function(void *p)
 
 static void test_QueueUserWorkItem(void)
 {
-    int i;
+    INT_PTR i;
     DWORD wait_result;
     DWORD before, after;
 
@@ -975,7 +1017,7 @@ static void test_RegisterWaitForSingleObject(void)
 
     if (!pRegisterWaitForSingleObject || !pUnregisterWait)
     {
-        skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
+        win_skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
         return;
     }
 
@@ -1043,7 +1085,7 @@ static DWORD WINAPI TLS_InheritanceProc(LPVOID p)
    inheritance with TLS_InheritanceProc.  */
 static DWORD WINAPI TLS_ThreadProc(LPVOID p)
 {
-  LONG id = (LONG) p;
+  LONG_PTR id = (LONG_PTR) p;
   LPVOID val;
   BOOL ret;
 
@@ -1163,7 +1205,7 @@ static DWORD WINAPI TLS_ThreadProc(LPVOID p)
 static void test_TLS(void)
 {
   HANDLE threads[2];
-  LONG i;
+  LONG_PTR i;
   DWORD ret;
   BOOL suc;
 
@@ -1194,9 +1236,103 @@ static void test_TLS(void)
   cleanup_thread_sync_helpers();
 }
 
+static void test_ThreadErrorMode(void)
+{
+    DWORD oldmode;
+    DWORD mode;
+    DWORD rtlmode;
+    BOOL ret;
+
+    if (!pSetThreadErrorMode || !pGetThreadErrorMode)
+    {
+        win_skip("SetThreadErrorMode and/or GetThreadErrorMode unavailable (added in Windows 7)\n");
+        return;
+    }
+
+    if (!pRtlGetThreadErrorMode) {
+        win_skip("RtlGetThreadErrorMode not available\n");
+        return;
+    }
+
+    oldmode = pGetThreadErrorMode();
+
+    ret = pSetThreadErrorMode(0, &mode);
+    ok(ret, "SetThreadErrorMode failed\n");
+    ok(mode == oldmode,
+       "SetThreadErrorMode returned old mode 0x%x, expected 0x%x\n",
+       mode, oldmode);
+    mode = pGetThreadErrorMode();
+    ok(mode == 0, "GetThreadErrorMode returned mode 0x%x, expected 0\n", mode);
+    rtlmode = pRtlGetThreadErrorMode();
+    ok(rtlmode == 0,
+       "RtlGetThreadErrorMode returned mode 0x%x, expected 0\n", mode);
+
+    ret = pSetThreadErrorMode(SEM_FAILCRITICALERRORS, &mode);
+    ok(ret, "SetThreadErrorMode failed\n");
+    ok(mode == 0,
+       "SetThreadErrorMode returned old mode 0x%x, expected 0\n", mode);
+    mode = pGetThreadErrorMode();
+    ok(mode == SEM_FAILCRITICALERRORS,
+       "GetThreadErrorMode returned mode 0x%x, expected SEM_FAILCRITICALERRORS\n",
+       mode);
+    rtlmode = pRtlGetThreadErrorMode();
+    ok(rtlmode == 0x10,
+       "RtlGetThreadErrorMode returned mode 0x%x, expected 0x10\n", mode);
+
+    ret = pSetThreadErrorMode(SEM_NOGPFAULTERRORBOX, &mode);
+    ok(ret, "SetThreadErrorMode failed\n");
+    ok(mode == SEM_FAILCRITICALERRORS,
+       "SetThreadErrorMode returned old mode 0x%x, expected SEM_FAILCRITICALERRORS\n",
+       mode);
+    mode = pGetThreadErrorMode();
+    ok(mode == SEM_NOGPFAULTERRORBOX,
+       "GetThreadErrorMode returned mode 0x%x, expected SEM_NOGPFAULTERRORBOX\n",
+       mode);
+    rtlmode = pRtlGetThreadErrorMode();
+    ok(rtlmode == 0x20,
+       "RtlGetThreadErrorMode returned mode 0x%x, expected 0x20\n", mode);
+
+    ret = pSetThreadErrorMode(SEM_NOOPENFILEERRORBOX, NULL);
+    ok(ret, "SetThreadErrorMode failed\n");
+    mode = pGetThreadErrorMode();
+    ok(mode == SEM_NOOPENFILEERRORBOX,
+       "GetThreadErrorMode returned mode 0x%x, expected SEM_NOOPENFILEERRORBOX\n",
+       mode);
+    rtlmode = pRtlGetThreadErrorMode();
+    ok(rtlmode == 0x40,
+       "RtlGetThreadErrorMode returned mode 0x%x, expected 0x40\n", rtlmode);
+
+    for (mode = 1; mode; mode <<= 1)
+    {
+        ret = pSetThreadErrorMode(mode, NULL);
+        if (mode & (SEM_FAILCRITICALERRORS |
+                    SEM_NOGPFAULTERRORBOX |
+                    SEM_NOOPENFILEERRORBOX))
+        {
+            ok(ret,
+               "SetThreadErrorMode(0x%x,NULL) failed with error %d\n",
+               mode, GetLastError());
+        }
+        else
+        {
+            DWORD GLE = GetLastError();
+            ok(!ret,
+               "SetThreadErrorMode(0x%x,NULL) succeeded, expected failure\n",
+               mode);
+            ok(GLE == ERROR_INVALID_PARAMETER,
+               "SetThreadErrorMode(0x%x,NULL) failed with %d, "
+               "expected ERROR_INVALID_PARAMETER\n",
+               mode, GLE);
+        }
+    }
+
+    pSetThreadErrorMode(oldmode, NULL);
+}
+
 START_TEST(thread)
 {
    HINSTANCE lib;
+   HINSTANCE ntdll;
    int argc;
    char **argv;
    argc = winetest_get_mainargs( &argv );
@@ -1205,13 +1341,22 @@ START_TEST(thread)
 */
    lib=GetModuleHandleA("kernel32.dll");
    ok(lib!=NULL,"Couldn't get a handle for kernel32.dll\n");
-   pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
-   pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
-   pQueueUserWorkItem=(QueueUserWorkItem_t)GetProcAddress(lib,"QueueUserWorkItem");
-   pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
-   pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
-   pRegisterWaitForSingleObject=(RegisterWaitForSingleObject_t)GetProcAddress(lib,"RegisterWaitForSingleObject");
-   pUnregisterWait=(UnregisterWait_t)GetProcAddress(lib,"UnregisterWait");
+   pGetThreadPriorityBoost=(void *)GetProcAddress(lib,"GetThreadPriorityBoost");
+   pOpenThread=(void *)GetProcAddress(lib,"OpenThread");
+   pQueueUserWorkItem=(void *)GetProcAddress(lib,"QueueUserWorkItem");
+   pSetThreadIdealProcessor=(void *)GetProcAddress(lib,"SetThreadIdealProcessor");
+   pSetThreadPriorityBoost=(void *)GetProcAddress(lib,"SetThreadPriorityBoost");
+   pRegisterWaitForSingleObject=(void *)GetProcAddress(lib,"RegisterWaitForSingleObject");
+   pUnregisterWait=(void *)GetProcAddress(lib,"UnregisterWait");
+   pIsWow64Process=(void *)GetProcAddress(lib,"IsWow64Process");
+   pSetThreadErrorMode=(void *)GetProcAddress(lib,"SetThreadErrorMode");
+   pGetThreadErrorMode=(void *)GetProcAddress(lib,"GetThreadErrorMode");
+
+   ntdll=GetModuleHandleA("ntdll.dll");
+   if (ntdll)
+   {
+       pRtlGetThreadErrorMode=(void *)GetProcAddress(ntdll,"RtlGetThreadErrorMode");
+   }
 
    if (argc >= 3)
    {
@@ -1255,4 +1400,5 @@ START_TEST(thread)
    test_QueueUserWorkItem();
    test_RegisterWaitForSingleObject();
    test_TLS();
+   test_ThreadErrorMode();
 }