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 )
62 THDB *thdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(THDB) );
63 if (!thdb) return NULL;
64 thdb->header.type = K32OBJ_THREAD;
65 thdb->header.refcount = 1;
67 thdb->teb.except = (void *)-1;
68 thdb->teb.htask16 = 0; /* FIXME */
69 thdb->teb.stack_sel = 0; /* FIXME */
70 thdb->teb.self = &thdb->teb;
71 thdb->teb.tls_ptr = thdb->tls_array;
73 thdb->exit_code = 0x103; /* STILL_ACTIVE */
75 /* Allocate the stack */
77 if (!stack_size) stack_size = 1024 * 1024; /* default size = 1Mb */
78 thdb->stack_base = VirtualAlloc( NULL, stack_size, MEM_COMMIT,
79 PAGE_EXECUTE_READWRITE );
80 if (!thdb->stack_base) goto error;
81 /* Set a guard page at the bottom of the stack */
82 VirtualProtect( thdb->stack_base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD,
84 thdb->teb.stack_top = (char *)thdb->stack_base + stack_size;
85 thdb->teb.stack_low = thdb->stack_base;
86 thdb->exit_stack = thdb->teb.stack_top;
88 /* Allocate the TEB selector (%fs register) */
90 thdb->teb_sel = SELECTOR_AllocBlock( &thdb->teb, 0x1000, SEGMENT_DATA,
92 if (!thdb->teb_sel) goto error;
94 /* Initialize the thread context */
98 thdb->pcontext = &thdb->context;
99 thdb->context.SegCs = cs;
100 thdb->context.SegDs = ds;
101 thdb->context.SegEs = ds;
102 thdb->context.SegGs = ds;
103 thdb->context.SegSs = ds;
104 thdb->context.SegFs = thdb->teb_sel;
105 thdb->context.Eip = (DWORD)start_addr;
106 thdb->context.Esp = (DWORD)thdb->teb.stack_top;
108 /* Add the thread to the linked list */
110 K32OBJ_AddTail( &THREAD_List, &thdb->header );
115 if (thdb->teb_sel) SELECTOR_FreeBlock( thdb->teb_sel, 1 );
116 if (thdb->stack_base) VirtualFree( thdb->stack_base, 0, MEM_RELEASE );
117 HeapFree( SystemHeap, 0, thdb );
122 /***********************************************************************
125 void THREAD_Destroy( K32OBJ *ptr )
127 THDB *thdb = (THDB *)ptr;
129 assert( ptr->type == K32OBJ_THREAD );
130 ptr->type = K32OBJ_UNKNOWN;
132 /* Note: when we get here, the thread has already been removed */
133 /* from the thread list */
135 /* Free the associated memory */
139 /* Check if we are deleting the current thread */
142 if (fs == thdb->teb_sel)
149 SELECTOR_FreeBlock( thdb->teb_sel, 1 );
150 HeapFree( SystemHeap, 0, thdb );
155 /***********************************************************************
156 * THREAD_SwitchThread
158 * Return the thread we want to switch to, and switch the contexts.
160 THDB *THREAD_SwitchThread( CONTEXT *context )
164 if (!pCurrentThread) return NULL;
165 cur = K32OBJ_RemoveHead( &THREAD_List );
166 K32OBJ_AddTail( &THREAD_List, cur );
167 K32OBJ_DecCount( cur );
168 next = (THDB *)THREAD_List.head;
169 if (next != pCurrentThread)
171 pCurrentThread->context = *context;
172 pCurrentThread = next;
173 *context = pCurrentThread->context;
175 return pCurrentThread;
179 /***********************************************************************
180 * CreateThread (KERNEL32.63)
182 * The only thing missing here is actually getting the thread to run ;-)
184 HANDLE32 WINAPI CreateThread( LPSECURITY_ATTRIBUTES attribs, DWORD stack,
185 LPTHREAD_START_ROUTINE start, LPVOID param,
186 DWORD flags, LPDWORD id )
189 THDB *thread = THREAD_Create( pCurrentProcess, stack, start );
190 if (!thread) return INVALID_HANDLE_VALUE32;
191 handle = PROCESS_AllocHandle( &thread->header, 0 );
192 if (handle == INVALID_HANDLE_VALUE32)
194 THREAD_Destroy( &thread->header );
195 return INVALID_HANDLE_VALUE32;
198 fprintf( stderr, "CreateThread: stub\n" );
203 /***********************************************************************
204 * GetCurrentThread (KERNEL32.200)
206 HANDLE32 WINAPI GetCurrentThread(void)
212 /***********************************************************************
213 * GetCurrentThreadId (KERNEL32.201)
214 * Returns crypted (xor'ed) pointer to THDB in Win95.
216 DWORD WINAPI GetCurrentThreadId(void)
218 return (DWORD)THREAD_Current();
222 /**********************************************************************
223 * GetLastError (KERNEL.148) (KERNEL32.227)
225 DWORD WINAPI GetLastError(void)
227 THDB *thread = THREAD_Current();
228 return thread->last_error;
232 /**********************************************************************
233 * SetLastError (KERNEL.147) (KERNEL32.497)
235 void WINAPI SetLastError( DWORD error )
238 if (!pCurrentThread) return; /* FIXME */
239 thread = THREAD_Current();
240 thread->last_error = error;
244 /**********************************************************************
245 * SetLastErrorEx (USER32.484)
247 void WINAPI SetLastErrorEx( DWORD error, DWORD type )
249 /* FIXME: what about 'type'? */
250 SetLastError( error );
254 /**********************************************************************
255 * TlsAlloc (KERNEL32.530)
257 DWORD WINAPI TlsAlloc(void)
259 DWORD i, mask, ret = 0;
260 THDB *thread = THREAD_Current();
261 DWORD *bits = thread->process->tls_bits;
262 EnterCriticalSection( &thread->process->crit_section );
263 if (*bits == 0xffffffff)
267 if (*bits == 0xffffffff)
269 LeaveCriticalSection( &thread->process->crit_section );
270 SetLastError( ERROR_NO_MORE_ITEMS );
274 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
276 LeaveCriticalSection( &thread->process->crit_section );
281 /**********************************************************************
282 * TlsFree (KERNEL32.531)
284 BOOL32 WINAPI TlsFree( DWORD index )
287 THDB *thread = THREAD_Current();
288 DWORD *bits = thread->process->tls_bits;
291 SetLastError( ERROR_INVALID_PARAMETER );
294 EnterCriticalSection( &thread->process->crit_section );
295 if (index >= 32) bits++;
296 mask = (1 << (index & 31));
297 if (!(*bits & mask)) /* already free? */
299 LeaveCriticalSection( &thread->process->crit_section );
300 SetLastError( ERROR_INVALID_PARAMETER );
304 thread->tls_array[index] = 0;
305 /* FIXME: should zero all other thread values */
306 LeaveCriticalSection( &thread->process->crit_section );
311 /**********************************************************************
312 * TlsGetValue (KERNEL32.532)
314 LPVOID WINAPI TlsGetValue( DWORD index )
316 THDB *thread = THREAD_Current();
319 SetLastError( ERROR_INVALID_PARAMETER );
322 SetLastError( ERROR_SUCCESS );
323 return thread->tls_array[index];
327 /**********************************************************************
328 * TlsSetValue (KERNEL32.533)
330 BOOL32 WINAPI TlsSetValue( DWORD index, LPVOID value )
332 THDB *thread = THREAD_Current();
335 SetLastError( ERROR_INVALID_PARAMETER );
338 thread->tls_array[index] = value;
343 /***********************************************************************
344 * GetThreadContext (KERNEL32.294)
346 BOOL32 WINAPI GetThreadContext( HANDLE32 handle, CONTEXT *context )
348 THDB *thread = THREAD_GetPtr( handle );
349 if (!thread) return FALSE;
350 *context = thread->context;
351 K32OBJ_DecCount( &thread->header );
356 /**********************************************************************
357 * NtCurrentTeb (NTDLL.89)
359 void WINAPI NtCurrentTeb( CONTEXT *context )
361 EAX_reg(context) = GetSelectorBase( FS_reg(context) );
365 /**********************************************************************
366 * GetThreadPriority (KERNEL32.296)
368 INT32 WINAPI GetThreadPriority(HANDLE32 hthread)
373 if (!(thread = THREAD_GetPtr( hthread ))) return 0;
374 ret = thread->delta_priority;
375 K32OBJ_DecCount( &thread->header );
380 /**********************************************************************
381 * SetThreadPriority (KERNEL32.514)
383 BOOL32 WINAPI SetThreadPriority(HANDLE32 hthread,INT32 priority)
387 if (!(thread = THREAD_GetPtr( hthread ))) return FALSE;
388 thread->delta_priority = priority;
389 K32OBJ_DecCount( &thread->header );
393 /**********************************************************************
394 * TerminateThread (KERNEL32)
396 BOOL32 WINAPI TerminateThread(DWORD threadid,DWORD exitcode)
398 fprintf(stdnimp,"TerminateThread(0x%08lx,%ld), STUB!\n",threadid,exitcode);
402 /**********************************************************************
403 * GetExitCodeThread (KERNEL32)
405 BOOL32 WINAPI GetExitCodeThread(HANDLE32 hthread,LPDWORD exitcode)
409 if (!(thread = THREAD_GetPtr( hthread ))) return FALSE;
410 if (exitcode) *exitcode = thread->exit_code;
411 K32OBJ_DecCount( &thread->header );
415 /**********************************************************************
416 * ResumeThread (KERNEL32)
418 BOOL32 WINAPI ResumeThread(DWORD threadid)
420 fprintf(stdnimp,"ResumeThread(0x%08lx), STUB!\n",threadid);
424 /**********************************************************************
425 * SuspendThread (KERNEL32)
427 BOOL32 WINAPI SuspendThread(DWORD threadid)
429 fprintf(stdnimp,"SuspendThread(0x%08lx), STUB!\n",threadid);