4 * Copyright 1996 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_TIMES_H
29 #include <sys/times.h>
42 #include "wine/winbase16.h"
43 #include "wine/library.h"
44 #include "wine/server.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(thread);
48 WINE_DECLARE_DEBUG_CHANNEL(relay);
51 /***********************************************************************
54 * Allocate the stack of a thread.
56 TEB *THREAD_InitStack( TEB *teb, DWORD stack_size )
59 DWORD page_size = getpagesize();
62 stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
64 if (!(base = VirtualAlloc( NULL, stack_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
67 teb->DeallocationStack = base;
68 teb->Tib.StackBase = (char *)base + stack_size;
69 teb->Tib.StackLimit = base; /* note: limit is lower than base since the stack grows down */
71 /* Setup guard pages */
73 VirtualProtect( base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
78 struct new_thread_info
80 LPTHREAD_START_ROUTINE func;
84 /***********************************************************************
87 * Start execution of a newly created thread. Does not return.
89 static void CALLBACK THREAD_Start( void *ptr )
91 struct new_thread_info *info = ptr;
92 LPTHREAD_START_ROUTINE func = info->func;
93 void *arg = info->arg;
95 RtlFreeHeap( GetProcessHeap(), 0, info );
98 DPRINTF("%04lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func );
102 MODULE_DllThreadAttach( NULL );
103 ExitThread( func( arg ) );
105 __EXCEPT(UnhandledExceptionFilter)
107 TerminateThread( GetCurrentThread(), GetExceptionCode() );
113 /***********************************************************************
114 * CreateThread (KERNEL32.@)
116 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
117 LPTHREAD_START_ROUTINE start, LPVOID param,
118 DWORD flags, LPDWORD id )
123 SIZE_T stack_reserve = 0, stack_commit = 0;
124 struct new_thread_info *info;
126 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) )))
128 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
134 if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
135 else stack_commit = stack;
137 status = RtlCreateUserThread( GetCurrentProcess(), NULL, (flags & CREATE_SUSPENDED) != 0,
138 NULL, stack_reserve, stack_commit,
139 THREAD_Start, info, &handle, &client_id );
140 if (status == STATUS_SUCCESS)
142 if (id) *id = (DWORD)client_id.UniqueThread;
143 if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle)
144 SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT );
148 RtlFreeHeap( GetProcessHeap(), 0, info );
149 SetLastError( RtlNtStatusToDosError(status) );
156 /***********************************************************************
157 * OpenThread [KERNEL32.@] Retrieves a handle to a thread from its thread id
159 HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
162 SERVER_START_REQ( open_thread )
164 req->tid = dwThreadId;
165 req->access = dwDesiredAccess;
166 req->inherit = bInheritHandle;
167 if (!wine_server_call_err( req )) ret = reply->handle;
174 /***********************************************************************
175 * ExitThread [KERNEL32.@] Ends a thread
180 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
183 SERVER_START_REQ( terminate_thread )
185 /* send the exit code to the server */
186 req->handle = GetCurrentThread();
187 req->exit_code = code;
188 wine_server_call( req );
195 LdrShutdownProcess();
202 RemoveEntryList( &NtCurrentTeb()->TlsLinks );
204 SYSDEPS_ExitThread( code );
209 /**********************************************************************
210 * TerminateThread [KERNEL32.@] Terminates a thread
216 BOOL WINAPI TerminateThread( HANDLE handle, /* [in] Handle to thread */
217 DWORD exit_code) /* [in] Exit code for thread */
219 NTSTATUS status = NtTerminateThread( handle, exit_code );
220 if (status) SetLastError( RtlNtStatusToDosError(status) );
225 /***********************************************************************
226 * FreeLibraryAndExitThread (KERNEL32.@)
228 void WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
230 FreeLibrary(hLibModule);
231 ExitThread(dwExitCode);
235 /**********************************************************************
236 * GetExitCodeThread (KERNEL32.@)
238 * Gets termination status of thread.
244 BOOL WINAPI GetExitCodeThread(
245 HANDLE hthread, /* [in] Handle to thread */
246 LPDWORD exitcode) /* [out] Address to receive termination status */
248 THREAD_BASIC_INFORMATION info;
249 NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
250 &info, sizeof(info), NULL );
254 SetLastError( RtlNtStatusToDosError(status) );
257 if (exitcode) *exitcode = info.ExitStatus;
262 /***********************************************************************
263 * SetThreadContext [KERNEL32.@] Sets context of thread.
269 BOOL WINAPI SetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
270 const CONTEXT *context ) /* [in] Address of context structure */
272 NTSTATUS status = NtSetContextThread( handle, context );
273 if (status) SetLastError( RtlNtStatusToDosError(status) );
278 /***********************************************************************
279 * GetThreadContext [KERNEL32.@] Retrieves context of thread.
285 BOOL WINAPI GetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
286 CONTEXT *context ) /* [out] Address of context structure */
288 NTSTATUS status = NtGetContextThread( handle, context );
289 if (status) SetLastError( RtlNtStatusToDosError(status) );
294 /**********************************************************************
295 * SuspendThread [KERNEL32.@] Suspends a thread.
298 * Success: Previous suspend count
299 * Failure: 0xFFFFFFFF
301 DWORD WINAPI SuspendThread( HANDLE hthread ) /* [in] Handle to the thread */
304 NTSTATUS status = NtSuspendThread( hthread, &ret );
309 SetLastError( RtlNtStatusToDosError(status) );
315 /**********************************************************************
316 * ResumeThread [KERNEL32.@] Resumes a thread.
318 * Decrements a thread's suspend count. When count is zero, the
319 * execution of the thread is resumed.
322 * Success: Previous suspend count
323 * Failure: 0xFFFFFFFF
326 DWORD WINAPI ResumeThread( HANDLE hthread ) /* [in] Identifies thread to restart */
329 NTSTATUS status = NtResumeThread( hthread, &ret );
334 SetLastError( RtlNtStatusToDosError(status) );
340 /**********************************************************************
341 * GetThreadPriority [KERNEL32.@] Returns priority for thread.
344 * Success: Thread's priority level.
345 * Failure: THREAD_PRIORITY_ERROR_RETURN
347 INT WINAPI GetThreadPriority(
348 HANDLE hthread) /* [in] Handle to thread */
350 THREAD_BASIC_INFORMATION info;
351 NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
352 &info, sizeof(info), NULL );
356 SetLastError( RtlNtStatusToDosError(status) );
357 return THREAD_PRIORITY_ERROR_RETURN;
359 return info.Priority;
363 /**********************************************************************
364 * SetThreadPriority [KERNEL32.@] Sets priority for thread.
370 BOOL WINAPI SetThreadPriority(
371 HANDLE hthread, /* [in] Handle to thread */
372 INT priority) /* [in] Thread priority level */
375 SERVER_START_REQ( set_thread_info )
377 req->handle = hthread;
378 req->priority = priority;
379 req->mask = SET_THREAD_INFO_PRIORITY;
380 ret = !wine_server_call_err( req );
387 /**********************************************************************
388 * GetThreadPriorityBoost [KERNEL32.@] Returns priority boost for thread.
390 * Always reports that priority boost is disabled.
396 BOOL WINAPI GetThreadPriorityBoost(
397 HANDLE hthread, /* [in] Handle to thread */
398 PBOOL pstate) /* [out] pointer to var that receives the boost state */
400 if (pstate) *pstate = FALSE;
405 /**********************************************************************
406 * SetThreadPriorityBoost [KERNEL32.@] Sets priority boost for thread.
408 * Priority boost is not implemented. Thsi function always returns
409 * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
412 * Always returns FALSE to indicate a failure
414 BOOL WINAPI SetThreadPriorityBoost(
415 HANDLE hthread, /* [in] Handle to thread */
416 BOOL disable) /* [in] TRUE to disable priority boost */
418 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
423 /**********************************************************************
424 * SetThreadAffinityMask (KERNEL32.@)
426 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
429 SERVER_START_REQ( set_thread_info )
431 req->handle = hThread;
432 req->affinity = dwThreadAffinityMask;
433 req->mask = SET_THREAD_INFO_AFFINITY;
434 ret = !wine_server_call_err( req );
435 /* FIXME: should return previous value */
442 /**********************************************************************
443 * SetThreadIdealProcessor [KERNEL32.@] Obtains timing information.
446 * Success: Value of last call to SetThreadIdealProcessor
449 DWORD WINAPI SetThreadIdealProcessor(
450 HANDLE hThread, /* [in] Specifies the thread of interest */
451 DWORD dwIdealProcessor) /* [in] Specifies the new preferred processor */
453 FIXME("(%p): stub\n",hThread);
454 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
459 /* callback for QueueUserAPC */
460 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
462 PAPCFUNC func = (PAPCFUNC)arg1;
466 /***********************************************************************
467 * QueueUserAPC (KERNEL32.@)
469 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
471 NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );
473 if (status) SetLastError( RtlNtStatusToDosError(status) );
478 /**********************************************************************
479 * GetThreadTimes [KERNEL32.@] Obtains timing information.
485 BOOL WINAPI GetThreadTimes(
486 HANDLE thread, /* [in] Specifies the thread of interest */
487 LPFILETIME creationtime, /* [out] When the thread was created */
488 LPFILETIME exittime, /* [out] When the thread was destroyed */
489 LPFILETIME kerneltime, /* [out] Time thread spent in kernel mode */
490 LPFILETIME usertime) /* [out] Time thread spent in user mode */
494 if (creationtime || exittime)
496 /* We need to do a server call to get the creation time or exit time */
497 /* This works on any thread */
499 SERVER_START_REQ( get_thread_info )
501 req->handle = thread;
503 if ((ret = !wine_server_call_err( req )))
506 RtlSecondsSince1970ToTime( reply->creation_time, (LARGE_INTEGER*)creationtime );
508 RtlSecondsSince1970ToTime( reply->exit_time, (LARGE_INTEGER*)exittime );
513 if (ret && (kerneltime || usertime))
515 /* We call times(2) for kernel time or user time */
516 /* We can only (portably) do this for the current thread */
517 if (thread == GetCurrentThread())
521 long clocks_per_sec = sysconf(_SC_CLK_TCK);
526 time = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
527 kerneltime->dwHighDateTime = time >> 32;
528 kerneltime->dwLowDateTime = (DWORD)time;
532 time = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
533 usertime->dwHighDateTime = time >> 32;
534 usertime->dwLowDateTime = (DWORD)time;
539 if (kerneltime) kerneltime->dwHighDateTime = kerneltime->dwLowDateTime = 0;
540 if (usertime) usertime->dwHighDateTime = usertime->dwLowDateTime = 0;
541 FIXME("Cannot get kerneltime or usertime of other threads\n");
548 /**********************************************************************
549 * VWin32_BoostThreadGroup [KERNEL.535]
551 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
553 FIXME("(0x%08lx,%d): stub\n", threadId, boost);
557 /**********************************************************************
558 * VWin32_BoostThreadStatic [KERNEL.536]
560 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
562 FIXME("(0x%08lx,%d): stub\n", threadId, boost);
566 /***********************************************************************
567 * GetCurrentThread [KERNEL32.@] Gets pseudohandle for current thread
570 * Pseudohandle for the current thread
572 #undef GetCurrentThread
573 HANDLE WINAPI GetCurrentThread(void)
575 return (HANDLE)0xfffffffe;
581 /***********************************************************************
582 * SetLastError (KERNEL.147)
583 * SetLastError (KERNEL32.@)
585 /* void WINAPI SetLastError( DWORD error ); */
586 __ASM_GLOBAL_FUNC( SetLastError,
587 "movl 4(%esp),%eax\n\t"
592 /***********************************************************************
593 * GetLastError (KERNEL.148)
594 * GetLastError (KERNEL32.@)
596 /* DWORD WINAPI GetLastError(void); */
597 __ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x60,%eax\n\tret" );
599 /***********************************************************************
600 * GetCurrentProcessId (KERNEL.471)
601 * GetCurrentProcessId (KERNEL32.@)
603 /* DWORD WINAPI GetCurrentProcessId(void) */
604 __ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" );
606 /***********************************************************************
607 * GetCurrentThreadId (KERNEL.462)
608 * GetCurrentThreadId (KERNEL32.@)
610 /* DWORD WINAPI GetCurrentThreadId(void) */
611 __ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" );
615 /**********************************************************************
616 * SetLastError (KERNEL.147)
617 * SetLastError (KERNEL32.@)
619 * Sets the last-error code.
621 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
623 NtCurrentTeb()->last_error = error;
626 /**********************************************************************
627 * GetLastError (KERNEL.148)
628 * GetLastError (KERNEL32.@)
630 * Returns last-error code.
632 DWORD WINAPI GetLastError(void)
634 return NtCurrentTeb()->last_error;
637 /***********************************************************************
638 * GetCurrentProcessId (KERNEL.471)
639 * GetCurrentProcessId (KERNEL32.@)
641 * Returns process identifier.
643 DWORD WINAPI GetCurrentProcessId(void)
645 return (DWORD)NtCurrentTeb()->ClientId.UniqueProcess;
648 /***********************************************************************
649 * GetCurrentThreadId (KERNEL.462)
650 * GetCurrentThreadId (KERNEL32.@)
652 * Returns thread identifier.
654 DWORD WINAPI GetCurrentThreadId(void)
656 return (DWORD)NtCurrentTeb()->ClientId.UniqueThread;
659 #endif /* __i386__ */