include: Make sure __int64 is correctly defined on PPC64.
[wine.git] / dlls / ntdll / thread.c
blob8e5a3a3a3a3d9a7ae9b1d1cece639db6ce39f1e5
1 /*
2 * NT threads support
4 * Copyright 1996, 2003 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <limits.h>
24 #include <sys/types.h>
26 #define NONAMELESSUNION
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "winternl.h"
30 #include "wine/server.h"
31 #include "wine/debug.h"
32 #include "ntdll_misc.h"
33 #include "ddk/wdm.h"
34 #include "wine/exception.h"
36 WINE_DECLARE_DEBUG_CHANNEL(relay);
37 WINE_DECLARE_DEBUG_CHANNEL(thread);
39 struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000;
42 /***********************************************************************
43 * __wine_dbg_get_channel_flags (NTDLL.@)
45 * Get the flags to use for a given channel, possibly setting them too in case of lazy init
47 unsigned char __cdecl __wine_dbg_get_channel_flags( struct __wine_debug_channel *channel )
49 return unix_funcs->dbg_get_channel_flags( channel );
52 /***********************************************************************
53 * __wine_dbg_strdup (NTDLL.@)
55 const char * __cdecl __wine_dbg_strdup( const char *str )
57 return unix_funcs->dbg_strdup( str );
60 /***********************************************************************
61 * __wine_dbg_header (NTDLL.@)
63 int __cdecl __wine_dbg_header( enum __wine_debug_class cls, struct __wine_debug_channel *channel,
64 const char *function )
66 return unix_funcs->dbg_header( cls, channel, function );
69 /***********************************************************************
70 * __wine_dbg_output (NTDLL.@)
72 int __cdecl __wine_dbg_output( const char *str )
74 return unix_funcs->dbg_output( str );
78 /***********************************************************************
79 * RtlExitUserThread (NTDLL.@)
81 void WINAPI RtlExitUserThread( ULONG status )
83 ULONG last;
85 NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL );
86 if (last) RtlExitUserProcess( status );
87 LdrShutdownThread();
88 RtlFreeThreadActivationContextStack();
89 for (;;) NtTerminateThread( GetCurrentThread(), status );
93 /***********************************************************************
94 * RtlUserThreadStart (NTDLL.@)
96 #ifdef __i386__
97 __ASM_STDCALL_FUNC( RtlUserThreadStart, 8,
98 "movl %ebx,8(%esp)\n\t" /* arg */
99 "movl %eax,4(%esp)\n\t" /* entry */
100 "jmp " __ASM_NAME("call_thread_func") )
102 /* wrapper to call BaseThreadInitThunk */
103 extern void DECLSPEC_NORETURN call_thread_func_wrapper( void *thunk, PRTL_THREAD_START_ROUTINE entry, void *arg );
104 __ASM_GLOBAL_FUNC( call_thread_func_wrapper,
105 "pushl %ebp\n\t"
106 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
107 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
108 "movl %esp,%ebp\n\t"
109 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
110 "subl $4,%esp\n\t"
111 "andl $~0xf,%esp\n\t"
112 "xorl %ecx,%ecx\n\t"
113 "movl 12(%ebp),%edx\n\t"
114 "movl 16(%ebp),%eax\n\t"
115 "movl %eax,(%esp)\n\t"
116 "call *8(%ebp)" )
118 void DECLSPEC_HIDDEN call_thread_func( PRTL_THREAD_START_ROUTINE entry, void *arg )
120 __TRY
122 TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
123 call_thread_func_wrapper( pBaseThreadInitThunk, entry, arg );
125 __EXCEPT(call_unhandled_exception_filter)
127 NtTerminateProcess( GetCurrentProcess(), GetExceptionCode() );
129 __ENDTRY
132 #else /* __i386__ */
134 void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg )
136 __TRY
138 TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
139 pBaseThreadInitThunk( 0, (LPTHREAD_START_ROUTINE)entry, arg );
141 __EXCEPT(call_unhandled_exception_filter)
143 NtTerminateProcess( GetCurrentProcess(), GetExceptionCode() );
145 __ENDTRY
148 #endif /* __i386__ */
151 /***********************************************************************
152 * RtlCreateUserThread (NTDLL.@)
154 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr,
155 BOOLEAN suspended, PVOID stack_addr,
156 SIZE_T stack_reserve, SIZE_T stack_commit,
157 PRTL_THREAD_START_ROUTINE start, void *param,
158 HANDLE *handle_ptr, CLIENT_ID *id )
160 ULONG flags = suspended ? THREAD_CREATE_FLAGS_CREATE_SUSPENDED : 0;
161 ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[2] ) / sizeof(ULONG_PTR)];
162 PS_ATTRIBUTE_LIST *attr_list = (PS_ATTRIBUTE_LIST *)buffer;
163 HANDLE handle, actctx;
164 TEB *teb;
165 ULONG ret;
166 NTSTATUS status;
167 CLIENT_ID client_id;
168 OBJECT_ATTRIBUTES attr;
170 attr_list->TotalLength = sizeof(buffer);
171 attr_list->Attributes[0].Attribute = PS_ATTRIBUTE_CLIENT_ID;
172 attr_list->Attributes[0].Size = sizeof(client_id);
173 attr_list->Attributes[0].ValuePtr = &client_id;
174 attr_list->Attributes[0].ReturnLength = NULL;
175 attr_list->Attributes[1].Attribute = PS_ATTRIBUTE_TEB_ADDRESS;
176 attr_list->Attributes[1].Size = sizeof(teb);
177 attr_list->Attributes[1].ValuePtr = &teb;
178 attr_list->Attributes[1].ReturnLength = NULL;
180 InitializeObjectAttributes( &attr, NULL, 0, NULL, descr );
182 RtlGetActiveActivationContext( &actctx );
183 if (actctx) flags |= THREAD_CREATE_FLAGS_CREATE_SUSPENDED;
185 status = NtCreateThreadEx( &handle, THREAD_ALL_ACCESS, &attr, process, start, param,
186 flags, 0, stack_commit, stack_reserve, attr_list );
187 if (!status)
189 if (actctx)
191 ULONG_PTR cookie;
192 RtlActivateActivationContextEx( 0, teb, actctx, &cookie );
193 if (!suspended) NtResumeThread( handle, &ret );
195 if (id) *id = client_id;
196 if (handle_ptr) *handle_ptr = handle;
197 else NtClose( handle );
199 if (actctx) RtlReleaseActivationContext( actctx );
200 return status;
204 /******************************************************************************
205 * RtlGetNtGlobalFlags (NTDLL.@)
207 ULONG WINAPI RtlGetNtGlobalFlags(void)
209 return NtCurrentTeb()->Peb->NtGlobalFlag;
213 /******************************************************************************
214 * RtlPushFrame (NTDLL.@)
216 void WINAPI RtlPushFrame( TEB_ACTIVE_FRAME *frame )
218 frame->Previous = NtCurrentTeb()->ActiveFrame;
219 NtCurrentTeb()->ActiveFrame = frame;
223 /******************************************************************************
224 * RtlPopFrame (NTDLL.@)
226 void WINAPI RtlPopFrame( TEB_ACTIVE_FRAME *frame )
228 NtCurrentTeb()->ActiveFrame = frame->Previous;
232 /******************************************************************************
233 * RtlGetFrame (NTDLL.@)
235 TEB_ACTIVE_FRAME * WINAPI RtlGetFrame(void)
237 return NtCurrentTeb()->ActiveFrame;
241 /***********************************************************************
242 * Fibers
243 ***********************************************************************/
246 static GLOBAL_FLS_DATA fls_data;
248 static RTL_CRITICAL_SECTION fls_section;
249 static RTL_CRITICAL_SECTION_DEBUG fls_critsect_debug =
251 0, 0, &fls_section,
252 { &fls_critsect_debug.ProcessLocksList, &fls_critsect_debug.ProcessLocksList },
253 0, 0, { (DWORD_PTR)(__FILE__ ": fls_section") }
255 static RTL_CRITICAL_SECTION fls_section = { &fls_critsect_debug, -1, 0, 0, 0, 0 };
257 #define MAX_FLS_DATA_COUNT 0xff0
259 void init_global_fls_data(void)
261 InitializeListHead( &fls_data.fls_list_head );
264 static void lock_fls_data(void)
266 RtlEnterCriticalSection( &fls_section );
269 static void unlock_fls_data(void)
271 RtlLeaveCriticalSection( &fls_section );
274 static unsigned int fls_chunk_size( unsigned int chunk_index )
276 return 0x10 << chunk_index;
279 static unsigned int fls_index_from_chunk_index( unsigned int chunk_index, unsigned int index )
281 return 0x10 * ((1 << chunk_index) - 1) + index;
284 static unsigned int fls_chunk_index_from_index( unsigned int index, unsigned int *index_in_chunk )
286 unsigned int chunk_index = 0;
288 while (index >= fls_chunk_size( chunk_index ))
289 index -= fls_chunk_size( chunk_index++ );
291 *index_in_chunk = index;
292 return chunk_index;
295 TEB_FLS_DATA *fls_alloc_data(void)
297 TEB_FLS_DATA *fls;
299 if (!(fls = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*fls) )))
300 return NULL;
302 lock_fls_data();
303 InsertTailList( &fls_data.fls_list_head, &fls->fls_list_entry );
304 unlock_fls_data();
306 return fls;
310 /***********************************************************************
311 * RtlFlsAlloc (NTDLL.@)
313 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsAlloc( PFLS_CALLBACK_FUNCTION callback, ULONG *ret_index )
315 unsigned int chunk_index, index, i;
316 FLS_INFO_CHUNK *chunk;
317 TEB_FLS_DATA *fls;
319 if (!(fls = NtCurrentTeb()->FlsSlots)
320 && !(NtCurrentTeb()->FlsSlots = fls = fls_alloc_data()))
321 return STATUS_NO_MEMORY;
323 lock_fls_data();
324 for (i = 0; i < ARRAY_SIZE(fls_data.fls_callback_chunks); ++i)
326 if (!fls_data.fls_callback_chunks[i] || fls_data.fls_callback_chunks[i]->count < fls_chunk_size( i ))
327 break;
330 if ((chunk_index = i) == ARRAY_SIZE(fls_data.fls_callback_chunks))
332 unlock_fls_data();
333 return STATUS_NO_MEMORY;
336 if ((chunk = fls_data.fls_callback_chunks[chunk_index]))
338 for (index = 0; index < fls_chunk_size( chunk_index ); ++index)
339 if (!chunk->callbacks[index].callback)
340 break;
341 assert( index < fls_chunk_size( chunk_index ));
343 else
345 fls_data.fls_callback_chunks[chunk_index] = chunk = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
346 offsetof(FLS_INFO_CHUNK, callbacks) + sizeof(*chunk->callbacks) * fls_chunk_size( chunk_index ));
347 if (!chunk)
349 unlock_fls_data();
350 return STATUS_NO_MEMORY;
353 if (chunk_index)
355 index = 0;
357 else
359 chunk->count = 1; /* FLS index 0 is prohibited. */
360 chunk->callbacks[0].callback = (void *)~(ULONG_PTR)0;
361 index = 1;
365 ++chunk->count;
366 chunk->callbacks[index].callback = callback ? callback : (PFLS_CALLBACK_FUNCTION)~(ULONG_PTR)0;
368 if ((*ret_index = fls_index_from_chunk_index( chunk_index, index )) > fls_data.fls_high_index)
369 fls_data.fls_high_index = *ret_index;
371 unlock_fls_data();
373 return STATUS_SUCCESS;
377 /***********************************************************************
378 * RtlFlsFree (NTDLL.@)
380 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsFree( ULONG index )
382 PFLS_CALLBACK_FUNCTION callback;
383 unsigned int chunk_index, idx;
384 FLS_INFO_CHUNK *chunk;
385 LIST_ENTRY *entry;
387 lock_fls_data();
389 if (!index || index > fls_data.fls_high_index)
391 unlock_fls_data();
392 return STATUS_INVALID_PARAMETER;
395 chunk_index = fls_chunk_index_from_index( index, &idx );
396 if (!(chunk = fls_data.fls_callback_chunks[chunk_index])
397 || !(callback = chunk->callbacks[idx].callback))
399 unlock_fls_data();
400 return STATUS_INVALID_PARAMETER;
403 for (entry = fls_data.fls_list_head.Flink; entry != &fls_data.fls_list_head; entry = entry->Flink)
405 TEB_FLS_DATA *fls = CONTAINING_RECORD(entry, TEB_FLS_DATA, fls_list_entry);
407 if (fls->fls_data_chunks[chunk_index] && fls->fls_data_chunks[chunk_index][idx + 1])
409 if (callback != (void *)~(ULONG_PTR)0)
411 TRACE_(relay)("Calling FLS callback %p, arg %p.\n", callback,
412 fls->fls_data_chunks[chunk_index][idx + 1]);
414 callback( fls->fls_data_chunks[chunk_index][idx + 1] );
416 fls->fls_data_chunks[chunk_index][idx + 1] = NULL;
420 --chunk->count;
421 chunk->callbacks[idx].callback = NULL;
423 unlock_fls_data();
424 return STATUS_SUCCESS;
428 /***********************************************************************
429 * RtlFlsSetValue (NTDLL.@)
431 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsSetValue( ULONG index, void *data )
433 unsigned int chunk_index, idx;
434 TEB_FLS_DATA *fls;
436 if (!index || index >= MAX_FLS_DATA_COUNT)
437 return STATUS_INVALID_PARAMETER;
439 if (!(fls = NtCurrentTeb()->FlsSlots)
440 && !(NtCurrentTeb()->FlsSlots = fls = fls_alloc_data()))
441 return STATUS_NO_MEMORY;
443 chunk_index = fls_chunk_index_from_index( index, &idx );
445 if (!fls->fls_data_chunks[chunk_index] &&
446 !(fls->fls_data_chunks[chunk_index] = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
447 (fls_chunk_size( chunk_index ) + 1) * sizeof(*fls->fls_data_chunks[chunk_index]) )))
448 return STATUS_NO_MEMORY;
450 fls->fls_data_chunks[chunk_index][idx + 1] = data;
452 return STATUS_SUCCESS;
456 /***********************************************************************
457 * RtlFlsGetValue (NTDLL.@)
459 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsGetValue( ULONG index, void **data )
461 unsigned int chunk_index, idx;
462 TEB_FLS_DATA *fls;
464 if (!index || index >= MAX_FLS_DATA_COUNT || !(fls = NtCurrentTeb()->FlsSlots))
465 return STATUS_INVALID_PARAMETER;
467 chunk_index = fls_chunk_index_from_index( index, &idx );
469 *data = fls->fls_data_chunks[chunk_index] ? fls->fls_data_chunks[chunk_index][idx + 1] : NULL;
470 return STATUS_SUCCESS;
474 /***********************************************************************
475 * RtlProcessFlsData (NTDLL.@)
477 void WINAPI DECLSPEC_HOTPATCH RtlProcessFlsData( void *teb_fls_data, ULONG flags )
479 TEB_FLS_DATA *fls = teb_fls_data;
480 unsigned int i, index;
482 TRACE_(thread)( "teb_fls_data %p, flags %#x.\n", teb_fls_data, flags );
484 if (flags & ~3)
485 FIXME_(thread)( "Unknown flags %#x.\n", flags );
487 if (!fls)
488 return;
490 if (flags & 1)
492 lock_fls_data();
493 for (i = 0; i < ARRAY_SIZE(fls->fls_data_chunks); ++i)
495 if (!fls->fls_data_chunks[i] || !fls_data.fls_callback_chunks[i]
496 || !fls_data.fls_callback_chunks[i]->count)
497 continue;
499 for (index = 0; index < fls_chunk_size( i ); ++index)
501 PFLS_CALLBACK_FUNCTION callback = fls_data.fls_callback_chunks[i]->callbacks[index].callback;
503 if (!fls->fls_data_chunks[i][index + 1])
504 continue;
506 if (callback && callback != (void *)~(ULONG_PTR)0)
508 TRACE_(relay)("Calling FLS callback %p, arg %p.\n", callback,
509 fls->fls_data_chunks[i][index + 1]);
511 callback( fls->fls_data_chunks[i][index + 1] );
513 fls->fls_data_chunks[i][index + 1] = NULL;
516 /* Not using RemoveEntryList() as Windows does not zero list entry here. */
517 fls->fls_list_entry.Flink->Blink = fls->fls_list_entry.Blink;
518 fls->fls_list_entry.Blink->Flink = fls->fls_list_entry.Flink;
519 unlock_fls_data();
522 if (flags & 2)
524 for (i = 0; i < ARRAY_SIZE(fls->fls_data_chunks); ++i)
525 RtlFreeHeap( GetProcessHeap(), 0, fls->fls_data_chunks[i] );
527 RtlFreeHeap( GetProcessHeap(), 0, fls );