server: Support unbound console input device.
[wine.git] / dlls / ntdll / thread.c
blob578c7a5436c5a2bf8278d781cb7b10538c0cd6a8
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 * KiUserApcDispatcher (NTDLL.@)
81 void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
82 PNTAPCFUNC func )
84 func( ctx, arg1, arg2 );
85 NtContinue( context, TRUE );
89 /***********************************************************************
90 * RtlExitUserThread (NTDLL.@)
92 void WINAPI RtlExitUserThread( ULONG status )
94 ULONG last;
96 NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL );
97 if (last) RtlExitUserProcess( status );
98 LdrShutdownThread();
99 RtlFreeThreadActivationContextStack();
100 for (;;) NtTerminateThread( GetCurrentThread(), status );
104 /***********************************************************************
105 * RtlUserThreadStart (NTDLL.@)
107 #ifdef __i386__
108 __ASM_STDCALL_FUNC( RtlUserThreadStart, 8,
109 "movl %ebx,8(%esp)\n\t" /* arg */
110 "movl %eax,4(%esp)\n\t" /* entry */
111 "jmp " __ASM_NAME("call_thread_func") )
113 /* wrapper to call BaseThreadInitThunk */
114 extern void DECLSPEC_NORETURN call_thread_func_wrapper( void *thunk, PRTL_THREAD_START_ROUTINE entry, void *arg );
115 __ASM_GLOBAL_FUNC( call_thread_func_wrapper,
116 "pushl %ebp\n\t"
117 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
118 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
119 "movl %esp,%ebp\n\t"
120 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
121 "subl $4,%esp\n\t"
122 "andl $~0xf,%esp\n\t"
123 "xorl %ecx,%ecx\n\t"
124 "movl 12(%ebp),%edx\n\t"
125 "movl 16(%ebp),%eax\n\t"
126 "movl %eax,(%esp)\n\t"
127 "call *8(%ebp)" )
129 void DECLSPEC_HIDDEN call_thread_func( PRTL_THREAD_START_ROUTINE entry, void *arg )
131 __TRY
133 TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
134 call_thread_func_wrapper( pBaseThreadInitThunk, entry, arg );
136 __EXCEPT(call_unhandled_exception_filter)
138 NtTerminateProcess( GetCurrentThread(), GetExceptionCode() );
140 __ENDTRY
143 #else /* __i386__ */
145 void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg )
147 __TRY
149 TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
150 pBaseThreadInitThunk( 0, (LPTHREAD_START_ROUTINE)entry, arg );
152 __EXCEPT(call_unhandled_exception_filter)
154 NtTerminateProcess( GetCurrentThread(), GetExceptionCode() );
156 __ENDTRY
159 #endif /* __i386__ */
162 /***********************************************************************
163 * RtlCreateUserThread (NTDLL.@)
165 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr,
166 BOOLEAN suspended, PVOID stack_addr,
167 SIZE_T stack_reserve, SIZE_T stack_commit,
168 PRTL_THREAD_START_ROUTINE start, void *param,
169 HANDLE *handle_ptr, CLIENT_ID *id )
171 ULONG flags = suspended ? THREAD_CREATE_FLAGS_CREATE_SUSPENDED : 0;
172 ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[2] ) / sizeof(ULONG_PTR)];
173 PS_ATTRIBUTE_LIST *attr_list = (PS_ATTRIBUTE_LIST *)buffer;
174 HANDLE handle, actctx;
175 TEB *teb;
176 ULONG ret;
177 NTSTATUS status;
178 CLIENT_ID client_id;
179 OBJECT_ATTRIBUTES attr;
181 attr_list->TotalLength = sizeof(buffer);
182 attr_list->Attributes[0].Attribute = PS_ATTRIBUTE_CLIENT_ID;
183 attr_list->Attributes[0].Size = sizeof(client_id);
184 attr_list->Attributes[0].ValuePtr = &client_id;
185 attr_list->Attributes[0].ReturnLength = NULL;
186 attr_list->Attributes[1].Attribute = PS_ATTRIBUTE_TEB_ADDRESS;
187 attr_list->Attributes[1].Size = sizeof(teb);
188 attr_list->Attributes[1].ValuePtr = &teb;
189 attr_list->Attributes[1].ReturnLength = NULL;
191 InitializeObjectAttributes( &attr, NULL, 0, NULL, descr );
193 RtlGetActiveActivationContext( &actctx );
194 if (actctx) flags |= THREAD_CREATE_FLAGS_CREATE_SUSPENDED;
196 status = NtCreateThreadEx( &handle, THREAD_ALL_ACCESS, &attr, process, start, param,
197 flags, 0, stack_commit, stack_reserve, attr_list );
198 if (!status)
200 if (actctx)
202 ULONG_PTR cookie;
203 RtlActivateActivationContextEx( 0, teb, actctx, &cookie );
204 if (!suspended) NtResumeThread( handle, &ret );
206 if (id) *id = client_id;
207 if (handle_ptr) *handle_ptr = handle;
208 else NtClose( handle );
210 if (actctx) RtlReleaseActivationContext( actctx );
211 return status;
215 /******************************************************************************
216 * RtlGetNtGlobalFlags (NTDLL.@)
218 ULONG WINAPI RtlGetNtGlobalFlags(void)
220 return NtCurrentTeb()->Peb->NtGlobalFlag;
224 /******************************************************************************
225 * RtlPushFrame (NTDLL.@)
227 void WINAPI RtlPushFrame( TEB_ACTIVE_FRAME *frame )
229 frame->Previous = NtCurrentTeb()->ActiveFrame;
230 NtCurrentTeb()->ActiveFrame = frame;
234 /******************************************************************************
235 * RtlPopFrame (NTDLL.@)
237 void WINAPI RtlPopFrame( TEB_ACTIVE_FRAME *frame )
239 NtCurrentTeb()->ActiveFrame = frame->Previous;
243 /******************************************************************************
244 * RtlGetFrame (NTDLL.@)
246 TEB_ACTIVE_FRAME * WINAPI RtlGetFrame(void)
248 return NtCurrentTeb()->ActiveFrame;
252 /***********************************************************************
253 * Fibers
254 ***********************************************************************/
257 static GLOBAL_FLS_DATA fls_data;
259 static RTL_CRITICAL_SECTION fls_section;
260 static RTL_CRITICAL_SECTION_DEBUG fls_critsect_debug =
262 0, 0, &fls_section,
263 { &fls_critsect_debug.ProcessLocksList, &fls_critsect_debug.ProcessLocksList },
264 0, 0, { (DWORD_PTR)(__FILE__ ": fls_section") }
266 static RTL_CRITICAL_SECTION fls_section = { &fls_critsect_debug, -1, 0, 0, 0, 0 };
268 #define MAX_FLS_DATA_COUNT 0xff0
270 void init_global_fls_data(void)
272 InitializeListHead( &fls_data.fls_list_head );
275 static void lock_fls_data(void)
277 RtlEnterCriticalSection( &fls_section );
280 static void unlock_fls_data(void)
282 RtlLeaveCriticalSection( &fls_section );
285 static unsigned int fls_chunk_size( unsigned int chunk_index )
287 return 0x10 << chunk_index;
290 static unsigned int fls_index_from_chunk_index( unsigned int chunk_index, unsigned int index )
292 return 0x10 * ((1 << chunk_index) - 1) + index;
295 static unsigned int fls_chunk_index_from_index( unsigned int index, unsigned int *index_in_chunk )
297 unsigned int chunk_index = 0;
299 while (index >= fls_chunk_size( chunk_index ))
300 index -= fls_chunk_size( chunk_index++ );
302 *index_in_chunk = index;
303 return chunk_index;
306 TEB_FLS_DATA *fls_alloc_data(void)
308 TEB_FLS_DATA *fls;
310 if (!(fls = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*fls) )))
311 return NULL;
313 lock_fls_data();
314 InsertTailList( &fls_data.fls_list_head, &fls->fls_list_entry );
315 unlock_fls_data();
317 return fls;
321 /***********************************************************************
322 * RtlFlsAlloc (NTDLL.@)
324 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsAlloc( PFLS_CALLBACK_FUNCTION callback, ULONG *ret_index )
326 unsigned int chunk_index, index, i;
327 FLS_INFO_CHUNK *chunk;
328 TEB_FLS_DATA *fls;
330 if (!(fls = NtCurrentTeb()->FlsSlots)
331 && !(NtCurrentTeb()->FlsSlots = fls = fls_alloc_data()))
332 return STATUS_NO_MEMORY;
334 lock_fls_data();
335 for (i = 0; i < ARRAY_SIZE(fls_data.fls_callback_chunks); ++i)
337 if (!fls_data.fls_callback_chunks[i] || fls_data.fls_callback_chunks[i]->count < fls_chunk_size( i ))
338 break;
341 if ((chunk_index = i) == ARRAY_SIZE(fls_data.fls_callback_chunks))
343 unlock_fls_data();
344 return STATUS_NO_MEMORY;
347 if ((chunk = fls_data.fls_callback_chunks[chunk_index]))
349 for (index = 0; index < fls_chunk_size( chunk_index ); ++index)
350 if (!chunk->callbacks[index].callback)
351 break;
352 assert( index < fls_chunk_size( chunk_index ));
354 else
356 fls_data.fls_callback_chunks[chunk_index] = chunk = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
357 offsetof(FLS_INFO_CHUNK, callbacks) + sizeof(*chunk->callbacks) * fls_chunk_size( chunk_index ));
358 if (!chunk)
360 unlock_fls_data();
361 return STATUS_NO_MEMORY;
364 if (chunk_index)
366 index = 0;
368 else
370 chunk->count = 1; /* FLS index 0 is prohibited. */
371 chunk->callbacks[0].callback = (void *)~(ULONG_PTR)0;
372 index = 1;
376 ++chunk->count;
377 chunk->callbacks[index].callback = callback ? callback : (PFLS_CALLBACK_FUNCTION)~(ULONG_PTR)0;
379 if ((*ret_index = fls_index_from_chunk_index( chunk_index, index )) > fls_data.fls_high_index)
380 fls_data.fls_high_index = *ret_index;
382 unlock_fls_data();
384 return STATUS_SUCCESS;
388 /***********************************************************************
389 * RtlFlsFree (NTDLL.@)
391 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsFree( ULONG index )
393 PFLS_CALLBACK_FUNCTION callback;
394 unsigned int chunk_index, idx;
395 FLS_INFO_CHUNK *chunk;
396 LIST_ENTRY *entry;
398 lock_fls_data();
400 if (!index || index > fls_data.fls_high_index)
402 unlock_fls_data();
403 return STATUS_INVALID_PARAMETER;
406 chunk_index = fls_chunk_index_from_index( index, &idx );
407 if (!(chunk = fls_data.fls_callback_chunks[chunk_index])
408 || !(callback = chunk->callbacks[idx].callback))
410 unlock_fls_data();
411 return STATUS_INVALID_PARAMETER;
414 for (entry = fls_data.fls_list_head.Flink; entry != &fls_data.fls_list_head; entry = entry->Flink)
416 TEB_FLS_DATA *fls = CONTAINING_RECORD(entry, TEB_FLS_DATA, fls_list_entry);
418 if (fls->fls_data_chunks[chunk_index] && fls->fls_data_chunks[chunk_index][idx + 1])
420 if (callback != (void *)~(ULONG_PTR)0)
422 TRACE_(relay)("Calling FLS callback %p, arg %p.\n", callback,
423 fls->fls_data_chunks[chunk_index][idx + 1]);
425 callback( fls->fls_data_chunks[chunk_index][idx + 1] );
427 fls->fls_data_chunks[chunk_index][idx + 1] = NULL;
431 --chunk->count;
432 chunk->callbacks[idx].callback = NULL;
434 unlock_fls_data();
435 return STATUS_SUCCESS;
439 /***********************************************************************
440 * RtlFlsSetValue (NTDLL.@)
442 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsSetValue( ULONG index, void *data )
444 unsigned int chunk_index, idx;
445 TEB_FLS_DATA *fls;
447 if (!index || index >= MAX_FLS_DATA_COUNT)
448 return STATUS_INVALID_PARAMETER;
450 if (!(fls = NtCurrentTeb()->FlsSlots)
451 && !(NtCurrentTeb()->FlsSlots = fls = fls_alloc_data()))
452 return STATUS_NO_MEMORY;
454 chunk_index = fls_chunk_index_from_index( index, &idx );
456 if (!fls->fls_data_chunks[chunk_index] &&
457 !(fls->fls_data_chunks[chunk_index] = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
458 (fls_chunk_size( chunk_index ) + 1) * sizeof(*fls->fls_data_chunks[chunk_index]) )))
459 return STATUS_NO_MEMORY;
461 fls->fls_data_chunks[chunk_index][idx + 1] = data;
463 return STATUS_SUCCESS;
467 /***********************************************************************
468 * RtlFlsGetValue (NTDLL.@)
470 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsGetValue( ULONG index, void **data )
472 unsigned int chunk_index, idx;
473 TEB_FLS_DATA *fls;
475 if (!index || index >= MAX_FLS_DATA_COUNT || !(fls = NtCurrentTeb()->FlsSlots))
476 return STATUS_INVALID_PARAMETER;
478 chunk_index = fls_chunk_index_from_index( index, &idx );
480 *data = fls->fls_data_chunks[chunk_index] ? fls->fls_data_chunks[chunk_index][idx + 1] : NULL;
481 return STATUS_SUCCESS;
485 /***********************************************************************
486 * RtlProcessFlsData (NTDLL.@)
488 void WINAPI DECLSPEC_HOTPATCH RtlProcessFlsData( void *teb_fls_data, ULONG flags )
490 TEB_FLS_DATA *fls = teb_fls_data;
491 unsigned int i, index;
493 TRACE_(thread)( "teb_fls_data %p, flags %#x.\n", teb_fls_data, flags );
495 if (flags & ~3)
496 FIXME_(thread)( "Unknown flags %#x.\n", flags );
498 if (!fls)
499 return;
501 if (flags & 1)
503 lock_fls_data();
504 for (i = 0; i < ARRAY_SIZE(fls->fls_data_chunks); ++i)
506 if (!fls->fls_data_chunks[i] || !fls_data.fls_callback_chunks[i]
507 || !fls_data.fls_callback_chunks[i]->count)
508 continue;
510 for (index = 0; index < fls_chunk_size( i ); ++index)
512 PFLS_CALLBACK_FUNCTION callback = fls_data.fls_callback_chunks[i]->callbacks[index].callback;
514 if (!fls->fls_data_chunks[i][index + 1])
515 continue;
517 if (callback && callback != (void *)~(ULONG_PTR)0)
519 TRACE_(relay)("Calling FLS callback %p, arg %p.\n", callback,
520 fls->fls_data_chunks[i][index + 1]);
522 callback( fls->fls_data_chunks[i][index + 1] );
524 fls->fls_data_chunks[i][index + 1] = NULL;
527 /* Not using RemoveEntryList() as Windows does not zero list entry here. */
528 fls->fls_list_entry.Flink->Blink = fls->fls_list_entry.Blink;
529 fls->fls_list_entry.Blink->Flink = fls->fls_list_entry.Flink;
530 unlock_fls_data();
533 if (flags & 2)
535 for (i = 0; i < ARRAY_SIZE(fls->fls_data_chunks); ++i)
536 RtlFreeHeap( GetProcessHeap(), 0, fls->fls_data_chunks[i] );
538 RtlFreeHeap( GetProcessHeap(), 0, fls );