blob: 9647432654afadce2a547f494a37e98a55adb563 [file] [log] [blame]
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001/*
2 * Win32 threads
3 *
4 * Copyright 1996 Alexandre Julliard
5 */
6
Patrik Stridvall478eee11999-07-31 13:13:23 +00007#include "config.h"
8
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00009#include <assert.h>
Alexandre Julliardf0167521999-03-21 19:26:25 +000010#include <fcntl.h>
Alexandre Julliard13e55191999-02-21 18:34:18 +000011#include <sys/types.h>
Howard Abrams13277481999-07-10 13:16:29 +000012#ifdef HAVE_SYS_MMAN_H
Alexandre Julliard0a860a01999-06-22 11:43:42 +000013#include <sys/mman.h>
Howard Abrams13277481999-07-10 13:16:29 +000014#endif
Alexandre Julliard02e90081998-01-04 17:49:09 +000015#include <unistd.h>
Marcus Meissner317af321999-02-17 13:51:06 +000016#include "wine/winbase16.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000017#include "thread.h"
Alexandre Julliard02e90081998-01-04 17:49:09 +000018#include "process.h"
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000019#include "task.h"
20#include "module.h"
Alexandre Julliard3ef93222000-04-13 17:03:22 +000021#include "global.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000022#include "winerror.h"
23#include "heap.h"
24#include "selectors.h"
25#include "winnt.h"
Alexandre Julliard642d3131998-07-12 19:29:36 +000026#include "server.h"
Ulrich Weigand36a1a251999-05-08 10:48:03 +000027#include "services.h"
Alexandre Julliard767e6f61998-08-09 12:47:43 +000028#include "stackframe.h"
Ulrich Weigandf0a1c2f1999-09-20 18:45:28 +000029#include "builtin16.h"
Alexandre Julliard15657091999-05-23 10:25:25 +000030#include "debugtools.h"
Juergen Schmied79d850f2000-06-12 21:56:02 +000031#include "winnls.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000032
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +000033DEFAULT_DEBUG_CHANNEL(thread);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000034
Alexandre Julliard0a860a01999-06-22 11:43:42 +000035/* TEB of the initial thread */
36static TEB initial_teb;
Alexandre Julliard13e55191999-02-21 18:34:18 +000037
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000038/***********************************************************************
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000039 * THREAD_IsWin16
40 */
Alexandre Julliard0a860a01999-06-22 11:43:42 +000041BOOL THREAD_IsWin16( TEB *teb )
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000042{
Ulrich Weigandf3bfa3a2000-01-30 21:16:06 +000043 return !teb || !(teb->tibflags & TEBF_WIN32);
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000044}
45
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000046/***********************************************************************
Alexandre Julliard0a860a01999-06-22 11:43:42 +000047 * THREAD_IdToTEB
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000048 *
Alexandre Julliard0a860a01999-06-22 11:43:42 +000049 * Convert a thread id to a TEB, making sure it is valid.
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000050 */
Alexandre Julliard0a860a01999-06-22 11:43:42 +000051TEB *THREAD_IdToTEB( DWORD id )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000052{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +000053 TEB *ret = NULL;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000054
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +000055 if (!id || id == GetCurrentThreadId()) return NtCurrentTeb();
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +000056
Alexandre Julliard9c2370b2000-08-30 00:00:48 +000057 SERVER_START_REQ
Alexandre Julliard8feb3bc1999-02-28 12:25:03 +000058 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +000059 struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
60 req->handle = -1;
61 req->tid_in = (void *)id;
62 if (!server_call_noerr( REQ_GET_THREAD_INFO )) ret = req->teb;
Alexandre Julliard8feb3bc1999-02-28 12:25:03 +000063 }
Alexandre Julliard9c2370b2000-08-30 00:00:48 +000064 SERVER_END_REQ;
65
66 if (!ret)
67 {
68 /* Allow task handles to be used; convert to main thread */
69 if ( IsTask16( id ) )
70 {
71 TDB *pTask = (TDB *)GlobalLock16( id );
72 if (pTask) return pTask->teb;
73 }
74 SetLastError( ERROR_INVALID_PARAMETER );
75 }
76 return ret;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000077}
78
79
Alexandre Julliard02e90081998-01-04 17:49:09 +000080/***********************************************************************
Alexandre Julliard0a860a01999-06-22 11:43:42 +000081 * THREAD_InitTEB
Alexandre Julliard02e90081998-01-04 17:49:09 +000082 *
Alexandre Julliard0a860a01999-06-22 11:43:42 +000083 * Initialization of a newly created TEB.
Alexandre Julliard02e90081998-01-04 17:49:09 +000084 */
Alexandre Julliard8c21dfc2000-05-01 21:21:31 +000085static BOOL THREAD_InitTEB( TEB *teb )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000086{
Alexandre Julliard3ef93222000-04-13 17:03:22 +000087 teb->except = (void *)~0UL;
Alexandre Julliard3ef93222000-04-13 17:03:22 +000088 teb->self = teb;
Alexandre Julliard8c21dfc2000-05-01 21:21:31 +000089 teb->tibflags = TEBF_WIN32;
Alexandre Julliard3ef93222000-04-13 17:03:22 +000090 teb->tls_ptr = teb->tls_array;
Alexandre Julliard3ef93222000-04-13 17:03:22 +000091 teb->exit_code = STILL_ACTIVE;
92 teb->socket = -1;
Alexandre Julliard5b4f3e82000-05-01 16:24:22 +000093 teb->stack_top = (void *)~0UL;
Alexandre Julliard3ef93222000-04-13 17:03:22 +000094 teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
95 teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
96 teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, SEGMENT_DATA, TRUE, FALSE );
97 return (teb->teb_sel != 0);
98}
99
100
101/***********************************************************************
102 * THREAD_FreeTEB
103 *
104 * Free data structures associated with a thread.
105 * Must be called from the context of another thread.
106 */
107static void CALLBACK THREAD_FreeTEB( TEB *teb )
108{
109 TRACE("(%p) called\n", teb );
110 if (teb->cleanup) SERVICE_Delete( teb->cleanup );
111
112 /* Free the associated memory */
113
114 if (teb->socket != -1) close( teb->socket );
115 if (teb->stack_sel) SELECTOR_FreeBlock( teb->stack_sel, 1 );
116 SELECTOR_FreeBlock( teb->teb_sel, 1 );
Alexandre Julliard86113532000-08-29 03:54:30 +0000117 if (teb->buffer) munmap( (void *)teb->buffer,
118 (char *)(teb->buffer_info+1) - (char *)teb->buffer );
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000119 if (teb->debug_info) HeapFree( GetProcessHeap(), 0, teb->debug_info );
120 VirtualFree( teb->stack_base, 0, MEM_RELEASE );
121}
122
123
124/***********************************************************************
125 * THREAD_InitStack
126 *
127 * Allocate the stack of a thread.
128 */
Alexandre Julliard8c21dfc2000-05-01 21:21:31 +0000129TEB *THREAD_InitStack( TEB *teb, DWORD stack_size, BOOL alloc_stack16 )
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000130{
131 DWORD old_prot, total_size;
132 DWORD page_size = VIRTUAL_GetPageSize();
133 void *base;
Alexandre Julliard02e90081998-01-04 17:49:09 +0000134
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000135 /* Allocate the stack */
136
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000137 if (stack_size >= 16*1024*1024)
Alexandre Julliard15657091999-05-23 10:25:25 +0000138 WARN("Thread stack size is %ld MB.\n",stack_size/1024/1024);
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000139
Alexandre Julliardce686032000-05-03 17:45:14 +0000140 /* if size is smaller than default, get stack size from parent */
141 if (stack_size < 1024 * 1024)
142 {
143 if (teb)
144 stack_size = 1024 * 1024; /* no parent */
145 else
146 stack_size = ((char *)NtCurrentTeb()->stack_top - (char *)NtCurrentTeb()->stack_base
147 - SIGNAL_STACK_SIZE - 3 * page_size);
148 }
149
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000150 /* FIXME: some Wine functions use a lot of stack, so we add 64Kb here */
151 stack_size += 64 * 1024;
152
153 /* Memory layout in allocated block:
154 *
155 * size contents
156 * 1 page NOACCESS guard page
157 * SIGNAL_STACK_SIZE signal stack
158 * 1 page NOACCESS guard page
159 * 1 page PAGE_GUARD guard page
160 * stack_size normal stack
161 * 64Kb 16-bit stack (optional)
162 * 1 page TEB (except for initial thread)
163 */
164
165 stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
166 total_size = stack_size + SIGNAL_STACK_SIZE + 3 * page_size;
167 if (alloc_stack16) total_size += 0x10000;
168 if (!teb) total_size += page_size;
169
170 if (!(base = VirtualAlloc( NULL, total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
171 return NULL;
172
173 if (!teb)
174 {
175 teb = (TEB *)((char *)base + total_size - page_size);
Alexandre Julliard8c21dfc2000-05-01 21:21:31 +0000176 if (!THREAD_InitTEB( teb ))
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000177 {
178 VirtualFree( base, 0, MEM_RELEASE );
179 return NULL;
180 }
181 }
182
183 teb->stack_low = base;
184 teb->stack_base = base;
185 teb->signal_stack = (char *)base + page_size;
186 teb->stack_top = (char *)base + 3 * page_size + SIGNAL_STACK_SIZE + stack_size;
187
188 /* Setup guard pages */
189
190 VirtualProtect( base, 1, PAGE_NOACCESS, &old_prot );
191 VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE, 1, PAGE_NOACCESS, &old_prot );
192 VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE + page_size, 1,
193 PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000194
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000195 /* Allocate the 16-bit stack selector */
196
197 if (alloc_stack16)
198 {
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000199 teb->stack_sel = SELECTOR_AllocBlock( teb->stack_top, 0x10000, SEGMENT_DATA,
200 FALSE, FALSE );
201 if (!teb->stack_sel) goto error;
202 teb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( teb->stack_sel,
203 0x10000 - sizeof(STACK16FRAME) );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000204 }
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000205 return teb;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000206
207error:
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000208 THREAD_FreeTEB( teb );
209 return NULL;
Alexandre Julliard301f2c61999-03-14 19:48:04 +0000210}
211
212
213/***********************************************************************
Alexandre Julliard5b4f3e82000-05-01 16:24:22 +0000214 * THREAD_Init
Alexandre Julliard13e55191999-02-21 18:34:18 +0000215 *
Alexandre Julliard5b4f3e82000-05-01 16:24:22 +0000216 * Setup the initial thread.
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000217 *
218 * NOTES: The first allocated TEB on NT is at 0x7ffde000.
Alexandre Julliard13e55191999-02-21 18:34:18 +0000219 */
Alexandre Julliard8c21dfc2000-05-01 21:21:31 +0000220void THREAD_Init(void)
Alexandre Julliard13e55191999-02-21 18:34:18 +0000221{
Alexandre Julliard8c21dfc2000-05-01 21:21:31 +0000222 if (!initial_teb.self) /* do it only once */
223 {
224 THREAD_InitTEB( &initial_teb );
225 assert( initial_teb.teb_sel );
Alexandre Julliard52900c82000-08-09 22:33:42 +0000226 initial_teb.process = &current_process;
Alexandre Julliard8c21dfc2000-05-01 21:21:31 +0000227 SYSDEPS_SetCurThread( &initial_teb );
228 }
Alexandre Julliard13e55191999-02-21 18:34:18 +0000229}
230
Alexandre Julliard8c21dfc2000-05-01 21:21:31 +0000231DECL_GLOBAL_CONSTRUCTOR(thread_init) { THREAD_Init(); }
Alexandre Julliard13e55191999-02-21 18:34:18 +0000232
233/***********************************************************************
234 * THREAD_Create
Juergen Schmied71e69dd1999-12-25 22:49:33 +0000235 *
Alexandre Julliard13e55191999-02-21 18:34:18 +0000236 */
Alexandre Julliardc192ba22000-05-29 21:25:10 +0000237TEB *THREAD_Create( int fd, DWORD stack_size, BOOL alloc_stack16 )
Alexandre Julliard13e55191999-02-21 18:34:18 +0000238{
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000239 TEB *teb;
Alexandre Julliard13e55191999-02-21 18:34:18 +0000240
Alexandre Julliard8c21dfc2000-05-01 21:21:31 +0000241 if ((teb = THREAD_InitStack( NULL, stack_size, alloc_stack16 )))
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000242 {
Alexandre Julliard52900c82000-08-09 22:33:42 +0000243 teb->tibflags = (current_process.flags & PDB32_WIN16_PROC) ? 0 : TEBF_WIN32;
244 teb->process = &current_process;
Alexandre Julliard8c21dfc2000-05-01 21:21:31 +0000245 teb->socket = fd;
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000246 fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */
247 TRACE("(%p) succeeded\n", teb);
248 }
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000249 return teb;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000250}
251
252
253/***********************************************************************
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000254 * THREAD_Start
255 *
256 * Start execution of a newly created thread. Does not return.
257 */
Alexandre Julliardf0167521999-03-21 19:26:25 +0000258static void THREAD_Start(void)
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000259{
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +0000260 HANDLE cleanup_object;
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000261 LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)NtCurrentTeb()->entry_point;
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +0000262
263 /* install cleanup handler */
264 if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
265 GetCurrentProcess(), &cleanup_object,
266 0, FALSE, DUPLICATE_SAME_ACCESS ))
Alexandre Julliard3ef93222000-04-13 17:03:22 +0000267 NtCurrentTeb()->cleanup = SERVICE_AddObject( cleanup_object, (PAPCFUNC)THREAD_FreeTEB,
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +0000268 (ULONG_PTR)NtCurrentTeb() );
269
270 PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );
Ulrich Weigande469a581999-03-27 16:45:57 +0000271 PE_InitTls();
Bertho Stultiensc1d1cfe1999-04-18 12:14:06 +0000272 MODULE_DllThreadAttach( NULL );
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000273 ExitThread( func( NtCurrentTeb()->entry_arg ) );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000274}
275
276
277/***********************************************************************
Alexandre Julliard349a9531997-02-02 19:01:52 +0000278 * CreateThread (KERNEL32.63)
Alexandre Julliard349a9531997-02-02 19:01:52 +0000279 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000280HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
Ulrich Weigand4526f2e1999-03-16 16:28:59 +0000281 LPTHREAD_START_ROUTINE start, LPVOID param,
282 DWORD flags, LPDWORD id )
Alexandre Julliard349a9531997-02-02 19:01:52 +0000283{
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +0000284 int socket, handle = -1;
285 TEB *teb;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000286 void *tid = 0;
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +0000287
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000288 SERVER_START_REQ
289 {
290 struct new_thread_request *req = server_alloc_req( sizeof(*req), 0 );
291
292 req->suspend = ((flags & CREATE_SUSPENDED) != 0);
293 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
294 if (!server_call_fd( REQ_NEW_THREAD, -1, &socket ))
295 {
296 handle = req->handle;
297 tid = req->tid;
298 }
299 }
300 SERVER_END_REQ;
301 if (handle == -1) return 0;
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +0000302
Alexandre Julliardc192ba22000-05-29 21:25:10 +0000303 if (!(teb = THREAD_Create( socket, stack, TRUE )))
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +0000304 {
305 close( socket );
306 return 0;
307 }
Ulrich Weigandf3bfa3a2000-01-30 21:16:06 +0000308 teb->tibflags |= TEBF_WIN32;
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000309 teb->entry_point = start;
310 teb->entry_arg = param;
311 teb->startup = THREAD_Start;
Alexandre Julliardc192ba22000-05-29 21:25:10 +0000312 teb->htask16 = GetCurrentTask();
Alexandre Julliard5b4f3e82000-05-01 16:24:22 +0000313 if (id) *id = (DWORD)tid;
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000314 if (SYSDEPS_SpawnThread( teb ) == -1)
Alexandre Julliard96c08d81999-02-28 13:27:56 +0000315 {
316 CloseHandle( handle );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000317 THREAD_FreeTEB( teb );
Alexandre Julliard617955d1999-06-26 18:40:24 +0000318 return 0;
Alexandre Julliard96c08d81999-02-28 13:27:56 +0000319 }
Alexandre Julliard349a9531997-02-02 19:01:52 +0000320 return handle;
321}
322
Ulrich Weigandf0a1c2f1999-09-20 18:45:28 +0000323/***********************************************************************
324 * CreateThread16 (KERNEL.441)
325 */
326static DWORD CALLBACK THREAD_StartThread16( LPVOID threadArgs )
327{
328 FARPROC16 start = ((FARPROC16 *)threadArgs)[0];
329 DWORD param = ((DWORD *)threadArgs)[1];
330 HeapFree( GetProcessHeap(), 0, threadArgs );
331
332 ((LPDWORD)CURRENT_STACK16)[-1] = param;
333 return CallTo16Long( start, sizeof(DWORD) );
334}
335HANDLE WINAPI CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
336 FARPROC16 start, SEGPTR param,
337 DWORD flags, LPDWORD id )
338{
339 DWORD *threadArgs = HeapAlloc( GetProcessHeap(), 0, 2*sizeof(DWORD) );
340 if (!threadArgs) return INVALID_HANDLE_VALUE;
341 threadArgs[0] = (DWORD)start;
342 threadArgs[1] = (DWORD)param;
343
344 return CreateThread( sa, stack, THREAD_StartThread16, threadArgs, flags, id );
345}
346
Alexandre Julliard349a9531997-02-02 19:01:52 +0000347
348/***********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000349 * ExitThread [KERNEL32.215] Ends a thread
350 *
351 * RETURNS
352 * None
Alexandre Julliard02e90081998-01-04 17:49:09 +0000353 */
Alexandre Julliard301f2c61999-03-14 19:48:04 +0000354void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
Alexandre Julliard02e90081998-01-04 17:49:09 +0000355{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000356 BOOL last;
357 SERVER_START_REQ
358 {
359 struct terminate_thread_request *req = server_alloc_req( sizeof(*req), 0 );
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000360
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000361 /* send the exit code to the server */
362 req->handle = GetCurrentThread();
363 req->exit_code = code;
364 server_call( REQ_TERMINATE_THREAD );
365 last = req->last;
366 }
367 SERVER_END_REQ;
368
369 if (last)
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000370 {
371 MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000372 exit( code );
373 }
374 else
375 {
376 MODULE_DllThreadDetach( NULL );
Alexandre Julliardc192ba22000-05-29 21:25:10 +0000377 if (!(NtCurrentTeb()->tibflags & TEBF_WIN32)) TASK_KillTask( 0 );
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000378 SYSDEPS_ExitThread( code );
379 }
Alexandre Julliard02e90081998-01-04 17:49:09 +0000380}
381
382
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000383/**********************************************************************
Ulrich Weigande469a581999-03-27 16:45:57 +0000384 * TlsAlloc [KERNEL32.530] Allocates a TLS index.
385 *
386 * Allocates a thread local storage index
387 *
388 * RETURNS
389 * Success: TLS Index
390 * Failure: 0xFFFFFFFF
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000391 */
Ulrich Weigande469a581999-03-27 16:45:57 +0000392DWORD WINAPI TlsAlloc( void )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000393{
394 DWORD i, mask, ret = 0;
Alexandre Julliard52900c82000-08-09 22:33:42 +0000395 DWORD *bits = current_process.tls_bits;
396 EnterCriticalSection( &current_process.crit_section );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000397 if (*bits == 0xffffffff)
398 {
399 bits++;
400 ret = 32;
401 if (*bits == 0xffffffff)
402 {
Alexandre Julliard52900c82000-08-09 22:33:42 +0000403 LeaveCriticalSection( &current_process.crit_section );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000404 SetLastError( ERROR_NO_MORE_ITEMS );
405 return 0xffffffff;
406 }
407 }
408 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
409 *bits |= mask;
Alexandre Julliard52900c82000-08-09 22:33:42 +0000410 LeaveCriticalSection( &current_process.crit_section );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000411 return ret + i;
412}
413
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000414
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000415/**********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000416 * TlsFree [KERNEL32.531] Releases a TLS index.
417 *
418 * Releases a thread local storage index, making it available for reuse
419 *
420 * RETURNS
421 * Success: TRUE
422 * Failure: FALSE
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000423 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000424BOOL WINAPI TlsFree(
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000425 DWORD index) /* [in] TLS Index to free */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000426{
427 DWORD mask;
Alexandre Julliard52900c82000-08-09 22:33:42 +0000428 DWORD *bits = current_process.tls_bits;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000429 if (index >= 64)
430 {
431 SetLastError( ERROR_INVALID_PARAMETER );
432 return FALSE;
433 }
Alexandre Julliard52900c82000-08-09 22:33:42 +0000434 EnterCriticalSection( &current_process.crit_section );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000435 if (index >= 32) bits++;
436 mask = (1 << (index & 31));
437 if (!(*bits & mask)) /* already free? */
438 {
Alexandre Julliard52900c82000-08-09 22:33:42 +0000439 LeaveCriticalSection( &current_process.crit_section );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000440 SetLastError( ERROR_INVALID_PARAMETER );
441 return FALSE;
442 }
443 *bits &= ~mask;
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000444 NtCurrentTeb()->tls_array[index] = 0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000445 /* FIXME: should zero all other thread values */
Alexandre Julliard52900c82000-08-09 22:33:42 +0000446 LeaveCriticalSection( &current_process.crit_section );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000447 return TRUE;
448}
449
450
451/**********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000452 * TlsGetValue [KERNEL32.532] Gets value in a thread's TLS slot
453 *
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000454 * RETURNS
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000455 * Success: Value stored in calling thread's TLS slot for index
456 * Failure: 0 and GetLastError returns NO_ERROR
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000457 */
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000458LPVOID WINAPI TlsGetValue(
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000459 DWORD index) /* [in] TLS index to retrieve value for */
460{
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000461 if (index >= 64)
462 {
463 SetLastError( ERROR_INVALID_PARAMETER );
464 return NULL;
465 }
466 SetLastError( ERROR_SUCCESS );
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000467 return NtCurrentTeb()->tls_array[index];
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000468}
469
470
471/**********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000472 * TlsSetValue [KERNEL32.533] Stores a value in the thread's TLS slot.
473 *
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000474 * RETURNS
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000475 * Success: TRUE
476 * Failure: FALSE
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000477 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000478BOOL WINAPI TlsSetValue(
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000479 DWORD index, /* [in] TLS index to set value for */
480 LPVOID value) /* [in] Value to be stored */
481{
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000482 if (index >= 64)
483 {
484 SetLastError( ERROR_INVALID_PARAMETER );
485 return FALSE;
486 }
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000487 NtCurrentTeb()->tls_array[index] = value;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000488 return TRUE;
489}
490
491
492/***********************************************************************
Alexandre Julliarda845b881998-06-01 10:44:35 +0000493 * SetThreadContext [KERNEL32.670] Sets context of thread.
494 *
495 * RETURNS
496 * Success: TRUE
497 * Failure: FALSE
498 */
Alexandre Julliard3e2517c2000-01-20 18:59:03 +0000499BOOL WINAPI SetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
500 const CONTEXT *context ) /* [in] Address of context structure */
Alexandre Julliarda845b881998-06-01 10:44:35 +0000501{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000502 BOOL ret;
503 SERVER_START_REQ
504 {
Alexandre Julliard92643002000-08-31 01:59:51 +0000505 struct set_thread_context_request *req = server_alloc_req( sizeof(*req),
506 sizeof(*context) );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000507 req->handle = handle;
508 req->flags = context->ContextFlags;
Alexandre Julliard92643002000-08-31 01:59:51 +0000509 memcpy( server_data_ptr(req), context, sizeof(*context) );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000510 ret = !server_call( REQ_SET_THREAD_CONTEXT );
511 }
512 SERVER_END_REQ;
513 return ret;
Alexandre Julliarda845b881998-06-01 10:44:35 +0000514}
515
Alexandre Julliard3e2517c2000-01-20 18:59:03 +0000516
Alexandre Julliarda845b881998-06-01 10:44:35 +0000517/***********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000518 * GetThreadContext [KERNEL32.294] Retrieves context of thread.
519 *
520 * RETURNS
521 * Success: TRUE
522 * Failure: FALSE
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000523 */
Alexandre Julliard3e2517c2000-01-20 18:59:03 +0000524BOOL WINAPI GetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
525 CONTEXT *context ) /* [out] Address of context structure */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000526{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000527 BOOL ret;
528 SERVER_START_REQ
529 {
Alexandre Julliard92643002000-08-31 01:59:51 +0000530 struct get_thread_context_request *req = server_alloc_req( sizeof(*req),
531 sizeof(*context) );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000532 req->handle = handle;
533 req->flags = context->ContextFlags;
Alexandre Julliard92643002000-08-31 01:59:51 +0000534 memcpy( server_data_ptr(req), context, sizeof(*context) );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000535 if ((ret = !server_call( REQ_GET_THREAD_CONTEXT )))
Alexandre Julliard92643002000-08-31 01:59:51 +0000536 memcpy( context, server_data_ptr(req), sizeof(*context) );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000537 }
538 SERVER_END_REQ;
539 return ret;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000540}
541
542
543/**********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000544 * GetThreadPriority [KERNEL32.296] Returns priority for thread.
545 *
546 * RETURNS
547 * Success: Thread's priority level.
548 * Failure: THREAD_PRIORITY_ERROR_RETURN
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000549 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000550INT WINAPI GetThreadPriority(
551 HANDLE hthread) /* [in] Handle to thread */
Alexandre Julliard349a9531997-02-02 19:01:52 +0000552{
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000553 INT ret = THREAD_PRIORITY_ERROR_RETURN;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000554 SERVER_START_REQ
555 {
556 struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
557 req->handle = hthread;
558 req->tid_in = 0;
559 if (!server_call( REQ_GET_THREAD_INFO )) ret = req->priority;
560 }
561 SERVER_END_REQ;
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000562 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000563}
564
Alexandre Julliard349a9531997-02-02 19:01:52 +0000565
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000566/**********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000567 * SetThreadPriority [KERNEL32.514] Sets priority for thread.
568 *
569 * RETURNS
570 * Success: TRUE
571 * Failure: FALSE
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000572 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000573BOOL WINAPI SetThreadPriority(
574 HANDLE hthread, /* [in] Handle to thread */
575 INT priority) /* [in] Thread priority level */
Alexandre Julliard349a9531997-02-02 19:01:52 +0000576{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000577 BOOL ret;
578 SERVER_START_REQ
579 {
580 struct set_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
581 req->handle = hthread;
582 req->priority = priority;
583 req->mask = SET_THREAD_INFO_PRIORITY;
584 ret = !server_call( REQ_SET_THREAD_INFO );
585 }
586 SERVER_END_REQ;
587 return ret;
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000588}
589
590
591/**********************************************************************
Slava Monichfb8934d2000-07-08 12:47:30 +0000592 * GetThreadPriorityBoost [KERNEL32.877] Returns priority boost for thread.
593 *
594 * Always reports that priority boost is disabled.
595 *
596 * RETURNS
597 * Success: TRUE.
598 * Failure: FALSE
599 */
600BOOL WINAPI GetThreadPriorityBoost(
601 HANDLE hthread, /* [in] Handle to thread */
602 PBOOL pstate) /* [out] pointer to var that receives the boost state */
603{
604 if (pstate) *pstate = FALSE;
605 return NO_ERROR;
606}
607
608
609/**********************************************************************
610 * SetThreadPriorityBoost [KERNEL32.893] Sets priority boost for thread.
611 *
612 * Priority boost is not implemented. Thsi function always returns
613 * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
614 *
615 * RETURNS
616 * Always returns FALSE to indicate a failure
617 */
618BOOL WINAPI SetThreadPriorityBoost(
619 HANDLE hthread, /* [in] Handle to thread */
620 BOOL disable) /* [in] TRUE to disable priority boost */
621{
622 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
623 return FALSE;
624}
625
626
627/**********************************************************************
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000628 * SetThreadAffinityMask (KERNEL32.669)
629 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000630DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000631{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000632 DWORD ret;
633 SERVER_START_REQ
634 {
635 struct set_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
636 req->handle = hThread;
637 req->affinity = dwThreadAffinityMask;
638 req->mask = SET_THREAD_INFO_AFFINITY;
639 ret = !server_call( REQ_SET_THREAD_INFO );
640 /* FIXME: should return previous value */
641 }
642 SERVER_END_REQ;
643 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000644}
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000645
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000646
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000647/**********************************************************************
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000648 * TerminateThread [KERNEL32.685] Terminates a thread
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000649 *
650 * RETURNS
651 * Success: TRUE
652 * Failure: FALSE
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000653 */
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000654BOOL WINAPI TerminateThread( HANDLE handle, /* [in] Handle to thread */
655 DWORD exit_code) /* [in] Exit code for thread */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000656{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000657 NTSTATUS status = NtTerminateThread( handle, exit_code );
658 if (status) SetLastError( RtlNtStatusToDosError(status) );
659 return !status;
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000660}
Alexandre Julliard77b99181997-09-14 17:17:23 +0000661
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000662
Alexandre Julliard77b99181997-09-14 17:17:23 +0000663/**********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000664 * GetExitCodeThread [KERNEL32.???] Gets termination status of thread.
665 *
666 * RETURNS
667 * Success: TRUE
668 * Failure: FALSE
Alexandre Julliard77b99181997-09-14 17:17:23 +0000669 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000670BOOL WINAPI GetExitCodeThread(
671 HANDLE hthread, /* [in] Handle to thread */
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000672 LPDWORD exitcode) /* [out] Address to receive termination status */
Alexandre Julliard77b99181997-09-14 17:17:23 +0000673{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000674 BOOL ret;
675 SERVER_START_REQ
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000676 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000677 struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
678 req->handle = hthread;
679 req->tid_in = 0;
680 ret = !server_call( REQ_GET_THREAD_INFO );
681 if (ret && exitcode) *exitcode = req->exit_code;
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000682 }
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000683 SERVER_END_REQ;
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000684 return ret;
Alexandre Julliard77b99181997-09-14 17:17:23 +0000685}
686
Alexandre Julliard77b99181997-09-14 17:17:23 +0000687
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000688/**********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000689 * ResumeThread [KERNEL32.587] Resumes a thread.
690 *
691 * Decrements a thread's suspend count. When count is zero, the
692 * execution of the thread is resumed.
693 *
694 * RETURNS
695 * Success: Previous suspend count
696 * Failure: 0xFFFFFFFF
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000697 * Already running: 0
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000698 */
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000699DWORD WINAPI ResumeThread(
Alexandre Julliarda3960291999-02-26 11:11:13 +0000700 HANDLE hthread) /* [in] Identifies thread to restart */
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000701{
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000702 DWORD ret = 0xffffffff;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000703 SERVER_START_REQ
704 {
705 struct resume_thread_request *req = server_alloc_req( sizeof(*req), 0 );
706 req->handle = hthread;
707 if (!server_call( REQ_RESUME_THREAD )) ret = req->count;
708 }
709 SERVER_END_REQ;
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000710 return ret;
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000711}
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000712
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000713
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000714/**********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000715 * SuspendThread [KERNEL32.681] Suspends a thread.
716 *
717 * RETURNS
718 * Success: Previous suspend count
719 * Failure: 0xFFFFFFFF
720 */
721DWORD WINAPI SuspendThread(
Alexandre Julliarda3960291999-02-26 11:11:13 +0000722 HANDLE hthread) /* [in] Handle to the thread */
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000723{
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000724 DWORD ret = 0xffffffff;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000725 SERVER_START_REQ
726 {
727 struct suspend_thread_request *req = server_alloc_req( sizeof(*req), 0 );
728 req->handle = hthread;
729 if (!server_call( REQ_SUSPEND_THREAD )) ret = req->count;
730 }
731 SERVER_END_REQ;
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000732 return ret;
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000733}
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000734
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000735
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000736/***********************************************************************
737 * QueueUserAPC (KERNEL32.566)
738 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000739DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000740{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000741 DWORD ret;
742 SERVER_START_REQ
743 {
744 struct queue_apc_request *req = server_alloc_req( sizeof(*req), 0 );
745 req->handle = hthread;
746 req->func = func;
747 req->param = (void *)data;
748 ret = !server_call( REQ_QUEUE_APC );
749 }
750 SERVER_END_REQ;
751 return ret;
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000752}
753
754
755/**********************************************************************
756 * GetThreadTimes [KERNEL32.???] Obtains timing information.
757 *
758 * NOTES
759 * What are the fields where these values are stored?
760 *
761 * RETURNS
762 * Success: TRUE
763 * Failure: FALSE
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000764 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000765BOOL WINAPI GetThreadTimes(
766 HANDLE thread, /* [in] Specifies the thread of interest */
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000767 LPFILETIME creationtime, /* [out] When the thread was created */
768 LPFILETIME exittime, /* [out] When the thread was destroyed */
769 LPFILETIME kerneltime, /* [out] Time thread spent in kernel mode */
770 LPFILETIME usertime) /* [out] Time thread spent in user mode */
771{
Alexandre Julliard15657091999-05-23 10:25:25 +0000772 FIXME("(0x%08x): stub\n",thread);
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000773 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
774 return FALSE;
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000775}
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000776
777
778/**********************************************************************
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000779 * VWin32_BoostThreadGroup [KERNEL.535]
780 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000781VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000782{
Alexandre Julliard15657091999-05-23 10:25:25 +0000783 FIXME("(0x%08lx,%d): stub\n", threadId, boost);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000784}
785
786/**********************************************************************
787 * VWin32_BoostThreadStatic [KERNEL.536]
788 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000789VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000790{
Alexandre Julliard15657091999-05-23 10:25:25 +0000791 FIXME("(0x%08lx,%d): stub\n", threadId, boost);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000792}
793
Juergen Schmied79d850f2000-06-12 21:56:02 +0000794
795/***********************************************************************
796 * GetThreadLocale (KERNEL32.295)
797 */
798LCID WINAPI GetThreadLocale(void)
799{
Alexandre Julliardbec32442000-07-10 15:23:04 +0000800 LCID ret = NtCurrentTeb()->CurrentLocale;
801 if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID();
802 return ret;
Juergen Schmied79d850f2000-06-12 21:56:02 +0000803}
804
805
Guy Albertellic66f5d51999-01-24 09:59:14 +0000806/**********************************************************************
807 * SetThreadLocale [KERNEL32.671] Sets the calling threads current locale.
808 *
809 * RETURNS
810 * Success: TRUE
811 * Failure: FALSE
812 *
Juergen Schmied79d850f2000-06-12 21:56:02 +0000813 * FIXME
814 * check if lcid is a valid cp
Guy Albertellic66f5d51999-01-24 09:59:14 +0000815 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000816BOOL WINAPI SetThreadLocale(
Guy Albertellic66f5d51999-01-24 09:59:14 +0000817 LCID lcid) /* [in] Locale identifier */
818{
Juergen Schmied79d850f2000-06-12 21:56:02 +0000819 switch (lcid)
820 {
821 case LOCALE_SYSTEM_DEFAULT:
822 lcid = GetSystemDefaultLCID();
823 break;
824 case LOCALE_USER_DEFAULT:
825 case LOCALE_NEUTRAL:
826 lcid = GetUserDefaultLCID();
827 break;
828 }
829 NtCurrentTeb()->CurrentLocale = lcid;
830 return TRUE;
Guy Albertellic66f5d51999-01-24 09:59:14 +0000831}
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000832
833
Alexandre Julliard114830e2000-04-11 20:01:59 +0000834/***********************************************************************
835 * GetCurrentThread [KERNEL32.200] Gets pseudohandle for current thread
836 *
837 * RETURNS
838 * Pseudohandle for the current thread
839 */
840#undef GetCurrentThread
841HANDLE WINAPI GetCurrentThread(void)
842{
843 return 0xfffffffe;
844}
845
846
David Elliott44f84b52000-10-29 01:24:54 +0000847/***********************************************************************
848 * ProcessIdToSessionId (KERNEL32)
849 * This function is available on Terminal Server 4SP4 and Windows 2000
850 */
851BOOL WINAPI ProcessIdToSessionId( DWORD procid, DWORD *sessionid_ptr )
852{
853 /* According to MSDN, if the calling process is not in a terminal
854 * services environment, then the sessionid returned is zero.
855 */
856 *sessionid_ptr = 0;
857 return TRUE;
858}
859
860
Alexandre Julliardca3c9ba2000-03-07 13:14:27 +0000861#ifdef __i386__
862
863/* void WINAPI SetLastError( DWORD error ); */
864__ASM_GLOBAL_FUNC( SetLastError,
865 "movl 4(%esp),%eax\n\t"
866 ".byte 0x64\n\t"
867 "movl %eax,0x60\n\t"
868 "ret $4" );
869
870/* DWORD WINAPI GetLastError(void); */
871__ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x60,%eax\n\tret" );
872
Alexandre Julliard114830e2000-04-11 20:01:59 +0000873/* DWORD WINAPI GetCurrentProcessId(void) */
874__ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" );
875
Alexandre Julliardca3c9ba2000-03-07 13:14:27 +0000876/* DWORD WINAPI GetCurrentThreadId(void) */
877__ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" );
878
879#else /* __i386__ */
880
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000881/**********************************************************************
882 * SetLastError [KERNEL.147] [KERNEL32.497] Sets the last-error code.
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000883 */
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000884void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
885{
886 NtCurrentTeb()->last_error = error;
887}
888
Alexandre Julliardca3c9ba2000-03-07 13:14:27 +0000889/**********************************************************************
890 * GetLastError [KERNEL.148] [KERNEL32.227] Returns last-error code.
891 */
892DWORD WINAPI GetLastError(void)
893{
894 return NtCurrentTeb()->last_error;
895}
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000896
897/***********************************************************************
Alexandre Julliard114830e2000-04-11 20:01:59 +0000898 * GetCurrentProcessId [KERNEL32.199] Returns process identifier.
899 */
900DWORD WINAPI GetCurrentProcessId(void)
901{
902 return (DWORD)NtCurrentTeb()->pid;
903}
904
905/***********************************************************************
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000906 * GetCurrentThreadId [KERNEL32.201] Returns thread identifier.
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000907 */
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000908DWORD WINAPI GetCurrentThreadId(void)
909{
910 return (DWORD)NtCurrentTeb()->tid;
911}
Alexandre Julliardca3c9ba2000-03-07 13:14:27 +0000912
913#endif /* __i386__ */