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

Last change on this file since 9582 was 9582, checked in by sandervl, 23 years ago

Set the codepage of the message queue for each new thread that is created. (done for the main thread in user32)

File size: 12.1 KB
Line 
1/* $Id: thread.cpp,v 1.47 2003-01-02 11:50:46 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#define DBG_LOCALLOG DBG_thread
38#include "dbglocal.h"
39
40ODINDEBUGCHANNEL(KERNEL32-THREAD)
41
42static ULONG priorityclass = NORMAL_PRIORITY_CLASS;
43
44//******************************************************************************
45//******************************************************************************
46DWORD WIN32API GetCurrentThreadId()
47{
48 // check cached identifier
49 TEB *teb = GetThreadTEB();
50 if(teb != NULL && teb->o.odin.threadId != 0xFFFFFFFF)
51 {
52 // this is set in InitializeTIB() already.
53 return teb->o.odin.threadId;
54 }
55
56//// dprintf(("GetCurrentThreadId\n"));
57 return MAKE_THREADID(O32_GetCurrentProcessId(), O32_GetCurrentThreadId());
58}
59//******************************************************************************
60//******************************************************************************
61HANDLE WIN32API GetCurrentThread()
62{
63 TEB *teb;
64
65 teb = GetThreadTEB();
66 if(teb == 0) {
67 SetLastError(ERROR_INVALID_HANDLE); //todo
68 return 0;
69 }
70 return teb->o.odin.hThread;
71}
72//******************************************************************************
73// these two debugging functions allow access to a
74// calldepth counter inside the TEB block of each thread
75//******************************************************************************
76ULONG WIN32API dbg_GetThreadCallDepth()
77{
78#ifdef DEBUG
79 TEB *teb;
80
81 teb = GetThreadTEB();
82 if(teb == NULL)
83 return 0;
84 else
85 return teb->o.odin.dbgCallDepth;
86#else
87 return 0;
88#endif
89}
90//******************************************************************************
91//******************************************************************************
92void WIN32API dbg_IncThreadCallDepth()
93{
94#ifdef DEBUG
95 TEB *teb;
96
97 teb = GetThreadTEB();
98 if(teb != NULL)
99 teb->o.odin.dbgCallDepth++;
100#endif
101}
102//******************************************************************************
103#define MAX_CALLSTACK_SIZE 128
104#ifdef DEBUG
105static char *pszLastCaller = NULL;
106#endif
107//******************************************************************************
108void WIN32API dbg_ThreadPushCall(char *pszCaller)
109{
110#ifdef DEBUG
111 TEB *teb;
112
113 // embedded dbg_IncThreadCallDepth
114 teb = GetThreadTEB();
115 if(teb == NULL)
116 return;
117
118 // add caller name to call stack trace
119 int iIndex = teb->o.odin.dbgCallDepth;
120
121 // allocate callstack on demand
122 if (teb->o.odin.arrstrCallStack == NULL)
123 teb->o.odin.arrstrCallStack = (PVOID*)malloc( sizeof(LPSTR) * MAX_CALLSTACK_SIZE);
124
125 // insert entry
126 if (iIndex < MAX_CALLSTACK_SIZE)
127 teb->o.odin.arrstrCallStack[iIndex] = (PVOID)pszCaller;
128
129 teb->o.odin.dbgCallDepth++;
130
131 pszLastCaller = pszCaller;
132#endif
133}
134//******************************************************************************
135//******************************************************************************
136void WIN32API dbg_DecThreadCallDepth()
137{
138#ifdef DEBUG
139 TEB *teb;
140
141 teb = GetThreadTEB();
142 if(teb != NULL)
143 --(teb->o.odin.dbgCallDepth);
144#endif
145}
146//******************************************************************************
147//******************************************************************************
148void WIN32API dbg_ThreadPopCall()
149{
150#ifdef DEBUG
151 TEB *teb;
152
153 // embedded dbg_DecThreadCallDepth
154 teb = GetThreadTEB();
155 if(teb == NULL)
156 return;
157
158 --(teb->o.odin.dbgCallDepth);
159
160 // add caller name to call stack trace
161 int iIndex = teb->o.odin.dbgCallDepth;
162
163 // insert entry
164 if (teb->o.odin.arrstrCallStack)
165 if (iIndex < MAX_CALLSTACK_SIZE)
166 teb->o.odin.arrstrCallStack[iIndex] = NULL;
167#endif
168}
169//******************************************************************************
170//******************************************************************************
171char* WIN32API dbg_GetLastCallerName()
172{
173#ifdef DEBUG
174 // retrieve last caller name from stack
175 TEB *teb;
176
177 // embedded dbg_DecThreadCallDepth
178 teb = GetThreadTEB();
179 if(teb != NULL)
180 {
181 int iIndex = teb->o.odin.dbgCallDepth - 1;
182 if ( (iIndex > 0) &&
183 (iIndex < MAX_CALLSTACK_SIZE) )
184 {
185 return (char*)teb->o.odin.arrstrCallStack[iIndex];
186 }
187 }
188#endif
189
190 return NULL;
191}
192//******************************************************************************
193//******************************************************************************
194VOID WIN32API ExitThread(DWORD exitcode)
195{
196 EXCEPTION_FRAME *exceptFrame;
197 TEB *teb;
198
199 dprintf(("ExitThread %x (%x)", GetCurrentThread(), exitcode));
200
201 teb = GetThreadTEB();
202 if(teb != 0) {
203 exceptFrame = (EXCEPTION_FRAME *)teb->o.odin.exceptFrame;
204 }
205 else DebugInt3();
206
207 HMSetThreadTerminated(GetCurrentThread());
208 Win32DllBase::detachThreadFromAllDlls(); //send DLL_THREAD_DETACH message to all dlls
209 Win32DllBase::tlsDetachThreadFromAllDlls(); //destroy TLS structures of all dlls
210 if(WinExe) WinExe->tlsDetachThread(); //destroy TLS structure of main exe
211
212 if(teb) DestroyTEB(teb);
213
214 if(exceptFrame) OS2UnsetExceptionHandler((void *)exceptFrame);
215
216 O32_ExitThread(exitcode);
217}
218/*****************************************************************************
219 * Name : DWORD SetThreadAffinityMask
220 * Purpose : The SetThreadAffinityMask function sets a processor affinity
221 * mask for a specified thread.
222 * A thread affinity mask is a bit vector in which each bit
223 * represents the processors that a thread is allowed to run on.
224 * A thread affinity mask must be a proper subset of the process
225 * affinity mask for the containing process of a thread. A thread
226 * is only allowed to run on the processors its process is allowed to run on.
227 * Parameters: HANDLE hThread handle to the thread of interest
228 * DWORD dwThreadAffinityMask a thread affinity mask
229 * Variables :
230 * Result : TRUE / FALSE
231 * Remark :
232 * Status : Fully functional
233 *
234 * Author : SvL
235 *****************************************************************************/
236
237DWORD WIN32API SetThreadAffinityMask(HANDLE hThread,
238 DWORD dwThreadAffinityMask)
239{
240 dprintf(("KERNEL32: SetThreadAffinityMask(%08xh,%08xh)", hThread, dwThreadAffinityMask));
241
242 if(hThread != GetCurrentThread()) {
243 dprintf(("WARNING: Setting the affinity mask for another thread than the current one is not supported!!"));
244 return FALSE;
245 }
246 return OSLibDosSetThreadAffinity(dwThreadAffinityMask);
247}
248//******************************************************************************
249//******************************************************************************
250VOID WIN32API Sleep(DWORD mSecs)
251{
252 dprintf2(("KERNEL32: Sleep %d", mSecs));
253 OSLibDosSleep(mSecs);
254}
255//******************************************************************************
256//******************************************************************************
257DWORD WIN32API GetPriorityClass(HANDLE hProcess)
258{
259 dprintf(("KERNEL32: GetPriorityClass %x", hProcess));
260 return priorityclass;
261// return O32_GetPriorityClass(hProcess);
262}
263//******************************************************************************
264//******************************************************************************
265BOOL WIN32API SetPriorityClass(HANDLE hProcess, DWORD dwPriority)
266{
267 dprintf(("KERNEL32: SetPriorityClass %x %x", hProcess, dwPriority));
268 priorityclass = dwPriority;
269 return TRUE;
270// return O32_SetPriorityClass(hProcess, dwPriority);
271}
272//******************************************************************************
273//******************************************************************************
274Win32Thread::Win32Thread(LPTHREAD_START_ROUTINE pUserCallback, LPVOID lpData, DWORD dwFlags, HANDLE hThread)
275{
276 lpUserData = lpData;
277 pCallback = pUserCallback;
278 this->dwFlags = dwFlags;
279 this->hThread = hThread;
280
281 teb = CreateTEB(hThread, 0xFFFFFFFF);
282 if(teb == NULL) {
283 DebugInt3();
284 }
285}
286//******************************************************************************
287//******************************************************************************
288DWORD OPEN32API Win32ThreadProc(LPVOID lpData)
289{
290 EXCEPTION_FRAME exceptFrame;
291 Win32Thread *me = (Win32Thread *)lpData;
292 ULONG threadCallback = (ULONG)me->pCallback;
293 LPVOID userdata = me->lpUserData;
294 DWORD rc;
295 TEB *winteb = (TEB *)me->teb;
296
297 delete(me); //only called once
298
299 if(InitializeThread(winteb) == FALSE) {
300 dprintf(("Win32ThreadProc: InitializeTIB failed!!"));
301 DebugInt3();
302 return 0;
303 }
304 dprintf(("Win32ThreadProc %x\n", GetCurrentThreadId()));
305
306 winteb->flags = me->dwFlags;
307
308 winteb->entry_point = (void *)threadCallback;
309 winteb->entry_arg = (void *)userdata;
310
311 winteb->o.odin.hab = OSLibWinInitialize();
312 winteb->o.odin.hmq = OSLibWinQueryMsgQueue(winteb->o.odin.hab);
313 rc = OSLibWinSetCp(winteb->o.odin.hmq, GetDisplayCodepage());
314 dprintf(("WinSetCP was %sOK", rc ? "" : "not "));
315
316 dprintf(("Win32ThreadProc: hab %x hmq %x", winteb->o.odin.hab, winteb->o.odin.hmq));
317 dprintf(("Stack top 0x%x, stack end 0x%x", winteb->stack_top, winteb->stack_low));
318
319 //Note: The Win32 exception structure referenced by FS:[0] is the same
320 // in OS/2
321 OS2SetExceptionHandler((void *)&exceptFrame);
322 winteb->o.odin.exceptFrame = (ULONG)&exceptFrame;
323
324 //Determine if thread callback is inside a PE dll; if true, then force
325 //switch to win32 TIB (FS selector)
326 //(necessary for Opera when loading win32 plugins that create threads)
327 Win32DllBase *dll;
328 dll = Win32DllBase::findModuleByAddr(threadCallback);
329 if(dll && dll->isPEImage()) {
330 dprintf(("Win32ThreadProc: Force win32 TIB switch"));
331 SetWin32TIB(TIB_SWITCH_FORCE_WIN32);
332 }
333 else SetWin32TIB(TIB_SWITCH_DEFAULT); //executable type determines whether or not FS is changed
334
335 DWORD dwProcessAffinityMask, dwSystemAffinityMask;
336
337 //Change the affinity mask of this thread to the mask for the whole process
338 if(GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask) == TRUE) {
339 SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
340 }
341
342 if(WinExe) WinExe->tlsAttachThread(); //setup TLS structure of main exe
343 Win32DllBase::tlsAttachThreadToAllDlls(); //setup TLS structures of all dlls
344 Win32DllBase::attachThreadToAllDlls(); //send DLL_THREAD_ATTACH message to all dlls
345
346 //Set FPU control word to 0x27F (same as in NT)
347 CONTROL87(0x27F, 0xFFF);
348 rc = AsmCallThreadHandler(threadCallback, userdata);
349
350 if(fExitProcess) {
351 OSLibDosExitThread(rc);
352 }
353 else {
354 HMSetThreadTerminated(GetCurrentThread());
355 winteb->o.odin.exceptFrame = 0;
356 Win32DllBase::detachThreadFromAllDlls(); //send DLL_THREAD_DETACH message to all dlls
357 Win32DllBase::tlsDetachThreadFromAllDlls(); //destroy TLS structures of all dlls
358 if(WinExe) WinExe->tlsDetachThread(); //destroy TLS structure of main exe
359 DestroyTEB(winteb); //destroys TIB and restores FS
360 OS2UnsetExceptionHandler((void *)&exceptFrame);
361 }
362
363 return rc;
364}
365//******************************************************************************
366//******************************************************************************
Note: See TracBrowser for help on using the repository browser.