source: trunk/src/kernel32/thread.cpp@ 21986

Last change on this file since 21986 was 21986, checked in by dmik, 13 years ago

kernel: Fix crash in PE/PEC (another regression of r21981).

Closes #78.

File size: 38.2 KB
Line 
1/* $Id: thread.cpp,v 1.55 2004-05-24 08:56:07 sandervl Exp $ */
2
3/*
4 * Win32 Thread API functions
5 *
6 * TODO: Initialize threadInfo structure during thread creation
7 *
8 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
9 *
10 * Project Odin Software License can be found in LICENSE.TXT
11 *
12 */
13
14/*****************************************************************************
15 * Includes *
16 *****************************************************************************/
17#include <odin.h>
18#include <odinwrap.h>
19#include <os2sel.h>
20
21#include <os2win.h>
22#include <stdarg.h>
23#include <string.h>
24#include "thread.h"
25#include <misc.h>
26#include <cpuhlp.h>
27#include <wprocess.h>
28#include "windllbase.h"
29#include "winexebase.h"
30#include "exceptutil.h"
31#include "oslibmisc.h"
32#include "oslibdos.h"
33#include "oslibthread.h"
34#include <handlemanager.h>
35#include <codepage.h>
36#include <heapstring.h>
37
38#include "hmhandle.h"
39#include "hmthread.h"
40#include <kbdhook.h>
41
42#include <FastInfoBlocks.h>
43#include <custombuild.h>
44
45#define DBG_LOCALLOG DBG_thread
46#include "dbglocal.h"
47
48ODINDEBUGCHANNEL(KERNEL32-THREAD)
49
50static ULONG priorityclass = NORMAL_PRIORITY_CLASS;
51
52#define MQP_INSTANCE_PERMQ 0x00000001 // from os2im.h
53
54// borrowed from ntddk.h
55void WINAPI RtlUnwind(
56 PEXCEPTION_FRAME,
57 LPVOID,
58 PEXCEPTION_RECORD,DWORD);
59
60//******************************************************************************
61//******************************************************************************
62HANDLE WIN32API CreateThread(LPSECURITY_ATTRIBUTES lpsa,
63 DWORD cbStack,
64 LPTHREAD_START_ROUTINE lpStartAddr,
65 LPVOID lpvThreadParm,
66 DWORD fdwCreate,
67 LPDWORD lpIDThread)
68{
69 return HMCreateThread(lpsa, cbStack, lpStartAddr, lpvThreadParm, fdwCreate, lpIDThread);
70}
71/*****************************************************************************
72 * Name : HMCreateThread
73 * Purpose : router function for CreateThread
74 * Parameters:
75 * Variables :
76 * Result :
77 * Remark :
78 * Status :
79 *
80 * Author : SvL
81 *****************************************************************************/
82HANDLE HMCreateThread(LPSECURITY_ATTRIBUTES lpsa,
83 DWORD cbStack,
84 LPTHREAD_START_ROUTINE lpStartAddr,
85 LPVOID lpvThreadParm,
86 DWORD fdwCreate,
87 LPDWORD lpIDThread,
88 BOOL fRegisterThread)
89{
90 HMDeviceHandler *pDeviceHandler; /* device handler for this handle */
91 PHMHANDLE pHandle;
92 HANDLE rc; /* API return code */
93
94 SetLastError(ERROR_SUCCESS);
95
96 pHandle = HMHandleGetFreePtr(HMTYPE_THREAD); /* get free handle */
97 if (pHandle == NULL) /* oops, no free handles ! */
98 {
99 SetLastError(ERROR_NOT_ENOUGH_MEMORY); /* use this as error message */
100 return 0; //according to MSDN
101 }
102
103 /* call the device handler */
104 rc = pHandle->pDeviceHandler->CreateThread(&pHandle->hmHandleData,
105 lpsa, cbStack, lpStartAddr,
106 lpvThreadParm, fdwCreate, lpIDThread, fRegisterThread);
107
108 if (rc == 0) /* oops, creation failed within the device handler */
109 {
110 HMHandleFree(pHandle->hmHandleData.hWin32Handle);
111 return 0; /* signal error */
112 }
113
114 return pHandle->hmHandleData.hWin32Handle;
115}
116/*****************************************************************************
117 *****************************************************************************/
118HANDLE WIN32API OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId)
119{
120 dprintf(("KERNEL32: OpenThread(%08xh, %08xh, %08xh) not implemented\n",
121 dwDesiredAccess, bInheritHandle, dwThreadId));
122 return NULL;
123}
124/*****************************************************************************
125 * Name : HMGetThreadPriority
126 * Purpose : router function for GetThreadPriority
127 * Parameters:
128 * Variables :
129 * Result :
130 * Remark :
131 * Status :
132 *
133 * Author : SvL
134 *****************************************************************************/
135INT WIN32API GetThreadPriority(HANDLE hThread)
136{
137 INT lpResult; /* result from the device handler's API */
138 PHMHANDLE pHMHandle; /* pointer to the handle structure in the table */
139
140 SetLastError(ERROR_SUCCESS);
141 /* validate handle */
142 pHMHandle = HMHandleQueryPtr(hThread); /* get the index */
143 if (pHMHandle == NULL) /* error ? */
144 {
145 return -1; //last error set by HMHandleQueryPtr (ERROR_INVALID_HANDLE)
146 }
147
148 lpResult = pHMHandle->pDeviceHandler->GetThreadPriority(hThread, &pHMHandle->hmHandleData);
149
150 return (lpResult); /* deliver return code */
151}
152/*****************************************************************************
153 * Name : HMSuspendThread
154 * Purpose : router function for SuspendThread
155 * Parameters:
156 * Variables :
157 * Result :
158 * Remark :
159 * Status :
160 *
161 * Author : SvL
162 *****************************************************************************/
163DWORD WIN32API SuspendThread(HANDLE hThread)
164{
165 HANDLE lpResult; /* result from the device handler's API */
166 PHMHANDLE pHMHandle; /* pointer to the handle structure in the table */
167
168 SetLastError(ERROR_SUCCESS);
169 /* validate handle */
170 pHMHandle = HMHandleQueryPtr(hThread); /* get the index */
171 if (pHMHandle == NULL) /* error ? */
172 {
173 return -1; //last error set by HMHandleQueryPtr (ERROR_INVALID_HANDLE)
174 }
175
176 lpResult = pHMHandle->pDeviceHandler->SuspendThread(hThread, &pHMHandle->hmHandleData);
177
178 return (lpResult); /* deliver return code */
179}
180/*****************************************************************************
181 * Name : HMSetThreadPriority
182 * Purpose : router function for SetThreadPriority
183 * Parameters:
184 * Variables :
185 * Result :
186 * Remark :
187 * Status :
188 *
189 * Author : SvL
190 *****************************************************************************/
191BOOL WIN32API SetThreadPriority(HANDLE hThread, int priority)
192{
193 BOOL lpResult; /* result from the device handler's API */
194 PHMHANDLE pHMHandle; /* pointer to the handle structure in the table */
195
196 SetLastError(ERROR_SUCCESS);
197 /* validate handle */
198 pHMHandle = HMHandleQueryPtr(hThread); /* get the index */
199 if (pHMHandle == NULL) /* error ? */
200 {
201 return FALSE; //last error set by HMHandleQueryPtr (ERROR_INVALID_HANDLE)
202 }
203 lpResult = pHMHandle->pDeviceHandler->SetThreadPriority(hThread, &pHMHandle->hmHandleData, priority);
204
205 return (lpResult); /* deliver return code */
206}
207/*****************************************************************************
208 * Name : HMGetThreadContext
209 * Purpose : router function for GetThreadContext
210 * Parameters:
211 * Variables :
212 * Result :
213 * Remark :
214 * Status :
215 *
216 * Author : SvL
217 *****************************************************************************/
218BOOL WIN32API GetThreadContext(HANDLE hThread, CONTEXT *lpContext)
219{
220 BOOL lpResult; /* result from the device handler's API */
221 PHMHANDLE pHMHandle; /* pointer to the handle structure in the table */
222
223 SetLastError(ERROR_SUCCESS);
224 /* validate handle */
225 pHMHandle = HMHandleQueryPtr(hThread); /* get the index */
226 if (pHMHandle == NULL) /* error ? */
227 {
228 return FALSE; //last error set by HMHandleQueryPtr (ERROR_INVALID_HANDLE)
229 }
230
231 lpResult = pHMHandle->pDeviceHandler->GetThreadContext(hThread, &pHMHandle->hmHandleData, lpContext);
232
233 return (lpResult); /* deliver return code */
234}
235/*****************************************************************************
236 * Name : HMSetThreadContext
237 * Purpose : router function for SetThreadContext
238 * Parameters:
239 * Variables :
240 * Result :
241 * Remark :
242 * Status :
243 *
244 * Author : SvL
245 *****************************************************************************/
246BOOL WIN32API SetThreadContext(HANDLE hThread, const CONTEXT *lpContext)
247{
248 BOOL lpResult; /* result from the device handler's API */
249 PHMHANDLE pHMHandle; /* pointer to the handle structure in the table */
250
251 SetLastError(ERROR_SUCCESS);
252 /* validate handle */
253 pHMHandle = HMHandleQueryPtr(hThread); /* get the index */
254 if (pHMHandle == NULL) /* error ? */
255 {
256 return FALSE; //last error set by HMHandleQueryPtr (ERROR_INVALID_HANDLE)
257 }
258 lpResult = pHMHandle->pDeviceHandler->SetThreadContext(hThread, &pHMHandle->hmHandleData, lpContext);
259
260 return (lpResult); /* deliver return code */
261}
262/*****************************************************************************
263 * Name : HMGetThreadTimes
264 * Purpose : router function for HMGetThreadTimes
265 * Parameters:
266 * Variables :
267 * Result :
268 * Remark :
269 * Status :
270 *
271 * Author : SvL
272 *****************************************************************************/
273BOOL WIN32API GetThreadTimes(HANDLE hThread, LPFILETIME lpCreationTime,
274 LPFILETIME lpExitTime, LPFILETIME lpKernelTime,
275 LPFILETIME lpUserTime)
276{
277 BOOL lpResult; /* result from the device handler's API */
278 PHMHANDLE pHMHandle; /* pointer to the handle structure in the table */
279
280 SetLastError(ERROR_SUCCESS);
281 /* validate handle */
282 pHMHandle = HMHandleQueryPtr(hThread); /* get the index */
283 if (pHMHandle == NULL) /* error ? */
284 {
285 return FALSE; //last error set by HMHandleQueryPtr (ERROR_INVALID_HANDLE)
286 }
287
288 lpResult = pHMHandle->pDeviceHandler->GetThreadTimes(hThread, &pHMHandle->hmHandleData,
289 lpCreationTime, lpExitTime,
290 lpKernelTime, lpUserTime);
291
292 return (lpResult); /* deliver return code */
293}
294/*****************************************************************************
295 * Name : HMTerminateThread
296 * Purpose : router function for TerminateThread
297 * Parameters:
298 * Variables :
299 * Result :
300 * Remark :
301 * Status :
302 *
303 * Author : SvL
304 *****************************************************************************/
305BOOL WIN32API TerminateThread(HANDLE hThread, DWORD exitcode)
306{
307 BOOL lpResult; /* result from the device handler's API */
308 PHMHANDLE pHMHandle; /* pointer to the handle structure in the table */
309
310 SetLastError(ERROR_SUCCESS);
311 /* validate handle */
312 pHMHandle = HMHandleQueryPtr(hThread); /* get the index */
313 if (pHMHandle == NULL) /* error ? */
314 {
315 return FALSE; //last error set by HMHandleQueryPtr (ERROR_INVALID_HANDLE)
316 }
317
318 lpResult = pHMHandle->pDeviceHandler->TerminateThread(hThread, &pHMHandle->hmHandleData, exitcode);
319
320 return (lpResult); /* deliver return code */
321}
322/*****************************************************************************
323 * Name : HMResumeThread
324 * Purpose : router function for ResumeThread
325 * Parameters:
326 * Variables :
327 * Result :
328 * Remark :
329 * Status :
330 *
331 * Author : SvL
332 *****************************************************************************/
333DWORD WIN32API ResumeThread(HANDLE hThread)
334{
335 DWORD lpResult; /* result from the device handler's API */
336 PHMHANDLE pHMHandle; /* pointer to the handle structure in the table */
337
338 SetLastError(ERROR_SUCCESS);
339 /* validate handle */
340 pHMHandle = HMHandleQueryPtr(hThread); /* get the index */
341 if (pHMHandle == NULL) /* error ? */
342 {
343 return -1; //last error set by HMHandleQueryPtr (ERROR_INVALID_HANDLE)
344 }
345
346 lpResult = pHMHandle->pDeviceHandler->ResumeThread(hThread, &pHMHandle->hmHandleData);
347
348 return (lpResult); /* deliver return code */
349}
350
351/*****************************************************************************
352 * Name : HMGetExitCodeThread
353 * Purpose : router function for GetExitCodeThread
354 * Parameters:
355 * Variables :
356 * Result :
357 * Remark :
358 * Status :
359 *
360 * Author : SvL
361 *****************************************************************************/
362BOOL WIN32API GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode)
363{
364 BOOL lpResult; /* result from the device handler's API */
365 PHMHANDLE pHMHandle; /* pointer to the handle structure in the table */
366
367 SetLastError(ERROR_SUCCESS);
368 /* validate handle */
369 pHMHandle = HMHandleQueryPtr(hThread); /* get the index */
370 if (pHMHandle == NULL) /* error ? */
371 {
372 return FALSE; //last error set by HMHandleQueryPtr (ERROR_INVALID_HANDLE)
373 }
374
375 lpResult = pHMHandle->pDeviceHandler->GetExitCodeThread(hThread, &pHMHandle->hmHandleData, lpExitCode);
376
377 return (lpResult); /* deliver return code */
378}
379
380/*****************************************************************************
381 * Name : HMSetThreadTerminated
382 * Purpose :
383 * Parameters:
384 * Variables :
385 * Result :
386 * Remark :
387 * Status :
388 *
389 * Author : SvL
390 *****************************************************************************/
391BOOL HMSetThreadTerminated(HANDLE hThread)
392{
393 BOOL lpResult; /* result from the device handler's API */
394 PHMHANDLE pHMHandle; /* pointer to the handle structure in the table */
395
396 SetLastError(ERROR_SUCCESS);
397 /* validate handle */
398 pHMHandle = HMHandleQueryPtr(hThread); /* get the index */
399 if (pHMHandle == NULL) /* error ? */
400 {
401 return FALSE; //last error set by HMHandleQueryPtr (ERROR_INVALID_HANDLE)
402 }
403 lpResult = pHMHandle->pDeviceHandler->SetThreadTerminated(hThread, &pHMHandle->hmHandleData);
404
405 return (lpResult); /* deliver return code */
406}
407
408//******************************************************************************
409//******************************************************************************
410DWORD WIN32API GetCurrentThreadId()
411{
412 // check cached identifier
413 TEB *teb = GetThreadTEB();
414 if(teb != NULL && teb->o.odin.threadId != 0xFFFFFFFF)
415 {
416 // this is set in InitializeTIB() already.
417 return teb->o.odin.threadId;
418 }
419
420//// dprintf(("GetCurrentThreadId\n"));
421 return MAKE_THREADID(O32_GetCurrentProcessId(), O32_GetCurrentThreadId());
422}
423//******************************************************************************
424//******************************************************************************
425HANDLE WIN32API GetCurrentThread()
426{
427 TEB *teb;
428
429 teb = GetThreadTEB();
430 if(teb == 0) {
431 DebugInt3();
432 SetLastError(ERROR_INVALID_HANDLE); //todo
433 return 0;
434 }
435 return teb->o.odin.hThread;
436}
437//******************************************************************************
438// these two debugging functions allow access to a
439// calldepth counter inside the TEB block of each thread
440//******************************************************************************
441ULONG WIN32API dbg_GetThreadCallDepth()
442{
443#ifdef DEBUG
444 TEB *teb;
445
446 teb = GetThreadTEB();
447 if(teb == NULL)
448 return 0;
449 else
450 return teb->o.odin.dbgCallDepth;
451#else
452 return 0;
453#endif
454}
455//******************************************************************************
456//******************************************************************************
457void WIN32API dbg_IncThreadCallDepth()
458{
459#ifdef DEBUG
460 TEB *teb;
461
462 teb = GetThreadTEB();
463 if(teb != NULL)
464 teb->o.odin.dbgCallDepth++;
465#endif
466}
467//******************************************************************************
468#define MAX_CALLSTACK_SIZE 128
469#ifdef DEBUG
470static const char *pszLastCaller = NULL;
471#endif
472//******************************************************************************
473void WIN32API dbg_ThreadPushCall(const char *pszCaller)
474{
475#ifdef DEBUG
476 TEB *teb;
477
478 // embedded dbg_IncThreadCallDepth
479 teb = GetThreadTEB();
480 if(teb == NULL)
481 return;
482
483 // add caller name to call stack trace
484 int iIndex = teb->o.odin.dbgCallDepth;
485
486 // allocate callstack on demand
487 if (teb->o.odin.arrstrCallStack == NULL)
488 teb->o.odin.arrstrCallStack = (PVOID*)malloc( sizeof(LPSTR) * MAX_CALLSTACK_SIZE);
489
490 // insert entry
491 if (iIndex < MAX_CALLSTACK_SIZE)
492 teb->o.odin.arrstrCallStack[iIndex] = (PVOID)pszCaller;
493
494 teb->o.odin.dbgCallDepth++;
495
496 pszLastCaller = pszCaller;
497#endif
498}
499//******************************************************************************
500//******************************************************************************
501void WIN32API dbg_DecThreadCallDepth()
502{
503#ifdef DEBUG
504 TEB *teb;
505
506 teb = GetThreadTEB();
507 if(teb != NULL)
508 --(teb->o.odin.dbgCallDepth);
509#endif
510}
511//******************************************************************************
512//******************************************************************************
513void WIN32API dbg_ThreadPopCall()
514{
515#ifdef DEBUG
516 TEB *teb;
517
518 // embedded dbg_DecThreadCallDepth
519 teb = GetThreadTEB();
520 if(teb == NULL)
521 return;
522
523 --(teb->o.odin.dbgCallDepth);
524
525 // add caller name to call stack trace
526 int iIndex = teb->o.odin.dbgCallDepth;
527
528 // insert entry
529 if (teb->o.odin.arrstrCallStack)
530 if (iIndex < MAX_CALLSTACK_SIZE)
531 teb->o.odin.arrstrCallStack[iIndex] = NULL;
532#endif
533}
534//******************************************************************************
535//******************************************************************************
536char* WIN32API dbg_GetLastCallerName()
537{
538#ifdef DEBUG
539 // retrieve last caller name from stack
540 TEB *teb;
541
542 // embedded dbg_DecThreadCallDepth
543 teb = GetThreadTEB();
544 if(teb != NULL)
545 {
546 int iIndex = teb->o.odin.dbgCallDepth - 1;
547 if ( (iIndex > 0) &&
548 (iIndex < MAX_CALLSTACK_SIZE) )
549 {
550 return (char*)teb->o.odin.arrstrCallStack[iIndex];
551 }
552 }
553#endif
554
555 return NULL;
556}
557//******************************************************************************
558//******************************************************************************
559VOID WIN32API ExitThread(DWORD exitcode)
560{
561 EXCEPTION_FRAME *exceptFrame;
562 TEB *teb;
563
564 dprintf(("ExitThread %x (%x)", GetCurrentThread(), exitcode));
565
566 // make sure the Win32 exception stack (if there is still any) is unwound
567 // before we destroy internal structures including the Win32 TIB
568 RtlUnwind(NULL, 0, 0, 0);
569
570 teb = GetThreadTEB();
571 if(teb != 0) {
572 exceptFrame = (EXCEPTION_FRAME *)teb->o.odin.exceptFrame;
573 }
574 else DebugInt3();
575
576 HMSetThreadTerminated(GetCurrentThread());
577 Win32DllBase::detachThreadFromAllDlls(); //send DLL_THREAD_DETACH message to all dlls
578 Win32DllBase::tlsDetachThreadFromAllDlls(); //destroy TLS structures of all dlls
579 if(WinExe) WinExe->tlsDetachThread(); //destroy TLS structure of main exe
580
581 if(teb) DestroyTEB(teb);
582
583 if(exceptFrame) OS2UnsetExceptionHandler((void *)exceptFrame);
584
585 O32_ExitThread(exitcode);
586}
587/*****************************************************************************
588 * Name : DWORD SetThreadAffinityMask
589 * Purpose : The SetThreadAffinityMask function sets a processor affinity
590 * mask for a specified thread.
591 * A thread affinity mask is a bit vector in which each bit
592 * represents the processors that a thread is allowed to run on.
593 * A thread affinity mask must be a proper subset of the process
594 * affinity mask for the containing process of a thread. A thread
595 * is only allowed to run on the processors its process is allowed to run on.
596 * Parameters: HANDLE hThread handle to the thread of interest
597 * DWORD dwThreadAffinityMask a thread affinity mask
598 * Variables :
599 * Result : TRUE / FALSE
600 * Remark :
601 * Status : Fully functional
602 *
603 * Author : SvL
604 *****************************************************************************/
605
606DWORD WIN32API SetThreadAffinityMask(HANDLE hThread,
607 DWORD dwThreadAffinityMask)
608{
609 dprintf(("KERNEL32: SetThreadAffinityMask(%08xh,%08xh)", hThread, dwThreadAffinityMask));
610
611 if(hThread != GetCurrentThread()) {
612 dprintf(("WARNING: Setting the affinity mask for another thread than the current one is not supported!!"));
613 return FALSE;
614 }
615 return OSLibDosSetThreadAffinity(dwThreadAffinityMask);
616}
617//******************************************************************************
618//******************************************************************************
619VOID WIN32API Sleep(DWORD mSecs)
620{
621 dprintf2(("KERNEL32: Sleep %d", mSecs));
622 OSLibDosSleep(mSecs);
623}
624//******************************************************************************
625//******************************************************************************
626DWORD WIN32API GetPriorityClass(HANDLE hProcess)
627{
628 dprintf(("KERNEL32: GetPriorityClass %x", hProcess));
629 return priorityclass;
630// return O32_GetPriorityClass(hProcess);
631}
632//******************************************************************************
633//******************************************************************************
634BOOL WIN32API SetPriorityClass(HANDLE hProcess, DWORD dwPriority)
635{
636 dprintf(("KERNEL32: SetPriorityClass %x %x", hProcess, dwPriority));
637 priorityclass = dwPriority;
638 return TRUE;
639// return O32_SetPriorityClass(hProcess, dwPriority);
640}
641//******************************************************************************
642//******************************************************************************
643/*****************************************************************************
644 * Name : BOOL SetThreadPriorityBoost
645 * Purpose : The SetThreadPriorityBoost function disables or enables
646 * the ability of the system to temporarily boost the priority
647 * of a thread.
648 * Parameters: Unknown (wrong)
649 * Variables :
650 * Result : Unknown
651 * Remark :
652 * Status : UNTESTED STUB
653 *
654 * Author : Patrick Haller [Tue, 1999/06/08 21:44]
655 *****************************************************************************/
656
657BOOL WIN32API SetThreadPriorityBoost(HANDLE hThread,
658 BOOL DisablePriorityBoost)
659{
660 dprintf(("KERNEL32: SetThreadPriorityBoost(%08xh, %08xh) not implemented\n",
661 hThread,DisablePriorityBoost));
662
663 return FALSE;
664}
665//******************************************************************************
666//******************************************************************************
667DWORD WIN32API QueueUserAPC(PAPCFUNC func, HANDLE hthread, ULONG_PTR data)
668{
669 dprintf(("KERNEL32: QueueUserAPC(%08xh, %08xh, %08xh) not implemented\n",
670 func, hthread, data));
671 return 0;
672}
673
674//******************************************************************************
675//******************************************************************************
676Win32Thread::Win32Thread(LPTHREAD_START_ROUTINE pUserCallback, LPVOID lpData, DWORD dwFlags, HANDLE hThread, DWORD cbCommitStack)
677{
678 lpUserData = lpData;
679 pCallback = pUserCallback;
680 this->dwFlags = dwFlags;
681 this->hThread = hThread;
682 this->cbCommitStack = cbCommitStack;
683
684 teb = CreateTEB(hThread, 0xFFFFFFFF);
685 if(teb == NULL) {
686 DebugInt3();
687 }
688}
689//******************************************************************************
690//******************************************************************************
691DWORD OPEN32API Win32Thread::Win32ThreadProc(LPVOID lpData)
692{
693 EXCEPTION_FRAME exceptFrame;
694 Win32Thread *me = (Win32Thread *)lpData;
695 ULONG threadCallback = (ULONG)me->pCallback;
696 DWORD rc;
697 TEB *winteb = (TEB *)me->teb;
698
699 if(InitializeThread(winteb) == FALSE) {
700 dprintf(("Win32ThreadProc: InitializeTIB failed!!"));
701 DebugInt3();
702 delete me;
703 return 0;
704 }
705 dprintf(("Win32ThreadProc: Thread handle 0x%x, thread id %d", GetCurrentThread(), GetCurrentThreadId()));
706
707 winteb->flags = me->dwFlags;
708
709 winteb->entry_point = (void *)threadCallback;
710 winteb->entry_arg = (void *)me->lpUserData;
711
712 winteb->o.odin.hab = OSLibWinInitialize();
713 dprintf(("Thread HAB %x", winteb->o.odin.hab));
714 winteb->o.odin.hmq = OSLibWinQueryMsgQueue(winteb->o.odin.hab);
715 dprintf(("Thread HMQ %x", winteb->o.odin.hmq));
716 rc = OSLibWinSetCp(winteb->o.odin.hmq, GetDisplayCodepage());
717 dprintf(("WinSetCP(%d) was %sOK", GetDisplayCodepage(), rc ? "" : "not "));
718 hookInit(winteb->o.odin.hab);
719
720 dprintf(("Stack top 0x%x, stack end 0x%x", winteb->stack_top, winteb->stack_low));
721
722 if (me->cbCommitStack) {
723 // pre-commit part of the stack
724 dprintf(("Pre-commit 0x%x bytes of stack", me->cbCommitStack));
725 PBYTE stack = ((PBYTE) (winteb->stack_top)) - 1;
726 for (int i = 0; i < (me->cbCommitStack + 0xFFF) / 0x1000; i++) {
727 BYTE unused = *stack;
728 unused = unused;
729 stack -= 0x1000;
730 }
731 }
732
733 if( IsDBCSEnv())
734 /* IM instace is created per message queue, that is, thread */
735 OSLibImSetMsgQueueProperty( winteb->o.odin.hmq, MQP_INSTANCE_PERMQ );
736
737 //Note: The Win32 exception structure referenced by FS:[0] is the same
738 // in OS/2
739 OS2SetExceptionHandler((void *)&exceptFrame);
740 winteb->o.odin.exceptFrame = (ULONG)&exceptFrame;
741
742 //Determine if thread callback is inside a PE dll; if true, then force
743 //switch to win32 TIB (FS selector)
744 //(necessary for Opera when loading win32 plugins that create threads)
745 Win32DllBase *dll;
746 dll = Win32DllBase::findModuleByAddr(threadCallback);
747 if(dll && dll->isPEImage()) {
748 dprintf(("Win32ThreadProc: Force win32 TIB switch"));
749 SetWin32TIB(TIB_SWITCH_FORCE_WIN32);
750 }
751 else SetWin32TIB(TIB_SWITCH_DEFAULT); //executable type determines whether or not FS is changed
752
753 DWORD dwProcessAffinityMask, dwSystemAffinityMask;
754
755 //Change the affinity mask of this thread to the mask for the whole process
756 if(GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask) == TRUE) {
757 SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
758 }
759
760 if(WinExe) WinExe->tlsAttachThread(); //setup TLS structure of main exe
761 Win32DllBase::tlsAttachThreadToAllDlls(); //setup TLS structures of all dlls
762 Win32DllBase::attachThreadToAllDlls(); //send DLL_THREAD_ATTACH message to all dlls
763
764 BOOL fAlignStack = ((ULONG)winteb->stack_top - (ULONG)winteb->stack_low) >= 128*1024;
765
766 //Set FPU control word to 0x27F (same as in NT)
767 CONTROL87(0x27F, 0xFFF);
768 rc = AsmCallThreadHandler(fAlignStack, threadCallback, me->lpUserData);
769
770 // make sure the Win32 exception stack (if there is still any) is unwound
771 // before we destroy internal structures including the Win32 TIB
772 RtlUnwind(NULL, 0, 0, 0);
773
774 if(fExitProcess) {
775 OSLibDosExitThread(rc);
776 }
777 else {
778 hookKill(winteb->o.odin.hab);
779 HMSetThreadTerminated(GetCurrentThread());
780 winteb->o.odin.exceptFrame = 0;
781 Win32DllBase::detachThreadFromAllDlls(); //send DLL_THREAD_DETACH message to all dlls
782 Win32DllBase::tlsDetachThreadFromAllDlls(); //destroy TLS structures of all dlls
783 if(WinExe) WinExe->tlsDetachThread(); //destroy TLS structure of main exe
784 DestroyTEB(winteb); //destroys TIB and restores FS
785 OS2UnsetExceptionHandler((void *)&exceptFrame);
786 }
787
788 delete me;
789 return rc;
790}
791//******************************************************************************
792//******************************************************************************
793
794/**
795 * Enter odin context with this thread.
796 *
797 * Is called when an OS/2 process is calling into an Odin32 DLL.
798 * This may be called also in a nested fashion and supports that.
799 * The conterpart of ODIN_ThreadLeaveOdinContext().
800 *
801 * @returns The old FS selector.
802 * @returns 0 if TEB creation failed.
803 * @param pExceptionRegRec OS/2 Exception Registration Record (2 ULONGs)
804 * must be located on the callers stack.
805 * @param fForceFSSwitch If set we will force switching to Odin32 FS selector.
806 * If clear it depends on defaults.
807 * @deprecated
808 */
809USHORT WIN32API ODIN_ThreadEnterOdinContext(void *pExceptionRegRec, BOOL fForceFSSwitch)
810{
811 USHORT selFSOld = 0;
812
813 /*
814 * Get TEB pointer, create it if necessary.
815 * @todo Check if this really is the thread which the TEB was created
816 * for. If not create the TEB.
817 */
818 TEB *pTeb = GetThreadTEB();
819 if (!pTeb)
820 {
821 HANDLE hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, TRUE);
822 pTeb = CreateTEB(hThreadMain, ODIN_GetCurrentThreadId());
823 if (!pTeb || InitializeThread(pTeb, fibGetTid() == 1) == FALSE)
824 {
825 dprintf(("ODIN_ThreadEnterOdinContext: Failed to create TEB!"));
826 }
827 }
828
829 /*
830 * Install the Odin32 exception handler.
831 * Note: The Win32 exception structure referenced by FS:[0] is the same in OS/2
832 */
833 if (pExceptionRegRec)
834 OS2SetExceptionHandler(pExceptionRegRec);
835 if ( pTeb
836 && !pTeb->o.odin.exceptFrame) /* if allready present, we'll keep the first one. */
837 pTeb->o.odin.exceptFrame = (ULONG)pExceptionRegRec;
838
839 /*
840 * Switch Selector if TIB was created.
841 */
842 if (pTeb)
843 selFSOld = SetWin32TIB(fForceFSSwitch ? TIB_SWITCH_FORCE_WIN32 : TIB_SWITCH_DEFAULT);
844
845 return selFSOld;
846}
847
848
849/**
850 * Leave odin context with this thread.
851 *
852 * Is called when an OS/2 process is returning from an Odin32 DLL.
853 * This may be called also in a nested fashion and supports that.
854 * The conterpart of ODIN_ThreadEnterOdinContext().
855 *
856 * @returns The old FS selector.
857 * @returns 0 if TEB creation failed.
858 * @param pExceptionRegRec OS/2 Exception Registration Record (2 ULONGs)
859 * must be located on the callers stack.
860 * @param fForceFSSwitch If set we will force switching to Odin32 FS selector.
861 * If clear it depends on defaults.
862 * @deprecated
863 */
864void WIN32API ODIN_ThreadLeaveOdinContext(void *pExceptionRegRec, USHORT selFSOld)
865{
866 /*
867 * Install the Odin32 exception handler.
868 * Note: The Win32 exception structure referenced by FS:[0] is the same in OS/2
869 */
870 if (pExceptionRegRec)
871 OS2UnsetExceptionHandler(pExceptionRegRec);
872 TEB *pTeb = GetThreadTEB();
873 if ( pTeb
874 && pTeb->o.odin.exceptFrame == (ULONG)pExceptionRegRec)
875 pTeb->o.odin.exceptFrame = 0;
876
877 /*
878 * Switch Back FS Selector.
879 */
880 if (selFSOld)
881 SetFS(selFSOld);
882}
883
884
885/**
886 * Leave odin context to call back into OS/2 code.
887 *
888 * Is called when and Odin32 Dll/Exe calls back into the OS/2 code.
889 * The conterpart of ODIN_ThreadEnterOdinContextNested().
890 *
891 * @returns The old FS selector.
892 * @returns 0 on failure.
893 * @param pExceptionRegRec New OS/2 exception handler frame which are to be registered
894 * before the Odin handler in the chain.
895 * Must be located on the callers stack.
896 * @param fRemoveOdinExcpt Remove the odin exception handler.
897 * @deprecated
898 */
899USHORT WIN32API ODIN_ThreadLeaveOdinContextNested(void *pExceptionRegRec, BOOL fRemoveOdinExcpt)
900{
901 /*
902 * Set OS/2 FS Selector.
903 */
904 USHORT selFSOld = RestoreOS2FS();
905
906 /*
907 * Remove the Odin exception handler (if requested).
908 */
909 if (fRemoveOdinExcpt)
910 {
911 TEB *pTeb = GetThreadTEB();
912 if (pTeb)
913 OS2UnsetExceptionHandler((void*)pTeb->o.odin.exceptFrame);
914 /* else: no TEB created propbably no exception handler to remove. */
915 }
916
917 /*
918 * Change exception handler if required.
919 */
920 if (pExceptionRegRec)
921 {
922 extern unsigned long _System DosSetExceptionHandler(void *);
923 DosSetExceptionHandler(pExceptionRegRec);
924 }
925
926 return selFSOld;
927}
928
929
930/**
931 * Re-enter Odin context after being back in OS/2 code.
932 *
933 * Is called when returning to Odin from OS/2 code.
934 * The conterpart of ODIN_ThreadLeaveOdinContextNested().
935 *
936 * @param pExceptionRegRec The exception registration record for the OS/2
937 * exception handler used with Nested Leave. NULL
938 * if not used.
939 * @param fRestoreOdinExcpt Restore the Odin exception handler.
940 * This flag must not be set unless fRemoveOdinExcpt
941 * was set when leaving the Odin context!
942 * @param selFSOld The Odin FS selector returned by the Nested Leave api.
943 *
944 * @deprecated
945 */
946void WIN32API ODIN_ThreadEnterOdinContextNested(void *pExceptionRegRec, BOOL fRestoreOdinExcpt, USHORT selFSOld)
947{
948 /*
949 * Remove the exception handler registered in ODIN_ThreadLeaveOdinContextNested
950 */
951 if (pExceptionRegRec)
952 OS2UnsetExceptionHandler(pExceptionRegRec);
953
954 /*
955 * Restore Odin exception handler (if requested).
956 */
957 if (fRestoreOdinExcpt)
958 {
959 TEB *pTeb = GetThreadTEB();
960 if (pTeb)
961 OS2SetExceptionHandler((void*)pTeb->o.odin.exceptFrame);
962 }
963
964 /*
965 * Switch Back FS Selector.
966 */
967 if (selFSOld)
968 SetFS(selFSOld);
969}
970
971
972/** Save thread context and/or load other thread context.
973 * @param pCtx Where to save the current thread context.
974 * @param fFlags Flags telling what to do.
975 * @todo Need to do special handling of NESTED flag?
976 */
977void WIN32API ODIN_ThreadContextSave(PODINTHREADCTX pCtx, unsigned fFlags)
978{
979 TEB *pTeb = NULL;
980
981 /*
982 * Do requested saves.
983 */
984 if (pCtx)
985 {
986 memset(pCtx, 0, sizeof(*pCtx));
987 pCtx->fFlags = fFlags;
988 if (fFlags & OTCTXF_SAVE_FPU)
989 pCtx->cw = _control87(0, 0);
990 if (fFlags & OTCTXF_SAVE_FS)
991 pCtx->fs = GetFS();
992 }
993
994 /*
995 * Get Odin32 TEB.
996 */
997 if (fFlags & (OTCTXF_LOAD_FS_ODIN32 | OTCTXF_LOAD_XCPT_ODIN32))
998 {
999 /*
1000 * Get TEB pointer, create it if necessary.
1001 * @todo Check if this really is the thread which the TEB was created
1002 * for. If not create the TEB. This is rather unlikely..
1003 */
1004 pTeb = GetThreadTEB();
1005 if (!pTeb)
1006 {
1007 HANDLE hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, TRUE);
1008 dprintf(("Setup external thread %x!", hThreadMain));
1009 pTeb = CreateTEB(hThreadMain, ODIN_GetCurrentThreadId());
1010 if (!pTeb || !InitializeThread(pTeb, fibGetTid() == 1))
1011 {
1012 dprintf(("ODIN_ThreadContextSave: Failed to create TEB!"));
1013 DebugInt3();
1014 }
1015 }
1016 }
1017
1018 /*
1019 * Install exception handler if requested.
1020 */
1021 if (fFlags & OTCTXF_LOAD_XCPT_ODIN32)
1022 {
1023 OS2UnsetExceptionHandler(&pCtx->XctpRegRec);
1024 if ( pTeb
1025 && !pTeb->o.odin.exceptFrame) /* if allready present, we'll keep the first one. */
1026 pTeb->o.odin.exceptFrame = (ULONG)&pCtx->XctpRegRec;
1027 }
1028
1029 /*
1030 * Do requested loads.
1031 */
1032 if (fFlags & OTCTXF_LOAD_FPU_ODIN32)
1033 CONTROL87(0x27F, 0xFFFF); //Set FPU control word to 0x27F (same as in NT)
1034 if (fFlags & OTCTXF_LOAD_FPU_OS2)
1035 CONTROL87(0x37F, 0xFFFF); //Set FPU control word to 0x37F as that's most common on OS/2.
1036 if ((fFlags & OTCTXF_LOAD_FS_ODIN32) && pTeb)
1037 SetFS(pTeb->teb_sel);
1038}
1039
1040
1041/** Restore saved thread context and/or do additional loads.
1042 * @param pCtx Where to save the current thread context.
1043 * @param fFlags Flags telling extra stuff to load.
1044 * Only CTCTXF_LOAD_* flags will be evaluated.
1045 * @todo Need to do special handling of NESTED flag?
1046 */
1047void WIN32API ODIN_ThreadContextRestore(PODINTHREADCTX pCtx, unsigned fFlags)
1048{
1049 /*
1050 * Restore context.
1051 */
1052 if (pCtx)
1053 {
1054 if (pCtx->fFlags & OTCTXF_SAVE_FPU)
1055 CONTROL87(pCtx->cw, 0xffff);
1056 if (pCtx->fFlags & OTCTXF_SAVE_FS)
1057 SetFS(pCtx->fs);
1058 if (pCtx->fFlags & OTCTXF_LOAD_XCPT_ODIN32)
1059 {
1060 TEB *pTeb = GetThreadTEB();
1061 if (pTeb && pTeb->o.odin.exceptFrame == (ULONG)&pCtx->XctpRegRec)
1062 pTeb->o.odin.exceptFrame = 0;
1063 OS2UnsetExceptionHandler(&pCtx->XctpRegRec);
1064 }
1065 memset(pCtx, 0, sizeof(*pCtx));
1066 }
1067
1068 /*
1069 * Do requested loads.
1070 */
1071 if (fFlags & OTCTXF_LOAD_FPU_ODIN32)
1072 CONTROL87(0x27F, 0xFFFF); //Set FPU control word to 0x27F (same as in NT)
1073 if (fFlags & OTCTXF_LOAD_FPU_OS2)
1074 CONTROL87(0x37F, 0xFFFF); //Set FPU control word to 0x37F as that's most common on OS/2.
1075 if ((fFlags & OTCTXF_LOAD_FS_ODIN32))
1076 {
1077 /*
1078 * Get TEB pointer, create it if necessary.
1079 * @todo Check if this really is the thread which the TEB was created
1080 * for. If not create the TEB. This is rather unlikely..
1081 */
1082 TEB *pTeb = GetThreadTEB();
1083 if (!pTeb)
1084 {
1085 HANDLE hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, TRUE);
1086 pTeb = CreateTEB(hThreadMain, ODIN_GetCurrentThreadId());
1087 if ( !pTeb
1088 || !InitializeThread(pTeb, fibGetTid() == 1))
1089 {
1090 dprintf(("ODIN_ThreadContextRestore: Failed to create TEB!"));
1091 DebugInt3();
1092 }
1093 }
1094 if (pTeb)
1095 SetFS(pTeb->teb_sel);
1096 }
1097}
1098
Note: See TracBrowser for help on using the repository browser.