/*
- * Unit test suite for directory functions.
+ * Unit test suite for thread functions.
*
* Copyright 2002 Geoffrey Hausheer
*
* 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)
{
*/
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
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;
}
static DWORD WINAPI threadFunc4(LPVOID p)
{
- HANDLE event = (HANDLE)p;
+ HANDLE event = p;
if(event != NULL) {
SetEvent(event);
}
#if CHECK_STACK
static DWORD WINAPI threadFunc5(LPVOID p)
{
- DWORD *exitCode = (DWORD *)p;
+ DWORD *exitCode = p;
SYSTEM_INFO sysInfo;
sysInfo.dwPageSize=0;
GetSystemInfo(&sysInfo);
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;
}
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());
"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);
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
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 */
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");
}
}
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 */
/* 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");
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);
"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");
}
}
static void test_QueueUserWorkItem(void)
{
- int i;
+ INT_PTR i;
DWORD wait_result;
DWORD before, after;
if (!pRegisterWaitForSingleObject || !pUnregisterWait)
{
- skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
+ win_skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
return;
}
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;
static void test_TLS(void)
{
HANDLE threads[2];
- LONG i;
+ LONG_PTR i;
DWORD ret;
BOOL suc;
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 );
*/
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)
{
test_QueueUserWorkItem();
test_RegisterWaitForSingleObject();
test_TLS();
+ test_ThreadErrorMode();
}