/* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */
#define _WIN32_WINNT 0x0500
+#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
CreateThread
*/
+/* Functions to ensure that from a group of threads, only one executes
+ certain chunks of code at a time, and we know which one is executing
+ it. It basically makes multithreaded execution linear, which defeats
+ the purpose of multiple threads, but makes testing easy. */
+static HANDLE start_event, stop_event;
+static LONG num_synced;
+
+static void init_thread_sync_helpers(void)
+{
+ start_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ ok(start_event != NULL, "CreateEvent failed\n");
+ stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ ok(stop_event != NULL, "CreateEvent failed\n");
+ num_synced = -1;
+}
+
+static BOOL sync_threads_and_run_one(DWORD sync_id, DWORD my_id)
+{
+ LONG num = InterlockedIncrement(&num_synced);
+ assert(-1 <= num && num <= 1);
+ if (num == 1)
+ {
+ ResetEvent( stop_event );
+ SetEvent( start_event );
+ }
+ else
+ {
+ DWORD ret = WaitForSingleObject(start_event, 10000);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed %x\n",ret);
+ }
+ return sync_id == my_id;
+}
+
+static void resync_after_run(void)
+{
+ LONG num = InterlockedDecrement(&num_synced);
+ assert(-1 <= num && num <= 1);
+ if (num == -1)
+ {
+ ResetEvent( start_event );
+ SetEvent( stop_event );
+ }
+ else
+ {
+ DWORD ret = WaitForSingleObject(stop_event, 10000);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+ }
+}
+
+static void cleanup_thread_sync_helpers(void)
+{
+ CloseHandle(start_event);
+ CloseHandle(stop_event);
+}
+
DWORD tlsIndex;
typedef struct {
*/
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());
int error;
DWORD i,j;
DWORD GLE, ret;
+ DWORD tid;
/* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
/* Test how passing NULL as a pointer to threadid works */
SetLastError(0xFACEaBAD);
- thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,NULL);
+ thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,&tid);
GLE = GetLastError();
if (thread[0]) { /* NT */
ok(GLE==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE);
{
HANDLE thread;
DWORD threadId;
+ DWORD suspend_count;
int error;
thread = CreateThread(NULL,0,threadFunc2,NULL,
if(error!=WAIT_OBJECT_0) {
TerminateThread(thread,1);
}
+
+ suspend_count = SuspendThread(thread);
+ ok(suspend_count == -1, "SuspendThread returned %d, expected -1\n", suspend_count);
+
+ suspend_count = ResumeThread(thread);
+ ok(suspend_count == 0 ||
+ broken(suspend_count == -1), /* win9x */
+ "ResumeThread returned %d, expected 0\n", suspend_count);
+
ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
}
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());
if (pOpenThread) {
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);
}
-}
/* check the GetThreadTimes function */
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");
"SetThreadAffinityMask passed for an illegal processor\n");
/* NOTE: This only works on WinNT/2000/XP) */
if (pSetThreadIdealProcessor) {
- todo_wine {
- SetLastError(0);
+ SetLastError(0xdeadbeef);
error=pSetThreadIdealProcessor(curthread,0);
- if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
- ok(error!=-1, "SetThreadIdealProcessor failed\n");
- }
+ if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+ {
+ win_skip("SetThreadIdealProcessor is not implemented\n");
+ return;
}
- if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
+ ok(error!=-1, "SetThreadIdealProcessor failed\n");
+
+ SetLastError(0xdeadbeef);
error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
ok(error==-1,
"SetThreadIdealProcessor succeeded with an illegal processor #\n");
- todo_wine {
+ 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_GetThreadExitCode(void)
{
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;
}
ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
}
+static DWORD TLS_main;
+static DWORD TLS_index0, TLS_index1;
+
+static DWORD WINAPI TLS_InheritanceProc(LPVOID p)
+{
+ /* We should NOT inherit the TLS values from our parent or from the
+ main thread. */
+ LPVOID val;
+
+ val = TlsGetValue(TLS_main);
+ ok(val == NULL, "TLS inheritance failed\n");
+
+ val = TlsGetValue(TLS_index0);
+ ok(val == NULL, "TLS inheritance failed\n");
+
+ val = TlsGetValue(TLS_index1);
+ ok(val == NULL, "TLS inheritance failed\n");
+
+ return 0;
+}
+
+/* Basic TLS usage test. Make sure we can create slots and the values we
+ store in them are separate among threads. Also test TLS value
+ inheritance with TLS_InheritanceProc. */
+static DWORD WINAPI TLS_ThreadProc(LPVOID p)
+{
+ LONG_PTR id = (LONG_PTR) p;
+ LPVOID val;
+ BOOL ret;
+
+ if (sync_threads_and_run_one(0, id))
+ {
+ TLS_index0 = TlsAlloc();
+ ok(TLS_index0 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
+ }
+ resync_after_run();
+
+ if (sync_threads_and_run_one(1, id))
+ {
+ TLS_index1 = TlsAlloc();
+ ok(TLS_index1 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
+
+ /* Slot indices should be different even if created in different
+ threads. */
+ ok(TLS_index0 != TLS_index1, "TlsAlloc failed\n");
+
+ /* Both slots should be initialized to NULL */
+ val = TlsGetValue(TLS_index0);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == NULL, "TLS slot not initialized correctly\n");
+
+ val = TlsGetValue(TLS_index1);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == NULL, "TLS slot not initialized correctly\n");
+ }
+ resync_after_run();
+
+ if (sync_threads_and_run_one(0, id))
+ {
+ val = TlsGetValue(TLS_index0);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == NULL, "TLS slot not initialized correctly\n");
+
+ val = TlsGetValue(TLS_index1);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == NULL, "TLS slot not initialized correctly\n");
+
+ ret = TlsSetValue(TLS_index0, (LPVOID) 1);
+ ok(ret, "TlsSetValue failed\n");
+
+ ret = TlsSetValue(TLS_index1, (LPVOID) 2);
+ ok(ret, "TlsSetValue failed\n");
+
+ val = TlsGetValue(TLS_index0);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n");
+
+ val = TlsGetValue(TLS_index1);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n");
+ }
+ resync_after_run();
+
+ if (sync_threads_and_run_one(1, id))
+ {
+ val = TlsGetValue(TLS_index0);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == NULL, "TLS slot not initialized correctly\n");
+
+ val = TlsGetValue(TLS_index1);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == NULL, "TLS slot not initialized correctly\n");
+
+ ret = TlsSetValue(TLS_index0, (LPVOID) 3);
+ ok(ret, "TlsSetValue failed\n");
+
+ ret = TlsSetValue(TLS_index1, (LPVOID) 4);
+ ok(ret, "TlsSetValue failed\n");
+
+ val = TlsGetValue(TLS_index0);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == (LPVOID) 3, "TLS slot not initialized correctly\n");
+
+ val = TlsGetValue(TLS_index1);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == (LPVOID) 4, "TLS slot not initialized correctly\n");
+ }
+ resync_after_run();
+
+ if (sync_threads_and_run_one(0, id))
+ {
+ HANDLE thread;
+ DWORD waitret, tid;
+
+ val = TlsGetValue(TLS_index0);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n");
+
+ val = TlsGetValue(TLS_index1);
+ ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
+ ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n");
+
+ thread = CreateThread(NULL, 0, TLS_InheritanceProc, 0, 0, &tid);
+ ok(thread != NULL, "CreateThread failed\n");
+ waitret = WaitForSingleObject(thread, 60000);
+ ok(waitret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+ CloseHandle(thread);
+
+ ret = TlsFree(TLS_index0);
+ ok(ret, "TlsFree failed\n");
+ }
+ resync_after_run();
+
+ if (sync_threads_and_run_one(1, id))
+ {
+ ret = TlsFree(TLS_index1);
+ ok(ret, "TlsFree failed\n");
+ }
+ resync_after_run();
+
+ return 0;
+}
+
+static void test_TLS(void)
+{
+ HANDLE threads[2];
+ LONG_PTR i;
+ DWORD ret;
+ BOOL suc;
+
+ init_thread_sync_helpers();
+
+ /* Allocate a TLS slot in the main thread to test for inheritance. */
+ TLS_main = TlsAlloc();
+ ok(TLS_main != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
+ suc = TlsSetValue(TLS_main, (LPVOID) 4114);
+ ok(suc, "TlsSetValue failed\n");
+
+ for (i = 0; i < 2; ++i)
+ {
+ DWORD tid;
+
+ threads[i] = CreateThread(NULL, 0, TLS_ThreadProc, (LPVOID) i, 0, &tid);
+ ok(threads[i] != NULL, "CreateThread failed\n");
+ }
+
+ ret = WaitForMultipleObjects(2, threads, TRUE, 60000);
+ ok(ret == WAIT_OBJECT_0 || ret == WAIT_OBJECT_0+1 /* nt4 */, "WaitForMultipleObjects failed %u\n",ret);
+
+ for (i = 0; i < 2; ++i)
+ CloseHandle(threads[i]);
+
+ suc = TlsFree(TLS_main);
+ ok(suc, "TlsFree failed\n");
+ cleanup_thread_sync_helpers();
+}
+
START_TEST(thread)
{
HINSTANCE lib;
while (1)
{
HANDLE hThread;
- hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, NULL);
+ DWORD tid;
+ hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, &tid);
ok(hThread != NULL, "CreateThread failed, error %u\n",
GetLastError());
ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0,
#endif
test_QueueUserWorkItem();
test_RegisterWaitForSingleObject();
+ test_TLS();
}