avifil32: Use HeapAlloc instead of Local Alloc.
[wine] / dlls / kernel / thread.c
1 /*
2  * Win32 threads
3  *
4  * Copyright 1996 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
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
31
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"
44
45 #include "kernel_private.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(thread);
48 WINE_DECLARE_DEBUG_CHANNEL(relay);
49
50
51 struct new_thread_info
52 {
53     LPTHREAD_START_ROUTINE func;
54     void                  *arg;
55 };
56
57 extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved );  /* FIXME */
58
59 /***********************************************************************
60  *           THREAD_Start
61  *
62  * Start execution of a newly created thread. Does not return.
63  */
64 static void CALLBACK THREAD_Start( void *ptr )
65 {
66     struct new_thread_info *info = ptr;
67     LPTHREAD_START_ROUTINE func = info->func;
68     void *arg = info->arg;
69
70     RtlFreeHeap( GetProcessHeap(), 0, info );
71
72     if (TRACE_ON(relay))
73         DPRINTF("%04lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func );
74
75     __TRY
76     {
77         MODULE_DllThreadAttach( NULL );
78         ExitThread( func( arg ) );
79     }
80     __EXCEPT(UnhandledExceptionFilter)
81     {
82         TerminateThread( GetCurrentThread(), GetExceptionCode() );
83     }
84     __ENDTRY
85 }
86
87
88 /***********************************************************************
89  *           CreateThread   (KERNEL32.@)
90  */
91 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
92                             LPTHREAD_START_ROUTINE start, LPVOID param,
93                             DWORD flags, LPDWORD id )
94 {
95      return CreateRemoteThread( GetCurrentProcess(),
96                                 sa, stack, start, param, flags, id );
97 }
98
99
100 /***************************************************************************
101  *                  CreateRemoteThread   (KERNEL32.@)
102  *
103  * Creates a thread that runs in the address space of another process
104  *
105  * PARAMS
106  *
107  * RETURNS
108  *   Success: Handle to the new thread.
109  *   Failure: NULL. Use GetLastError() to find the error cause.
110  *
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.
116  */
117 HANDLE WINAPI CreateRemoteThread( HANDLE hProcess, SECURITY_ATTRIBUTES *sa, SIZE_T stack,
118                                   LPTHREAD_START_ROUTINE start, LPVOID param,
119                                   DWORD flags, LPDWORD id )
120 {
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;
126
127     if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) )))
128     {
129         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
130         return 0;
131     }
132     info->func = start;
133     info->arg  = param;
134
135     if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
136     else stack_commit = stack;
137
138     status = RtlCreateUserThread( hProcess, NULL, TRUE,
139                                   NULL, stack_reserve, stack_commit,
140                                   THREAD_Start, info, &handle, &client_id );
141     if (status == STATUS_SUCCESS)
142     {
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))
147         {
148             ULONG ret;
149             if (NtResumeThread( handle, &ret ))
150             {
151                 NtClose( handle );
152                 RtlFreeHeap( GetProcessHeap(), 0, info );
153                 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
154                 handle = 0;
155             }
156         }
157     }
158     else
159     {
160         RtlFreeHeap( GetProcessHeap(), 0, info );
161         SetLastError( RtlNtStatusToDosError(status) );
162         handle = 0;
163     }
164     return handle;
165 }
166
167
168 /***********************************************************************
169  * OpenThread  [KERNEL32.@]   Retrieves a handle to a thread from its thread id
170  */
171 HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
172 {
173     NTSTATUS status;
174     HANDLE handle;
175     OBJECT_ATTRIBUTES attr;
176     CLIENT_ID cid;
177
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;
184
185     cid.UniqueProcess = 0; /* FIXME */
186     cid.UniqueThread = (HANDLE)dwThreadId;
187     status = NtOpenThread( &handle, dwDesiredAccess, &attr, &cid );
188     if (status)
189     {
190         SetLastError( RtlNtStatusToDosError(status) );
191         handle = 0;
192     }
193     return handle;
194 }
195
196
197 /***********************************************************************
198  * ExitThread [KERNEL32.@]  Ends a thread
199  *
200  * RETURNS
201  *    None
202  */
203 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
204 {
205     BOOL last;
206     SERVER_START_REQ( terminate_thread )
207     {
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;
213     }
214     SERVER_END_REQ;
215
216     if (last)
217     {
218         LdrShutdownProcess();
219         exit( code );
220     }
221     else RtlExitUserThread( code );
222 }
223
224
225 /**********************************************************************
226  * TerminateThread [KERNEL32.@]  Terminates a thread
227  *
228  * RETURNS
229  *    Success: TRUE
230  *    Failure: FALSE
231  */
232 BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
233                              DWORD exit_code)  /* [in] Exit code for thread */
234 {
235     NTSTATUS status = NtTerminateThread( handle, exit_code );
236     if (status) SetLastError( RtlNtStatusToDosError(status) );
237     return !status;
238 }
239
240
241 /***********************************************************************
242  *           FreeLibraryAndExitThread (KERNEL32.@)
243  */
244 void WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
245 {
246     FreeLibrary(hLibModule);
247     ExitThread(dwExitCode);
248 }
249
250
251 /**********************************************************************
252  *              GetExitCodeThread (KERNEL32.@)
253  *
254  * Gets termination status of thread.
255  *
256  * RETURNS
257  *    Success: TRUE
258  *    Failure: FALSE
259  */
260 BOOL WINAPI GetExitCodeThread(
261     HANDLE hthread, /* [in]  Handle to thread */
262     LPDWORD exitcode) /* [out] Address to receive termination status */
263 {
264     THREAD_BASIC_INFORMATION info;
265     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
266                                                 &info, sizeof(info), NULL );
267
268     if (status)
269     {
270         SetLastError( RtlNtStatusToDosError(status) );
271         return FALSE;
272     }
273     if (exitcode) *exitcode = info.ExitStatus;
274     return TRUE;
275 }
276
277
278 /***********************************************************************
279  * SetThreadContext [KERNEL32.@]  Sets context of thread.
280  *
281  * RETURNS
282  *    Success: TRUE
283  *    Failure: FALSE
284  */
285 BOOL WINAPI SetThreadContext( HANDLE handle,           /* [in]  Handle to thread with context */
286                               const CONTEXT *context ) /* [in] Address of context structure */
287 {
288     NTSTATUS status = NtSetContextThread( handle, context );
289     if (status) SetLastError( RtlNtStatusToDosError(status) );
290     return !status;
291 }
292
293
294 /***********************************************************************
295  * GetThreadContext [KERNEL32.@]  Retrieves context of thread.
296  *
297  * RETURNS
298  *    Success: TRUE
299  *    Failure: FALSE
300  */
301 BOOL WINAPI GetThreadContext( HANDLE handle,     /* [in]  Handle to thread with context */
302                               CONTEXT *context ) /* [out] Address of context structure */
303 {
304     NTSTATUS status = NtGetContextThread( handle, context );
305     if (status) SetLastError( RtlNtStatusToDosError(status) );
306     return !status;
307 }
308
309
310 /**********************************************************************
311  * SuspendThread [KERNEL32.@]  Suspends a thread.
312  *
313  * RETURNS
314  *    Success: Previous suspend count
315  *    Failure: 0xFFFFFFFF
316  */
317 DWORD WINAPI SuspendThread( HANDLE hthread ) /* [in] Handle to the thread */
318 {
319     DWORD ret;
320     NTSTATUS status = NtSuspendThread( hthread, &ret );
321
322     if (status)
323     {
324         ret = ~0U;
325         SetLastError( RtlNtStatusToDosError(status) );
326     }
327     return ret;
328 }
329
330
331 /**********************************************************************
332  * ResumeThread [KERNEL32.@]  Resumes a thread.
333  *
334  * Decrements a thread's suspend count.  When count is zero, the
335  * execution of the thread is resumed.
336  *
337  * RETURNS
338  *    Success: Previous suspend count
339  *    Failure: 0xFFFFFFFF
340  *    Already running: 0
341  */
342 DWORD WINAPI ResumeThread( HANDLE hthread ) /* [in] Identifies thread to restart */
343 {
344     DWORD ret;
345     NTSTATUS status = NtResumeThread( hthread, &ret );
346
347     if (status)
348     {
349         ret = ~0U;
350         SetLastError( RtlNtStatusToDosError(status) );
351     }
352     return ret;
353 }
354
355
356 /**********************************************************************
357  * GetThreadPriority [KERNEL32.@]  Returns priority for thread.
358  *
359  * RETURNS
360  *    Success: Thread's priority level.
361  *    Failure: THREAD_PRIORITY_ERROR_RETURN
362  */
363 INT WINAPI GetThreadPriority(
364     HANDLE hthread) /* [in] Handle to thread */
365 {
366     THREAD_BASIC_INFORMATION info;
367     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
368                                                 &info, sizeof(info), NULL );
369
370     if (status)
371     {
372         SetLastError( RtlNtStatusToDosError(status) );
373         return THREAD_PRIORITY_ERROR_RETURN;
374     }
375     return info.Priority;
376 }
377
378
379 /**********************************************************************
380  * SetThreadPriority [KERNEL32.@]  Sets priority for thread.
381  *
382  * RETURNS
383  *    Success: TRUE
384  *    Failure: FALSE
385  */
386 BOOL WINAPI SetThreadPriority(
387     HANDLE hthread, /* [in] Handle to thread */
388     INT priority)   /* [in] Thread priority level */
389 {
390     DWORD       prio = priority;
391     NTSTATUS    status;
392
393     status = NtSetInformationThread(hthread, ThreadBasePriority,
394                                     &prio, sizeof(prio));
395
396     if (status)
397     {
398         SetLastError( RtlNtStatusToDosError(status) );
399         return FALSE;
400     }
401
402     return TRUE;
403 }
404
405
406 /**********************************************************************
407  * GetThreadPriorityBoost [KERNEL32.@]  Returns priority boost for thread.
408  *
409  * Always reports that priority boost is disabled.
410  *
411  * RETURNS
412  *    Success: TRUE.
413  *    Failure: FALSE
414  */
415 BOOL WINAPI GetThreadPriorityBoost(
416     HANDLE hthread, /* [in] Handle to thread */
417     PBOOL pstate)   /* [out] pointer to var that receives the boost state */
418 {
419     if (pstate) *pstate = FALSE;
420     return NO_ERROR;
421 }
422
423
424 /**********************************************************************
425  * SetThreadPriorityBoost [KERNEL32.@]  Sets priority boost for thread.
426  *
427  * Priority boost is not implemented. Thsi function always returns
428  * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
429  *
430  * RETURNS
431  *    Always returns FALSE to indicate a failure
432  */
433 BOOL WINAPI SetThreadPriorityBoost(
434     HANDLE hthread, /* [in] Handle to thread */
435     BOOL disable)   /* [in] TRUE to disable priority boost */
436 {
437     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
438     return FALSE;
439 }
440
441
442 /**********************************************************************
443  *           SetThreadAffinityMask   (KERNEL32.@)
444  */
445 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
446 {
447     NTSTATUS                    status;
448     THREAD_BASIC_INFORMATION    tbi;
449
450     status = NtQueryInformationThread( hThread, ThreadBasicInformation, 
451                                        &tbi, sizeof(tbi), NULL );
452     if (status)
453     {
454         SetLastError( RtlNtStatusToDosError(status) );
455         return 0;
456     }
457     status = NtSetInformationThread( hThread, ThreadAffinityMask, 
458                                      &dwThreadAffinityMask,
459                                      sizeof(dwThreadAffinityMask));
460     if (status)
461     {
462         SetLastError( RtlNtStatusToDosError(status) );
463         return 0;
464     }
465     return tbi.AffinityMask;
466 }
467
468
469 /**********************************************************************
470  * SetThreadIdealProcessor [KERNEL32.@]  Obtains timing information.
471  *
472  * RETURNS
473  *    Success: Value of last call to SetThreadIdealProcessor
474  *    Failure: -1
475  */
476 DWORD WINAPI SetThreadIdealProcessor(
477     HANDLE hThread,          /* [in] Specifies the thread of interest */
478     DWORD dwIdealProcessor)  /* [in] Specifies the new preferred processor */
479 {
480     FIXME("(%p): stub\n",hThread);
481     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
482     return -1L;
483 }
484
485
486 /* callback for QueueUserAPC */
487 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
488 {
489     PAPCFUNC func = (PAPCFUNC)arg1;
490     func( arg2 );
491 }
492
493 /***********************************************************************
494  *              QueueUserAPC  (KERNEL32.@)
495  */
496 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
497 {
498     NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );
499
500     if (status) SetLastError( RtlNtStatusToDosError(status) );
501     return !status;
502 }
503
504 /***********************************************************************
505  *              QueueUserWorkItem  (KERNEL32.@)
506  */
507 BOOL WINAPI QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags )
508 {
509     FIXME("(%p,%p,0x%08lx): stub\n", Function, Context, Flags);
510     return FALSE;
511 }
512
513 /**********************************************************************
514  * GetThreadTimes [KERNEL32.@]  Obtains timing information.
515  *
516  * RETURNS
517  *    Success: TRUE
518  *    Failure: FALSE
519  */
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 */
526 {
527     KERNEL_USER_TIMES   kusrt;
528     NTSTATUS            status;
529
530     status = NtQueryInformationThread(thread, ThreadTimes, &kusrt,
531                                       sizeof(kusrt), NULL);
532     if (status)
533     {
534         SetLastError( RtlNtStatusToDosError(status) );
535         return FALSE;
536     }
537     if (creationtime)
538     {
539         creationtime->dwLowDateTime = kusrt.CreateTime.u.LowPart;
540         creationtime->dwHighDateTime = kusrt.CreateTime.u.HighPart;
541     }
542     if (exittime)
543     {
544         exittime->dwLowDateTime = kusrt.ExitTime.u.LowPart;
545         exittime->dwHighDateTime = kusrt.ExitTime.u.HighPart;
546     }
547     if (kerneltime)
548     {
549         kerneltime->dwLowDateTime = kusrt.KernelTime.u.LowPart;
550         kerneltime->dwHighDateTime = kusrt.KernelTime.u.HighPart;
551     }
552     if (usertime)
553     {
554         usertime->dwLowDateTime = kusrt.UserTime.u.LowPart;
555         usertime->dwHighDateTime = kusrt.UserTime.u.HighPart;
556     }
557     
558     return TRUE;
559 }
560
561
562 /**********************************************************************
563  * VWin32_BoostThreadGroup [KERNEL.535]
564  */
565 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
566 {
567     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
568 }
569
570
571 /**********************************************************************
572  * VWin32_BoostThreadStatic [KERNEL.536]
573  */
574 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
575 {
576     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
577 }
578
579
580 /***********************************************************************
581  * GetCurrentThread [KERNEL32.@]  Gets pseudohandle for current thread
582  *
583  * RETURNS
584  *    Pseudohandle for the current thread
585  */
586 #undef GetCurrentThread
587 HANDLE WINAPI GetCurrentThread(void)
588 {
589     return (HANDLE)0xfffffffe;
590 }
591
592
593 #ifdef __i386__
594
595 /***********************************************************************
596  *              SetLastError (KERNEL.147)
597  *              SetLastError (KERNEL32.@)
598  */
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" )
605
606 /***********************************************************************
607  *              GetLastError (KERNEL.148)
608  *              GetLastError (KERNEL32.@)
609  */
610 /* DWORD WINAPI GetLastError(void); */
611 __ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x34,%eax\n\tret" )
612
613 /***********************************************************************
614  *              GetCurrentProcessId (KERNEL.471)
615  *              GetCurrentProcessId (KERNEL32.@)
616  */
617 /* DWORD WINAPI GetCurrentProcessId(void) */
618 __ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" )
619
620 /***********************************************************************
621  *              GetCurrentThreadId (KERNEL.462)
622  *              GetCurrentThreadId (KERNEL32.@)
623  */
624 /* DWORD WINAPI GetCurrentThreadId(void) */
625 __ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" )
626
627 #else  /* __i386__ */
628
629 /**********************************************************************
630  *              SetLastError (KERNEL.147)
631  *              SetLastError (KERNEL32.@)
632  *
633  * Sets the last-error code.
634  *
635  * RETURNS
636  * Nothing.
637  */
638 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
639 {
640     NtCurrentTeb()->LastErrorValue = error;
641 }
642
643 /**********************************************************************
644  *              GetLastError (KERNEL.148)
645  *              GetLastError (KERNEL32.@)
646  *
647  * Get the last-error code.
648  *
649  * RETURNS
650  *  last-error code.
651  */
652 DWORD WINAPI GetLastError(void)
653 {
654     return NtCurrentTeb()->LastErrorValue;
655 }
656
657 /***********************************************************************
658  *              GetCurrentProcessId (KERNEL.471)
659  *              GetCurrentProcessId (KERNEL32.@)
660  *
661  * Get the current process identifier.
662  *
663  * RETURNS
664  *  current process identifier
665  */
666 DWORD WINAPI GetCurrentProcessId(void)
667 {
668     return (DWORD)NtCurrentTeb()->ClientId.UniqueProcess;
669 }
670
671 /***********************************************************************
672  *              GetCurrentThreadId (KERNEL.462)
673  *              GetCurrentThreadId (KERNEL32.@)
674  *
675  * Get the current thread identifier.
676  *
677  * RETURNS
678  *  current thread identifier
679  */
680 DWORD WINAPI GetCurrentThreadId(void)
681 {
682     return (DWORD)NtCurrentTeb()->ClientId.UniqueThread;
683 }
684
685 #endif  /* __i386__ */