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

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

Kernel32 updates.

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