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

Last change on this file since 21308 was 21308, checked in by ydario, 16 years ago

Minor updates, backout imm changes.

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