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/exception.h"
44 #include "wine/library.h"
45 #include "wine/pthread.h"
46 #include "wine/server.h"
47 #include "wine/debug.h"
49 #include "kernel_private.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(thread
);
52 WINE_DECLARE_DEBUG_CHANNEL(relay
);
55 /***********************************************************************
58 * Allocate the stack of a thread.
60 TEB
*THREAD_InitStack( TEB
*teb
, DWORD stack_size
)
63 DWORD page_size
= getpagesize();
66 stack_size
= (stack_size
+ (page_size
- 1)) & ~(page_size
- 1);
67 if (stack_size
< 1024 * 1024) stack_size
= 1024 * 1024; /* Xlib needs a large stack */
69 if (!(base
= VirtualAlloc( NULL
, stack_size
, MEM_COMMIT
, PAGE_READWRITE
)))
72 teb
->DeallocationStack
= base
;
73 teb
->Tib
.StackBase
= (char *)base
+ stack_size
;
74 teb
->Tib
.StackLimit
= base
; /* note: limit is lower than base since the stack grows down */
76 /* Setup guard pages */
78 VirtualProtect( base
, 1, PAGE_READWRITE
| PAGE_GUARD
, &old_prot
);
83 struct new_thread_info
85 LPTHREAD_START_ROUTINE func
;
89 /***********************************************************************
92 * Start execution of a newly created thread. Does not return.
94 static void CALLBACK
THREAD_Start( void *ptr
)
96 struct new_thread_info
*info
= ptr
;
97 LPTHREAD_START_ROUTINE func
= info
->func
;
98 void *arg
= info
->arg
;
100 RtlFreeHeap( GetProcessHeap(), 0, info
);
103 DPRINTF("%04lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func
);
107 MODULE_DllThreadAttach( NULL
);
108 ExitThread( func( arg
) );
110 __EXCEPT(UnhandledExceptionFilter
)
112 TerminateThread( GetCurrentThread(), GetExceptionCode() );
118 /***********************************************************************
119 * CreateThread (KERNEL32.@)
121 HANDLE WINAPI
CreateThread( SECURITY_ATTRIBUTES
*sa
, SIZE_T stack
,
122 LPTHREAD_START_ROUTINE start
, LPVOID param
,
123 DWORD flags
, LPDWORD id
)
125 return CreateRemoteThread( GetCurrentProcess(),
126 sa
, stack
, start
, param
, flags
, id
);
130 /***************************************************************************
131 * CreateRemoteThread (KERNEL32.@)
133 * Creates a thread that runs in the address space of another process
138 * Success: Handle to the new thread.
139 * Failure: NULL. Use GetLastError() to find the error cause.
142 * Improper memory allocation: there's no ability to free new_thread_info
144 * Bad start address for RtlCreateUserThread because the library
145 * may be loaded at different address in other process.
147 HANDLE WINAPI
CreateRemoteThread( HANDLE hProcess
, SECURITY_ATTRIBUTES
*sa
, SIZE_T stack
,
148 LPTHREAD_START_ROUTINE start
, LPVOID param
,
149 DWORD flags
, LPDWORD id
)
154 SIZE_T stack_reserve
= 0, stack_commit
= 0;
155 struct new_thread_info
*info
;
157 if (!(info
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info
) )))
159 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
165 if (flags
& STACK_SIZE_PARAM_IS_A_RESERVATION
) stack_reserve
= stack
;
166 else stack_commit
= stack
;
168 status
= RtlCreateUserThread( hProcess
, NULL
, TRUE
,
169 NULL
, stack_reserve
, stack_commit
,
170 THREAD_Start
, info
, &handle
, &client_id
);
171 if (status
== STATUS_SUCCESS
)
173 if (id
) *id
= (DWORD
)client_id
.UniqueThread
;
174 if (sa
&& (sa
->nLength
>= sizeof(*sa
)) && sa
->bInheritHandle
)
175 SetHandleInformation( handle
, HANDLE_FLAG_INHERIT
, HANDLE_FLAG_INHERIT
);
176 if (!(flags
& CREATE_SUSPENDED
))
179 if (NtResumeThread( handle
, &ret
))
182 RtlFreeHeap( GetProcessHeap(), 0, info
);
183 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
190 RtlFreeHeap( GetProcessHeap(), 0, info
);
191 SetLastError( RtlNtStatusToDosError(status
) );
198 /***********************************************************************
199 * OpenThread [KERNEL32.@] Retrieves a handle to a thread from its thread id
201 HANDLE WINAPI
OpenThread( DWORD dwDesiredAccess
, BOOL bInheritHandle
, DWORD dwThreadId
)
204 SERVER_START_REQ( open_thread
)
206 req
->tid
= dwThreadId
;
207 req
->access
= dwDesiredAccess
;
208 req
->inherit
= bInheritHandle
;
209 if (!wine_server_call_err( req
)) ret
= reply
->handle
;
216 /***********************************************************************
217 * ExitThread [KERNEL32.@] Ends a thread
222 void WINAPI
ExitThread( DWORD code
) /* [in] Exit code for this thread */
225 SERVER_START_REQ( terminate_thread
)
227 /* send the exit code to the server */
228 req
->handle
= GetCurrentThread();
229 req
->exit_code
= code
;
230 wine_server_call( req
);
237 LdrShutdownProcess();
243 wine_server_exit_thread( code
);
248 /**********************************************************************
249 * TerminateThread [KERNEL32.@] Terminates a thread
255 BOOL WINAPI
TerminateThread( HANDLE handle
, /* [in] Handle to thread */
256 DWORD exit_code
) /* [in] Exit code for thread */
258 NTSTATUS status
= NtTerminateThread( handle
, exit_code
);
259 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
264 /***********************************************************************
265 * FreeLibraryAndExitThread (KERNEL32.@)
267 void WINAPI
FreeLibraryAndExitThread(HINSTANCE hLibModule
, DWORD dwExitCode
)
269 FreeLibrary(hLibModule
);
270 ExitThread(dwExitCode
);
274 /**********************************************************************
275 * GetExitCodeThread (KERNEL32.@)
277 * Gets termination status of thread.
283 BOOL WINAPI
GetExitCodeThread(
284 HANDLE hthread
, /* [in] Handle to thread */
285 LPDWORD exitcode
) /* [out] Address to receive termination status */
287 THREAD_BASIC_INFORMATION info
;
288 NTSTATUS status
= NtQueryInformationThread( hthread
, ThreadBasicInformation
,
289 &info
, sizeof(info
), NULL
);
293 SetLastError( RtlNtStatusToDosError(status
) );
296 if (exitcode
) *exitcode
= info
.ExitStatus
;
301 /***********************************************************************
302 * SetThreadContext [KERNEL32.@] Sets context of thread.
308 BOOL WINAPI
SetThreadContext( HANDLE handle
, /* [in] Handle to thread with context */
309 const CONTEXT
*context
) /* [in] Address of context structure */
311 NTSTATUS status
= NtSetContextThread( handle
, context
);
312 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
317 /***********************************************************************
318 * GetThreadContext [KERNEL32.@] Retrieves context of thread.
324 BOOL WINAPI
GetThreadContext( HANDLE handle
, /* [in] Handle to thread with context */
325 CONTEXT
*context
) /* [out] Address of context structure */
327 NTSTATUS status
= NtGetContextThread( handle
, context
);
328 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
333 /**********************************************************************
334 * SuspendThread [KERNEL32.@] Suspends a thread.
337 * Success: Previous suspend count
338 * Failure: 0xFFFFFFFF
340 DWORD WINAPI
SuspendThread( HANDLE hthread
) /* [in] Handle to the thread */
343 NTSTATUS status
= NtSuspendThread( hthread
, &ret
);
348 SetLastError( RtlNtStatusToDosError(status
) );
354 /**********************************************************************
355 * ResumeThread [KERNEL32.@] Resumes a thread.
357 * Decrements a thread's suspend count. When count is zero, the
358 * execution of the thread is resumed.
361 * Success: Previous suspend count
362 * Failure: 0xFFFFFFFF
365 DWORD WINAPI
ResumeThread( HANDLE hthread
) /* [in] Identifies thread to restart */
368 NTSTATUS status
= NtResumeThread( hthread
, &ret
);
373 SetLastError( RtlNtStatusToDosError(status
) );
379 /**********************************************************************
380 * GetThreadPriority [KERNEL32.@] Returns priority for thread.
383 * Success: Thread's priority level.
384 * Failure: THREAD_PRIORITY_ERROR_RETURN
386 INT WINAPI
GetThreadPriority(
387 HANDLE hthread
) /* [in] Handle to thread */
389 THREAD_BASIC_INFORMATION info
;
390 NTSTATUS status
= NtQueryInformationThread( hthread
, ThreadBasicInformation
,
391 &info
, sizeof(info
), NULL
);
395 SetLastError( RtlNtStatusToDosError(status
) );
396 return THREAD_PRIORITY_ERROR_RETURN
;
398 return info
.Priority
;
402 /**********************************************************************
403 * SetThreadPriority [KERNEL32.@] Sets priority for thread.
409 BOOL WINAPI
SetThreadPriority(
410 HANDLE hthread
, /* [in] Handle to thread */
411 INT priority
) /* [in] Thread priority level */
414 SERVER_START_REQ( set_thread_info
)
416 req
->handle
= hthread
;
417 req
->priority
= priority
;
418 req
->mask
= SET_THREAD_INFO_PRIORITY
;
419 ret
= !wine_server_call_err( req
);
426 /**********************************************************************
427 * GetThreadPriorityBoost [KERNEL32.@] Returns priority boost for thread.
429 * Always reports that priority boost is disabled.
435 BOOL WINAPI
GetThreadPriorityBoost(
436 HANDLE hthread
, /* [in] Handle to thread */
437 PBOOL pstate
) /* [out] pointer to var that receives the boost state */
439 if (pstate
) *pstate
= FALSE
;
444 /**********************************************************************
445 * SetThreadPriorityBoost [KERNEL32.@] Sets priority boost for thread.
447 * Priority boost is not implemented. Thsi function always returns
448 * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
451 * Always returns FALSE to indicate a failure
453 BOOL WINAPI
SetThreadPriorityBoost(
454 HANDLE hthread
, /* [in] Handle to thread */
455 BOOL disable
) /* [in] TRUE to disable priority boost */
457 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
462 /**********************************************************************
463 * SetThreadAffinityMask (KERNEL32.@)
465 DWORD WINAPI
SetThreadAffinityMask( HANDLE hThread
, DWORD dwThreadAffinityMask
)
468 SERVER_START_REQ( set_thread_info
)
470 req
->handle
= hThread
;
471 req
->affinity
= dwThreadAffinityMask
;
472 req
->mask
= SET_THREAD_INFO_AFFINITY
;
473 ret
= !wine_server_call_err( req
);
474 /* FIXME: should return previous value */
481 /**********************************************************************
482 * SetThreadIdealProcessor [KERNEL32.@] Obtains timing information.
485 * Success: Value of last call to SetThreadIdealProcessor
488 DWORD WINAPI
SetThreadIdealProcessor(
489 HANDLE hThread
, /* [in] Specifies the thread of interest */
490 DWORD dwIdealProcessor
) /* [in] Specifies the new preferred processor */
492 FIXME("(%p): stub\n",hThread
);
493 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
498 /* callback for QueueUserAPC */
499 static void CALLBACK
call_user_apc( ULONG_PTR arg1
, ULONG_PTR arg2
, ULONG_PTR arg3
)
501 PAPCFUNC func
= (PAPCFUNC
)arg1
;
505 /***********************************************************************
506 * QueueUserAPC (KERNEL32.@)
508 DWORD WINAPI
QueueUserAPC( PAPCFUNC func
, HANDLE hthread
, ULONG_PTR data
)
510 NTSTATUS status
= NtQueueApcThread( hthread
, call_user_apc
, (ULONG_PTR
)func
, data
, 0 );
512 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
516 /***********************************************************************
517 * QueueUserWorkItem (KERNEL32.@)
519 BOOL WINAPI
QueueUserWorkItem( LPTHREAD_START_ROUTINE Function
, PVOID Context
, ULONG Flags
)
521 FIXME("(%p,%p,0x%08lx): stub\n", Function
, Context
, Flags
);
525 /**********************************************************************
526 * GetThreadTimes [KERNEL32.@] Obtains timing information.
532 BOOL WINAPI
GetThreadTimes(
533 HANDLE thread
, /* [in] Specifies the thread of interest */
534 LPFILETIME creationtime
, /* [out] When the thread was created */
535 LPFILETIME exittime
, /* [out] When the thread was destroyed */
536 LPFILETIME kerneltime
, /* [out] Time thread spent in kernel mode */
537 LPFILETIME usertime
) /* [out] Time thread spent in user mode */
541 if (creationtime
|| exittime
)
543 /* We need to do a server call to get the creation time or exit time */
544 /* This works on any thread */
546 SERVER_START_REQ( get_thread_info
)
548 req
->handle
= thread
;
550 if ((ret
= !wine_server_call_err( req
)))
553 RtlSecondsSince1970ToTime( reply
->creation_time
, (LARGE_INTEGER
*)creationtime
);
555 RtlSecondsSince1970ToTime( reply
->exit_time
, (LARGE_INTEGER
*)exittime
);
560 if (ret
&& (kerneltime
|| usertime
))
562 /* We call times(2) for kernel time or user time */
563 /* We can only (portably) do this for the current thread */
564 if (thread
== GetCurrentThread())
568 long clocks_per_sec
= sysconf(_SC_CLK_TCK
);
573 time
= (ULONGLONG
)time_buf
.tms_stime
* 10000000 / clocks_per_sec
;
574 kerneltime
->dwHighDateTime
= time
>> 32;
575 kerneltime
->dwLowDateTime
= (DWORD
)time
;
579 time
= (ULONGLONG
)time_buf
.tms_utime
* 10000000 / clocks_per_sec
;
580 usertime
->dwHighDateTime
= time
>> 32;
581 usertime
->dwLowDateTime
= (DWORD
)time
;
586 if (kerneltime
) kerneltime
->dwHighDateTime
= kerneltime
->dwLowDateTime
= 0;
587 if (usertime
) usertime
->dwHighDateTime
= usertime
->dwLowDateTime
= 0;
588 FIXME("Cannot get kerneltime or usertime of other threads\n");
595 /**********************************************************************
596 * VWin32_BoostThreadGroup [KERNEL.535]
598 VOID WINAPI
VWin32_BoostThreadGroup( DWORD threadId
, INT boost
)
600 FIXME("(0x%08lx,%d): stub\n", threadId
, boost
);
604 /**********************************************************************
605 * VWin32_BoostThreadStatic [KERNEL.536]
607 VOID WINAPI
VWin32_BoostThreadStatic( DWORD threadId
, INT boost
)
609 FIXME("(0x%08lx,%d): stub\n", threadId
, boost
);
613 /***********************************************************************
614 * GetCurrentThread [KERNEL32.@] Gets pseudohandle for current thread
617 * Pseudohandle for the current thread
619 #undef GetCurrentThread
620 HANDLE WINAPI
GetCurrentThread(void)
622 return (HANDLE
)0xfffffffe;
628 /***********************************************************************
629 * SetLastError (KERNEL.147)
630 * SetLastError (KERNEL32.@)
632 /* void WINAPI SetLastError( DWORD error ); */
633 __ASM_GLOBAL_FUNC( SetLastError
,
634 "movl 4(%esp),%eax\n\t"
639 /***********************************************************************
640 * GetLastError (KERNEL.148)
641 * GetLastError (KERNEL32.@)
643 /* DWORD WINAPI GetLastError(void); */
644 __ASM_GLOBAL_FUNC( GetLastError
, ".byte 0x64\n\tmovl 0x34,%eax\n\tret" )
646 /***********************************************************************
647 * GetCurrentProcessId (KERNEL.471)
648 * GetCurrentProcessId (KERNEL32.@)
650 /* DWORD WINAPI GetCurrentProcessId(void) */
651 __ASM_GLOBAL_FUNC( GetCurrentProcessId
, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" )
653 /***********************************************************************
654 * GetCurrentThreadId (KERNEL.462)
655 * GetCurrentThreadId (KERNEL32.@)
657 /* DWORD WINAPI GetCurrentThreadId(void) */
658 __ASM_GLOBAL_FUNC( GetCurrentThreadId
, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" )
662 /**********************************************************************
663 * SetLastError (KERNEL.147)
664 * SetLastError (KERNEL32.@)
666 * Sets the last-error code.
668 void WINAPI
SetLastError( DWORD error
) /* [in] Per-thread error code */
670 NtCurrentTeb()->LastErrorValue
= error
;
673 /**********************************************************************
674 * GetLastError (KERNEL.148)
675 * GetLastError (KERNEL32.@)
677 * Returns last-error code.
679 DWORD WINAPI
GetLastError(void)
681 return NtCurrentTeb()->LastErrorValue
;
684 /***********************************************************************
685 * GetCurrentProcessId (KERNEL.471)
686 * GetCurrentProcessId (KERNEL32.@)
688 * Returns process identifier.
690 DWORD WINAPI
GetCurrentProcessId(void)
692 return (DWORD
)NtCurrentTeb()->ClientId
.UniqueProcess
;
695 /***********************************************************************
696 * GetCurrentThreadId (KERNEL.462)
697 * GetCurrentThreadId (KERNEL32.@)
699 * Returns thread identifier.
701 DWORD WINAPI
GetCurrentThreadId(void)
703 return (DWORD
)NtCurrentTeb()->ClientId
.UniqueThread
;
706 #endif /* __i386__ */