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

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

Add a bunch of Win32 API stubs needed for Flash above 10.0.45.

This is mainly to prevent the plugin from hitting the breakpoints in
the debug version of Odin. These APIs seem to be only referenced
by some of the libraries built in to the Win32 plugin DLL but never
actually called at runtime. This is why the release version of Odin
does not complain and Flash actually works w/o them at all.

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