4 * Copyright 1996 Alexandre Julliard
12 #include "selectors.h"
15 THDB *pCurrentThread = NULL;
17 /***********************************************************************
20 * Return a pointer to a thread object. The object count must be decremented
21 * when no longer used.
23 static THDB *THREAD_GetPtr( HANDLE32 handle )
27 if (handle == 0xfffffffe) /* Self-thread handle */
29 thread = (THDB *)GetCurrentThreadId();
30 K32OBJ_IncCount( &thread->header );
32 else thread = (THDB *)PROCESS_GetObjPtr( handle, K32OBJ_THREAD );
37 /***********************************************************************
40 THDB *THREAD_Create( PDB32 *pdb, DWORD stack_size,
41 LPTHREAD_START_ROUTINE start_addr )
43 THDB *thdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(THDB) );
44 if (!thdb) return NULL;
45 thdb->header.type = K32OBJ_THREAD;
46 thdb->header.refcount = 1;
48 thdb->teb.except = (void *)-1;
49 thdb->teb.htask16 = 0; /* FIXME */
50 thdb->teb.stack_sel = 0; /* FIXME */
51 thdb->teb.self = &thdb->teb;
52 thdb->teb.tls_ptr = thdb->tls_array;
54 thdb->exit_code = 0x103; /* STILL_ACTIVE */
56 /* Allocate the stack */
58 if (!stack_size) stack_size = 1024 * 1024; /* default size = 1Mb */
59 thdb->stack_base = VirtualAlloc( NULL, stack_size, MEM_COMMIT,
60 PAGE_EXECUTE_READWRITE );
61 if (!thdb->stack_base) goto error;
62 /* Un-commit the first page (FIXME: should use PAGE_GUARD instead) */
63 VirtualFree( thdb->stack_base, 1, MEM_DECOMMIT );
64 thdb->teb.stack_top = (char *)thdb->stack_base + stack_size;
65 thdb->teb.stack_low = thdb->teb.stack_top;
66 thdb->exit_stack = thdb->teb.stack_top;
68 /* Allocate the TEB selector (%fs register) */
70 thdb->teb_sel = SELECTOR_AllocBlock( &thdb->teb, 0x1000, SEGMENT_DATA,
72 if (!thdb->teb_sel) goto error;
74 /* Initialize the thread context */
76 thdb->pcontext = &thdb->context;
77 thdb->context.SegCs = WINE_CODE_SELECTOR;
78 thdb->context.SegDs = WINE_DATA_SELECTOR;
79 thdb->context.SegEs = WINE_DATA_SELECTOR;
80 thdb->context.SegFs = thdb->teb_sel;
81 thdb->context.SegGs = WINE_DATA_SELECTOR;
82 thdb->context.SegSs = WINE_DATA_SELECTOR;
83 thdb->context.Eip = (DWORD)start_addr;
84 thdb->context.Esp = (DWORD)thdb->teb.stack_top;
89 if (thdb->teb_sel) SELECTOR_FreeBlock( thdb->teb_sel, 1 );
90 if (thdb->stack_base) VirtualFree( thdb->stack_base, 0, MEM_RELEASE );
91 HeapFree( SystemHeap, 0, thdb );
96 /***********************************************************************
99 void THREAD_Destroy( K32OBJ *ptr )
101 THDB *thdb = (THDB *)ptr;
102 assert( ptr->type == K32OBJ_THREAD );
103 ptr->type = K32OBJ_UNKNOWN;
104 SELECTOR_FreeBlock( thdb->teb_sel, 1 );
105 HeapFree( SystemHeap, 0, thdb );
109 /***********************************************************************
110 * CreateThread (KERNEL32.63)
112 * The only thing missing here is actually getting the thread to run ;-)
114 HANDLE32 CreateThread( LPSECURITY_ATTRIBUTES attribs, DWORD stack,
115 LPTHREAD_START_ROUTINE start, LPVOID param,
116 DWORD flags, LPDWORD id )
119 THDB *thread = THREAD_Create( pCurrentProcess, stack, start );
120 if (!thread) return INVALID_HANDLE_VALUE32;
121 handle = PROCESS_AllocHandle( &thread->header, 0 );
122 if (handle == INVALID_HANDLE_VALUE32)
124 THREAD_Destroy( &thread->header );
125 return INVALID_HANDLE_VALUE32;
128 fprintf( stderr, "CreateThread: stub\n" );
133 /***********************************************************************
134 * GetCurrentThread (KERNEL32.200)
136 HANDLE32 GetCurrentThread(void)
142 /***********************************************************************
143 * GetCurrentThreadId (KERNEL32.201)
144 * Returns crypted (xor'ed) pointer to THDB in Win95.
146 DWORD GetCurrentThreadId(void)
148 /* FIXME: should probably use %fs register here */
149 assert( pCurrentThread );
150 return (DWORD)pCurrentThread;
154 /**********************************************************************
155 * GetLastError (KERNEL.148) (KERNEL32.227)
157 DWORD GetLastError(void)
159 THDB *thread = (THDB *)GetCurrentThreadId();
160 return thread->last_error;
164 /**********************************************************************
165 * SetLastError (KERNEL.147) (KERNEL32.497)
167 void SetLastError( DWORD error )
170 if (!pCurrentThread) return; /* FIXME */
171 thread = (THDB *)GetCurrentThreadId();
172 thread->last_error = error;
176 /**********************************************************************
177 * SetLastErrorEx (USER32.484)
179 void SetLastErrorEx( DWORD error, DWORD type )
181 /* FIXME: what about 'type'? */
182 SetLastError( error );
186 /**********************************************************************
187 * TlsAlloc (KERNEL32.530)
191 DWORD i, mask, ret = 0;
192 THDB *thread = (THDB *)GetCurrentThreadId();
193 DWORD *bits = thread->process->tls_bits;
194 EnterCriticalSection( &thread->process->crit_section );
195 if (*bits == 0xffffffff)
199 if (*bits == 0xffffffff)
201 LeaveCriticalSection( &thread->process->crit_section );
202 SetLastError( ERROR_NO_MORE_ITEMS );
206 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
208 LeaveCriticalSection( &thread->process->crit_section );
213 /**********************************************************************
214 * TlsFree (KERNEL32.531)
216 BOOL32 TlsFree( DWORD index )
219 THDB *thread = (THDB *)GetCurrentThreadId();
220 DWORD *bits = thread->process->tls_bits;
223 SetLastError( ERROR_INVALID_PARAMETER );
226 EnterCriticalSection( &thread->process->crit_section );
227 if (index >= 32) bits++;
228 mask = (1 << (index & 31));
229 if (!(*bits & mask)) /* already free? */
231 LeaveCriticalSection( &thread->process->crit_section );
232 SetLastError( ERROR_INVALID_PARAMETER );
236 thread->tls_array[index] = 0;
237 /* FIXME: should zero all other thread values */
238 LeaveCriticalSection( &thread->process->crit_section );
243 /**********************************************************************
244 * TlsGetValue (KERNEL32.532)
246 LPVOID TlsGetValue( DWORD index )
248 THDB *thread = (THDB *)GetCurrentThreadId();
251 SetLastError( ERROR_INVALID_PARAMETER );
254 SetLastError( ERROR_SUCCESS );
255 return thread->tls_array[index];
259 /**********************************************************************
260 * TlsSetValue (KERNEL32.533)
262 BOOL32 TlsSetValue( DWORD index, LPVOID value )
264 THDB *thread = (THDB *)GetCurrentThreadId();
267 SetLastError( ERROR_INVALID_PARAMETER );
270 thread->tls_array[index] = value;
275 /***********************************************************************
276 * GetThreadContext (KERNEL32.294)
278 BOOL32 GetThreadContext( HANDLE32 handle, CONTEXT *context )
280 THDB *thread = (THDB*)PROCESS_GetObjPtr( handle, K32OBJ_THREAD );
281 if (!thread) return FALSE;
282 *context = thread->context;
283 K32OBJ_DecCount( &thread->header );
288 /**********************************************************************
289 * NtCurrentTeb (NTDLL.89)
291 void NtCurrentTeb( CONTEXT *context )
293 EAX_reg(context) = GetSelectorBase( FS_reg(context) );
297 /**********************************************************************
298 * GetThreadPriority (KERNEL32.296)
300 INT32 GetThreadPriority(HANDLE32 hthread)
305 if (!(thread = THREAD_GetPtr( hthread ))) return 0;
306 ret = thread->delta_priority;
307 K32OBJ_DecCount( &thread->header );
312 /**********************************************************************
313 * SetThreadPriority (KERNEL32.514)
315 BOOL32 SetThreadPriority(HANDLE32 hthread,INT32 priority)
319 if (!(thread = THREAD_GetPtr( hthread ))) return FALSE;
320 thread->delta_priority = priority;
321 K32OBJ_DecCount( &thread->header );