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
)
44 THDB
*thdb
= HeapAlloc( SystemHeap
, HEAP_ZERO_MEMORY
, sizeof(THDB
) );
45 if (!thdb
) return NULL
;
46 thdb
->header
.type
= K32OBJ_THREAD
;
47 thdb
->header
.refcount
= 1;
49 thdb
->teb
.except
= (void *)-1;
50 thdb
->teb
.htask16
= 0; /* FIXME */
51 thdb
->teb
.stack_sel
= 0; /* FIXME */
52 thdb
->teb
.self
= &thdb
->teb
;
53 thdb
->teb
.tls_ptr
= thdb
->tls_array
;
55 thdb
->exit_code
= 0x103; /* STILL_ACTIVE */
57 /* Allocate the stack */
59 if (!stack_size
) stack_size
= 1024 * 1024; /* default size = 1Mb */
60 thdb
->stack_base
= VirtualAlloc( NULL
, stack_size
, MEM_COMMIT
,
61 PAGE_EXECUTE_READWRITE
);
62 if (!thdb
->stack_base
) goto error
;
63 /* Set a guard page at the bottom of the stack */
64 VirtualProtect( thdb
->stack_base
, 1, PAGE_EXECUTE_READWRITE
| PAGE_GUARD
,
66 thdb
->teb
.stack_top
= (char *)thdb
->stack_base
+ stack_size
- 1;
67 thdb
->teb
.stack_low
= thdb
->stack_base
;
68 thdb
->exit_stack
= thdb
->teb
.stack_top
;
70 /* Allocate the TEB selector (%fs register) */
72 thdb
->teb_sel
= SELECTOR_AllocBlock( &thdb
->teb
, 0x1000, SEGMENT_DATA
,
74 if (!thdb
->teb_sel
) goto error
;
76 /* Initialize the thread context */
78 thdb
->pcontext
= &thdb
->context
;
79 thdb
->context
.SegCs
= WINE_CODE_SELECTOR
;
80 thdb
->context
.SegDs
= WINE_DATA_SELECTOR
;
81 thdb
->context
.SegEs
= WINE_DATA_SELECTOR
;
82 thdb
->context
.SegFs
= thdb
->teb_sel
;
83 thdb
->context
.SegGs
= WINE_DATA_SELECTOR
;
84 thdb
->context
.SegSs
= WINE_DATA_SELECTOR
;
85 thdb
->context
.Eip
= (DWORD
)start_addr
;
86 thdb
->context
.Esp
= (DWORD
)thdb
->teb
.stack_top
;
91 if (thdb
->teb_sel
) SELECTOR_FreeBlock( thdb
->teb_sel
, 1 );
92 if (thdb
->stack_base
) VirtualFree( thdb
->stack_base
, 0, MEM_RELEASE
);
93 HeapFree( SystemHeap
, 0, thdb
);
98 /***********************************************************************
101 void THREAD_Destroy( K32OBJ
*ptr
)
103 THDB
*thdb
= (THDB
*)ptr
;
104 assert( ptr
->type
== K32OBJ_THREAD
);
105 ptr
->type
= K32OBJ_UNKNOWN
;
106 SELECTOR_FreeBlock( thdb
->teb_sel
, 1 );
107 HeapFree( SystemHeap
, 0, thdb
);
111 /***********************************************************************
112 * CreateThread (KERNEL32.63)
114 * The only thing missing here is actually getting the thread to run ;-)
116 HANDLE32
CreateThread( LPSECURITY_ATTRIBUTES attribs
, DWORD stack
,
117 LPTHREAD_START_ROUTINE start
, LPVOID param
,
118 DWORD flags
, LPDWORD id
)
121 THDB
*thread
= THREAD_Create( pCurrentProcess
, stack
, start
);
122 if (!thread
) return INVALID_HANDLE_VALUE32
;
123 handle
= PROCESS_AllocHandle( &thread
->header
, 0 );
124 if (handle
== INVALID_HANDLE_VALUE32
)
126 THREAD_Destroy( &thread
->header
);
127 return INVALID_HANDLE_VALUE32
;
130 fprintf( stderr
, "CreateThread: stub\n" );
135 /***********************************************************************
136 * GetCurrentThread (KERNEL32.200)
138 HANDLE32
GetCurrentThread(void)
144 /***********************************************************************
145 * GetCurrentThreadId (KERNEL32.201)
146 * Returns crypted (xor'ed) pointer to THDB in Win95.
148 DWORD
GetCurrentThreadId(void)
150 /* FIXME: should probably use %fs register here */
151 assert( pCurrentThread
);
152 return (DWORD
)pCurrentThread
;
156 /**********************************************************************
157 * GetLastError (KERNEL.148) (KERNEL32.227)
159 DWORD
GetLastError(void)
161 THDB
*thread
= (THDB
*)GetCurrentThreadId();
162 return thread
->last_error
;
166 /**********************************************************************
167 * SetLastError (KERNEL.147) (KERNEL32.497)
169 void SetLastError( DWORD error
)
172 if (!pCurrentThread
) return; /* FIXME */
173 thread
= (THDB
*)GetCurrentThreadId();
174 thread
->last_error
= error
;
178 /**********************************************************************
179 * SetLastErrorEx (USER32.484)
181 void SetLastErrorEx( DWORD error
, DWORD type
)
183 /* FIXME: what about 'type'? */
184 SetLastError( error
);
188 /**********************************************************************
189 * TlsAlloc (KERNEL32.530)
193 DWORD i
, mask
, ret
= 0;
194 THDB
*thread
= (THDB
*)GetCurrentThreadId();
195 DWORD
*bits
= thread
->process
->tls_bits
;
196 EnterCriticalSection( &thread
->process
->crit_section
);
197 if (*bits
== 0xffffffff)
201 if (*bits
== 0xffffffff)
203 LeaveCriticalSection( &thread
->process
->crit_section
);
204 SetLastError( ERROR_NO_MORE_ITEMS
);
208 for (i
= 0, mask
= 1; i
< 32; i
++, mask
<<= 1) if (!(*bits
& mask
)) break;
210 LeaveCriticalSection( &thread
->process
->crit_section
);
215 /**********************************************************************
216 * TlsFree (KERNEL32.531)
218 BOOL32
TlsFree( DWORD index
)
221 THDB
*thread
= (THDB
*)GetCurrentThreadId();
222 DWORD
*bits
= thread
->process
->tls_bits
;
225 SetLastError( ERROR_INVALID_PARAMETER
);
228 EnterCriticalSection( &thread
->process
->crit_section
);
229 if (index
>= 32) bits
++;
230 mask
= (1 << (index
& 31));
231 if (!(*bits
& mask
)) /* already free? */
233 LeaveCriticalSection( &thread
->process
->crit_section
);
234 SetLastError( ERROR_INVALID_PARAMETER
);
238 thread
->tls_array
[index
] = 0;
239 /* FIXME: should zero all other thread values */
240 LeaveCriticalSection( &thread
->process
->crit_section
);
245 /**********************************************************************
246 * TlsGetValue (KERNEL32.532)
248 LPVOID
TlsGetValue( DWORD index
)
250 THDB
*thread
= (THDB
*)GetCurrentThreadId();
253 SetLastError( ERROR_INVALID_PARAMETER
);
256 SetLastError( ERROR_SUCCESS
);
257 return thread
->tls_array
[index
];
261 /**********************************************************************
262 * TlsSetValue (KERNEL32.533)
264 BOOL32
TlsSetValue( DWORD index
, LPVOID value
)
266 THDB
*thread
= (THDB
*)GetCurrentThreadId();
269 SetLastError( ERROR_INVALID_PARAMETER
);
272 thread
->tls_array
[index
] = value
;
277 /***********************************************************************
278 * GetThreadContext (KERNEL32.294)
280 BOOL32
GetThreadContext( HANDLE32 handle
, CONTEXT
*context
)
282 THDB
*thread
= (THDB
*)PROCESS_GetObjPtr( handle
, K32OBJ_THREAD
);
283 if (!thread
) return FALSE
;
284 *context
= thread
->context
;
285 K32OBJ_DecCount( &thread
->header
);
290 /**********************************************************************
291 * NtCurrentTeb (NTDLL.89)
293 void NtCurrentTeb( CONTEXT
*context
)
295 EAX_reg(context
) = GetSelectorBase( FS_reg(context
) );
299 /**********************************************************************
300 * GetThreadPriority (KERNEL32.296)
302 INT32
GetThreadPriority(HANDLE32 hthread
)
307 if (!(thread
= THREAD_GetPtr( hthread
))) return 0;
308 ret
= thread
->delta_priority
;
309 K32OBJ_DecCount( &thread
->header
);
314 /**********************************************************************
315 * SetThreadPriority (KERNEL32.514)
317 BOOL32
SetThreadPriority(HANDLE32 hthread
,INT32 priority
)
321 if (!(thread
= THREAD_GetPtr( hthread
))) return FALSE
;
322 thread
->delta_priority
= priority
;
323 K32OBJ_DecCount( &thread
->header
);