4 * Copyright 1996 Alexandre Julliard
12 #include "selectors.h"
18 THDB *pCurrentThread = NULL;
19 static K32OBJ_LIST THREAD_List;
21 /***********************************************************************
24 * Return a pointer to a thread object. The object count must be decremented
25 * when no longer used.
27 static THDB *THREAD_GetPtr( HANDLE32 handle )
31 if (handle == 0xfffffffe) /* Self-thread handle */
33 thread = THREAD_Current();
34 K32OBJ_IncCount( &thread->header );
36 else thread = (THDB *)PROCESS_GetObjPtr( handle, K32OBJ_THREAD );
41 /***********************************************************************
44 * Return the current thread THDB pointer.
46 THDB *THREAD_Current(void)
48 /* FIXME: should probably use %fs register here */
49 assert( pCurrentThread );
50 return pCurrentThread;
54 /***********************************************************************
57 THDB *THREAD_Create( PDB32 *pdb, DWORD stack_size,
58 LPTHREAD_START_ROUTINE start_addr )
61 THDB *thdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(THDB) );
62 if (!thdb) return NULL;
63 thdb->header.type = K32OBJ_THREAD;
64 thdb->header.refcount = 1;
66 thdb->teb.except = (void *)-1;
67 thdb->teb.htask16 = 0; /* FIXME */
68 thdb->teb.stack_sel = 0; /* FIXME */
69 thdb->teb.self = &thdb->teb;
70 thdb->teb.tls_ptr = thdb->tls_array;
72 thdb->exit_code = 0x103; /* STILL_ACTIVE */
74 /* Allocate the stack */
76 if (!stack_size) stack_size = 1024 * 1024; /* default size = 1Mb */
77 thdb->stack_base = VirtualAlloc( NULL, stack_size, MEM_COMMIT,
78 PAGE_EXECUTE_READWRITE );
79 if (!thdb->stack_base) goto error;
80 /* Set a guard page at the bottom of the stack */
81 VirtualProtect( thdb->stack_base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD,
83 thdb->teb.stack_top = (char *)thdb->stack_base + stack_size;
84 thdb->teb.stack_low = thdb->stack_base;
85 thdb->exit_stack = thdb->teb.stack_top;
87 /* Allocate the TEB selector (%fs register) */
89 thdb->teb_sel = SELECTOR_AllocBlock( &thdb->teb, 0x1000, SEGMENT_DATA,
91 if (!thdb->teb_sel) goto error;
93 /* Initialize the thread context */
95 thdb->pcontext = &thdb->context;
96 thdb->context.SegCs = WINE_CODE_SELECTOR;
97 thdb->context.SegDs = WINE_DATA_SELECTOR;
98 thdb->context.SegEs = WINE_DATA_SELECTOR;
99 thdb->context.SegFs = thdb->teb_sel;
100 thdb->context.SegGs = WINE_DATA_SELECTOR;
101 thdb->context.SegSs = WINE_DATA_SELECTOR;
102 thdb->context.Eip = (DWORD)start_addr;
103 thdb->context.Esp = (DWORD)thdb->teb.stack_top;
105 /* Add the thread to the linked list */
107 K32OBJ_AddTail( &THREAD_List, &thdb->header );
112 if (thdb->teb_sel) SELECTOR_FreeBlock( thdb->teb_sel, 1 );
113 if (thdb->stack_base) VirtualFree( thdb->stack_base, 0, MEM_RELEASE );
114 HeapFree( SystemHeap, 0, thdb );
119 /***********************************************************************
122 void THREAD_Destroy( K32OBJ *ptr )
124 THDB *thdb = (THDB *)ptr;
126 assert( ptr->type == K32OBJ_THREAD );
127 ptr->type = K32OBJ_UNKNOWN;
129 /* Note: when we get here, the thread has already been removed */
130 /* from the thread list */
132 /* Free the associated memory */
134 SELECTOR_FreeBlock( thdb->teb_sel, 1 );
135 HeapFree( SystemHeap, 0, thdb );
140 /***********************************************************************
141 * THREAD_SwitchThread
143 * Return the thread we want to switch to, and switch the contexts.
145 THDB *THREAD_SwitchThread( CONTEXT *context )
149 if (!pCurrentThread) return NULL;
150 cur = K32OBJ_RemoveHead( &THREAD_List );
151 K32OBJ_AddTail( &THREAD_List, cur );
152 K32OBJ_DecCount( cur );
153 next = (THDB *)THREAD_List.head;
154 if (next != pCurrentThread)
156 pCurrentThread->context = *context;
157 pCurrentThread = next;
158 *context = pCurrentThread->context;
160 return pCurrentThread;
164 /***********************************************************************
165 * CreateThread (KERNEL32.63)
167 * The only thing missing here is actually getting the thread to run ;-)
169 HANDLE32 WINAPI CreateThread( LPSECURITY_ATTRIBUTES attribs, DWORD stack,
170 LPTHREAD_START_ROUTINE start, LPVOID param,
171 DWORD flags, LPDWORD id )
174 THDB *thread = THREAD_Create( pCurrentProcess, stack, start );
175 if (!thread) return INVALID_HANDLE_VALUE32;
176 handle = PROCESS_AllocHandle( &thread->header, 0 );
177 if (handle == INVALID_HANDLE_VALUE32)
179 THREAD_Destroy( &thread->header );
180 return INVALID_HANDLE_VALUE32;
183 fprintf( stderr, "CreateThread: stub\n" );
188 /***********************************************************************
189 * GetCurrentThread (KERNEL32.200)
191 HANDLE32 WINAPI GetCurrentThread(void)
197 /***********************************************************************
198 * GetCurrentThreadId (KERNEL32.201)
199 * Returns crypted (xor'ed) pointer to THDB in Win95.
201 DWORD WINAPI GetCurrentThreadId(void)
203 return (DWORD)THREAD_Current();
207 /**********************************************************************
208 * GetLastError (KERNEL.148) (KERNEL32.227)
210 DWORD WINAPI GetLastError(void)
212 THDB *thread = THREAD_Current();
213 return thread->last_error;
217 /**********************************************************************
218 * SetLastError (KERNEL.147) (KERNEL32.497)
220 void WINAPI SetLastError( DWORD error )
223 if (!pCurrentThread) return; /* FIXME */
224 thread = THREAD_Current();
225 thread->last_error = error;
229 /**********************************************************************
230 * SetLastErrorEx (USER32.484)
232 void WINAPI SetLastErrorEx( DWORD error, DWORD type )
234 /* FIXME: what about 'type'? */
235 SetLastError( error );
239 /**********************************************************************
240 * TlsAlloc (KERNEL32.530)
242 DWORD WINAPI TlsAlloc(void)
244 DWORD i, mask, ret = 0;
245 THDB *thread = THREAD_Current();
246 DWORD *bits = thread->process->tls_bits;
247 EnterCriticalSection( &thread->process->crit_section );
248 if (*bits == 0xffffffff)
252 if (*bits == 0xffffffff)
254 LeaveCriticalSection( &thread->process->crit_section );
255 SetLastError( ERROR_NO_MORE_ITEMS );
259 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
261 LeaveCriticalSection( &thread->process->crit_section );
266 /**********************************************************************
267 * TlsFree (KERNEL32.531)
269 BOOL32 WINAPI TlsFree( DWORD index )
272 THDB *thread = THREAD_Current();
273 DWORD *bits = thread->process->tls_bits;
276 SetLastError( ERROR_INVALID_PARAMETER );
279 EnterCriticalSection( &thread->process->crit_section );
280 if (index >= 32) bits++;
281 mask = (1 << (index & 31));
282 if (!(*bits & mask)) /* already free? */
284 LeaveCriticalSection( &thread->process->crit_section );
285 SetLastError( ERROR_INVALID_PARAMETER );
289 thread->tls_array[index] = 0;
290 /* FIXME: should zero all other thread values */
291 LeaveCriticalSection( &thread->process->crit_section );
296 /**********************************************************************
297 * TlsGetValue (KERNEL32.532)
299 LPVOID WINAPI TlsGetValue( DWORD index )
301 THDB *thread = THREAD_Current();
304 SetLastError( ERROR_INVALID_PARAMETER );
307 SetLastError( ERROR_SUCCESS );
308 return thread->tls_array[index];
312 /**********************************************************************
313 * TlsSetValue (KERNEL32.533)
315 BOOL32 WINAPI TlsSetValue( DWORD index, LPVOID value )
317 THDB *thread = THREAD_Current();
320 SetLastError( ERROR_INVALID_PARAMETER );
323 thread->tls_array[index] = value;
328 /***********************************************************************
329 * GetThreadContext (KERNEL32.294)
331 BOOL32 WINAPI GetThreadContext( HANDLE32 handle, CONTEXT *context )
333 THDB *thread = (THDB*)PROCESS_GetObjPtr( handle, K32OBJ_THREAD );
334 if (!thread) return FALSE;
335 *context = thread->context;
336 K32OBJ_DecCount( &thread->header );
341 /**********************************************************************
342 * NtCurrentTeb (NTDLL.89)
344 void WINAPI NtCurrentTeb( CONTEXT *context )
346 EAX_reg(context) = GetSelectorBase( FS_reg(context) );
350 /**********************************************************************
351 * GetThreadPriority (KERNEL32.296)
353 INT32 WINAPI GetThreadPriority(HANDLE32 hthread)
358 if (!(thread = THREAD_GetPtr( hthread ))) return 0;
359 ret = thread->delta_priority;
360 K32OBJ_DecCount( &thread->header );
365 /**********************************************************************
366 * SetThreadPriority (KERNEL32.514)
368 BOOL32 WINAPI SetThreadPriority(HANDLE32 hthread,INT32 priority)
372 if (!(thread = THREAD_GetPtr( hthread ))) return FALSE;
373 thread->delta_priority = priority;
374 K32OBJ_DecCount( &thread->header );
378 /**********************************************************************
379 * TerminateThread (KERNEL32)
381 BOOL32 WINAPI TerminateThread(DWORD threadid,DWORD exitcode)
383 fprintf(stdnimp,"TerminateThread(0x%08lx,%ld), STUB!\n",threadid,exitcode);
387 /**********************************************************************
388 * GetExitCodeThread (KERNEL32)
390 BOOL32 WINAPI GetExitCodeThread(HANDLE32 hthread,LPDWORD exitcode)
394 if (!(thread = THREAD_GetPtr( hthread ))) return FALSE;
395 if (exitcode) *exitcode = thread->exit_code;
396 K32OBJ_DecCount( &thread->header );
400 /**********************************************************************
401 * ResumeThread (KERNEL32)
403 BOOL32 WINAPI ResumeThread(DWORD threadid)
405 fprintf(stdnimp,"ResumeThread(0x%08lx), STUB!\n",threadid);
409 /**********************************************************************
410 * SuspendThread (KERNEL32)
412 BOOL32 WINAPI SuspendThread(DWORD threadid)
414 fprintf(stdnimp,"SuspendThread(0x%08lx), STUB!\n",threadid);