Map WM_MENUSELECT 32->16 bits for closing menu.
[wine/hacks.git] / scheduler / thread.c
blob4038a8a92aa2af10654280d4602c7a898497e506
1 /*
2 * Win32 threads
4 * Copyright 1996 Alexandre Julliard
5 */
7 #include "config.h"
9 #include <assert.h>
10 #include <fcntl.h>
11 #include <sys/types.h>
12 #ifdef HAVE_SYS_MMAN_H
13 #include <sys/mman.h>
14 #endif
15 #include <unistd.h>
16 #include "wine/winbase16.h"
17 #include "thread.h"
18 #include "process.h"
19 #include "task.h"
20 #include "module.h"
21 #include "user.h"
22 #include "winerror.h"
23 #include "heap.h"
24 #include "selectors.h"
25 #include "winnt.h"
26 #include "server.h"
27 #include "services.h"
28 #include "stackframe.h"
29 #include "builtin16.h"
30 #include "debugtools.h"
31 #include "queue.h"
32 #include "hook.h"
34 DEFAULT_DEBUG_CHANNEL(thread)
36 /* TEB of the initial thread */
37 static TEB initial_teb;
39 /* Global thread list (FIXME: not thread-safe) */
40 TEB *THREAD_First = &initial_teb;
42 /***********************************************************************
43 * THREAD_IsWin16
45 BOOL THREAD_IsWin16( TEB *teb )
47 return !teb || !(teb->flags & TEBF_WIN32);
50 /***********************************************************************
51 * THREAD_IdToTEB
53 * Convert a thread id to a TEB, making sure it is valid.
55 TEB *THREAD_IdToTEB( DWORD id )
57 TEB *teb = THREAD_First;
59 if (!id) return NtCurrentTeb();
60 while (teb)
62 if ((DWORD)teb->tid == id) return teb;
63 teb = teb->next;
65 /* Allow task handles to be used; convert to main thread */
66 if ( IsTask16( id ) )
68 TDB *pTask = (TDB *)GlobalLock16( id );
69 if (pTask) return pTask->teb;
71 SetLastError( ERROR_INVALID_PARAMETER );
72 return NULL;
76 /***********************************************************************
77 * THREAD_InitTEB
79 * Initialization of a newly created TEB.
81 static BOOL THREAD_InitTEB( TEB *teb, DWORD stack_size, BOOL alloc_stack16,
82 LPSECURITY_ATTRIBUTES sa )
84 DWORD old_prot;
86 /* Allocate the stack */
88 /* FIXME:
89 * If stacksize smaller than 1 MB, allocate 1MB
90 * (one program wanted only 10 kB, which is recommendable, but some WINE
91 * functions, noteably in the files subdir, push HUGE structures and
92 * arrays on the stack. They probably shouldn't.)
93 * If stacksize larger than 16 MB, warn the user. (We could shrink the stack
94 * but this could give more or less unexplainable crashes.)
96 if (stack_size<1024*1024)
97 stack_size = 1024 * 1024;
98 if (stack_size >= 16*1024*1024)
99 WARN("Thread stack size is %ld MB.\n",stack_size/1024/1024);
100 teb->stack_base = VirtualAlloc(NULL, stack_size + SIGNAL_STACK_SIZE +
101 (alloc_stack16 ? 0x10000 : 0),
102 MEM_COMMIT, PAGE_EXECUTE_READWRITE );
103 if (!teb->stack_base) goto error;
104 /* Set a guard page at the bottom of the stack */
105 VirtualProtect( teb->stack_base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
106 teb->stack_top = (char *)teb->stack_base + stack_size;
107 teb->stack_low = teb->stack_base;
108 teb->signal_stack = teb->stack_top; /* start of signal stack */
110 /* Allocate the 16-bit stack selector */
112 if (alloc_stack16)
114 teb->stack_sel = SELECTOR_AllocBlock( teb->stack_top, 0x10000, SEGMENT_DATA,
115 FALSE, FALSE );
116 if (!teb->stack_sel) goto error;
117 teb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( teb->stack_sel,
118 0x10000 - sizeof(STACK16FRAME) );
119 teb->signal_stack = (char *)teb->signal_stack + 0x10000;
122 /* Create the thread event */
124 if (!(teb->event = CreateEventA( NULL, FALSE, FALSE, NULL ))) goto error;
125 teb->event = ConvertToGlobalHandle( teb->event );
127 /* StaticUnicodeString */
129 teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
130 teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
132 return TRUE;
134 error:
135 if (teb->event) CloseHandle( teb->event );
136 if (teb->stack_sel) SELECTOR_FreeBlock( teb->stack_sel, 1 );
137 if (teb->stack_base) VirtualFree( teb->stack_base, 0, MEM_RELEASE );
138 return FALSE;
142 /***********************************************************************
143 * THREAD_FreeTEB
145 * Free data structures associated with a thread.
146 * Must be called from the context of another thread.
148 void CALLBACK THREAD_FreeTEB( ULONG_PTR arg )
150 TEB *teb = (TEB *)arg;
151 TEB **pptr = &THREAD_First;
153 TRACE("(%p) called\n", teb );
154 SERVICE_Delete( teb->cleanup );
156 PROCESS_CallUserSignalProc( USIG_THREAD_EXIT, (DWORD)teb->tid, 0 );
158 CloseHandle( teb->event );
159 while (*pptr && (*pptr != teb)) pptr = &(*pptr)->next;
160 if (*pptr) *pptr = teb->next;
162 /* Free the associated memory */
164 if (teb->stack_sel) SELECTOR_FreeBlock( teb->stack_sel, 1 );
165 SELECTOR_FreeBlock( teb->teb_sel, 1 );
166 close( teb->socket );
167 if (teb->buffer) munmap( teb->buffer, teb->buffer_size );
168 VirtualFree( teb->stack_base, 0, MEM_RELEASE );
169 VirtualFree( teb, 0, MEM_FREE );
173 /***********************************************************************
174 * THREAD_CreateInitialThread
176 * Create the initial thread.
178 TEB *THREAD_CreateInitialThread( PDB *pdb, int server_fd )
180 initial_teb.except = (void *)-1;
181 initial_teb.self = &initial_teb;
182 initial_teb.flags = /* TEBF_WIN32 */ 0;
183 initial_teb.tls_ptr = initial_teb.tls_array;
184 initial_teb.process = pdb;
185 initial_teb.exit_code = 0x103; /* STILL_ACTIVE */
186 initial_teb.socket = server_fd;
188 /* Allocate the TEB selector (%fs register) */
190 if (!(initial_teb.teb_sel = SELECTOR_AllocBlock( &initial_teb, 0x1000,
191 SEGMENT_DATA, TRUE, FALSE )))
193 MESSAGE("Could not allocate fs register for initial thread\n" );
194 return NULL;
196 SYSDEPS_SetCurThread( &initial_teb );
198 /* Now proceed with normal initialization */
200 if (CLIENT_InitThread()) return NULL;
201 if (!THREAD_InitTEB( &initial_teb, 0, TRUE, NULL )) return NULL;
202 return &initial_teb;
206 /***********************************************************************
207 * THREAD_Create
209 * NOTES:
210 * Native NT dlls are using the space left on the allocated page
211 * the first allocated TEB on NT is at 0x7ffde000, since we can't
212 * allocate in this area and don't support a granularity of 4kb
213 * yet we leave it to VirtualAlloc to choose an address.
215 TEB *THREAD_Create( PDB *pdb, DWORD flags, DWORD stack_size, BOOL alloc_stack16,
216 LPSECURITY_ATTRIBUTES sa, int *server_handle )
218 struct new_thread_request *req = get_req_buffer();
219 HANDLE cleanup_object;
221 TEB *teb = VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
222 if (!teb) return NULL;
223 teb->except = (void *)-1;
224 teb->htask16 = pdb->task;
225 teb->self = teb;
226 teb->flags = (pdb->flags & PDB32_WIN16_PROC)? 0 : TEBF_WIN32;
227 teb->tls_ptr = teb->tls_array;
228 teb->process = pdb;
229 teb->exit_code = 0x103; /* STILL_ACTIVE */
230 teb->socket = -1;
232 /* Allocate the TEB selector (%fs register) */
234 *server_handle = -1;
235 teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, SEGMENT_DATA, TRUE, FALSE );
236 if (!teb->teb_sel) goto error;
238 /* Create the thread on the server side */
240 req->pid = teb->process->server_pid;
241 req->suspend = ((flags & CREATE_SUSPENDED) != 0);
242 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
243 if (server_call_fd( REQ_NEW_THREAD, -1, &teb->socket )) goto error;
244 teb->tid = req->tid;
245 *server_handle = req->handle;
246 fcntl( teb->socket, F_SETFD, 1 ); /* set close on exec flag */
248 /* Do the rest of the initialization */
250 if (!THREAD_InitTEB( teb, stack_size, alloc_stack16, sa )) goto error;
251 teb->next = THREAD_First;
252 THREAD_First = teb;
254 /* Install cleanup handler */
255 if ( !DuplicateHandle( GetCurrentProcess(), *server_handle,
256 GetCurrentProcess(), &cleanup_object,
257 0, FALSE, DUPLICATE_SAME_ACCESS ) ) goto error;
258 teb->cleanup = SERVICE_AddObject( cleanup_object, THREAD_FreeTEB, (ULONG_PTR)teb );
260 TRACE("(%p) succeeded\n", teb);
261 return teb;
263 error:
264 if (*server_handle != -1) CloseHandle( *server_handle );
265 if (teb->teb_sel) SELECTOR_FreeBlock( teb->teb_sel, 1 );
266 if (teb->socket != -1) close( teb->socket );
267 VirtualFree( teb, 0, MEM_FREE );
268 return NULL;
272 /***********************************************************************
273 * THREAD_Start
275 * Start execution of a newly created thread. Does not return.
277 static void THREAD_Start(void)
279 LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)NtCurrentTeb()->entry_point;
280 PROCESS_CallUserSignalProc( USIG_THREAD_INIT, (DWORD)NtCurrentTeb()->tid, 0 );
281 PE_InitTls();
282 MODULE_DllThreadAttach( NULL );
284 if (NtCurrentTeb()->process->flags & PDB32_DEBUGGED) DEBUG_SendCreateThreadEvent( func );
286 ExitThread( func( NtCurrentTeb()->entry_arg ) );
290 /***********************************************************************
291 * CreateThread (KERNEL32.63)
293 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
294 LPTHREAD_START_ROUTINE start, LPVOID param,
295 DWORD flags, LPDWORD id )
297 int handle = -1;
298 TEB *teb = THREAD_Create( PROCESS_Current(), flags, stack, TRUE, sa, &handle );
299 if (!teb) return 0;
300 teb->flags |= TEBF_WIN32;
301 teb->entry_point = start;
302 teb->entry_arg = param;
303 teb->startup = THREAD_Start;
304 if (SYSDEPS_SpawnThread( teb ) == -1)
306 CloseHandle( handle );
307 return 0;
309 if (id) *id = (DWORD)teb->tid;
310 return handle;
313 /***********************************************************************
314 * CreateThread16 (KERNEL.441)
316 static DWORD CALLBACK THREAD_StartThread16( LPVOID threadArgs )
318 FARPROC16 start = ((FARPROC16 *)threadArgs)[0];
319 DWORD param = ((DWORD *)threadArgs)[1];
320 HeapFree( GetProcessHeap(), 0, threadArgs );
322 ((LPDWORD)CURRENT_STACK16)[-1] = param;
323 return CallTo16Long( start, sizeof(DWORD) );
325 HANDLE WINAPI CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
326 FARPROC16 start, SEGPTR param,
327 DWORD flags, LPDWORD id )
329 DWORD *threadArgs = HeapAlloc( GetProcessHeap(), 0, 2*sizeof(DWORD) );
330 if (!threadArgs) return INVALID_HANDLE_VALUE;
331 threadArgs[0] = (DWORD)start;
332 threadArgs[1] = (DWORD)param;
334 return CreateThread( sa, stack, THREAD_StartThread16, threadArgs, flags, id );
338 /***********************************************************************
339 * ExitThread [KERNEL32.215] Ends a thread
341 * RETURNS
342 * None
344 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
346 MODULE_DllThreadDetach( NULL );
347 TerminateThread( GetCurrentThread(), code );
351 /***********************************************************************
352 * GetCurrentThread [KERNEL32.200] Gets pseudohandle for current thread
354 * RETURNS
355 * Pseudohandle for the current thread
357 HANDLE WINAPI GetCurrentThread(void)
359 return CURRENT_THREAD_PSEUDOHANDLE;
363 /**********************************************************************
364 * GetLastError [KERNEL.148] [KERNEL32.227] Returns last-error code.
366 * RETURNS
367 * Calling thread's last error code value.
369 DWORD WINAPI GetLastError(void)
371 return NtCurrentTeb()->last_error;
375 /**********************************************************************
376 * SetLastErrorEx [USER32.485] Sets the last-error code.
378 * RETURNS
379 * None.
381 void WINAPI SetLastErrorEx(
382 DWORD error, /* [in] Per-thread error code */
383 DWORD type) /* [in] Error type */
385 TRACE("(0x%08lx, 0x%08lx)\n", error,type);
386 switch(type) {
387 case 0:
388 break;
389 case SLE_ERROR:
390 case SLE_MINORERROR:
391 case SLE_WARNING:
392 /* Fall through for now */
393 default:
394 FIXME("(error=%08lx, type=%08lx): Unhandled type\n", error,type);
395 break;
397 SetLastError( error );
401 /**********************************************************************
402 * TlsAlloc [KERNEL32.530] Allocates a TLS index.
404 * Allocates a thread local storage index
406 * RETURNS
407 * Success: TLS Index
408 * Failure: 0xFFFFFFFF
410 DWORD WINAPI TlsAlloc( void )
412 PDB *process = PROCESS_Current();
413 DWORD i, mask, ret = 0;
414 DWORD *bits = process->tls_bits;
415 EnterCriticalSection( &process->crit_section );
416 if (*bits == 0xffffffff)
418 bits++;
419 ret = 32;
420 if (*bits == 0xffffffff)
422 LeaveCriticalSection( &process->crit_section );
423 SetLastError( ERROR_NO_MORE_ITEMS );
424 return 0xffffffff;
427 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
428 *bits |= mask;
429 LeaveCriticalSection( &process->crit_section );
430 return ret + i;
434 /**********************************************************************
435 * TlsFree [KERNEL32.531] Releases a TLS index.
437 * Releases a thread local storage index, making it available for reuse
439 * RETURNS
440 * Success: TRUE
441 * Failure: FALSE
443 BOOL WINAPI TlsFree(
444 DWORD index) /* [in] TLS Index to free */
446 PDB *process = PROCESS_Current();
447 DWORD mask;
448 DWORD *bits = process->tls_bits;
449 if (index >= 64)
451 SetLastError( ERROR_INVALID_PARAMETER );
452 return FALSE;
454 EnterCriticalSection( &process->crit_section );
455 if (index >= 32) bits++;
456 mask = (1 << (index & 31));
457 if (!(*bits & mask)) /* already free? */
459 LeaveCriticalSection( &process->crit_section );
460 SetLastError( ERROR_INVALID_PARAMETER );
461 return FALSE;
463 *bits &= ~mask;
464 NtCurrentTeb()->tls_array[index] = 0;
465 /* FIXME: should zero all other thread values */
466 LeaveCriticalSection( &process->crit_section );
467 return TRUE;
471 /**********************************************************************
472 * TlsGetValue [KERNEL32.532] Gets value in a thread's TLS slot
474 * RETURNS
475 * Success: Value stored in calling thread's TLS slot for index
476 * Failure: 0 and GetLastError returns NO_ERROR
478 LPVOID WINAPI TlsGetValue(
479 DWORD index) /* [in] TLS index to retrieve value for */
481 if (index >= 64)
483 SetLastError( ERROR_INVALID_PARAMETER );
484 return NULL;
486 SetLastError( ERROR_SUCCESS );
487 return NtCurrentTeb()->tls_array[index];
491 /**********************************************************************
492 * TlsSetValue [KERNEL32.533] Stores a value in the thread's TLS slot.
494 * RETURNS
495 * Success: TRUE
496 * Failure: FALSE
498 BOOL WINAPI TlsSetValue(
499 DWORD index, /* [in] TLS index to set value for */
500 LPVOID value) /* [in] Value to be stored */
502 if (index >= 64)
504 SetLastError( ERROR_INVALID_PARAMETER );
505 return FALSE;
507 NtCurrentTeb()->tls_array[index] = value;
508 return TRUE;
512 /***********************************************************************
513 * SetThreadContext [KERNEL32.670] Sets context of thread.
515 * RETURNS
516 * Success: TRUE
517 * Failure: FALSE
519 BOOL WINAPI SetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
520 const CONTEXT *context ) /* [in] Address of context structure */
522 struct set_thread_context_request *req = get_req_buffer();
523 req->handle = handle;
524 req->flags = context->ContextFlags;
525 memcpy( &req->context, context, sizeof(*context) );
526 return !server_call( REQ_SET_THREAD_CONTEXT );
530 /***********************************************************************
531 * GetThreadContext [KERNEL32.294] Retrieves context of thread.
533 * RETURNS
534 * Success: TRUE
535 * Failure: FALSE
537 BOOL WINAPI GetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
538 CONTEXT *context ) /* [out] Address of context structure */
540 struct get_thread_context_request *req = get_req_buffer();
541 req->handle = handle;
542 req->flags = context->ContextFlags;
543 memcpy( &req->context, context, sizeof(*context) );
544 if (server_call( REQ_GET_THREAD_CONTEXT )) return FALSE;
545 memcpy( context, &req->context, sizeof(*context) );
546 return TRUE;
550 /**********************************************************************
551 * GetThreadPriority [KERNEL32.296] Returns priority for thread.
553 * RETURNS
554 * Success: Thread's priority level.
555 * Failure: THREAD_PRIORITY_ERROR_RETURN
557 INT WINAPI GetThreadPriority(
558 HANDLE hthread) /* [in] Handle to thread */
560 INT ret = THREAD_PRIORITY_ERROR_RETURN;
561 struct get_thread_info_request *req = get_req_buffer();
562 req->handle = hthread;
563 if (!server_call( REQ_GET_THREAD_INFO )) ret = req->priority;
564 return ret;
568 /**********************************************************************
569 * SetThreadPriority [KERNEL32.514] Sets priority for thread.
571 * RETURNS
572 * Success: TRUE
573 * Failure: FALSE
575 BOOL WINAPI SetThreadPriority(
576 HANDLE hthread, /* [in] Handle to thread */
577 INT priority) /* [in] Thread priority level */
579 struct set_thread_info_request *req = get_req_buffer();
580 req->handle = hthread;
581 req->priority = priority;
582 req->mask = SET_THREAD_INFO_PRIORITY;
583 return !server_call( REQ_SET_THREAD_INFO );
587 /**********************************************************************
588 * SetThreadAffinityMask (KERNEL32.669)
590 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
592 struct set_thread_info_request *req = get_req_buffer();
593 req->handle = hThread;
594 req->affinity = dwThreadAffinityMask;
595 req->mask = SET_THREAD_INFO_AFFINITY;
596 if (server_call( REQ_SET_THREAD_INFO )) return 0;
597 return 1; /* FIXME: should return previous value */
601 /**********************************************************************
602 * TerminateThread [KERNEL32.685] Terminates a thread
604 * RETURNS
605 * Success: TRUE
606 * Failure: FALSE
608 BOOL WINAPI TerminateThread(
609 HANDLE handle, /* [in] Handle to thread */
610 DWORD exitcode) /* [in] Exit code for thread */
612 struct terminate_thread_request *req = get_req_buffer();
613 req->handle = handle;
614 req->exit_code = exitcode;
615 return !server_call( REQ_TERMINATE_THREAD );
619 /**********************************************************************
620 * GetExitCodeThread [KERNEL32.???] Gets termination status of thread.
622 * RETURNS
623 * Success: TRUE
624 * Failure: FALSE
626 BOOL WINAPI GetExitCodeThread(
627 HANDLE hthread, /* [in] Handle to thread */
628 LPDWORD exitcode) /* [out] Address to receive termination status */
630 BOOL ret = FALSE;
631 struct get_thread_info_request *req = get_req_buffer();
632 req->handle = hthread;
633 if (!server_call( REQ_GET_THREAD_INFO ))
635 if (exitcode) *exitcode = req->exit_code;
636 ret = TRUE;
638 return ret;
642 /**********************************************************************
643 * ResumeThread [KERNEL32.587] Resumes a thread.
645 * Decrements a thread's suspend count. When count is zero, the
646 * execution of the thread is resumed.
648 * RETURNS
649 * Success: Previous suspend count
650 * Failure: 0xFFFFFFFF
651 * Already running: 0
653 DWORD WINAPI ResumeThread(
654 HANDLE hthread) /* [in] Identifies thread to restart */
656 DWORD ret = 0xffffffff;
657 struct resume_thread_request *req = get_req_buffer();
658 req->handle = hthread;
659 if (!server_call( REQ_RESUME_THREAD )) ret = req->count;
660 return ret;
664 /**********************************************************************
665 * SuspendThread [KERNEL32.681] Suspends a thread.
667 * RETURNS
668 * Success: Previous suspend count
669 * Failure: 0xFFFFFFFF
671 DWORD WINAPI SuspendThread(
672 HANDLE hthread) /* [in] Handle to the thread */
674 DWORD ret = 0xffffffff;
675 struct suspend_thread_request *req = get_req_buffer();
676 req->handle = hthread;
677 if (!server_call( REQ_SUSPEND_THREAD )) ret = req->count;
678 return ret;
682 /***********************************************************************
683 * QueueUserAPC (KERNEL32.566)
685 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
687 struct queue_apc_request *req = get_req_buffer();
688 req->handle = hthread;
689 req->func = func;
690 req->param = (void *)data;
691 return !server_call( REQ_QUEUE_APC );
695 /**********************************************************************
696 * GetThreadTimes [KERNEL32.???] Obtains timing information.
698 * NOTES
699 * What are the fields where these values are stored?
701 * RETURNS
702 * Success: TRUE
703 * Failure: FALSE
705 BOOL WINAPI GetThreadTimes(
706 HANDLE thread, /* [in] Specifies the thread of interest */
707 LPFILETIME creationtime, /* [out] When the thread was created */
708 LPFILETIME exittime, /* [out] When the thread was destroyed */
709 LPFILETIME kerneltime, /* [out] Time thread spent in kernel mode */
710 LPFILETIME usertime) /* [out] Time thread spent in user mode */
712 FIXME("(0x%08x): stub\n",thread);
713 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
714 return FALSE;
718 /**********************************************************************
719 * AttachThreadInput [KERNEL32.8] Attaches input of 1 thread to other
721 * Attaches the input processing mechanism of one thread to that of
722 * another thread.
724 * RETURNS
725 * Success: TRUE
726 * Failure: FALSE
728 * TODO:
729 * 1. Reset the Key State (currenly per thread key state is not maintained)
731 BOOL WINAPI AttachThreadInput(
732 DWORD idAttach, /* [in] Thread to attach */
733 DWORD idAttachTo, /* [in] Thread to attach to */
734 BOOL fAttach) /* [in] Attach or detach */
736 MESSAGEQUEUE *pSrcMsgQ = 0, *pTgtMsgQ = 0;
737 BOOL16 bRet = 0;
739 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
741 /* A thread cannot attach to itself */
742 if ( idAttach == idAttachTo )
743 goto CLEANUP;
745 /* According to the docs this method should fail if a
746 * "Journal record" hook is installed. (attaches all input queues together)
748 if ( HOOK_IsHooked( WH_JOURNALRECORD ) )
749 goto CLEANUP;
751 /* Retrieve message queues corresponding to the thread id's */
752 pTgtMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetThreadQueue16( idAttach ) );
753 pSrcMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetThreadQueue16( idAttachTo ) );
755 /* Ensure we have message queues and that Src and Tgt threads
756 * are not system threads.
758 if ( !pSrcMsgQ || !pTgtMsgQ || !pSrcMsgQ->pQData || !pTgtMsgQ->pQData )
759 goto CLEANUP;
761 if (fAttach) /* Attach threads */
763 /* Only attach if currently detached */
764 if ( pTgtMsgQ->pQData != pSrcMsgQ->pQData )
766 /* First release the target threads perQData */
767 PERQDATA_Release( pTgtMsgQ->pQData );
769 /* Share a reference to the source threads perQDATA */
770 PERQDATA_Addref( pSrcMsgQ->pQData );
771 pTgtMsgQ->pQData = pSrcMsgQ->pQData;
774 else /* Detach threads */
776 /* Only detach if currently attached */
777 if ( pTgtMsgQ->pQData == pSrcMsgQ->pQData )
779 /* First release the target threads perQData */
780 PERQDATA_Release( pTgtMsgQ->pQData );
782 /* Give the target thread its own private perQDATA once more */
783 pTgtMsgQ->pQData = PERQDATA_CreateInstance();
787 /* TODO: Reset the Key State */
789 bRet = 1; /* Success */
791 CLEANUP:
793 /* Unlock the queues before returning */
794 if ( pSrcMsgQ )
795 QUEUE_Unlock( pSrcMsgQ );
796 if ( pTgtMsgQ )
797 QUEUE_Unlock( pTgtMsgQ );
799 return bRet;
802 /**********************************************************************
803 * VWin32_BoostThreadGroup [KERNEL.535]
805 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
807 FIXME("(0x%08lx,%d): stub\n", threadId, boost);
810 /**********************************************************************
811 * VWin32_BoostThreadStatic [KERNEL.536]
813 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
815 FIXME("(0x%08lx,%d): stub\n", threadId, boost);
818 /**********************************************************************
819 * SetThreadLocale [KERNEL32.671] Sets the calling threads current locale.
821 * RETURNS
822 * Success: TRUE
823 * Failure: FALSE
825 * NOTES
826 * Implemented in NT only (3.1 and above according to MS
828 BOOL WINAPI SetThreadLocale(
829 LCID lcid) /* [in] Locale identifier */
831 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
832 return FALSE;
836 /**********************************************************************
837 * SetLastError [KERNEL.147] [KERNEL32.497] Sets the last-error code.
839 * RETURNS
840 * None.
842 #undef SetLastError
843 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
845 NtCurrentTeb()->last_error = error;
849 /***********************************************************************
850 * GetCurrentThreadId [KERNEL32.201] Returns thread identifier.
852 * RETURNS
853 * Thread identifier of calling thread
855 #undef GetCurrentThreadId
856 DWORD WINAPI GetCurrentThreadId(void)
858 return (DWORD)NtCurrentTeb()->tid;