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
24 #include <sys/types.h>
26 #define NONAMELESSUNION
28 #define WIN32_NO_STATUS
30 #include "wine/server.h"
31 #include "wine/debug.h"
32 #include "ntdll_misc.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
,
84 func( ctx
, arg1
, arg2
);
85 NtContinue( context
, TRUE
);
89 /***********************************************************************
90 * RtlExitUserThread (NTDLL.@)
92 void WINAPI
RtlExitUserThread( ULONG status
)
96 NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread
, &last
, sizeof(last
), NULL
);
97 if (last
) RtlExitUserProcess( status
);
99 RtlFreeThreadActivationContextStack();
100 for (;;) NtTerminateThread( GetCurrentThread(), status
);
104 /***********************************************************************
105 * RtlUserThreadStart (NTDLL.@)
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
,
117 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
118 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
120 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
122 "andl $~0xf,%esp\n\t"
124 "movl 12(%ebp),%edx\n\t"
125 "movl 16(%ebp),%eax\n\t"
126 "movl %eax,(%esp)\n\t"
129 void DECLSPEC_HIDDEN
call_thread_func( PRTL_THREAD_START_ROUTINE entry
, void *arg
)
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() );
145 void WINAPI
RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry
, void *arg
)
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() );
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
;
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
);
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
);
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 /***********************************************************************
254 ***********************************************************************/
257 static GLOBAL_FLS_DATA fls_data
;
259 static RTL_CRITICAL_SECTION fls_section
;
260 static RTL_CRITICAL_SECTION_DEBUG fls_critsect_debug
=
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
;
306 TEB_FLS_DATA
*fls_alloc_data(void)
310 if (!(fls
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*fls
) )))
314 InsertTailList( &fls_data
.fls_list_head
, &fls
->fls_list_entry
);
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
;
330 if (!(fls
= NtCurrentTeb()->FlsSlots
)
331 && !(NtCurrentTeb()->FlsSlots
= fls
= fls_alloc_data()))
332 return STATUS_NO_MEMORY
;
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
))
341 if ((chunk_index
= i
) == ARRAY_SIZE(fls_data
.fls_callback_chunks
))
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
)
352 assert( index
< fls_chunk_size( chunk_index
));
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
));
361 return STATUS_NO_MEMORY
;
370 chunk
->count
= 1; /* FLS index 0 is prohibited. */
371 chunk
->callbacks
[0].callback
= (void *)~(ULONG_PTR
)0;
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
;
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
;
400 if (!index
|| index
> fls_data
.fls_high_index
)
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
))
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
;
432 chunk
->callbacks
[idx
].callback
= NULL
;
435 return STATUS_SUCCESS
;
439 /***********************************************************************
440 * RtlFlsSetValue (NTDLL.@)
442 NTSTATUS WINAPI DECLSPEC_HOTPATCH
RtlFlsSetValue( ULONG index
, void *data
)
444 unsigned int chunk_index
, idx
;
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
;
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
);
496 FIXME_(thread
)( "Unknown flags %#x.\n", flags
);
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
)
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])
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
;
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
);