kernel32: Add a stub implementation for CmdBatNotification.
[wine/testsucceed.git] / dlls / kernel / thread.c
bloba6956125d23c2a156e838b28b57e4631b84d4f81
1 /*
2 * Win32 threads
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winnls.h"
38 #include "thread.h"
39 #include "wine/winbase16.h"
40 #include "wine/exception.h"
41 #include "wine/library.h"
42 #include "wine/server.h"
43 #include "wine/debug.h"
45 #include "kernel_private.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(thread);
48 WINE_DECLARE_DEBUG_CHANNEL(relay);
51 struct new_thread_info
53 LPTHREAD_START_ROUTINE func;
54 void *arg;
57 extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved ); /* FIXME */
59 /***********************************************************************
60 * THREAD_Start
62 * Start execution of a newly created thread. Does not return.
64 static void CALLBACK THREAD_Start( void *ptr )
66 struct new_thread_info *info = ptr;
67 LPTHREAD_START_ROUTINE func = info->func;
68 void *arg = info->arg;
70 RtlFreeHeap( GetProcessHeap(), 0, info );
72 if (TRACE_ON(relay))
73 DPRINTF("%04lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func );
75 __TRY
77 MODULE_DllThreadAttach( NULL );
78 ExitThread( func( arg ) );
80 __EXCEPT(UnhandledExceptionFilter)
82 TerminateThread( GetCurrentThread(), GetExceptionCode() );
84 __ENDTRY
88 /***********************************************************************
89 * CreateThread (KERNEL32.@)
91 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
92 LPTHREAD_START_ROUTINE start, LPVOID param,
93 DWORD flags, LPDWORD id )
95 return CreateRemoteThread( GetCurrentProcess(),
96 sa, stack, start, param, flags, id );
100 /***************************************************************************
101 * CreateRemoteThread (KERNEL32.@)
103 * Creates a thread that runs in the address space of another process
105 * PARAMS
107 * RETURNS
108 * Success: Handle to the new thread.
109 * Failure: NULL. Use GetLastError() to find the error cause.
111 * BUGS
112 * Improper memory allocation: there's no ability to free new_thread_info
113 * in other process.
114 * Bad start address for RtlCreateUserThread because the library
115 * may be loaded at different address in other process.
117 HANDLE WINAPI CreateRemoteThread( HANDLE hProcess, SECURITY_ATTRIBUTES *sa, SIZE_T stack,
118 LPTHREAD_START_ROUTINE start, LPVOID param,
119 DWORD flags, LPDWORD id )
121 HANDLE handle;
122 CLIENT_ID client_id;
123 NTSTATUS status;
124 SIZE_T stack_reserve = 0, stack_commit = 0;
125 struct new_thread_info *info;
127 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) )))
129 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
130 return 0;
132 info->func = start;
133 info->arg = param;
135 if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
136 else stack_commit = stack;
138 status = RtlCreateUserThread( hProcess, NULL, TRUE,
139 NULL, stack_reserve, stack_commit,
140 THREAD_Start, info, &handle, &client_id );
141 if (status == STATUS_SUCCESS)
143 if (id) *id = (DWORD)client_id.UniqueThread;
144 if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle)
145 SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT );
146 if (!(flags & CREATE_SUSPENDED))
148 ULONG ret;
149 if (NtResumeThread( handle, &ret ))
151 NtClose( handle );
152 RtlFreeHeap( GetProcessHeap(), 0, info );
153 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
154 handle = 0;
158 else
160 RtlFreeHeap( GetProcessHeap(), 0, info );
161 SetLastError( RtlNtStatusToDosError(status) );
162 handle = 0;
164 return handle;
168 /***********************************************************************
169 * OpenThread [KERNEL32.@] Retrieves a handle to a thread from its thread id
171 HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
173 NTSTATUS status;
174 HANDLE handle;
175 OBJECT_ATTRIBUTES attr;
176 CLIENT_ID cid;
178 attr.Length = sizeof(attr);
179 attr.RootDirectory = 0;
180 attr.Attributes = bInheritHandle ? OBJ_INHERIT : 0;
181 attr.ObjectName = NULL;
182 attr.SecurityDescriptor = NULL;
183 attr.SecurityQualityOfService = NULL;
185 cid.UniqueProcess = 0; /* FIXME */
186 cid.UniqueThread = (HANDLE)dwThreadId;
187 status = NtOpenThread( &handle, dwDesiredAccess, &attr, &cid );
188 if (status)
190 SetLastError( RtlNtStatusToDosError(status) );
191 handle = 0;
193 return handle;
197 /***********************************************************************
198 * ExitThread [KERNEL32.@] Ends a thread
200 * RETURNS
201 * None
203 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
205 BOOL last;
206 SERVER_START_REQ( terminate_thread )
208 /* send the exit code to the server */
209 req->handle = GetCurrentThread();
210 req->exit_code = code;
211 wine_server_call( req );
212 last = reply->last;
214 SERVER_END_REQ;
216 if (last)
218 LdrShutdownProcess();
219 exit( code );
221 else RtlExitUserThread( code );
225 /**********************************************************************
226 * TerminateThread [KERNEL32.@] Terminates a thread
228 * RETURNS
229 * Success: TRUE
230 * Failure: FALSE
232 BOOL WINAPI TerminateThread( HANDLE handle, /* [in] Handle to thread */
233 DWORD exit_code) /* [in] Exit code for thread */
235 NTSTATUS status = NtTerminateThread( handle, exit_code );
236 if (status) SetLastError( RtlNtStatusToDosError(status) );
237 return !status;
241 /***********************************************************************
242 * FreeLibraryAndExitThread (KERNEL32.@)
244 void WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
246 FreeLibrary(hLibModule);
247 ExitThread(dwExitCode);
251 /**********************************************************************
252 * GetExitCodeThread (KERNEL32.@)
254 * Gets termination status of thread.
256 * RETURNS
257 * Success: TRUE
258 * Failure: FALSE
260 BOOL WINAPI GetExitCodeThread(
261 HANDLE hthread, /* [in] Handle to thread */
262 LPDWORD exitcode) /* [out] Address to receive termination status */
264 THREAD_BASIC_INFORMATION info;
265 NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
266 &info, sizeof(info), NULL );
268 if (status)
270 SetLastError( RtlNtStatusToDosError(status) );
271 return FALSE;
273 if (exitcode) *exitcode = info.ExitStatus;
274 return TRUE;
278 /***********************************************************************
279 * SetThreadContext [KERNEL32.@] Sets context of thread.
281 * RETURNS
282 * Success: TRUE
283 * Failure: FALSE
285 BOOL WINAPI SetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
286 const CONTEXT *context ) /* [in] Address of context structure */
288 NTSTATUS status = NtSetContextThread( handle, context );
289 if (status) SetLastError( RtlNtStatusToDosError(status) );
290 return !status;
294 /***********************************************************************
295 * GetThreadContext [KERNEL32.@] Retrieves context of thread.
297 * RETURNS
298 * Success: TRUE
299 * Failure: FALSE
301 BOOL WINAPI GetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
302 CONTEXT *context ) /* [out] Address of context structure */
304 NTSTATUS status = NtGetContextThread( handle, context );
305 if (status) SetLastError( RtlNtStatusToDosError(status) );
306 return !status;
310 /**********************************************************************
311 * SuspendThread [KERNEL32.@] Suspends a thread.
313 * RETURNS
314 * Success: Previous suspend count
315 * Failure: 0xFFFFFFFF
317 DWORD WINAPI SuspendThread( HANDLE hthread ) /* [in] Handle to the thread */
319 DWORD ret;
320 NTSTATUS status = NtSuspendThread( hthread, &ret );
322 if (status)
324 ret = ~0U;
325 SetLastError( RtlNtStatusToDosError(status) );
327 return ret;
331 /**********************************************************************
332 * ResumeThread [KERNEL32.@] Resumes a thread.
334 * Decrements a thread's suspend count. When count is zero, the
335 * execution of the thread is resumed.
337 * RETURNS
338 * Success: Previous suspend count
339 * Failure: 0xFFFFFFFF
340 * Already running: 0
342 DWORD WINAPI ResumeThread( HANDLE hthread ) /* [in] Identifies thread to restart */
344 DWORD ret;
345 NTSTATUS status = NtResumeThread( hthread, &ret );
347 if (status)
349 ret = ~0U;
350 SetLastError( RtlNtStatusToDosError(status) );
352 return ret;
356 /**********************************************************************
357 * GetThreadPriority [KERNEL32.@] Returns priority for thread.
359 * RETURNS
360 * Success: Thread's priority level.
361 * Failure: THREAD_PRIORITY_ERROR_RETURN
363 INT WINAPI GetThreadPriority(
364 HANDLE hthread) /* [in] Handle to thread */
366 THREAD_BASIC_INFORMATION info;
367 NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
368 &info, sizeof(info), NULL );
370 if (status)
372 SetLastError( RtlNtStatusToDosError(status) );
373 return THREAD_PRIORITY_ERROR_RETURN;
375 return info.Priority;
379 /**********************************************************************
380 * SetThreadPriority [KERNEL32.@] Sets priority for thread.
382 * RETURNS
383 * Success: TRUE
384 * Failure: FALSE
386 BOOL WINAPI SetThreadPriority(
387 HANDLE hthread, /* [in] Handle to thread */
388 INT priority) /* [in] Thread priority level */
390 DWORD prio = priority;
391 NTSTATUS status;
393 status = NtSetInformationThread(hthread, ThreadBasePriority,
394 &prio, sizeof(prio));
396 if (status)
398 SetLastError( RtlNtStatusToDosError(status) );
399 return FALSE;
402 return TRUE;
406 /**********************************************************************
407 * GetThreadPriorityBoost [KERNEL32.@] Returns priority boost for thread.
409 * Always reports that priority boost is disabled.
411 * RETURNS
412 * Success: TRUE.
413 * Failure: FALSE
415 BOOL WINAPI GetThreadPriorityBoost(
416 HANDLE hthread, /* [in] Handle to thread */
417 PBOOL pstate) /* [out] pointer to var that receives the boost state */
419 if (pstate) *pstate = FALSE;
420 return NO_ERROR;
424 /**********************************************************************
425 * SetThreadPriorityBoost [KERNEL32.@] Sets priority boost for thread.
427 * Priority boost is not implemented. Thsi function always returns
428 * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
430 * RETURNS
431 * Always returns FALSE to indicate a failure
433 BOOL WINAPI SetThreadPriorityBoost(
434 HANDLE hthread, /* [in] Handle to thread */
435 BOOL disable) /* [in] TRUE to disable priority boost */
437 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
438 return FALSE;
442 /**********************************************************************
443 * SetThreadAffinityMask (KERNEL32.@)
445 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
447 NTSTATUS status;
448 THREAD_BASIC_INFORMATION tbi;
450 status = NtQueryInformationThread( hThread, ThreadBasicInformation,
451 &tbi, sizeof(tbi), NULL );
452 if (status)
454 SetLastError( RtlNtStatusToDosError(status) );
455 return 0;
457 status = NtSetInformationThread( hThread, ThreadAffinityMask,
458 &dwThreadAffinityMask,
459 sizeof(dwThreadAffinityMask));
460 if (status)
462 SetLastError( RtlNtStatusToDosError(status) );
463 return 0;
465 return tbi.AffinityMask;
469 /**********************************************************************
470 * SetThreadIdealProcessor [KERNEL32.@] Obtains timing information.
472 * RETURNS
473 * Success: Value of last call to SetThreadIdealProcessor
474 * Failure: -1
476 DWORD WINAPI SetThreadIdealProcessor(
477 HANDLE hThread, /* [in] Specifies the thread of interest */
478 DWORD dwIdealProcessor) /* [in] Specifies the new preferred processor */
480 FIXME("(%p): stub\n",hThread);
481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
482 return -1L;
486 /* callback for QueueUserAPC */
487 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
489 PAPCFUNC func = (PAPCFUNC)arg1;
490 func( arg2 );
493 /***********************************************************************
494 * QueueUserAPC (KERNEL32.@)
496 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
498 NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );
500 if (status) SetLastError( RtlNtStatusToDosError(status) );
501 return !status;
504 /***********************************************************************
505 * QueueUserWorkItem (KERNEL32.@)
507 BOOL WINAPI QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags )
509 FIXME("(%p,%p,0x%08lx): stub\n", Function, Context, Flags);
510 return FALSE;
513 /**********************************************************************
514 * GetThreadTimes [KERNEL32.@] Obtains timing information.
516 * RETURNS
517 * Success: TRUE
518 * Failure: FALSE
520 BOOL WINAPI GetThreadTimes(
521 HANDLE thread, /* [in] Specifies the thread of interest */
522 LPFILETIME creationtime, /* [out] When the thread was created */
523 LPFILETIME exittime, /* [out] When the thread was destroyed */
524 LPFILETIME kerneltime, /* [out] Time thread spent in kernel mode */
525 LPFILETIME usertime) /* [out] Time thread spent in user mode */
527 KERNEL_USER_TIMES kusrt;
528 NTSTATUS status;
530 status = NtQueryInformationThread(thread, ThreadTimes, &kusrt,
531 sizeof(kusrt), NULL);
532 if (status)
534 SetLastError( RtlNtStatusToDosError(status) );
535 return FALSE;
537 if (creationtime)
539 creationtime->dwLowDateTime = kusrt.CreateTime.u.LowPart;
540 creationtime->dwHighDateTime = kusrt.CreateTime.u.HighPart;
542 if (exittime)
544 exittime->dwLowDateTime = kusrt.ExitTime.u.LowPart;
545 exittime->dwHighDateTime = kusrt.ExitTime.u.HighPart;
547 if (kerneltime)
549 kerneltime->dwLowDateTime = kusrt.KernelTime.u.LowPart;
550 kerneltime->dwHighDateTime = kusrt.KernelTime.u.HighPart;
552 if (usertime)
554 usertime->dwLowDateTime = kusrt.UserTime.u.LowPart;
555 usertime->dwHighDateTime = kusrt.UserTime.u.HighPart;
558 return TRUE;
562 /**********************************************************************
563 * VWin32_BoostThreadGroup [KERNEL.535]
565 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
567 FIXME("(0x%08lx,%d): stub\n", threadId, boost);
571 /**********************************************************************
572 * VWin32_BoostThreadStatic [KERNEL.536]
574 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
576 FIXME("(0x%08lx,%d): stub\n", threadId, boost);
580 /***********************************************************************
581 * GetCurrentThread [KERNEL32.@] Gets pseudohandle for current thread
583 * RETURNS
584 * Pseudohandle for the current thread
586 #undef GetCurrentThread
587 HANDLE WINAPI GetCurrentThread(void)
589 return (HANDLE)0xfffffffe;
593 #ifdef __i386__
595 /***********************************************************************
596 * SetLastError (KERNEL.147)
597 * SetLastError (KERNEL32.@)
599 /* void WINAPI SetLastError( DWORD error ); */
600 __ASM_GLOBAL_FUNC( SetLastError,
601 "movl 4(%esp),%eax\n\t"
602 ".byte 0x64\n\t"
603 "movl %eax,0x34\n\t"
604 "ret $4" )
606 /***********************************************************************
607 * GetLastError (KERNEL.148)
608 * GetLastError (KERNEL32.@)
610 /* DWORD WINAPI GetLastError(void); */
611 __ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x34,%eax\n\tret" )
613 /***********************************************************************
614 * GetCurrentProcessId (KERNEL.471)
615 * GetCurrentProcessId (KERNEL32.@)
617 /* DWORD WINAPI GetCurrentProcessId(void) */
618 __ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" )
620 /***********************************************************************
621 * GetCurrentThreadId (KERNEL.462)
622 * GetCurrentThreadId (KERNEL32.@)
624 /* DWORD WINAPI GetCurrentThreadId(void) */
625 __ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" )
627 #else /* __i386__ */
629 /**********************************************************************
630 * SetLastError (KERNEL.147)
631 * SetLastError (KERNEL32.@)
633 * Sets the last-error code.
635 * RETURNS
636 * Nothing.
638 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
640 NtCurrentTeb()->LastErrorValue = error;
643 /**********************************************************************
644 * GetLastError (KERNEL.148)
645 * GetLastError (KERNEL32.@)
647 * Get the last-error code.
649 * RETURNS
650 * last-error code.
652 DWORD WINAPI GetLastError(void)
654 return NtCurrentTeb()->LastErrorValue;
657 /***********************************************************************
658 * GetCurrentProcessId (KERNEL.471)
659 * GetCurrentProcessId (KERNEL32.@)
661 * Get the current process identifier.
663 * RETURNS
664 * current process identifier
666 DWORD WINAPI GetCurrentProcessId(void)
668 return (DWORD)NtCurrentTeb()->ClientId.UniqueProcess;
671 /***********************************************************************
672 * GetCurrentThreadId (KERNEL.462)
673 * GetCurrentThreadId (KERNEL32.@)
675 * Get the current thread identifier.
677 * RETURNS
678 * current thread identifier
680 DWORD WINAPI GetCurrentThreadId(void)
682 return (DWORD)NtCurrentTeb()->ClientId.UniqueThread;
685 #endif /* __i386__ */