source: branches/gcc-kmk/src/kernel32/thread.cpp@ 21707

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

Make Win32ThreadProc static member of Win32Thread.

This is more correct than using "friend" and also solves the forward
definition problem.

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 Win32Thread::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.