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

Last change on this file since 21626 was 21626, checked in by dmik, 14 years ago

kernel32: To complete the Win32 exception chain unwind support, make sure it is unwound when the thread terminates itself with ExitThread/ExitProcess etc. before removing its exception handlers from stack.

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