1 /* $Id: thread.c,v 1.34 2003/01/22 02:24:36 ekohl Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/thread/thread.c
6 * PURPOSE: Thread functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Tls functions are modified from WINE
13 /* INCLUDES ******************************************************************/
18 #include <kernel32/kernel32.h>
21 //static VOID ThreadAttachDlls (VOID);
23 /* FUNCTIONS *****************************************************************/
25 static EXCEPTION_DISPOSITION __cdecl
26 _except_handler(struct _EXCEPTION_RECORD
*ExceptionRecord
,
27 void * EstablisherFrame
,
28 struct _CONTEXT
*ContextRecord
,
29 void * DispatcherContext
)
33 /* We should not get to here */
34 return(ExceptionContinueSearch
);
39 ThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress
,
44 __try1(_except_handler
)
46 /* FIXME: notify csrss of thread creation ?? */
47 uExitCode
= (lpStartAddress
)(lpParameter
);
53 ExitThread(uExitCode
);
58 CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes
,
60 LPTHREAD_START_ROUTINE lpStartAddress
,
62 DWORD dwCreationFlags
,
65 return(CreateRemoteThread(NtCurrentProcess(),
76 CreateRemoteThread(HANDLE hProcess
,
77 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
79 LPTHREAD_START_ROUTINE lpStartAddress
,
81 DWORD dwCreationFlags
,
85 OBJECT_ATTRIBUTES ObjectAttributes
;
87 CONTEXT ThreadContext
;
88 INITIAL_TEB InitialTeb
;
89 BOOLEAN CreateSuspended
= FALSE
;
91 ULONG OldPageProtection
;
94 ObjectAttributes
.Length
= sizeof(OBJECT_ATTRIBUTES
);
95 ObjectAttributes
.RootDirectory
= NULL
;
96 ObjectAttributes
.ObjectName
= NULL
;
97 ObjectAttributes
.Attributes
= 0;
98 if (lpThreadAttributes
!= NULL
)
100 if (lpThreadAttributes
->bInheritHandle
)
101 ObjectAttributes
.Attributes
= OBJ_INHERIT
;
102 ObjectAttributes
.SecurityDescriptor
=
103 lpThreadAttributes
->lpSecurityDescriptor
;
105 ObjectAttributes
.SecurityQualityOfService
= NULL
;
107 if ((dwCreationFlags
& CREATE_SUSPENDED
) == CREATE_SUSPENDED
)
108 CreateSuspended
= TRUE
;
110 CreateSuspended
= FALSE
;
112 InitialTeb
.StackReserve
= 0x100000; /* 1MByte */
113 /* FIXME: use correct commit size */
115 InitialTeb
.StackCommit
= (dwStackSize
== 0) ? PAGE_SIZE
: dwStackSize
;
117 InitialTeb
.StackCommit
= InitialTeb
.StackReserve
- PAGE_SIZE
;
119 /* size of guard page */
120 InitialTeb
.StackCommit
+= PAGE_SIZE
;
123 InitialTeb
.StackAllocate
= NULL
;
124 Status
= NtAllocateVirtualMemory(hProcess
,
125 &InitialTeb
.StackAllocate
,
127 &InitialTeb
.StackReserve
,
130 if (!NT_SUCCESS(Status
))
132 DPRINT("Error reserving stack space!\n");
133 SetLastErrorByStatus(Status
);
137 DPRINT("StackDeallocation: %p ReserveSize: 0x%lX\n",
138 InitialTeb
.StackDeallocation
, InitialTeb
.StackReserve
);
140 InitialTeb
.StackBase
= (PVOID
)((ULONG
)InitialTeb
.StackAllocate
+ InitialTeb
.StackReserve
);
141 InitialTeb
.StackLimit
= (PVOID
)((ULONG
)InitialTeb
.StackBase
- InitialTeb
.StackCommit
);
143 DPRINT("StackBase: %p\nStackCommit: 0x%lX\n",
144 InitialTeb
.StackBase
,
145 InitialTeb
.StackCommit
);
147 /* Commit stack pages */
148 Status
= NtAllocateVirtualMemory(hProcess
,
149 &InitialTeb
.StackLimit
,
151 &InitialTeb
.StackCommit
,
154 if (!NT_SUCCESS(Status
))
156 /* release the stack space */
157 NtFreeVirtualMemory(hProcess
,
158 InitialTeb
.StackAllocate
,
159 &InitialTeb
.StackReserve
,
162 DPRINT("Error comitting stack page(s)!\n");
163 SetLastErrorByStatus(Status
);
167 DPRINT("StackLimit: %p\n",
168 InitialTeb
.StackLimit
);
170 /* Protect guard page */
171 Status
= NtProtectVirtualMemory(hProcess
,
172 InitialTeb
.StackLimit
,
174 PAGE_GUARD
| PAGE_READWRITE
,
176 if (!NT_SUCCESS(Status
))
178 /* release the stack space */
179 NtFreeVirtualMemory(hProcess
,
180 InitialTeb
.StackAllocate
,
181 &InitialTeb
.StackReserve
,
184 DPRINT("Error comitting guard page!\n");
185 SetLastErrorByStatus(Status
);
189 memset(&ThreadContext
,0,sizeof(CONTEXT
));
190 ThreadContext
.Eip
= (LONG
)ThreadStartup
;
191 ThreadContext
.SegGs
= USER_DS
;
192 ThreadContext
.SegFs
= TEB_SELECTOR
;
193 ThreadContext
.SegEs
= USER_DS
;
194 ThreadContext
.SegDs
= USER_DS
;
195 ThreadContext
.SegCs
= USER_CS
;
196 ThreadContext
.SegSs
= USER_DS
;
197 ThreadContext
.Esp
= (ULONG
)InitialTeb
.StackBase
- 12;
198 ThreadContext
.EFlags
= (1<<1) + (1<<9);
200 /* initialize call stack */
201 *((PULONG
)((ULONG
)InitialTeb
.StackBase
- 4)) = (ULONG
)lpParameter
;
202 *((PULONG
)((ULONG
)InitialTeb
.StackBase
- 8)) = (ULONG
)lpStartAddress
;
203 *((PULONG
)((ULONG
)InitialTeb
.StackBase
- 12)) = 0xdeadbeef;
205 DPRINT("Esp: %p\n", ThreadContext
.Esp
);
206 DPRINT("Eip: %p\n", ThreadContext
.Eip
);
208 Status
= NtCreateThread(&ThreadHandle
,
216 if (!NT_SUCCESS(Status
))
218 NtFreeVirtualMemory(hProcess
,
219 InitialTeb
.StackAllocate
,
220 &InitialTeb
.StackReserve
,
223 DPRINT("NtCreateThread() failed!\n");
224 SetLastErrorByStatus(Status
);
228 if (lpThreadId
!= NULL
)
229 memcpy(lpThreadId
, &ClientId
.UniqueThread
,sizeof(ULONG
));
231 return(ThreadHandle
);
238 return(NtCurrentTeb());
246 errCode
= NtYieldExecution();
252 GetCurrentThreadId(VOID
)
254 return((DWORD
)(NtCurrentTeb()->Cid
).UniqueThread
);
259 ExitThread(DWORD uExitCode
)
265 * Terminate process if this is the last thread
266 * of the current process
268 Status
= NtQueryInformationThread(NtCurrentThread(),
273 if (NT_SUCCESS(Status
) && LastThread
== TRUE
)
275 ExitProcess(uExitCode
);
278 /* FIXME: notify csrss of thread termination */
282 Status
= NtTerminateThread(NtCurrentThread(),
284 if (!NT_SUCCESS(Status
))
286 SetLastErrorByStatus(Status
);
292 GetThreadTimes(HANDLE hThread
,
293 LPFILETIME lpCreationTime
,
294 LPFILETIME lpExitTime
,
295 LPFILETIME lpKernelTime
,
296 LPFILETIME lpUserTime
)
298 KERNEL_USER_TIMES KernelUserTimes
;
302 Status
= NtQueryInformationThread(hThread
,
305 sizeof(KERNEL_USER_TIMES
),
307 if (!NT_SUCCESS(Status
))
309 SetLastErrorByStatus(Status
);
313 memcpy(lpCreationTime
, &KernelUserTimes
.CreateTime
, sizeof(FILETIME
));
314 memcpy(lpExitTime
, &KernelUserTimes
.ExitTime
, sizeof(FILETIME
));
315 memcpy(lpKernelTime
, &KernelUserTimes
.KernelTime
, sizeof(FILETIME
));
316 memcpy(lpUserTime
, &KernelUserTimes
.UserTime
, sizeof(FILETIME
));
323 GetThreadContext(HANDLE hThread
,
328 Status
= NtGetContextThread(hThread
,
330 if (!NT_SUCCESS(Status
))
332 SetLastErrorByStatus(Status
);
341 SetThreadContext(HANDLE hThread
,
342 CONST CONTEXT
*lpContext
)
346 Status
= NtSetContextThread(hThread
,
348 if (!NT_SUCCESS(Status
))
350 SetLastErrorByStatus(Status
);
359 GetExitCodeThread(HANDLE hThread
,
362 THREAD_BASIC_INFORMATION ThreadBasic
;
366 Status
= NtQueryInformationThread(hThread
,
367 ThreadBasicInformation
,
369 sizeof(THREAD_BASIC_INFORMATION
),
371 if (!NT_SUCCESS(Status
))
373 SetLastErrorByStatus(Status
);
377 memcpy(lpExitCode
, &ThreadBasic
.ExitStatus
, sizeof(DWORD
));
384 ResumeThread(HANDLE hThread
)
386 ULONG PreviousResumeCount
;
389 Status
= NtResumeThread(hThread
,
390 &PreviousResumeCount
);
391 if (!NT_SUCCESS(Status
))
393 SetLastErrorByStatus(Status
);
397 return(PreviousResumeCount
);
402 TerminateThread(HANDLE hThread
,
409 SetLastError(ERROR_INVALID_HANDLE
);
413 Status
= NtTerminateThread(hThread
,
415 if (!NT_SUCCESS(Status
))
417 SetLastErrorByStatus(Status
);
426 SuspendThread(HANDLE hThread
)
428 ULONG PreviousSuspendCount
;
431 Status
= NtSuspendThread(hThread
,
432 &PreviousSuspendCount
);
433 if (!NT_SUCCESS(Status
))
435 SetLastErrorByStatus(Status
);
439 return(PreviousSuspendCount
);
444 SetThreadAffinityMask(HANDLE hThread
,
445 DWORD dwThreadAffinityMask
)
447 THREAD_BASIC_INFORMATION ThreadBasic
;
448 KAFFINITY AffinityMask
;
452 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
454 Status
= NtQueryInformationThread(hThread
,
455 ThreadBasicInformation
,
457 sizeof(THREAD_BASIC_INFORMATION
),
459 if (!NT_SUCCESS(Status
))
461 SetLastErrorByStatus(Status
);
465 Status
= NtSetInformationThread(hThread
,
469 if (!NT_SUCCESS(Status
))
470 SetLastErrorByStatus(Status
);
472 return(ThreadBasic
.AffinityMask
);
477 SetThreadPriority(HANDLE hThread
,
480 THREAD_BASIC_INFORMATION ThreadBasic
;
484 Status
= NtQueryInformationThread(hThread
,
485 ThreadBasicInformation
,
487 sizeof(THREAD_BASIC_INFORMATION
),
489 if (!NT_SUCCESS(Status
))
491 SetLastErrorByStatus(Status
);
495 ThreadBasic
.BasePriority
= nPriority
;
497 Status
= NtSetInformationThread(hThread
,
498 ThreadBasicInformation
,
500 sizeof(THREAD_BASIC_INFORMATION
));
501 if (!NT_SUCCESS(Status
))
503 SetLastErrorByStatus(Status
);
512 GetThreadPriority(HANDLE hThread
)
514 THREAD_BASIC_INFORMATION ThreadBasic
;
518 Status
= NtQueryInformationThread(hThread
,
519 ThreadBasicInformation
,
521 sizeof(THREAD_BASIC_INFORMATION
),
523 if (!NT_SUCCESS(Status
))
525 SetLastErrorByStatus(Status
);
526 return(THREAD_PRIORITY_ERROR_RETURN
);
529 return(ThreadBasic
.BasePriority
);
534 GetThreadPriorityBoost(IN HANDLE hThread
,
535 OUT PBOOL pDisablePriorityBoost
)
541 Status
= NtQueryInformationThread(hThread
,
546 if (!NT_SUCCESS(Status
))
548 SetLastErrorByStatus(Status
);
552 *pDisablePriorityBoost
= !((WINBOOL
)PriorityBoost
);
559 SetThreadPriorityBoost(IN HANDLE hThread
,
560 IN WINBOOL bDisablePriorityBoost
)
565 PriorityBoost
= (ULONG
)!bDisablePriorityBoost
;
567 Status
= NtSetInformationThread(hThread
,
571 if (!NT_SUCCESS(Status
))
573 SetLastErrorByStatus(Status
);
582 GetThreadSelectorEntry(IN HANDLE hThread
,
584 OUT LPLDT_ENTRY lpSelectorEntry
)
586 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);