wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / ntdll / thread.c
blob3cb3bd469ba0a0e81b6fb77c1d82b497d53c72cb
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 = { { NULL }, { &fls_data.fls_list_head, &fls_data.fls_list_head } };
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 static void lock_fls_data(void)
259 RtlEnterCriticalSection( &fls_section );
262 static void unlock_fls_data(void)
264 RtlLeaveCriticalSection( &fls_section );
267 static unsigned int fls_chunk_size( unsigned int chunk_index )
269 return 0x10 << chunk_index;
272 static unsigned int fls_index_from_chunk_index( unsigned int chunk_index, unsigned int index )
274 return 0x10 * ((1 << chunk_index) - 1) + index;
277 static unsigned int fls_chunk_index_from_index( unsigned int index, unsigned int *index_in_chunk )
279 unsigned int chunk_index = 0;
281 while (index >= fls_chunk_size( chunk_index ))
282 index -= fls_chunk_size( chunk_index++ );
284 *index_in_chunk = index;
285 return chunk_index;
288 TEB_FLS_DATA *fls_alloc_data(void)
290 TEB_FLS_DATA *fls;
292 if (!(fls = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*fls) )))
293 return NULL;
295 lock_fls_data();
296 InsertTailList( &fls_data.fls_list_head, &fls->fls_list_entry );
297 unlock_fls_data();
299 return fls;
303 /***********************************************************************
304 * RtlFlsAlloc (NTDLL.@)
306 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsAlloc( PFLS_CALLBACK_FUNCTION callback, ULONG *ret_index )
308 unsigned int chunk_index, index, i;
309 FLS_INFO_CHUNK *chunk;
310 TEB_FLS_DATA *fls;
312 if (!(fls = NtCurrentTeb()->FlsSlots)
313 && !(NtCurrentTeb()->FlsSlots = fls = fls_alloc_data()))
314 return STATUS_NO_MEMORY;
316 lock_fls_data();
317 for (i = 0; i < ARRAY_SIZE(fls_data.fls_callback_chunks); ++i)
319 if (!fls_data.fls_callback_chunks[i] || fls_data.fls_callback_chunks[i]->count < fls_chunk_size( i ))
320 break;
323 if ((chunk_index = i) == ARRAY_SIZE(fls_data.fls_callback_chunks))
325 unlock_fls_data();
326 return STATUS_NO_MEMORY;
329 if ((chunk = fls_data.fls_callback_chunks[chunk_index]))
331 for (index = 0; index < fls_chunk_size( chunk_index ); ++index)
332 if (!chunk->callbacks[index].callback)
333 break;
334 assert( index < fls_chunk_size( chunk_index ));
336 else
338 fls_data.fls_callback_chunks[chunk_index] = chunk = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
339 offsetof(FLS_INFO_CHUNK, callbacks) + sizeof(*chunk->callbacks) * fls_chunk_size( chunk_index ));
340 if (!chunk)
342 unlock_fls_data();
343 return STATUS_NO_MEMORY;
346 if (chunk_index)
348 index = 0;
350 else
352 chunk->count = 1; /* FLS index 0 is prohibited. */
353 chunk->callbacks[0].callback = (void *)~(ULONG_PTR)0;
354 index = 1;
358 ++chunk->count;
359 chunk->callbacks[index].callback = callback ? callback : (PFLS_CALLBACK_FUNCTION)~(ULONG_PTR)0;
361 if ((*ret_index = fls_index_from_chunk_index( chunk_index, index )) > fls_data.fls_high_index)
362 fls_data.fls_high_index = *ret_index;
364 unlock_fls_data();
366 return STATUS_SUCCESS;
370 /***********************************************************************
371 * RtlFlsFree (NTDLL.@)
373 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsFree( ULONG index )
375 PFLS_CALLBACK_FUNCTION callback;
376 unsigned int chunk_index, idx;
377 FLS_INFO_CHUNK *chunk;
378 LIST_ENTRY *entry;
380 lock_fls_data();
382 if (!index || index > fls_data.fls_high_index)
384 unlock_fls_data();
385 return STATUS_INVALID_PARAMETER;
388 chunk_index = fls_chunk_index_from_index( index, &idx );
389 if (!(chunk = fls_data.fls_callback_chunks[chunk_index])
390 || !(callback = chunk->callbacks[idx].callback))
392 unlock_fls_data();
393 return STATUS_INVALID_PARAMETER;
396 for (entry = fls_data.fls_list_head.Flink; entry != &fls_data.fls_list_head; entry = entry->Flink)
398 TEB_FLS_DATA *fls = CONTAINING_RECORD(entry, TEB_FLS_DATA, fls_list_entry);
400 if (fls->fls_data_chunks[chunk_index] && fls->fls_data_chunks[chunk_index][idx + 1])
402 if (callback != (void *)~(ULONG_PTR)0)
404 TRACE_(relay)("Calling FLS callback %p, arg %p.\n", callback,
405 fls->fls_data_chunks[chunk_index][idx + 1]);
407 callback( fls->fls_data_chunks[chunk_index][idx + 1] );
409 fls->fls_data_chunks[chunk_index][idx + 1] = NULL;
413 --chunk->count;
414 chunk->callbacks[idx].callback = NULL;
416 unlock_fls_data();
417 return STATUS_SUCCESS;
421 /***********************************************************************
422 * RtlFlsSetValue (NTDLL.@)
424 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsSetValue( ULONG index, void *data )
426 unsigned int chunk_index, idx;
427 TEB_FLS_DATA *fls;
429 if (!index || index >= MAX_FLS_DATA_COUNT)
430 return STATUS_INVALID_PARAMETER;
432 if (!(fls = NtCurrentTeb()->FlsSlots)
433 && !(NtCurrentTeb()->FlsSlots = fls = fls_alloc_data()))
434 return STATUS_NO_MEMORY;
436 chunk_index = fls_chunk_index_from_index( index, &idx );
438 if (!fls->fls_data_chunks[chunk_index] &&
439 !(fls->fls_data_chunks[chunk_index] = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
440 (fls_chunk_size( chunk_index ) + 1) * sizeof(*fls->fls_data_chunks[chunk_index]) )))
441 return STATUS_NO_MEMORY;
443 fls->fls_data_chunks[chunk_index][idx + 1] = data;
445 return STATUS_SUCCESS;
449 /***********************************************************************
450 * RtlFlsGetValue (NTDLL.@)
452 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsGetValue( ULONG index, void **data )
454 unsigned int chunk_index, idx;
455 TEB_FLS_DATA *fls;
457 if (!index || index >= MAX_FLS_DATA_COUNT || !(fls = NtCurrentTeb()->FlsSlots))
458 return STATUS_INVALID_PARAMETER;
460 chunk_index = fls_chunk_index_from_index( index, &idx );
462 *data = fls->fls_data_chunks[chunk_index] ? fls->fls_data_chunks[chunk_index][idx + 1] : NULL;
463 return STATUS_SUCCESS;
467 /***********************************************************************
468 * RtlProcessFlsData (NTDLL.@)
470 void WINAPI DECLSPEC_HOTPATCH RtlProcessFlsData( void *teb_fls_data, ULONG flags )
472 TEB_FLS_DATA *fls = teb_fls_data;
473 unsigned int i, index;
475 TRACE_(thread)( "teb_fls_data %p, flags %#x.\n", teb_fls_data, flags );
477 if (flags & ~3)
478 FIXME_(thread)( "Unknown flags %#x.\n", flags );
480 if (!fls)
481 return;
483 if (flags & 1)
485 lock_fls_data();
486 for (i = 0; i < ARRAY_SIZE(fls->fls_data_chunks); ++i)
488 if (!fls->fls_data_chunks[i] || !fls_data.fls_callback_chunks[i]
489 || !fls_data.fls_callback_chunks[i]->count)
490 continue;
492 for (index = 0; index < fls_chunk_size( i ); ++index)
494 PFLS_CALLBACK_FUNCTION callback = fls_data.fls_callback_chunks[i]->callbacks[index].callback;
496 if (!fls->fls_data_chunks[i][index + 1])
497 continue;
499 if (callback && callback != (void *)~(ULONG_PTR)0)
501 TRACE_(relay)("Calling FLS callback %p, arg %p.\n", callback,
502 fls->fls_data_chunks[i][index + 1]);
504 callback( fls->fls_data_chunks[i][index + 1] );
506 fls->fls_data_chunks[i][index + 1] = NULL;
509 /* Not using RemoveEntryList() as Windows does not zero list entry here. */
510 fls->fls_list_entry.Flink->Blink = fls->fls_list_entry.Blink;
511 fls->fls_list_entry.Blink->Flink = fls->fls_list_entry.Flink;
512 unlock_fls_data();
515 if (flags & 2)
517 for (i = 0; i < ARRAY_SIZE(fls->fls_data_chunks); ++i)
518 RtlFreeHeap( GetProcessHeap(), 0, fls->fls_data_chunks[i] );
520 RtlFreeHeap( GetProcessHeap(), 0, fls );