4 * Copyright 1996 Alexandre Julliard
15 #include "selectors.h"
26 # define CLONE_VM 0x00000100
27 # define CLONE_FS 0x00000200
28 # define CLONE_FILES 0x00000400
29 # define CLONE_SIGHAND 0x00000800
30 # define CLONE_PID 0x00001000
31 /* If we didn't get the flags, we probably didn't get the prototype either */
32 extern int clone( int (*fn)(void *arg), void *stack, int flags, void *arg );
33 # endif /* CLONE_VM */
34 #endif /* HAVE_CLONE */
40 static BOOL32 THREAD_Signaled( K32OBJ *obj, DWORD thread_id );
41 static void THREAD_Satisfied( K32OBJ *obj, DWORD thread_id );
42 static void THREAD_AddWait( K32OBJ *obj, DWORD thread_id );
43 static void THREAD_RemoveWait( K32OBJ *obj, DWORD thread_id );
44 static void THREAD_Destroy( K32OBJ *obj );
46 const K32OBJ_OPS THREAD_Ops =
48 THREAD_Signaled, /* signaled */
49 THREAD_Satisfied, /* satisfied */
50 THREAD_AddWait, /* add_wait */
51 THREAD_RemoveWait, /* remove_wait */
52 THREAD_Destroy /* destroy */
56 /***********************************************************************
59 * Return a pointer to a thread object. The object count must be decremented
60 * when no longer used.
62 static THDB *THREAD_GetPtr( HANDLE32 handle )
66 if (handle == 0xfffffffe) /* Self-thread handle */
68 thread = THREAD_Current();
69 K32OBJ_IncCount( &thread->header );
71 else thread = (THDB *)PROCESS_GetObjPtr( handle, K32OBJ_THREAD );
76 /**********************************************************************
77 * NtCurrentTeb (NTDLL.89)
79 TEB * WINAPI NtCurrentTeb(void)
85 /* Check if we have a current thread */
88 if (fs == ds) return NULL; /* FIXME: should be an assert */
89 __asm__( "movl %%fs:(24),%0" : "=r" (teb) );
92 if (!pCurrentThread) return NULL;
93 return &pCurrentThread->teb;
98 /***********************************************************************
101 * Return the current thread THDB pointer.
103 THDB *THREAD_Current(void)
105 TEB *teb = NtCurrentTeb();
106 if (!teb) return NULL;
107 return (THDB *)((char *)teb - (int)&((THDB *)0)->teb);
111 /***********************************************************************
114 * Add a thread to a queue.
116 void THREAD_AddQueue( THREAD_QUEUE *queue, THDB *thread )
118 THREAD_ENTRY *entry = HeapAlloc( SystemHeap, HEAP_NO_SERIALIZE,
122 entry->thread = thread;
125 entry->next = (*queue)->next;
126 (*queue)->next = entry;
128 else entry->next = entry;
133 /***********************************************************************
136 * Remove a thread from a queue.
138 void THREAD_RemoveQueue( THREAD_QUEUE *queue, THDB *thread )
140 THREAD_ENTRY *entry = *queue;
142 if (entry->next == entry) /* Only one element in the queue */
144 assert( entry->thread == thread );
150 while (entry->next->thread != thread)
153 assert( entry != *queue ); /* Have we come all the way around? */
155 if ((next = entry->next) == *queue) *queue = entry;
156 entry->next = entry->next->next;
157 entry = next; /* This is the one we want to free */
159 HeapFree( SystemHeap, 0, entry );
164 /***********************************************************************
167 THDB *THREAD_Create( PDB32 *pdb, DWORD stack_size,
168 LPTHREAD_START_ROUTINE start_addr, LPVOID param )
173 THDB *thdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(THDB) );
174 if (!thdb) return NULL;
175 thdb->header.type = K32OBJ_THREAD;
176 thdb->header.refcount = 1;
178 thdb->teb.except = (void *)-1;
179 thdb->teb.htask16 = 0; /* FIXME */
180 thdb->teb.stack_sel = 0; /* FIXME */
181 thdb->teb.self = &thdb->teb;
182 thdb->teb.tls_ptr = thdb->tls_array;
183 thdb->wait_list = &thdb->wait_struct;
184 thdb->process2 = pdb;
185 thdb->exit_code = 0x103; /* STILL_ACTIVE */
186 thdb->entry_point = start_addr;
187 thdb->entry_arg = param;
189 /* Allocate the stack */
191 if (!stack_size) stack_size = 1024 * 1024; /* default size = 1Mb */
192 thdb->stack_base = VirtualAlloc( NULL, stack_size, MEM_COMMIT,
193 PAGE_EXECUTE_READWRITE );
194 if (!thdb->stack_base) goto error;
195 /* Set a guard page at the bottom of the stack */
196 VirtualProtect( thdb->stack_base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD,
198 thdb->teb.stack_top = (char *)thdb->stack_base + stack_size;
199 thdb->teb.stack_low = thdb->stack_base;
200 thdb->exit_stack = thdb->teb.stack_top;
202 /* Allocate the TEB selector (%fs register) */
204 thdb->teb_sel = SELECTOR_AllocBlock( &thdb->teb, 0x1000, SEGMENT_DATA,
206 if (!thdb->teb_sel) goto error;
208 /* Allocate the event */
210 if (!(thdb->event = EVENT_Create( TRUE, FALSE ))) goto error;
212 /* Initialize the thread context */
216 thdb->pcontext = &thdb->context;
217 thdb->context.SegCs = cs;
218 thdb->context.SegDs = ds;
219 thdb->context.SegEs = ds;
220 thdb->context.SegGs = ds;
221 thdb->context.SegSs = ds;
222 thdb->context.SegFs = thdb->teb_sel;
223 thdb->context.Eip = (DWORD)start_addr;
224 thdb->context.Esp = (DWORD)thdb->teb.stack_top;
228 if (thdb->event) K32OBJ_DecCount( thdb->event );
229 if (thdb->teb_sel) SELECTOR_FreeBlock( thdb->teb_sel, 1 );
230 if (thdb->stack_base) VirtualFree( thdb->stack_base, 0, MEM_RELEASE );
231 HeapFree( SystemHeap, 0, thdb );
236 /***********************************************************************
239 * Startup routine for a new thread.
241 static void THREAD_Start( THDB *thdb )
243 LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point;
244 thdb->unix_pid = getpid();
245 SET_FS( thdb->teb_sel );
246 ExitThread( func( thdb->entry_arg ) );
250 /***********************************************************************
253 static BOOL32 THREAD_Signaled( K32OBJ *obj, DWORD thread_id )
255 THDB *thdb = (THDB *)obj;
256 assert( obj->type == K32OBJ_THREAD );
257 return K32OBJ_OPS( thdb->event )->signaled( thdb->event, thread_id );
261 /***********************************************************************
264 * Wait on this object has been satisfied.
266 static void THREAD_Satisfied( K32OBJ *obj, DWORD thread_id )
268 THDB *thdb = (THDB *)obj;
269 assert( obj->type == K32OBJ_THREAD );
270 return K32OBJ_OPS( thdb->event )->satisfied( thdb->event, thread_id );
274 /***********************************************************************
277 * Add thread to object wait queue.
279 static void THREAD_AddWait( K32OBJ *obj, DWORD thread_id )
281 THDB *thdb = (THDB *)obj;
282 assert( obj->type == K32OBJ_THREAD );
283 return K32OBJ_OPS( thdb->event )->add_wait( thdb->event, thread_id );
287 /***********************************************************************
290 * Remove thread from object wait queue.
292 static void THREAD_RemoveWait( K32OBJ *obj, DWORD thread_id )
294 THDB *thdb = (THDB *)obj;
295 assert( obj->type == K32OBJ_THREAD );
296 return K32OBJ_OPS( thdb->event )->remove_wait( thdb->event, thread_id );
300 /***********************************************************************
303 static void THREAD_Destroy( K32OBJ *ptr )
305 THDB *thdb = (THDB *)ptr;
307 assert( ptr->type == K32OBJ_THREAD );
308 ptr->type = K32OBJ_UNKNOWN;
310 /* Free the associated memory */
314 /* Check if we are deleting the current thread */
317 if (fs == thdb->teb_sel)
324 K32OBJ_DecCount( thdb->event );
325 SELECTOR_FreeBlock( thdb->teb_sel, 1 );
326 HeapFree( SystemHeap, 0, thdb );
331 /***********************************************************************
332 * CreateThread (KERNEL32.63)
334 HANDLE32 WINAPI CreateThread( LPSECURITY_ATTRIBUTES attribs, DWORD stack,
335 LPTHREAD_START_ROUTINE start, LPVOID param,
336 DWORD flags, LPDWORD id )
339 THDB *thread = THREAD_Create( pCurrentProcess, stack, start, param );
340 if (!thread) return INVALID_HANDLE_VALUE32;
341 handle = PROCESS_AllocHandle( &thread->header, 0 );
342 if (handle == INVALID_HANDLE_VALUE32)
344 K32OBJ_DecCount( &thread->header );
345 return INVALID_HANDLE_VALUE32;
348 if (clone( (int (*)(void *))THREAD_Start, thread->teb.stack_top,
349 CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, thread ) < 0)
351 K32OBJ_DecCount( &thread->header );
352 return INVALID_HANDLE_VALUE32;
355 fprintf( stderr, "CreateThread: stub\n" );
356 #endif /* __linux__ */
357 *id = THDB_TO_THREAD_ID( thread );
362 /***********************************************************************
363 * ExitThread (KERNEL32.215)
365 void WINAPI ExitThread( DWORD code )
367 THDB *thdb = THREAD_Current();
371 thdb->exit_code = code;
372 EVENT_Set( thdb->event );
373 /* FIXME: should free the stack somehow */
374 K32OBJ_DecCount( &thdb->header );
375 /* Completely unlock the system lock just in case */
376 count = SYSTEM_LOCK_COUNT();
377 while (count--) SYSTEM_UNLOCK();
382 /***********************************************************************
383 * GetCurrentThread (KERNEL32.200)
385 HANDLE32 WINAPI GetCurrentThread(void)
391 /***********************************************************************
392 * GetCurrentThreadId (KERNEL32.201)
394 DWORD WINAPI GetCurrentThreadId(void)
396 return THDB_TO_THREAD_ID( THREAD_Current() );
400 /**********************************************************************
401 * GetLastError (KERNEL.148) (KERNEL32.227)
403 DWORD WINAPI GetLastError(void)
405 THDB *thread = THREAD_Current();
406 return thread->last_error;
410 /**********************************************************************
411 * SetLastError (KERNEL.147) (KERNEL32.497)
413 void WINAPI SetLastError( DWORD error )
415 THDB *thread = THREAD_Current();
416 /* This one must work before we have a thread (FIXME) */
417 if (thread) thread->last_error = error;
421 /**********************************************************************
422 * SetLastErrorEx (USER32.484)
424 void WINAPI SetLastErrorEx( DWORD error, DWORD type )
426 /* FIXME: what about 'type'? */
427 SetLastError( error );
431 /**********************************************************************
432 * TlsAlloc (KERNEL32.530)
434 DWORD WINAPI TlsAlloc(void)
436 DWORD i, mask, ret = 0;
437 THDB *thread = THREAD_Current();
438 DWORD *bits = thread->process->tls_bits;
439 EnterCriticalSection( &thread->process->crit_section );
440 if (*bits == 0xffffffff)
444 if (*bits == 0xffffffff)
446 LeaveCriticalSection( &thread->process->crit_section );
447 SetLastError( ERROR_NO_MORE_ITEMS );
451 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
453 LeaveCriticalSection( &thread->process->crit_section );
458 /**********************************************************************
459 * TlsFree (KERNEL32.531)
461 BOOL32 WINAPI TlsFree( DWORD index )
464 THDB *thread = THREAD_Current();
465 DWORD *bits = thread->process->tls_bits;
468 SetLastError( ERROR_INVALID_PARAMETER );
471 EnterCriticalSection( &thread->process->crit_section );
472 if (index >= 32) bits++;
473 mask = (1 << (index & 31));
474 if (!(*bits & mask)) /* already free? */
476 LeaveCriticalSection( &thread->process->crit_section );
477 SetLastError( ERROR_INVALID_PARAMETER );
481 thread->tls_array[index] = 0;
482 /* FIXME: should zero all other thread values */
483 LeaveCriticalSection( &thread->process->crit_section );
488 /**********************************************************************
489 * TlsGetValue (KERNEL32.532)
491 LPVOID WINAPI TlsGetValue( DWORD index )
493 THDB *thread = THREAD_Current();
496 SetLastError( ERROR_INVALID_PARAMETER );
499 SetLastError( ERROR_SUCCESS );
500 return thread->tls_array[index];
504 /**********************************************************************
505 * TlsSetValue (KERNEL32.533)
507 BOOL32 WINAPI TlsSetValue( DWORD index, LPVOID value )
509 THDB *thread = THREAD_Current();
512 SetLastError( ERROR_INVALID_PARAMETER );
515 thread->tls_array[index] = value;
520 /***********************************************************************
521 * GetThreadContext (KERNEL32.294)
523 BOOL32 WINAPI GetThreadContext( HANDLE32 handle, CONTEXT *context )
525 THDB *thread = THREAD_GetPtr( handle );
526 if (!thread) return FALSE;
527 *context = thread->context;
528 K32OBJ_DecCount( &thread->header );
533 /**********************************************************************
534 * GetThreadPriority (KERNEL32.296)
536 INT32 WINAPI GetThreadPriority(HANDLE32 hthread)
541 if (!(thread = THREAD_GetPtr( hthread ))) return 0;
542 ret = thread->delta_priority;
543 K32OBJ_DecCount( &thread->header );
548 /**********************************************************************
549 * SetThreadPriority (KERNEL32.514)
551 BOOL32 WINAPI SetThreadPriority(HANDLE32 hthread,INT32 priority)
555 if (!(thread = THREAD_GetPtr( hthread ))) return FALSE;
556 thread->delta_priority = priority;
557 K32OBJ_DecCount( &thread->header );
561 /**********************************************************************
562 * TerminateThread (KERNEL32)
564 BOOL32 WINAPI TerminateThread(HANDLE32 handle,DWORD exitcode)
566 fprintf(stdnimp,"TerminateThread(0x%08x,%ld), STUB!\n",handle,exitcode);
570 /**********************************************************************
571 * GetExitCodeThread (KERNEL32)
573 BOOL32 WINAPI GetExitCodeThread(HANDLE32 hthread,LPDWORD exitcode)
577 if (!(thread = THREAD_GetPtr( hthread ))) return FALSE;
578 if (exitcode) *exitcode = thread->exit_code;
579 K32OBJ_DecCount( &thread->header );
583 /**********************************************************************
584 * ResumeThread (KERNEL32)
586 BOOL32 WINAPI ResumeThread( HANDLE32 handle )
588 fprintf(stdnimp,"ResumeThread(0x%08x), STUB!\n",handle);
592 /**********************************************************************
593 * SuspendThread (KERNEL32)
595 BOOL32 WINAPI SuspendThread( HANDLE32 handle )
597 fprintf(stdnimp,"SuspendThread(0x%08x), STUB!\n",handle);