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

Last change on this file since 21981 was 21981, checked in by dmik, 13 years ago

kernel32: Fix stack size interpretation in CreateThread().

It now uses the stack size parameter as a number of bytes to
pre-commit, not as a total stack size, unless
STACK_SIZE_PARAM_IS_A_RESERVATION is set.

Closes #77.

File size: 38.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
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, DWORD cbCommitStack)
677{
678 lpUserData = lpData;
679 pCallback = pUserCallback;
680 this->dwFlags = dwFlags;
681 this->hThread = hThread;
682 this->cbCommitStack = cbCommitStack;
683
684 teb = CreateTEB(hThread, 0xFFFFFFFF);
685 if(teb == NULL) {
686 DebugInt3();
687 }
688}
689//******************************************************************************
690//******************************************************************************
691DWORD OPEN32API Win32Thread::Win32ThreadProc(LPVOID lpData)
692{
693 EXCEPTION_FRAME exceptFrame;
694 Win32Thread *me = (Win32Thread *)lpData;
695 ULONG dwFlags = me->dwFlags;
696 ULONG threadCallback = (ULONG)me->pCallback;
697 LPVOID userdata = me->lpUserData;
698 DWORD rc;
699 TEB *winteb = (TEB *)me->teb;
700
701 delete(me); //only called once
702
703 if(InitializeThread(winteb) == FALSE) {
704 dprintf(("Win32ThreadProc: InitializeTIB failed!!"));
705 DebugInt3();
706 return 0;
707 }
708 dprintf(("Win32ThreadProc: Thread handle 0x%x, thread id %d", GetCurrentThread(), GetCurrentThreadId()));
709
710 winteb->flags = dwFlags;
711
712 winteb->entry_point = (void *)threadCallback;
713 winteb->entry_arg = (void *)userdata;
714
715 winteb->o.odin.hab = OSLibWinInitialize();
716 dprintf(("Thread HAB %x", winteb->o.odin.hab));
717 winteb->o.odin.hmq = OSLibWinQueryMsgQueue(winteb->o.odin.hab);
718 dprintf(("Thread HMQ %x", winteb->o.odin.hmq));
719 rc = OSLibWinSetCp(winteb->o.odin.hmq, GetDisplayCodepage());
720 dprintf(("WinSetCP(%d) was %sOK", GetDisplayCodepage(), rc ? "" : "not "));
721 hookInit(winteb->o.odin.hab);
722
723 dprintf(("Stack top 0x%x, stack end 0x%x", winteb->stack_top, winteb->stack_low));
724
725 if (me->cbCommitStack) {
726 // pre-commit part of the stack
727 PBYTE stack = ((PBYTE) (winteb->stack_top)) - 1;
728 for (int i = 0; i < (me->cbCommitStack + 0xFFF) / 0x1000; i++) {
729 BYTE unused = *stack;
730 unused = unused;
731 stack -= 0x1000;
732 }
733 }
734
735 if( IsDBCSEnv())
736 /* IM instace is created per message queue, that is, thread */
737 OSLibImSetMsgQueueProperty( winteb->o.odin.hmq, MQP_INSTANCE_PERMQ );
738
739 //Note: The Win32 exception structure referenced by FS:[0] is the same
740 // in OS/2
741 OS2SetExceptionHandler((void *)&exceptFrame);
742 winteb->o.odin.exceptFrame = (ULONG)&exceptFrame;
743
744 //Determine if thread callback is inside a PE dll; if true, then force
745 //switch to win32 TIB (FS selector)
746 //(necessary for Opera when loading win32 plugins that create threads)
747 Win32DllBase *dll;
748 dll = Win32DllBase::findModuleByAddr(threadCallback);
749 if(dll && dll->isPEImage()) {
750 dprintf(("Win32ThreadProc: Force win32 TIB switch"));
751 SetWin32TIB(TIB_SWITCH_FORCE_WIN32);
752 }
753 else SetWin32TIB(TIB_SWITCH_DEFAULT); //executable type determines whether or not FS is changed
754
755 DWORD dwProcessAffinityMask, dwSystemAffinityMask;
756
757 //Change the affinity mask of this thread to the mask for the whole process
758 if(GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask) == TRUE) {
759 SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
760 }
761
762 if(WinExe) WinExe->tlsAttachThread(); //setup TLS structure of main exe
763 Win32DllBase::tlsAttachThreadToAllDlls(); //setup TLS structures of all dlls
764 Win32DllBase::attachThreadToAllDlls(); //send DLL_THREAD_ATTACH message to all dlls
765
766 BOOL fAlignStack = ((ULONG)winteb->stack_top - (ULONG)winteb->stack_low) >= 128*1024;
767
768 //Set FPU control word to 0x27F (same as in NT)
769 CONTROL87(0x27F, 0xFFF);
770 rc = AsmCallThreadHandler(fAlignStack, threadCallback, userdata);
771
772 // make sure the Win32 exception stack (if there is still any) is unwound
773 // before we destroy internal structures including the Win32 TIB
774 RtlUnwind(NULL, 0, 0, 0);
775
776 if(fExitProcess) {
777 OSLibDosExitThread(rc);
778 }
779 else {
780 hookKill(winteb->o.odin.hab);
781 HMSetThreadTerminated(GetCurrentThread());
782 winteb->o.odin.exceptFrame = 0;
783 Win32DllBase::detachThreadFromAllDlls(); //send DLL_THREAD_DETACH message to all dlls
784 Win32DllBase::tlsDetachThreadFromAllDlls(); //destroy TLS structures of all dlls
785 if(WinExe) WinExe->tlsDetachThread(); //destroy TLS structure of main exe
786 DestroyTEB(winteb); //destroys TIB and restores FS
787 OS2UnsetExceptionHandler((void *)&exceptFrame);
788 }
789
790 return rc;
791}
792//******************************************************************************
793//******************************************************************************
794
795/**
796 * Enter odin context with this thread.
797 *
798 * Is called when an OS/2 process is calling into an Odin32 DLL.
799 * This may be called also in a nested fashion and supports that.
800 * The conterpart of ODIN_ThreadLeaveOdinContext().
801 *
802 * @returns The old FS selector.
803 * @returns 0 if TEB creation failed.
804 * @param pExceptionRegRec OS/2 Exception Registration Record (2 ULONGs)
805 * must be located on the callers stack.
806 * @param fForceFSSwitch If set we will force switching to Odin32 FS selector.
807 * If clear it depends on defaults.
808 * @deprecated
809 */
810USHORT WIN32API ODIN_ThreadEnterOdinContext(void *pExceptionRegRec, BOOL fForceFSSwitch)
811{
812 USHORT selFSOld = 0;
813
814 /*
815 * Get TEB pointer, create it if necessary.
816 * @todo Check if this really is the thread which the TEB was created
817 * for. If not create the TEB.
818 */
819 TEB *pTeb = GetThreadTEB();
820 if (!pTeb)
821 {
822 HANDLE hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, TRUE);
823 pTeb = CreateTEB(hThreadMain, ODIN_GetCurrentThreadId());
824 if (!pTeb || InitializeThread(pTeb, fibGetTid() == 1) == FALSE)
825 {
826 dprintf(("ODIN_ThreadEnterOdinContext: Failed to create TEB!"));
827 }
828 }
829
830 /*
831 * Install the Odin32 exception handler.
832 * Note: The Win32 exception structure referenced by FS:[0] is the same in OS/2
833 */
834 if (pExceptionRegRec)
835 OS2SetExceptionHandler(pExceptionRegRec);
836 if ( pTeb
837 && !pTeb->o.odin.exceptFrame) /* if allready present, we'll keep the first one. */
838 pTeb->o.odin.exceptFrame = (ULONG)pExceptionRegRec;
839
840 /*
841 * Switch Selector if TIB was created.
842 */
843 if (pTeb)
844 selFSOld = SetWin32TIB(fForceFSSwitch ? TIB_SWITCH_FORCE_WIN32 : TIB_SWITCH_DEFAULT);
845
846 return selFSOld;
847}
848
849
850/**
851 * Leave odin context with this thread.
852 *
853 * Is called when an OS/2 process is returning from an Odin32 DLL.
854 * This may be called also in a nested fashion and supports that.
855 * The conterpart of ODIN_ThreadEnterOdinContext().
856 *
857 * @returns The old FS selector.
858 * @returns 0 if TEB creation failed.
859 * @param pExceptionRegRec OS/2 Exception Registration Record (2 ULONGs)
860 * must be located on the callers stack.
861 * @param fForceFSSwitch If set we will force switching to Odin32 FS selector.
862 * If clear it depends on defaults.
863 * @deprecated
864 */
865void WIN32API ODIN_ThreadLeaveOdinContext(void *pExceptionRegRec, USHORT selFSOld)
866{
867 /*
868 * Install the Odin32 exception handler.
869 * Note: The Win32 exception structure referenced by FS:[0] is the same in OS/2
870 */
871 if (pExceptionRegRec)
872 OS2UnsetExceptionHandler(pExceptionRegRec);
873 TEB *pTeb = GetThreadTEB();
874 if ( pTeb
875 && pTeb->o.odin.exceptFrame == (ULONG)pExceptionRegRec)
876 pTeb->o.odin.exceptFrame = 0;
877
878 /*
879 * Switch Back FS Selector.
880 */
881 if (selFSOld)
882 SetFS(selFSOld);
883}
884
885
886/**
887 * Leave odin context to call back into OS/2 code.
888 *
889 * Is called when and Odin32 Dll/Exe calls back into the OS/2 code.
890 * The conterpart of ODIN_ThreadEnterOdinContextNested().
891 *
892 * @returns The old FS selector.
893 * @returns 0 on failure.
894 * @param pExceptionRegRec New OS/2 exception handler frame which are to be registered
895 * before the Odin handler in the chain.
896 * Must be located on the callers stack.
897 * @param fRemoveOdinExcpt Remove the odin exception handler.
898 * @deprecated
899 */
900USHORT WIN32API ODIN_ThreadLeaveOdinContextNested(void *pExceptionRegRec, BOOL fRemoveOdinExcpt)
901{
902 /*
903 * Set OS/2 FS Selector.
904 */
905 USHORT selFSOld = RestoreOS2FS();
906
907 /*
908 * Remove the Odin exception handler (if requested).
909 */
910 if (fRemoveOdinExcpt)
911 {
912 TEB *pTeb = GetThreadTEB();
913 if (pTeb)
914 OS2UnsetExceptionHandler((void*)pTeb->o.odin.exceptFrame);
915 /* else: no TEB created propbably no exception handler to remove. */
916 }
917
918 /*
919 * Change exception handler if required.
920 */
921 if (pExceptionRegRec)
922 {
923 extern unsigned long _System DosSetExceptionHandler(void *);
924 DosSetExceptionHandler(pExceptionRegRec);
925 }
926
927 return selFSOld;
928}
929
930
931/**
932 * Re-enter Odin context after being back in OS/2 code.
933 *
934 * Is called when returning to Odin from OS/2 code.
935 * The conterpart of ODIN_ThreadLeaveOdinContextNested().
936 *
937 * @param pExceptionRegRec The exception registration record for the OS/2
938 * exception handler used with Nested Leave. NULL
939 * if not used.
940 * @param fRestoreOdinExcpt Restore the Odin exception handler.
941 * This flag must not be set unless fRemoveOdinExcpt
942 * was set when leaving the Odin context!
943 * @param selFSOld The Odin FS selector returned by the Nested Leave api.
944 *
945 * @deprecated
946 */
947void WIN32API ODIN_ThreadEnterOdinContextNested(void *pExceptionRegRec, BOOL fRestoreOdinExcpt, USHORT selFSOld)
948{
949 /*
950 * Remove the exception handler registered in ODIN_ThreadLeaveOdinContextNested
951 */
952 if (pExceptionRegRec)
953 OS2UnsetExceptionHandler(pExceptionRegRec);
954
955 /*
956 * Restore Odin exception handler (if requested).
957 */
958 if (fRestoreOdinExcpt)
959 {
960 TEB *pTeb = GetThreadTEB();
961 if (pTeb)
962 OS2SetExceptionHandler((void*)pTeb->o.odin.exceptFrame);
963 }
964
965 /*
966 * Switch Back FS Selector.
967 */
968 if (selFSOld)
969 SetFS(selFSOld);
970}
971
972
973/** Save thread context and/or load other thread context.
974 * @param pCtx Where to save the current thread context.
975 * @param fFlags Flags telling what to do.
976 * @todo Need to do special handling of NESTED flag?
977 */
978void WIN32API ODIN_ThreadContextSave(PODINTHREADCTX pCtx, unsigned fFlags)
979{
980 TEB *pTeb = NULL;
981
982 /*
983 * Do requested saves.
984 */
985 if (pCtx)
986 {
987 memset(pCtx, 0, sizeof(*pCtx));
988 pCtx->fFlags = fFlags;
989 if (fFlags & OTCTXF_SAVE_FPU)
990 pCtx->cw = _control87(0, 0);
991 if (fFlags & OTCTXF_SAVE_FS)
992 pCtx->fs = GetFS();
993 }
994
995 /*
996 * Get Odin32 TEB.
997 */
998 if (fFlags & (OTCTXF_LOAD_FS_ODIN32 | OTCTXF_LOAD_XCPT_ODIN32))
999 {
1000 /*
1001 * Get TEB pointer, create it if necessary.
1002 * @todo Check if this really is the thread which the TEB was created
1003 * for. If not create the TEB. This is rather unlikely..
1004 */
1005 pTeb = GetThreadTEB();
1006 if (!pTeb)
1007 {
1008 HANDLE hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, TRUE);
1009 dprintf(("Setup external thread %x!", hThreadMain));
1010 pTeb = CreateTEB(hThreadMain, ODIN_GetCurrentThreadId());
1011 if (!pTeb || !InitializeThread(pTeb, fibGetTid() == 1))
1012 {
1013 dprintf(("ODIN_ThreadContextSave: Failed to create TEB!"));
1014 DebugInt3();
1015 }
1016 }
1017 }
1018
1019 /*
1020 * Install exception handler if requested.
1021 */
1022 if (fFlags & OTCTXF_LOAD_XCPT_ODIN32)
1023 {
1024 OS2UnsetExceptionHandler(&pCtx->XctpRegRec);
1025 if ( pTeb
1026 && !pTeb->o.odin.exceptFrame) /* if allready present, we'll keep the first one. */
1027 pTeb->o.odin.exceptFrame = (ULONG)&pCtx->XctpRegRec;
1028 }
1029
1030 /*
1031 * Do requested loads.
1032 */
1033 if (fFlags & OTCTXF_LOAD_FPU_ODIN32)
1034 CONTROL87(0x27F, 0xFFFF); //Set FPU control word to 0x27F (same as in NT)
1035 if (fFlags & OTCTXF_LOAD_FPU_OS2)
1036 CONTROL87(0x37F, 0xFFFF); //Set FPU control word to 0x37F as that's most common on OS/2.
1037 if ((fFlags & OTCTXF_LOAD_FS_ODIN32) && pTeb)
1038 SetFS(pTeb->teb_sel);
1039}
1040
1041
1042/** Restore saved thread context and/or do additional loads.
1043 * @param pCtx Where to save the current thread context.
1044 * @param fFlags Flags telling extra stuff to load.
1045 * Only CTCTXF_LOAD_* flags will be evaluated.
1046 * @todo Need to do special handling of NESTED flag?
1047 */
1048void WIN32API ODIN_ThreadContextRestore(PODINTHREADCTX pCtx, unsigned fFlags)
1049{
1050 /*
1051 * Restore context.
1052 */
1053 if (pCtx)
1054 {
1055 if (pCtx->fFlags & OTCTXF_SAVE_FPU)
1056 CONTROL87(pCtx->cw, 0xffff);
1057 if (pCtx->fFlags & OTCTXF_SAVE_FS)
1058 SetFS(pCtx->fs);
1059 if (pCtx->fFlags & OTCTXF_LOAD_XCPT_ODIN32)
1060 {
1061 TEB *pTeb = GetThreadTEB();
1062 if (pTeb && pTeb->o.odin.exceptFrame == (ULONG)&pCtx->XctpRegRec)
1063 pTeb->o.odin.exceptFrame = 0;
1064 OS2UnsetExceptionHandler(&pCtx->XctpRegRec);
1065 }
1066 memset(pCtx, 0, sizeof(*pCtx));
1067 }
1068
1069 /*
1070 * Do requested loads.
1071 */
1072 if (fFlags & OTCTXF_LOAD_FPU_ODIN32)
1073 CONTROL87(0x27F, 0xFFFF); //Set FPU control word to 0x27F (same as in NT)
1074 if (fFlags & OTCTXF_LOAD_FPU_OS2)
1075 CONTROL87(0x37F, 0xFFFF); //Set FPU control word to 0x37F as that's most common on OS/2.
1076 if ((fFlags & OTCTXF_LOAD_FS_ODIN32))
1077 {
1078 /*
1079 * Get TEB pointer, create it if necessary.
1080 * @todo Check if this really is the thread which the TEB was created
1081 * for. If not create the TEB. This is rather unlikely..
1082 */
1083 TEB *pTeb = GetThreadTEB();
1084 if (!pTeb)
1085 {
1086 HANDLE hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, TRUE);
1087 pTeb = CreateTEB(hThreadMain, ODIN_GetCurrentThreadId());
1088 if ( !pTeb
1089 || !InitializeThread(pTeb, fibGetTid() == 1))
1090 {
1091 dprintf(("ODIN_ThreadContextRestore: Failed to create TEB!"));
1092 DebugInt3();
1093 }
1094 }
1095 if (pTeb)
1096 SetFS(pTeb->teb_sel);
1097 }
1098}
1099
Note: See TracBrowser for help on using the repository browser.