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

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

Merge branch gcc-kmk to trunk.

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