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

Last change on this file since 9924 was 9913, checked in by sandervl, 22 years ago

Don't change the stack alignment if the thread has less than 128 kb stack.

File size: 17.8 KB
Line 
1/* $Id: thread.cpp,v 1.52 2003-03-06 12:49:08 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
18#include <odin.h>
19#include <odinwrap.h>
20#include <os2sel.h>
21
22#include <os2win.h>
23#include <stdarg.h>
24#include <string.h>
25#include "thread.h"
26#include <misc.h>
27#include <cpuhlp.h>
28#include <wprocess.h>
29#include <windllbase.h>
30#include <winexebase.h>
31#include "exceptutil.h"
32#include "oslibmisc.h"
33#include "oslibdos.h"
34#include <handlemanager.h>
35#include <codepage.h>
36
37#include <FastInfoBlocks.h>
38
39#define DBG_LOCALLOG DBG_thread
40#include "dbglocal.h"
41
42ODINDEBUGCHANNEL(KERNEL32-THREAD)
43
44static ULONG priorityclass = NORMAL_PRIORITY_CLASS;
45
46//******************************************************************************
47//******************************************************************************
48DWORD WIN32API GetCurrentThreadId()
49{
50 // check cached identifier
51 TEB *teb = GetThreadTEB();
52 if(teb != NULL && teb->o.odin.threadId != 0xFFFFFFFF)
53 {
54 // this is set in InitializeTIB() already.
55 return teb->o.odin.threadId;
56 }
57
58//// dprintf(("GetCurrentThreadId\n"));
59 return MAKE_THREADID(O32_GetCurrentProcessId(), O32_GetCurrentThreadId());
60}
61//******************************************************************************
62//******************************************************************************
63HANDLE WIN32API GetCurrentThread()
64{
65 TEB *teb;
66
67 teb = GetThreadTEB();
68 if(teb == 0) {
69 DebugInt3();
70 SetLastError(ERROR_INVALID_HANDLE); //todo
71 return 0;
72 }
73 return teb->o.odin.hThread;
74}
75//******************************************************************************
76// these two debugging functions allow access to a
77// calldepth counter inside the TEB block of each thread
78//******************************************************************************
79ULONG WIN32API dbg_GetThreadCallDepth()
80{
81#ifdef DEBUG
82 TEB *teb;
83
84 teb = GetThreadTEB();
85 if(teb == NULL)
86 return 0;
87 else
88 return teb->o.odin.dbgCallDepth;
89#else
90 return 0;
91#endif
92}
93//******************************************************************************
94//******************************************************************************
95void WIN32API dbg_IncThreadCallDepth()
96{
97#ifdef DEBUG
98 TEB *teb;
99
100 teb = GetThreadTEB();
101 if(teb != NULL)
102 teb->o.odin.dbgCallDepth++;
103#endif
104}
105//******************************************************************************
106#define MAX_CALLSTACK_SIZE 128
107#ifdef DEBUG
108static char *pszLastCaller = NULL;
109#endif
110//******************************************************************************
111void WIN32API dbg_ThreadPushCall(char *pszCaller)
112{
113#ifdef DEBUG
114 TEB *teb;
115
116 // embedded dbg_IncThreadCallDepth
117 teb = GetThreadTEB();
118 if(teb == NULL)
119 return;
120
121 // add caller name to call stack trace
122 int iIndex = teb->o.odin.dbgCallDepth;
123
124 // allocate callstack on demand
125 if (teb->o.odin.arrstrCallStack == NULL)
126 teb->o.odin.arrstrCallStack = (PVOID*)malloc( sizeof(LPSTR) * MAX_CALLSTACK_SIZE);
127
128 // insert entry
129 if (iIndex < MAX_CALLSTACK_SIZE)
130 teb->o.odin.arrstrCallStack[iIndex] = (PVOID)pszCaller;
131
132 teb->o.odin.dbgCallDepth++;
133
134 pszLastCaller = pszCaller;
135#endif
136}
137//******************************************************************************
138//******************************************************************************
139void WIN32API dbg_DecThreadCallDepth()
140{
141#ifdef DEBUG
142 TEB *teb;
143
144 teb = GetThreadTEB();
145 if(teb != NULL)
146 --(teb->o.odin.dbgCallDepth);
147#endif
148}
149//******************************************************************************
150//******************************************************************************
151void WIN32API dbg_ThreadPopCall()
152{
153#ifdef DEBUG
154 TEB *teb;
155
156 // embedded dbg_DecThreadCallDepth
157 teb = GetThreadTEB();
158 if(teb == NULL)
159 return;
160
161 --(teb->o.odin.dbgCallDepth);
162
163 // add caller name to call stack trace
164 int iIndex = teb->o.odin.dbgCallDepth;
165
166 // insert entry
167 if (teb->o.odin.arrstrCallStack)
168 if (iIndex < MAX_CALLSTACK_SIZE)
169 teb->o.odin.arrstrCallStack[iIndex] = NULL;
170#endif
171}
172//******************************************************************************
173//******************************************************************************
174char* WIN32API dbg_GetLastCallerName()
175{
176#ifdef DEBUG
177 // retrieve last caller name from stack
178 TEB *teb;
179
180 // embedded dbg_DecThreadCallDepth
181 teb = GetThreadTEB();
182 if(teb != NULL)
183 {
184 int iIndex = teb->o.odin.dbgCallDepth - 1;
185 if ( (iIndex > 0) &&
186 (iIndex < MAX_CALLSTACK_SIZE) )
187 {
188 return (char*)teb->o.odin.arrstrCallStack[iIndex];
189 }
190 }
191#endif
192
193 return NULL;
194}
195//******************************************************************************
196//******************************************************************************
197VOID WIN32API ExitThread(DWORD exitcode)
198{
199 EXCEPTION_FRAME *exceptFrame;
200 TEB *teb;
201
202 dprintf(("ExitThread %x (%x)", GetCurrentThread(), exitcode));
203
204 teb = GetThreadTEB();
205 if(teb != 0) {
206 exceptFrame = (EXCEPTION_FRAME *)teb->o.odin.exceptFrame;
207 }
208 else DebugInt3();
209
210 HMSetThreadTerminated(GetCurrentThread());
211 Win32DllBase::detachThreadFromAllDlls(); //send DLL_THREAD_DETACH message to all dlls
212 Win32DllBase::tlsDetachThreadFromAllDlls(); //destroy TLS structures of all dlls
213 if(WinExe) WinExe->tlsDetachThread(); //destroy TLS structure of main exe
214
215 if(teb) DestroyTEB(teb);
216
217 if(exceptFrame) OS2UnsetExceptionHandler((void *)exceptFrame);
218
219 O32_ExitThread(exitcode);
220}
221/*****************************************************************************
222 * Name : DWORD SetThreadAffinityMask
223 * Purpose : The SetThreadAffinityMask function sets a processor affinity
224 * mask for a specified thread.
225 * A thread affinity mask is a bit vector in which each bit
226 * represents the processors that a thread is allowed to run on.
227 * A thread affinity mask must be a proper subset of the process
228 * affinity mask for the containing process of a thread. A thread
229 * is only allowed to run on the processors its process is allowed to run on.
230 * Parameters: HANDLE hThread handle to the thread of interest
231 * DWORD dwThreadAffinityMask a thread affinity mask
232 * Variables :
233 * Result : TRUE / FALSE
234 * Remark :
235 * Status : Fully functional
236 *
237 * Author : SvL
238 *****************************************************************************/
239
240DWORD WIN32API SetThreadAffinityMask(HANDLE hThread,
241 DWORD dwThreadAffinityMask)
242{
243 dprintf(("KERNEL32: SetThreadAffinityMask(%08xh,%08xh)", hThread, dwThreadAffinityMask));
244
245 if(hThread != GetCurrentThread()) {
246 dprintf(("WARNING: Setting the affinity mask for another thread than the current one is not supported!!"));
247 return FALSE;
248 }
249 return OSLibDosSetThreadAffinity(dwThreadAffinityMask);
250}
251//******************************************************************************
252//******************************************************************************
253VOID WIN32API Sleep(DWORD mSecs)
254{
255 dprintf2(("KERNEL32: Sleep %d", mSecs));
256 OSLibDosSleep(mSecs);
257}
258//******************************************************************************
259//******************************************************************************
260DWORD WIN32API GetPriorityClass(HANDLE hProcess)
261{
262 dprintf(("KERNEL32: GetPriorityClass %x", hProcess));
263 return priorityclass;
264// return O32_GetPriorityClass(hProcess);
265}
266//******************************************************************************
267//******************************************************************************
268BOOL WIN32API SetPriorityClass(HANDLE hProcess, DWORD dwPriority)
269{
270 dprintf(("KERNEL32: SetPriorityClass %x %x", hProcess, dwPriority));
271 priorityclass = dwPriority;
272 return TRUE;
273// return O32_SetPriorityClass(hProcess, dwPriority);
274}
275//******************************************************************************
276//******************************************************************************
277Win32Thread::Win32Thread(LPTHREAD_START_ROUTINE pUserCallback, LPVOID lpData, DWORD dwFlags, HANDLE hThread)
278{
279 lpUserData = lpData;
280 pCallback = pUserCallback;
281 this->dwFlags = dwFlags;
282 this->hThread = hThread;
283
284 teb = CreateTEB(hThread, 0xFFFFFFFF);
285 if(teb == NULL) {
286 DebugInt3();
287 }
288}
289//******************************************************************************
290//******************************************************************************
291DWORD OPEN32API Win32ThreadProc(LPVOID lpData)
292{
293 EXCEPTION_FRAME exceptFrame;
294 Win32Thread *me = (Win32Thread *)lpData;
295 ULONG threadCallback = (ULONG)me->pCallback;
296 LPVOID userdata = me->lpUserData;
297 DWORD rc;
298 TEB *winteb = (TEB *)me->teb;
299
300 delete(me); //only called once
301
302 if(InitializeThread(winteb) == FALSE) {
303 dprintf(("Win32ThreadProc: InitializeTIB failed!!"));
304 DebugInt3();
305 return 0;
306 }
307 dprintf(("Win32ThreadProc: Thread handle 0x%x, thread id %d", GetCurrentThread(), GetCurrentThreadId()));
308
309 winteb->flags = me->dwFlags;
310
311 winteb->entry_point = (void *)threadCallback;
312 winteb->entry_arg = (void *)userdata;
313
314 winteb->o.odin.hab = OSLibWinInitialize();
315 dprintf(("Thread HAB %x", winteb->o.odin.hab));
316 winteb->o.odin.hmq = OSLibWinQueryMsgQueue(winteb->o.odin.hab);
317 rc = OSLibWinSetCp(winteb->o.odin.hmq, GetDisplayCodepage());
318 dprintf(("WinSetCP was %sOK", rc ? "" : "not "));
319
320 dprintf(("Win32ThreadProc: hab %x hmq %x", winteb->o.odin.hab, winteb->o.odin.hmq));
321 dprintf(("Stack top 0x%x, stack end 0x%x", winteb->stack_top, winteb->stack_low));
322
323 //Note: The Win32 exception structure referenced by FS:[0] is the same
324 // in OS/2
325 OS2SetExceptionHandler((void *)&exceptFrame);
326 winteb->o.odin.exceptFrame = (ULONG)&exceptFrame;
327
328 //Determine if thread callback is inside a PE dll; if true, then force
329 //switch to win32 TIB (FS selector)
330 //(necessary for Opera when loading win32 plugins that create threads)
331 Win32DllBase *dll;
332 dll = Win32DllBase::findModuleByAddr(threadCallback);
333 if(dll && dll->isPEImage()) {
334 dprintf(("Win32ThreadProc: Force win32 TIB switch"));
335 SetWin32TIB(TIB_SWITCH_FORCE_WIN32);
336 }
337 else SetWin32TIB(TIB_SWITCH_DEFAULT); //executable type determines whether or not FS is changed
338
339 DWORD dwProcessAffinityMask, dwSystemAffinityMask;
340
341 //Change the affinity mask of this thread to the mask for the whole process
342 if(GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask) == TRUE) {
343 SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
344 }
345
346 if(WinExe) WinExe->tlsAttachThread(); //setup TLS structure of main exe
347 Win32DllBase::tlsAttachThreadToAllDlls(); //setup TLS structures of all dlls
348 Win32DllBase::attachThreadToAllDlls(); //send DLL_THREAD_ATTACH message to all dlls
349
350 BOOL fAlignStack = ((ULONG)winteb->stack_top - (ULONG)winteb->stack_low) >= 128*1024;
351
352 //Set FPU control word to 0x27F (same as in NT)
353 CONTROL87(0x27F, 0xFFF);
354 rc = AsmCallThreadHandler(fAlignStack, threadCallback, userdata);
355
356 if(fExitProcess) {
357 OSLibDosExitThread(rc);
358 }
359 else {
360 HMSetThreadTerminated(GetCurrentThread());
361 winteb->o.odin.exceptFrame = 0;
362 Win32DllBase::detachThreadFromAllDlls(); //send DLL_THREAD_DETACH message to all dlls
363 Win32DllBase::tlsDetachThreadFromAllDlls(); //destroy TLS structures of all dlls
364 if(WinExe) WinExe->tlsDetachThread(); //destroy TLS structure of main exe
365 DestroyTEB(winteb); //destroys TIB and restores FS
366 OS2UnsetExceptionHandler((void *)&exceptFrame);
367 }
368
369 return rc;
370}
371//******************************************************************************
372//******************************************************************************
373
374/**
375 * Enter odin context with this thread.
376 *
377 * Is called when an OS/2 process is calling into an Odin32 DLL.
378 * This may be called also in a nested fashion and supports that.
379 * The conterpart of ODIN_ThreadLeaveOdinContext().
380 *
381 * @returns The old FS selector.
382 * @returns 0 if TEB creation failed.
383 * @param pExceptionRegRec OS/2 Exception Registration Record (2 ULONGs)
384 * must be located on the callers stack.
385 * @param fForceFSSwitch If set we will force switching to Odin32 FS selector.
386 * If clear it depends on defaults.
387 */
388USHORT WIN32API ODIN_ThreadEnterOdinContext(void *pExceptionRegRec, BOOL fForceFSSwitch)
389{
390 USHORT selFSOld = 0;
391
392 /*
393 * Get TEB pointer, create it if necessary.
394 * @todo Check if this really is the thread which the TEB was created
395 * for. If not create the TEB.
396 */
397 TEB *pTeb = GetThreadTEB();
398 if (!pTeb)
399 {
400 BOOL fMainThread = fibGetTid() == 1;
401 HANDLE hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, fMainThread);
402 pTeb = CreateTEB(hThreadMain, fibGetTid());
403 if (!pTeb || InitializeThread(pTeb, fMainThread) == FALSE)
404 {
405 dprintf(("ODIN_ThreadEnterOdinContext: Failed to create TEB!"));
406 }
407 }
408
409 /*
410 * Install the Odin32 exception handler.
411 * Note: The Win32 exception structure referenced by FS:[0] is the same in OS/2
412 */
413 if (pExceptionRegRec)
414 OS2SetExceptionHandler(pExceptionRegRec);
415 if ( pTeb
416 && !pTeb->o.odin.exceptFrame) /* if allready present, we'll keep the first one. */
417 pTeb->o.odin.exceptFrame = (ULONG)pExceptionRegRec;
418
419 /*
420 * Switch Selector if TIB was created.
421 */
422 if (pTeb)
423 selFSOld = SetWin32TIB(fForceFSSwitch ? TIB_SWITCH_FORCE_WIN32 : TIB_SWITCH_DEFAULT);
424
425 return selFSOld;
426}
427
428
429/**
430 * Leave odin context with this thread.
431 *
432 * Is called when an OS/2 process is returning from an Odin32 DLL.
433 * This may be called also in a nested fashion and supports that.
434 * The conterpart of ODIN_ThreadEnterOdinContext().
435 *
436 * @returns The old FS selector.
437 * @returns 0 if TEB creation failed.
438 * @param pExceptionRegRec OS/2 Exception Registration Record (2 ULONGs)
439 * must be located on the callers stack.
440 * @param fForceFSSwitch If set we will force switching to Odin32 FS selector.
441 * If clear it depends on defaults.
442 */
443void WIN32API ODIN_ThreadLeaveOdinContext(void *pExceptionRegRec, USHORT selFSOld)
444{
445 /*
446 * Install the Odin32 exception handler.
447 * Note: The Win32 exception structure referenced by FS:[0] is the same in OS/2
448 */
449 if (pExceptionRegRec)
450 OS2UnsetExceptionHandler(pExceptionRegRec);
451 TEB *pTeb = GetThreadTEB();
452 if ( pTeb
453 && pTeb->o.odin.exceptFrame == (ULONG)pExceptionRegRec)
454 pTeb->o.odin.exceptFrame = 0;
455
456 /*
457 * Switch Back FS Selector.
458 */
459 if (selFSOld)
460 SetFS(selFSOld);
461}
462
463
464/**
465 * Leave odin context to call back into OS/2 code.
466 *
467 * Is called when and Odin32 Dll/Exe calls back into the OS/2 code.
468 * The conterpart of ODIN_ThreadEnterOdinContextNested().
469 *
470 * @returns The old FS selector.
471 * @returns 0 on failure.
472 * @param pExceptionRegRec New OS/2 exception handler frame which are to be registered
473 * before the Odin handler in the chain.
474 * Must be located on the callers stack.
475 * @param fRemoveOdinExcpt Remove the odin exception handler.
476 */
477USHORT WIN32API ODIN_ThreadLeaveOdinContextNested(void *pExceptionRegRec, BOOL fRemoveOdinExcpt)
478{
479 /*
480 * Set OS/2 FS Selector.
481 */
482 USHORT selFSOld = RestoreOS2FS();
483
484 /*
485 * Remove the Odin exception handler (if requested).
486 */
487 if (fRemoveOdinExcpt)
488 {
489 TEB *pTeb = GetThreadTEB();
490 if (pTeb)
491 OS2UnsetExceptionHandler((void*)pTeb->o.odin.exceptFrame);
492 /* else: no TEB created propbably no exception handler to remove. */
493 }
494
495 /*
496 * Change exception handler if required.
497 */
498 if (pExceptionRegRec)
499 {
500 extern unsigned long _System DosSetExceptionHandler(void *);
501 DosSetExceptionHandler(pExceptionRegRec);
502 }
503
504 return selFSOld;
505}
506
507
508/**
509 * Re-enter Odin context after being back in OS/2 code.
510 *
511 * Is called when returning to Odin from OS/2 code.
512 * The conterpart of ODIN_ThreadLeaveOdinContextNested().
513 *
514 * @param pExceptionRegRec The exception registration record for the OS/2
515 * exception handler used with Nested Leave. NULL
516 * if not used.
517 * @param fRestoreOdinExcpt Restore the Odin exception handler.
518 * This flag must not be set unless fRemoveOdinExcpt
519 * was set when leaving the Odin context!
520 * @param selFSOld The Odin FS selector returned by the Nested Leave api.
521 *
522 */
523void WIN32API ODIN_ThreadEnterOdinContextNested(void *pExceptionRegRec, BOOL fRestoreOdinExcpt, USHORT selFSOld)
524{
525 /*
526 * Remove the exception handler registered in ODIN_ThreadLeaveOdinContextNested
527 */
528 if (pExceptionRegRec)
529 OS2UnsetExceptionHandler(pExceptionRegRec);
530
531 /*
532 * Restore Odin exception handler (if requested).
533 */
534 if (fRestoreOdinExcpt)
535 {
536 TEB *pTeb = GetThreadTEB();
537 if (pTeb)
538 OS2SetExceptionHandler((void*)pTeb->o.odin.exceptFrame);
539 }
540
541 /*
542 * Switch Back FS Selector.
543 */
544 if (selFSOld)
545 SetFS(selFSOld);
546}
547
548
Note: See TracBrowser for help on using the repository browser.