Added tracing for delayed imports and removed the fixme.
[wine/testsucceed.git] / scheduler / thread.c
blob6e75b2057a54d3703d4961b63f453d6cc282295c
1 /*
2 * Win32 threads
4 * Copyright 1996 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <unistd.h>
11 #include "wine/winbase16.h"
12 #include "thread.h"
13 #include "process.h"
14 #include "task.h"
15 #include "module.h"
16 #include "user.h"
17 #include "winerror.h"
18 #include "heap.h"
19 #include "selectors.h"
20 #include "winnt.h"
21 #include "server.h"
22 #include "stackframe.h"
23 #include "debug.h"
24 #include "queue.h"
25 #include "hook.h"
27 #ifndef __i386__
28 THDB *pCurrentThread;
29 #endif
31 /* Is threading code initialized? */
32 BOOL THREAD_InitDone = FALSE;
34 /* THDB of the initial thread */
35 static THDB initial_thdb;
37 /* Global thread list (FIXME: not thread-safe) */
38 THDB *THREAD_First = &initial_thdb;
40 /***********************************************************************
41 * THREAD_Current
43 * Return the current thread THDB pointer.
45 THDB *THREAD_Current(void)
47 if (!THREAD_InitDone) return NULL;
48 return (THDB *)((char *)NtCurrentTeb() - (int)&((THDB *)0)->teb);
51 /***********************************************************************
52 * THREAD_IsWin16
54 BOOL THREAD_IsWin16( THDB *thdb )
56 if (!thdb || !thdb->process)
57 return TRUE;
58 else
60 TDB* pTask = (TDB*)GlobalLock16( thdb->process->task );
61 return !pTask || pTask->thdb == thdb;
65 /***********************************************************************
66 * THREAD_IdToTHDB
68 * Convert a thread id to a THDB, making sure it is valid.
70 THDB *THREAD_IdToTHDB( DWORD id )
72 THDB *thdb = THREAD_First;
74 if (!id) return THREAD_Current();
75 while (thdb)
77 if ((DWORD)thdb->server_tid == id) return thdb;
78 thdb = thdb->next;
80 /* Allow task handles to be used; convert to main thread */
81 if ( IsTask16( id ) )
83 TDB *pTask = (TDB *)GlobalLock16( id );
84 if (pTask) return pTask->thdb;
86 SetLastError( ERROR_INVALID_PARAMETER );
87 return NULL;
91 /***********************************************************************
92 * THREAD_InitTHDB
94 * Initialization of a newly created THDB.
96 static BOOL THREAD_InitTHDB( THDB *thdb, DWORD stack_size, BOOL alloc_stack16,
97 int *server_thandle, int *server_phandle )
99 DWORD old_prot;
101 /* Allocate the stack */
103 /* FIXME:
104 * If stacksize smaller than 1 MB, allocate 1MB
105 * (one program wanted only 10 kB, which is recommendable, but some WINE
106 * functions, noteably in the files subdir, push HUGE structures and
107 * arrays on the stack. They probably shouldn't.)
108 * If stacksize larger than 16 MB, warn the user. (We could shrink the stack
109 * but this could give more or less unexplainable crashes.)
111 if (stack_size<1024*1024)
112 stack_size = 1024 * 1024;
113 if (stack_size >= 16*1024*1024)
114 WARN(thread,"Thread stack size is %ld MB.\n",stack_size/1024/1024);
115 thdb->stack_base = VirtualAlloc(NULL,
116 stack_size + (alloc_stack16 ? 0x10000 : 0),
117 MEM_COMMIT, PAGE_EXECUTE_READWRITE );
118 if (!thdb->stack_base) goto error;
119 /* Set a guard page at the bottom of the stack */
120 VirtualProtect( thdb->stack_base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD,
121 &old_prot );
122 thdb->teb.stack_top = (char *)thdb->stack_base + stack_size;
123 thdb->teb.stack_low = thdb->stack_base;
124 thdb->exit_stack = thdb->teb.stack_top;
126 /* Allocate the 16-bit stack selector */
128 if (alloc_stack16)
130 thdb->teb.stack_sel = SELECTOR_AllocBlock( thdb->teb.stack_top,
131 0x10000, SEGMENT_DATA,
132 FALSE, FALSE );
133 if (!thdb->teb.stack_sel) goto error;
134 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( thdb->teb.stack_sel,
135 0x10000 - sizeof(STACK16FRAME) );
138 /* Create the thread socket */
140 if (CLIENT_NewThread( thdb, server_thandle, server_phandle )) goto error;
142 /* Create the thread event */
144 if (!(thdb->event = CreateEventA( NULL, FALSE, FALSE, NULL ))) goto error;
145 thdb->event = ConvertToGlobalHandle( thdb->event );
146 return TRUE;
148 error:
149 if (thdb->socket != -1) close( thdb->socket );
150 if (thdb->event) CloseHandle( thdb->event );
151 if (thdb->teb.stack_sel) SELECTOR_FreeBlock( thdb->teb.stack_sel, 1 );
152 if (thdb->stack_base) VirtualFree( thdb->stack_base, 0, MEM_RELEASE );
153 return FALSE;
157 /***********************************************************************
158 * THREAD_CreateInitialThread
160 * Create the initial thread.
162 THDB *THREAD_CreateInitialThread( PDB *pdb )
164 int fd[2];
165 char buffer[16];
166 extern void server_init( int fd );
167 extern void select_loop(void);
169 initial_thdb.process = pdb;
170 initial_thdb.teb.except = (void *)-1;
171 initial_thdb.teb.self = &initial_thdb.teb;
172 initial_thdb.teb.flags = (pdb->flags & PDB32_WIN16_PROC)? 0 : TEBF_WIN32;
173 initial_thdb.teb.tls_ptr = initial_thdb.tls_array;
174 initial_thdb.teb.process = pdb;
175 initial_thdb.exit_code = 0x103; /* STILL_ACTIVE */
176 initial_thdb.socket = -1;
178 /* Start the server */
180 if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
182 perror("socketpair");
183 exit(1);
185 switch(fork())
187 case -1: /* error */
188 perror("fork");
189 exit(1);
190 case 0: /* child */
191 close( fd[0] );
192 sprintf( buffer, "%d", fd[1] );
193 /*#define EXEC_SERVER*/
194 #ifdef EXEC_SERVER
195 execlp( "wineserver", "wineserver", buffer, NULL );
196 execl( "/usr/local/bin/wineserver", "wineserver", buffer, NULL );
197 execl( "./server/wineserver", "wineserver", buffer, NULL );
198 #endif
199 server_init( fd[1] );
200 select_loop();
201 exit(0);
202 default: /* parent */
203 initial_thdb.socket = fd[0];
204 close( fd[1] );
205 break;
208 /* Allocate the TEB selector (%fs register) */
210 if (!(initial_thdb.teb_sel = SELECTOR_AllocBlock( &initial_thdb.teb, 0x1000,
211 SEGMENT_DATA, TRUE, FALSE )))
213 MSG("Could not allocate fs register for initial thread\n" );
214 return NULL;
216 SET_CUR_THREAD( &initial_thdb );
217 THREAD_InitDone = TRUE;
219 /* Now proceed with normal initialization */
221 if (!THREAD_InitTHDB( &initial_thdb, 0, TRUE, NULL, NULL )) return NULL;
222 return &initial_thdb;
226 /***********************************************************************
227 * THREAD_Create
229 THDB *THREAD_Create( PDB *pdb, DWORD stack_size, BOOL alloc_stack16,
230 int *server_thandle, int *server_phandle,
231 LPTHREAD_START_ROUTINE start_addr, LPVOID param )
233 THDB *thdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(THDB) );
234 if (!thdb) return NULL;
235 thdb->process = pdb;
236 thdb->teb.except = (void *)-1;
237 thdb->teb.htask16 = pdb->task;
238 thdb->teb.self = &thdb->teb;
239 thdb->teb.flags = (pdb->flags & PDB32_WIN16_PROC)? 0 : TEBF_WIN32;
240 thdb->teb.tls_ptr = thdb->tls_array;
241 thdb->teb.process = pdb;
242 thdb->exit_code = 0x103; /* STILL_ACTIVE */
243 thdb->entry_point = start_addr;
244 thdb->entry_arg = param;
245 thdb->socket = -1;
247 /* Allocate the TEB selector (%fs register) */
249 thdb->teb_sel = SELECTOR_AllocBlock( &thdb->teb, 0x1000, SEGMENT_DATA,
250 TRUE, FALSE );
251 if (!thdb->teb_sel) goto error;
253 /* Do the rest of the initialization */
255 if (!THREAD_InitTHDB( thdb, stack_size, alloc_stack16, server_thandle, server_phandle ))
256 goto error;
257 thdb->next = THREAD_First;
258 THREAD_First = thdb;
259 PE_InitTls( thdb );
260 return thdb;
262 error:
263 if (thdb->teb_sel) SELECTOR_FreeBlock( thdb->teb_sel, 1 );
264 HeapFree( SystemHeap, 0, thdb );
265 return NULL;
269 /***********************************************************************
270 * THREAD_Start
272 * Start execution of a newly created thread. Does not return.
274 void THREAD_Start( THDB *thdb )
276 LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point;
277 assert( THREAD_Current() == thdb );
278 CLIENT_InitThread();
279 MODULE_InitializeDLLs( 0, DLL_THREAD_ATTACH, NULL );
280 ExitThread( func( thdb->entry_arg ) );
284 /***********************************************************************
285 * CreateThread (KERNEL32.63)
287 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
288 LPTHREAD_START_ROUTINE start, LPVOID param,
289 DWORD flags, LPDWORD id )
291 int handle = -1;
292 BOOL inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
293 THDB *thread = THREAD_Create( PROCESS_Current(), stack,
294 TRUE, &handle, NULL, start, param );
295 if (!thread) return INVALID_HANDLE_VALUE;
296 if (SYSDEPS_SpawnThread( thread ) == -1)
298 CloseHandle( handle );
299 return INVALID_HANDLE_VALUE;
301 if (id) *id = (DWORD)thread->server_tid;
302 return handle;
306 /***********************************************************************
307 * ExitThread [KERNEL32.215] Ends a thread
309 * RETURNS
310 * None
312 void WINAPI ExitThread(
313 DWORD code) /* [in] Exit code for this thread */
315 THDB *thdb = THREAD_Current();
316 THDB **pptr = &THREAD_First;
317 WORD ds;
319 MODULE_InitializeDLLs( 0, DLL_THREAD_DETACH, NULL );
321 thdb->exit_code = code;
323 /* cleanup the message queue, if there's one */
324 if (thdb->teb.queue)
325 USER_QueueCleanup( thdb->teb.queue );
327 CloseHandle( thdb->event );
328 while (*pptr && (*pptr != thdb)) pptr = &(*pptr)->next;
329 if (*pptr) *pptr = thdb->next;
331 /* Free the associated memory */
333 if (thdb->teb.stack_sel) SELECTOR_FreeBlock( thdb->teb.stack_sel, 1 );
334 GET_DS( ds );
335 SET_FS( ds );
336 SELECTOR_FreeBlock( thdb->teb_sel, 1 );
337 close( thdb->socket );
338 HeapFree( SystemHeap, HEAP_NO_SERIALIZE, thdb );
340 /* FIXME: should free the stack somehow */
342 SYSDEPS_ExitThread();
346 /***********************************************************************
347 * GetCurrentThread [KERNEL32.200] Gets pseudohandle for current thread
349 * RETURNS
350 * Pseudohandle for the current thread
352 HANDLE WINAPI GetCurrentThread(void)
354 return CURRENT_THREAD_PSEUDOHANDLE;
358 /***********************************************************************
359 * GetCurrentThreadId [KERNEL32.201] Returns thread identifier.
361 * RETURNS
362 * Thread identifier of calling thread
364 DWORD WINAPI GetCurrentThreadId(void)
366 THDB *thdb = THREAD_Current();
367 /* FIXME: should not get here without a thread */
368 return thdb ? (DWORD)thdb->server_tid : 0x12345678;
372 /**********************************************************************
373 * GetLastError [KERNEL.148] [KERNEL32.227] Returns last-error code.
375 * RETURNS
376 * Calling thread's last error code value.
378 DWORD WINAPI GetLastError(void)
380 THDB *thread = THREAD_Current();
381 DWORD ret = thread->last_error;
382 TRACE(thread,"0x%lx\n",ret);
383 return ret;
387 /**********************************************************************
388 * SetLastError [KERNEL.147] [KERNEL32.497] Sets the last-error code.
390 * RETURNS
391 * None.
393 void WINAPI SetLastError(
394 DWORD error) /* [in] Per-thread error code */
396 THDB *thread = THREAD_Current();
397 /* This one must work before we have a thread (FIXME) */
399 TRACE(thread,"%p error=0x%lx\n",thread,error);
401 if (thread)
402 thread->last_error = error;
406 /**********************************************************************
407 * SetLastErrorEx [USER32.485] Sets the last-error code.
409 * RETURNS
410 * None.
412 void WINAPI SetLastErrorEx(
413 DWORD error, /* [in] Per-thread error code */
414 DWORD type) /* [in] Error type */
416 TRACE(thread, "(0x%08lx, 0x%08lx)\n", error,type);
417 switch(type) {
418 case 0:
419 break;
420 case SLE_ERROR:
421 case SLE_MINORERROR:
422 case SLE_WARNING:
423 /* Fall through for now */
424 default:
425 FIXME(thread, "(error=%08lx, type=%08lx): Unhandled type\n", error,type);
426 break;
428 SetLastError( error );
432 /**********************************************************************
433 * THREAD_TlsAlloc
435 DWORD THREAD_TlsAlloc(THDB *thread)
437 DWORD i, mask, ret = 0;
438 DWORD *bits = thread->process->tls_bits;
439 EnterCriticalSection( &thread->process->crit_section );
440 if (*bits == 0xffffffff)
442 bits++;
443 ret = 32;
444 if (*bits == 0xffffffff)
446 LeaveCriticalSection( &thread->process->crit_section );
447 SetLastError( ERROR_NO_MORE_ITEMS );
448 return 0xffffffff;
451 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
452 *bits |= mask;
453 LeaveCriticalSection( &thread->process->crit_section );
454 return ret + i;
458 /**********************************************************************
459 * TlsAlloc [KERNEL32.530] Allocates a TLS index.
461 * Allocates a thread local storage index
463 * RETURNS
464 * Success: TLS Index
465 * Failure: 0xFFFFFFFF
467 DWORD WINAPI TlsAlloc(void)
469 return THREAD_TlsAlloc(THREAD_Current());
473 /**********************************************************************
474 * TlsFree [KERNEL32.531] Releases a TLS index.
476 * Releases a thread local storage index, making it available for reuse
478 * RETURNS
479 * Success: TRUE
480 * Failure: FALSE
482 BOOL WINAPI TlsFree(
483 DWORD index) /* [in] TLS Index to free */
485 DWORD mask;
486 THDB *thread = THREAD_Current();
487 DWORD *bits = thread->process->tls_bits;
488 if (index >= 64)
490 SetLastError( ERROR_INVALID_PARAMETER );
491 return FALSE;
493 EnterCriticalSection( &thread->process->crit_section );
494 if (index >= 32) bits++;
495 mask = (1 << (index & 31));
496 if (!(*bits & mask)) /* already free? */
498 LeaveCriticalSection( &thread->process->crit_section );
499 SetLastError( ERROR_INVALID_PARAMETER );
500 return FALSE;
502 *bits &= ~mask;
503 thread->tls_array[index] = 0;
504 /* FIXME: should zero all other thread values */
505 LeaveCriticalSection( &thread->process->crit_section );
506 return TRUE;
510 /**********************************************************************
511 * TlsGetValue [KERNEL32.532] Gets value in a thread's TLS slot
513 * RETURNS
514 * Success: Value stored in calling thread's TLS slot for index
515 * Failure: 0 and GetLastError returns NO_ERROR
517 LPVOID WINAPI TlsGetValue(
518 DWORD index) /* [in] TLS index to retrieve value for */
520 THDB *thread = THREAD_Current();
521 if (index >= 64)
523 SetLastError( ERROR_INVALID_PARAMETER );
524 return NULL;
526 SetLastError( ERROR_SUCCESS );
527 return thread->tls_array[index];
531 /**********************************************************************
532 * TlsSetValue [KERNEL32.533] Stores a value in the thread's TLS slot.
534 * RETURNS
535 * Success: TRUE
536 * Failure: FALSE
538 BOOL WINAPI TlsSetValue(
539 DWORD index, /* [in] TLS index to set value for */
540 LPVOID value) /* [in] Value to be stored */
542 THDB *thread = THREAD_Current();
543 if (index >= 64)
545 SetLastError( ERROR_INVALID_PARAMETER );
546 return FALSE;
548 thread->tls_array[index] = value;
549 return TRUE;
553 /***********************************************************************
554 * SetThreadContext [KERNEL32.670] Sets context of thread.
556 * RETURNS
557 * Success: TRUE
558 * Failure: FALSE
560 BOOL WINAPI SetThreadContext(
561 HANDLE handle, /* [in] Handle to thread with context */
562 CONTEXT *context) /* [out] Address of context structure */
564 FIXME( thread, "not implemented\n" );
565 return TRUE;
568 /***********************************************************************
569 * GetThreadContext [KERNEL32.294] Retrieves context of thread.
571 * RETURNS
572 * Success: TRUE
573 * Failure: FALSE
575 BOOL WINAPI GetThreadContext(
576 HANDLE handle, /* [in] Handle to thread with context */
577 CONTEXT *context) /* [out] Address of context structure */
579 WORD cs, ds;
581 FIXME( thread, "returning dummy info\n" );
583 /* make up some plausible values for segment registers */
584 GET_CS(cs);
585 GET_DS(ds);
586 context->SegCs = cs;
587 context->SegDs = ds;
588 context->SegEs = ds;
589 context->SegGs = ds;
590 context->SegSs = ds;
591 context->SegFs = ds;
592 return TRUE;
596 /**********************************************************************
597 * GetThreadPriority [KERNEL32.296] Returns priority for thread.
599 * RETURNS
600 * Success: Thread's priority level.
601 * Failure: THREAD_PRIORITY_ERROR_RETURN
603 INT WINAPI GetThreadPriority(
604 HANDLE hthread) /* [in] Handle to thread */
606 struct get_thread_info_request req;
607 struct get_thread_info_reply reply;
608 req.handle = hthread;
609 CLIENT_SendRequest( REQ_GET_THREAD_INFO, -1, 1, &req, sizeof(req) );
610 if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL ))
611 return THREAD_PRIORITY_ERROR_RETURN;
612 return reply.priority;
616 /**********************************************************************
617 * SetThreadPriority [KERNEL32.514] Sets priority for thread.
619 * RETURNS
620 * Success: TRUE
621 * Failure: FALSE
623 BOOL WINAPI SetThreadPriority(
624 HANDLE hthread, /* [in] Handle to thread */
625 INT priority) /* [in] Thread priority level */
627 struct set_thread_info_request req;
628 req.handle = hthread;
629 req.priority = priority;
630 req.mask = SET_THREAD_INFO_PRIORITY;
631 CLIENT_SendRequest( REQ_SET_THREAD_INFO, -1, 1, &req, sizeof(req) );
632 return !CLIENT_WaitReply( NULL, NULL, 0 );
636 /**********************************************************************
637 * SetThreadAffinityMask (KERNEL32.669)
639 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
641 struct set_thread_info_request req;
642 req.handle = hThread;
643 req.affinity = dwThreadAffinityMask;
644 req.mask = SET_THREAD_INFO_AFFINITY;
645 CLIENT_SendRequest( REQ_SET_THREAD_INFO, -1, 1, &req, sizeof(req) );
646 if (CLIENT_WaitReply( NULL, NULL, 0 )) return 0;
647 return 1; /* FIXME: should return previous value */
651 /**********************************************************************
652 * TerminateThread [KERNEL32.685] Terminates a thread
654 * RETURNS
655 * Success: TRUE
656 * Failure: FALSE
658 BOOL WINAPI TerminateThread(
659 HANDLE handle, /* [in] Handle to thread */
660 DWORD exitcode) /* [in] Exit code for thread */
662 struct terminate_thread_request req;
663 req.handle = handle;
664 req.exit_code = exitcode;
665 CLIENT_SendRequest( REQ_TERMINATE_THREAD, -1, 1, &req, sizeof(req) );
666 return !CLIENT_WaitReply( NULL, NULL, 0 );
670 /**********************************************************************
671 * GetExitCodeThread [KERNEL32.???] Gets termination status of thread.
673 * RETURNS
674 * Success: TRUE
675 * Failure: FALSE
677 BOOL WINAPI GetExitCodeThread(
678 HANDLE hthread, /* [in] Handle to thread */
679 LPDWORD exitcode) /* [out] Address to receive termination status */
681 struct get_thread_info_request req;
682 struct get_thread_info_reply reply;
683 req.handle = hthread;
684 CLIENT_SendRequest( REQ_GET_THREAD_INFO, -1, 1, &req, sizeof(req) );
685 if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return FALSE;
686 if (exitcode) *exitcode = reply.exit_code;
687 return TRUE;
691 /**********************************************************************
692 * ResumeThread [KERNEL32.587] Resumes a thread.
694 * Decrements a thread's suspend count. When count is zero, the
695 * execution of the thread is resumed.
697 * RETURNS
698 * Success: Previous suspend count
699 * Failure: 0xFFFFFFFF
700 * Already running: 0
702 DWORD WINAPI ResumeThread(
703 HANDLE hthread) /* [in] Identifies thread to restart */
705 struct resume_thread_request req;
706 struct resume_thread_reply reply;
707 req.handle = hthread;
708 CLIENT_SendRequest( REQ_RESUME_THREAD, -1, 1, &req, sizeof(req) );
709 if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return 0xffffffff;
710 return reply.count;
714 /**********************************************************************
715 * SuspendThread [KERNEL32.681] Suspends a thread.
717 * RETURNS
718 * Success: Previous suspend count
719 * Failure: 0xFFFFFFFF
721 DWORD WINAPI SuspendThread(
722 HANDLE hthread) /* [in] Handle to the thread */
724 struct suspend_thread_request req;
725 struct suspend_thread_reply reply;
726 req.handle = hthread;
727 CLIENT_SendRequest( REQ_SUSPEND_THREAD, -1, 1, &req, sizeof(req) );
728 if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return 0xffffffff;
729 return reply.count;
733 /***********************************************************************
734 * QueueUserAPC (KERNEL32.566)
736 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
738 struct queue_apc_request req;
739 req.handle = hthread;
740 req.func = func;
741 req.param = (void *)data;
742 CLIENT_SendRequest( REQ_QUEUE_APC, -1, 1, &req, sizeof(req) );
743 return !CLIENT_WaitReply( NULL, NULL, 0 );
747 /**********************************************************************
748 * GetThreadTimes [KERNEL32.???] Obtains timing information.
750 * NOTES
751 * What are the fields where these values are stored?
753 * RETURNS
754 * Success: TRUE
755 * Failure: FALSE
757 BOOL WINAPI GetThreadTimes(
758 HANDLE thread, /* [in] Specifies the thread of interest */
759 LPFILETIME creationtime, /* [out] When the thread was created */
760 LPFILETIME exittime, /* [out] When the thread was destroyed */
761 LPFILETIME kerneltime, /* [out] Time thread spent in kernel mode */
762 LPFILETIME usertime) /* [out] Time thread spent in user mode */
764 FIXME(thread,"(0x%08x): stub\n",thread);
765 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
766 return FALSE;
770 /**********************************************************************
771 * AttachThreadInput [KERNEL32.8] Attaches input of 1 thread to other
773 * Attaches the input processing mechanism of one thread to that of
774 * another thread.
776 * RETURNS
777 * Success: TRUE
778 * Failure: FALSE
780 * TODO:
781 * 1. Reset the Key State (currenly per thread key state is not maintained)
783 BOOL WINAPI AttachThreadInput(
784 DWORD idAttach, /* [in] Thread to attach */
785 DWORD idAttachTo, /* [in] Thread to attach to */
786 BOOL fAttach) /* [in] Attach or detach */
788 MESSAGEQUEUE *pSrcMsgQ = 0, *pTgtMsgQ = 0;
789 BOOL16 bRet = 0;
791 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
793 /* A thread cannot attach to itself */
794 if ( idAttach == idAttachTo )
795 goto CLEANUP;
797 /* According to the docs this method should fail if a
798 * "Journal record" hook is installed. (attaches all input queues together)
800 if ( HOOK_IsHooked( WH_JOURNALRECORD ) )
801 goto CLEANUP;
803 /* Retrieve message queues corresponding to the thread id's */
804 pTgtMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetThreadQueue16( idAttach ) );
805 pSrcMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetThreadQueue16( idAttachTo ) );
807 /* Ensure we have message queues and that Src and Tgt threads
808 * are not system threads.
810 if ( !pSrcMsgQ || !pTgtMsgQ || !pSrcMsgQ->pQData || !pTgtMsgQ->pQData )
811 goto CLEANUP;
813 if (fAttach) /* Attach threads */
815 /* Only attach if currently detached */
816 if ( pTgtMsgQ->pQData != pSrcMsgQ->pQData )
818 /* First release the target threads perQData */
819 PERQDATA_Release( pTgtMsgQ->pQData );
821 /* Share a reference to the source threads perQDATA */
822 PERQDATA_Addref( pSrcMsgQ->pQData );
823 pTgtMsgQ->pQData = pSrcMsgQ->pQData;
826 else /* Detach threads */
828 /* Only detach if currently attached */
829 if ( pTgtMsgQ->pQData == pSrcMsgQ->pQData )
831 /* First release the target threads perQData */
832 PERQDATA_Release( pTgtMsgQ->pQData );
834 /* Give the target thread its own private perQDATA once more */
835 pTgtMsgQ->pQData = PERQDATA_CreateInstance();
839 /* TODO: Reset the Key State */
841 bRet = 1; // Success
843 CLEANUP:
845 /* Unlock the queues before returning */
846 if ( pSrcMsgQ )
847 QUEUE_Unlock( pSrcMsgQ );
848 if ( pTgtMsgQ )
849 QUEUE_Unlock( pTgtMsgQ );
851 return bRet;
854 /**********************************************************************
855 * VWin32_BoostThreadGroup [KERNEL.535]
857 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
859 FIXME(thread, "(0x%08lx,%d): stub\n", threadId, boost);
862 /**********************************************************************
863 * VWin32_BoostThreadStatic [KERNEL.536]
865 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
867 FIXME(thread, "(0x%08lx,%d): stub\n", threadId, boost);
870 /**********************************************************************
871 * SetThreadLocale [KERNEL32.671] Sets the calling threads current locale.
873 * RETURNS
874 * Success: TRUE
875 * Failure: FALSE
877 * NOTES
878 * Implemented in NT only (3.1 and above according to MS
880 BOOL WINAPI SetThreadLocale(
881 LCID lcid) /* [in] Locale identifier */
883 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
884 return FALSE;