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

Last change on this file since 21529 was 21529, checked in by dmik, 15 years ago

Fixed completely broken national (non-Latin1) character input in Odin. There were two problems:
1) When translating OS2 WM_CHAR to Win32 WM_CHAR in UNICODE mode, ANSI->UNICODE conversion of the character was not done.
2) When hosting windows on threads created with CreateThread(), characters in WM_CHAR were wrongly converted from OS/2 codepage to ANSI codepage while they already were in ANSI due to the message queue begin switched to it at thread startup.
3) The main thread's message queue is now also switched to ANSI at startup so the conversion from step 2) should normally not take place now.

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