reg: Use is_switch() where possible.
[wine.git] / dlls / ntdll / thread.c
blob25496609f0814b5a12beb5da44b1f6558057734b
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/debug.h"
31 #include "ntdll_misc.h"
32 #include "ddk/wdm.h"
33 #include "wine/exception.h"
35 WINE_DECLARE_DEBUG_CHANNEL(relay);
36 WINE_DECLARE_DEBUG_CHANNEL(thread);
38 struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000;
41 /***********************************************************************
42 * __wine_dbg_get_channel_flags (NTDLL.@)
44 * Get the flags to use for a given channel, possibly setting them too in case of lazy init
46 unsigned char __cdecl __wine_dbg_get_channel_flags( struct __wine_debug_channel *channel )
48 return unix_funcs->dbg_get_channel_flags( channel );
51 /***********************************************************************
52 * __wine_dbg_strdup (NTDLL.@)
54 const char * __cdecl __wine_dbg_strdup( const char *str )
56 return unix_funcs->dbg_strdup( str );
59 /***********************************************************************
60 * __wine_dbg_header (NTDLL.@)
62 int __cdecl __wine_dbg_header( enum __wine_debug_class cls, struct __wine_debug_channel *channel,
63 const char *function )
65 return unix_funcs->dbg_header( cls, channel, function );
68 /***********************************************************************
69 * __wine_dbg_output (NTDLL.@)
71 int __cdecl __wine_dbg_output( const char *str )
73 return unix_funcs->dbg_output( str );
77 /***********************************************************************
78 * RtlExitUserThread (NTDLL.@)
80 void WINAPI RtlExitUserThread( ULONG status )
82 ULONG last;
84 NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL );
85 if (last) RtlExitUserProcess( status );
86 LdrShutdownThread();
87 for (;;) NtTerminateThread( GetCurrentThread(), status );
91 /***********************************************************************
92 * RtlUserThreadStart (NTDLL.@)
94 #ifdef __i386__
95 __ASM_STDCALL_FUNC( RtlUserThreadStart, 8,
96 "movl %ebx,8(%esp)\n\t" /* arg */
97 "movl %eax,4(%esp)\n\t" /* entry */
98 "jmp " __ASM_NAME("call_thread_func") )
100 /* wrapper to call BaseThreadInitThunk */
101 extern void DECLSPEC_NORETURN call_thread_func_wrapper( void *thunk, PRTL_THREAD_START_ROUTINE entry, void *arg );
102 __ASM_GLOBAL_FUNC( call_thread_func_wrapper,
103 "pushl %ebp\n\t"
104 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
105 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
106 "movl %esp,%ebp\n\t"
107 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
108 "subl $4,%esp\n\t"
109 "andl $~0xf,%esp\n\t"
110 "xorl %ecx,%ecx\n\t"
111 "movl 12(%ebp),%edx\n\t"
112 "movl 16(%ebp),%eax\n\t"
113 "movl %eax,(%esp)\n\t"
114 "call *8(%ebp)" )
116 void DECLSPEC_HIDDEN call_thread_func( PRTL_THREAD_START_ROUTINE entry, void *arg )
118 __TRY
120 TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
121 call_thread_func_wrapper( pBaseThreadInitThunk, entry, arg );
123 __EXCEPT(call_unhandled_exception_filter)
125 NtTerminateProcess( GetCurrentProcess(), GetExceptionCode() );
127 __ENDTRY
130 #else /* __i386__ */
132 void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg )
134 __TRY
136 TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
137 pBaseThreadInitThunk( 0, (LPTHREAD_START_ROUTINE)entry, arg );
139 __EXCEPT(call_unhandled_exception_filter)
141 NtTerminateProcess( GetCurrentProcess(), GetExceptionCode() );
143 __ENDTRY
146 #endif /* __i386__ */
149 /***********************************************************************
150 * RtlCreateUserThread (NTDLL.@)
152 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr,
153 BOOLEAN suspended, PVOID stack_addr,
154 SIZE_T stack_reserve, SIZE_T stack_commit,
155 PRTL_THREAD_START_ROUTINE start, void *param,
156 HANDLE *handle_ptr, CLIENT_ID *id )
158 ULONG flags = suspended ? THREAD_CREATE_FLAGS_CREATE_SUSPENDED : 0;
159 ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[2] ) / sizeof(ULONG_PTR)];
160 PS_ATTRIBUTE_LIST *attr_list = (PS_ATTRIBUTE_LIST *)buffer;
161 HANDLE handle, actctx;
162 TEB *teb;
163 ULONG ret;
164 NTSTATUS status;
165 CLIENT_ID client_id;
166 OBJECT_ATTRIBUTES attr;
168 attr_list->TotalLength = sizeof(buffer);
169 attr_list->Attributes[0].Attribute = PS_ATTRIBUTE_CLIENT_ID;
170 attr_list->Attributes[0].Size = sizeof(client_id);
171 attr_list->Attributes[0].ValuePtr = &client_id;
172 attr_list->Attributes[0].ReturnLength = NULL;
173 attr_list->Attributes[1].Attribute = PS_ATTRIBUTE_TEB_ADDRESS;
174 attr_list->Attributes[1].Size = sizeof(teb);
175 attr_list->Attributes[1].ValuePtr = &teb;
176 attr_list->Attributes[1].ReturnLength = NULL;
178 InitializeObjectAttributes( &attr, NULL, 0, NULL, descr );
180 RtlGetActiveActivationContext( &actctx );
181 if (actctx) flags |= THREAD_CREATE_FLAGS_CREATE_SUSPENDED;
183 status = NtCreateThreadEx( &handle, THREAD_ALL_ACCESS, &attr, process, start, param,
184 flags, 0, stack_commit, stack_reserve, attr_list );
185 if (!status)
187 if (actctx)
189 ULONG_PTR cookie;
190 RtlActivateActivationContextEx( 0, teb, actctx, &cookie );
191 if (!suspended) NtResumeThread( handle, &ret );
193 if (id) *id = client_id;
194 if (handle_ptr) *handle_ptr = handle;
195 else NtClose( handle );
197 if (actctx) RtlReleaseActivationContext( actctx );
198 return status;
202 /******************************************************************************
203 * RtlGetNtGlobalFlags (NTDLL.@)
205 ULONG WINAPI RtlGetNtGlobalFlags(void)
207 return NtCurrentTeb()->Peb->NtGlobalFlag;
211 /******************************************************************************
212 * RtlPushFrame (NTDLL.@)
214 void WINAPI RtlPushFrame( TEB_ACTIVE_FRAME *frame )
216 frame->Previous = NtCurrentTeb()->ActiveFrame;
217 NtCurrentTeb()->ActiveFrame = frame;
221 /******************************************************************************
222 * RtlPopFrame (NTDLL.@)
224 void WINAPI RtlPopFrame( TEB_ACTIVE_FRAME *frame )
226 NtCurrentTeb()->ActiveFrame = frame->Previous;
230 /******************************************************************************
231 * RtlGetFrame (NTDLL.@)
233 TEB_ACTIVE_FRAME * WINAPI RtlGetFrame(void)
235 return NtCurrentTeb()->ActiveFrame;
239 /***********************************************************************
240 * Fibers
241 ***********************************************************************/
244 static GLOBAL_FLS_DATA fls_data;
246 static RTL_CRITICAL_SECTION fls_section;
247 static RTL_CRITICAL_SECTION_DEBUG fls_critsect_debug =
249 0, 0, &fls_section,
250 { &fls_critsect_debug.ProcessLocksList, &fls_critsect_debug.ProcessLocksList },
251 0, 0, { (DWORD_PTR)(__FILE__ ": fls_section") }
253 static RTL_CRITICAL_SECTION fls_section = { &fls_critsect_debug, -1, 0, 0, 0, 0 };
255 #define MAX_FLS_DATA_COUNT 0xff0
257 void init_global_fls_data(void)
259 InitializeListHead( &fls_data.fls_list_head );
262 static void lock_fls_data(void)
264 RtlEnterCriticalSection( &fls_section );
267 static void unlock_fls_data(void)
269 RtlLeaveCriticalSection( &fls_section );
272 static unsigned int fls_chunk_size( unsigned int chunk_index )
274 return 0x10 << chunk_index;
277 static unsigned int fls_index_from_chunk_index( unsigned int chunk_index, unsigned int index )
279 return 0x10 * ((1 << chunk_index) - 1) + index;
282 static unsigned int fls_chunk_index_from_index( unsigned int index, unsigned int *index_in_chunk )
284 unsigned int chunk_index = 0;
286 while (index >= fls_chunk_size( chunk_index ))
287 index -= fls_chunk_size( chunk_index++ );
289 *index_in_chunk = index;
290 return chunk_index;
293 TEB_FLS_DATA *fls_alloc_data(void)
295 TEB_FLS_DATA *fls;
297 if (!(fls = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*fls) )))
298 return NULL;
300 lock_fls_data();
301 InsertTailList( &fls_data.fls_list_head, &fls->fls_list_entry );
302 unlock_fls_data();
304 return fls;
308 /***********************************************************************
309 * RtlFlsAlloc (NTDLL.@)
311 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsAlloc( PFLS_CALLBACK_FUNCTION callback, ULONG *ret_index )
313 unsigned int chunk_index, index, i;
314 FLS_INFO_CHUNK *chunk;
315 TEB_FLS_DATA *fls;
317 if (!(fls = NtCurrentTeb()->FlsSlots)
318 && !(NtCurrentTeb()->FlsSlots = fls = fls_alloc_data()))
319 return STATUS_NO_MEMORY;
321 lock_fls_data();
322 for (i = 0; i < ARRAY_SIZE(fls_data.fls_callback_chunks); ++i)
324 if (!fls_data.fls_callback_chunks[i] || fls_data.fls_callback_chunks[i]->count < fls_chunk_size( i ))
325 break;
328 if ((chunk_index = i) == ARRAY_SIZE(fls_data.fls_callback_chunks))
330 unlock_fls_data();
331 return STATUS_NO_MEMORY;
334 if ((chunk = fls_data.fls_callback_chunks[chunk_index]))
336 for (index = 0; index < fls_chunk_size( chunk_index ); ++index)
337 if (!chunk->callbacks[index].callback)
338 break;
339 assert( index < fls_chunk_size( chunk_index ));
341 else
343 fls_data.fls_callback_chunks[chunk_index] = chunk = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
344 offsetof(FLS_INFO_CHUNK, callbacks) + sizeof(*chunk->callbacks) * fls_chunk_size( chunk_index ));
345 if (!chunk)
347 unlock_fls_data();
348 return STATUS_NO_MEMORY;
351 if (chunk_index)
353 index = 0;
355 else
357 chunk->count = 1; /* FLS index 0 is prohibited. */
358 chunk->callbacks[0].callback = (void *)~(ULONG_PTR)0;
359 index = 1;
363 ++chunk->count;
364 chunk->callbacks[index].callback = callback ? callback : (PFLS_CALLBACK_FUNCTION)~(ULONG_PTR)0;
366 if ((*ret_index = fls_index_from_chunk_index( chunk_index, index )) > fls_data.fls_high_index)
367 fls_data.fls_high_index = *ret_index;
369 unlock_fls_data();
371 return STATUS_SUCCESS;
375 /***********************************************************************
376 * RtlFlsFree (NTDLL.@)
378 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsFree( ULONG index )
380 PFLS_CALLBACK_FUNCTION callback;
381 unsigned int chunk_index, idx;
382 FLS_INFO_CHUNK *chunk;
383 LIST_ENTRY *entry;
385 lock_fls_data();
387 if (!index || index > fls_data.fls_high_index)
389 unlock_fls_data();
390 return STATUS_INVALID_PARAMETER;
393 chunk_index = fls_chunk_index_from_index( index, &idx );
394 if (!(chunk = fls_data.fls_callback_chunks[chunk_index])
395 || !(callback = chunk->callbacks[idx].callback))
397 unlock_fls_data();
398 return STATUS_INVALID_PARAMETER;
401 for (entry = fls_data.fls_list_head.Flink; entry != &fls_data.fls_list_head; entry = entry->Flink)
403 TEB_FLS_DATA *fls = CONTAINING_RECORD(entry, TEB_FLS_DATA, fls_list_entry);
405 if (fls->fls_data_chunks[chunk_index] && fls->fls_data_chunks[chunk_index][idx + 1])
407 if (callback != (void *)~(ULONG_PTR)0)
409 TRACE_(relay)("Calling FLS callback %p, arg %p.\n", callback,
410 fls->fls_data_chunks[chunk_index][idx + 1]);
412 callback( fls->fls_data_chunks[chunk_index][idx + 1] );
414 fls->fls_data_chunks[chunk_index][idx + 1] = NULL;
418 --chunk->count;
419 chunk->callbacks[idx].callback = NULL;
421 unlock_fls_data();
422 return STATUS_SUCCESS;
426 /***********************************************************************
427 * RtlFlsSetValue (NTDLL.@)
429 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsSetValue( ULONG index, void *data )
431 unsigned int chunk_index, idx;
432 TEB_FLS_DATA *fls;
434 if (!index || index >= MAX_FLS_DATA_COUNT)
435 return STATUS_INVALID_PARAMETER;
437 if (!(fls = NtCurrentTeb()->FlsSlots)
438 && !(NtCurrentTeb()->FlsSlots = fls = fls_alloc_data()))
439 return STATUS_NO_MEMORY;
441 chunk_index = fls_chunk_index_from_index( index, &idx );
443 if (!fls->fls_data_chunks[chunk_index] &&
444 !(fls->fls_data_chunks[chunk_index] = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
445 (fls_chunk_size( chunk_index ) + 1) * sizeof(*fls->fls_data_chunks[chunk_index]) )))
446 return STATUS_NO_MEMORY;
448 fls->fls_data_chunks[chunk_index][idx + 1] = data;
450 return STATUS_SUCCESS;
454 /***********************************************************************
455 * RtlFlsGetValue (NTDLL.@)
457 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsGetValue( ULONG index, void **data )
459 unsigned int chunk_index, idx;
460 TEB_FLS_DATA *fls;
462 if (!index || index >= MAX_FLS_DATA_COUNT || !(fls = NtCurrentTeb()->FlsSlots))
463 return STATUS_INVALID_PARAMETER;
465 chunk_index = fls_chunk_index_from_index( index, &idx );
467 *data = fls->fls_data_chunks[chunk_index] ? fls->fls_data_chunks[chunk_index][idx + 1] : NULL;
468 return STATUS_SUCCESS;
472 /***********************************************************************
473 * RtlProcessFlsData (NTDLL.@)
475 void WINAPI DECLSPEC_HOTPATCH RtlProcessFlsData( void *teb_fls_data, ULONG flags )
477 TEB_FLS_DATA *fls = teb_fls_data;
478 unsigned int i, index;
480 TRACE_(thread)( "teb_fls_data %p, flags %#x.\n", teb_fls_data, flags );
482 if (flags & ~3)
483 FIXME_(thread)( "Unknown flags %#x.\n", flags );
485 if (!fls)
486 return;
488 if (flags & 1)
490 lock_fls_data();
491 for (i = 0; i < ARRAY_SIZE(fls->fls_data_chunks); ++i)
493 if (!fls->fls_data_chunks[i] || !fls_data.fls_callback_chunks[i]
494 || !fls_data.fls_callback_chunks[i]->count)
495 continue;
497 for (index = 0; index < fls_chunk_size( i ); ++index)
499 PFLS_CALLBACK_FUNCTION callback = fls_data.fls_callback_chunks[i]->callbacks[index].callback;
501 if (!fls->fls_data_chunks[i][index + 1])
502 continue;
504 if (callback && callback != (void *)~(ULONG_PTR)0)
506 TRACE_(relay)("Calling FLS callback %p, arg %p.\n", callback,
507 fls->fls_data_chunks[i][index + 1]);
509 callback( fls->fls_data_chunks[i][index + 1] );
511 fls->fls_data_chunks[i][index + 1] = NULL;
514 /* Not using RemoveEntryList() as Windows does not zero list entry here. */
515 fls->fls_list_entry.Flink->Blink = fls->fls_list_entry.Blink;
516 fls->fls_list_entry.Blink->Flink = fls->fls_list_entry.Flink;
517 unlock_fls_data();
520 if (flags & 2)
522 for (i = 0; i < ARRAY_SIZE(fls->fls_data_chunks); ++i)
523 RtlFreeHeap( GetProcessHeap(), 0, fls->fls_data_chunks[i] );
525 RtlFreeHeap( GetProcessHeap(), 0, fls );