1 | /* $Id: hmthread.cpp,v 1.19 2003-03-27 15:27:37 sandervl Exp $ */
|
---|
2 |
|
---|
3 | /*
|
---|
4 | * Project Odin Software License can be found in LICENSE.TXT
|
---|
5 | *
|
---|
6 | * Win32 thread handle class
|
---|
7 | *
|
---|
8 | *
|
---|
9 | * TODO: Handle is not destroyed when thread terminates (or else GetExitCodeThread won't work)
|
---|
10 | * Create thread token during thread creation??
|
---|
11 | * Fix for WaitForSingleObject when thread is already terminated, but
|
---|
12 | * WaitForMultipleObjects can still fail!
|
---|
13 | * WaitForSingle/MultipleObjects needs to be rewritten! (not using
|
---|
14 | * Open32)
|
---|
15 | *
|
---|
16 | ************************************************************************************
|
---|
17 | * NOTE: If we ever decide to allocate our own stack, then we MUST use VirtualAlloc!!!!
|
---|
18 | * (alignment reasons)
|
---|
19 | ************************************************************************************
|
---|
20 | *
|
---|
21 | * Copyright 2000 Sander van Leeuwen (sandervl@xs4all.nl)
|
---|
22 | *
|
---|
23 | */
|
---|
24 | #include <os2win.h>
|
---|
25 | #include <stdlib.h>
|
---|
26 | #include <string.h>
|
---|
27 | #include <misc.h>
|
---|
28 | #include <wprocess.h>
|
---|
29 |
|
---|
30 | #include <HandleManager.H>
|
---|
31 | #include "HMThread.h"
|
---|
32 | #include "oslibdos.h"
|
---|
33 | #include "oslibthread.h"
|
---|
34 | #include "oslibmem.h"
|
---|
35 |
|
---|
36 | #include <win/thread.h>
|
---|
37 | #include "thread.h"
|
---|
38 | #include "asmutil.h"
|
---|
39 | #include "winexebase.h"
|
---|
40 |
|
---|
41 | #define DBG_LOCALLOG DBG_hmthread
|
---|
42 | #include "dbglocal.h"
|
---|
43 |
|
---|
44 |
|
---|
45 | typedef struct {
|
---|
46 | HANDLE hDupThread; //original thread handle if duplicated
|
---|
47 | DWORD dwState; //THREAD_ALIVE, THREAD_TERMINATED
|
---|
48 | } OBJ_THREAD;
|
---|
49 |
|
---|
50 | #define GET_THREADHANDLE(hThread) (threadobj && threadobj->hDupThread) ? threadobj->hDupThread : hThread
|
---|
51 |
|
---|
52 | //******************************************************************************
|
---|
53 | //******************************************************************************
|
---|
54 | HANDLE HMDeviceThreadClass::CreateThread(PHMHANDLEDATA pHMHandleData,
|
---|
55 | LPSECURITY_ATTRIBUTES lpsa,
|
---|
56 | DWORD cbStack,
|
---|
57 | LPTHREAD_START_ROUTINE lpStartAddr,
|
---|
58 | LPVOID lpvThreadParm,
|
---|
59 | DWORD fdwCreate,
|
---|
60 | LPDWORD lpIDThread,
|
---|
61 | BOOL fRegisterThread)
|
---|
62 | {
|
---|
63 | Win32Thread *winthread;
|
---|
64 | DWORD threadid;
|
---|
65 | HANDLE hThread = pHMHandleData->hHMHandle;
|
---|
66 |
|
---|
67 | if(lpIDThread == NULL) {
|
---|
68 | lpIDThread = &threadid;
|
---|
69 | }
|
---|
70 | pHMHandleData->dwInternalType = HMTYPE_THREAD;
|
---|
71 | OBJ_THREAD *threadobj = (OBJ_THREAD *)malloc(sizeof(OBJ_THREAD));
|
---|
72 | if(threadobj == 0) {
|
---|
73 | DebugInt3();
|
---|
74 | SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
---|
75 | return(0);
|
---|
76 | }
|
---|
77 | threadobj->hDupThread = 0; //not a duplicate
|
---|
78 | threadobj->dwState = THREAD_ALIVE;
|
---|
79 | pHMHandleData->dwUserData = (DWORD)threadobj;
|
---|
80 |
|
---|
81 | //SvL: This doesn't really create a thread, but only sets up the
|
---|
82 | // handle of the current thread.
|
---|
83 | if(fRegisterThread) {
|
---|
84 | pHMHandleData->hHMHandle = O32_GetCurrentThread(); //return Open32 handle of thread
|
---|
85 | return pHMHandleData->hHMHandle;
|
---|
86 | }
|
---|
87 | winthread = new Win32Thread(lpStartAddr, lpvThreadParm, fdwCreate, hThread);
|
---|
88 |
|
---|
89 | if(winthread == 0) {
|
---|
90 | dprintf(("Win32Thread creation failed, no more memory"));
|
---|
91 | DebugInt3();
|
---|
92 | SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
---|
93 | return(0);
|
---|
94 | }
|
---|
95 | if(winthread->_GetTEB() == 0) {
|
---|
96 | dprintf(("Win32Thread->teb creation failed, no more memory"));
|
---|
97 | DebugInt3();
|
---|
98 | SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
---|
99 | return(0);
|
---|
100 | }
|
---|
101 |
|
---|
102 | // @@@PH Note: with debug code enabled, ODIN might request more stack space!
|
---|
103 | //SvL: Also need more stack in release build (RealPlayer 7 sometimes runs
|
---|
104 | // out of stack
|
---|
105 | if (cbStack > 0) {
|
---|
106 | cbStack <<= 1; // double stack
|
---|
107 | }
|
---|
108 | else {
|
---|
109 | cbStack = (WinExe) ? WinExe->getDefaultStackSize() : 0x100000; // per default 1MB stack per thread
|
---|
110 | }
|
---|
111 | dprintf(("Thread stack size 0x%x", cbStack));
|
---|
112 |
|
---|
113 | //************************************************************************************
|
---|
114 | //NOTE: If we ever decide to allocate our own stack, then we MUST use VirtualAlloc!!!!
|
---|
115 | // (alignment reasons)
|
---|
116 | //************************************************************************************
|
---|
117 | pHMHandleData->hHMHandle = O32_CreateThread(lpsa, cbStack, winthread->GetOS2Callback(),
|
---|
118 | (LPVOID)winthread, fdwCreate, lpIDThread);
|
---|
119 |
|
---|
120 | if(pHMHandleData->hHMHandle == 0) {
|
---|
121 | dprintf(("Thread creation failed!!"));
|
---|
122 | DebugInt3();
|
---|
123 | }
|
---|
124 |
|
---|
125 | *lpIDThread = MAKE_THREADID(O32_GetCurrentProcessId(), *lpIDThread);
|
---|
126 |
|
---|
127 | TEB *teb = GetTEBFromThreadHandle(hThread);
|
---|
128 | if(teb) {
|
---|
129 | //store thread id in TEB
|
---|
130 | teb->o.odin.threadId = *lpIDThread;
|
---|
131 | teb->o.odin.dwSuspend = (fdwCreate & CREATE_SUSPENDED) ? 1 : 0;
|
---|
132 | }
|
---|
133 | else DebugInt3();
|
---|
134 |
|
---|
135 | dprintf(("CreateThread created %08x, id %x", pHMHandleData->hHMHandle, *lpIDThread));
|
---|
136 |
|
---|
137 | return pHMHandleData->hHMHandle;
|
---|
138 | }
|
---|
139 | /*****************************************************************************
|
---|
140 | * Name : HMDeviceFileClass::DuplicateHandle
|
---|
141 | * Purpose :
|
---|
142 | * Parameters:
|
---|
143 | * various parameters as required
|
---|
144 | * Variables :
|
---|
145 | * Result :
|
---|
146 | * Remark : DUPLICATE_CLOSE_SOURCE flag handled in HMDuplicateHandle
|
---|
147 | *
|
---|
148 | * Status : partially implemented
|
---|
149 | *
|
---|
150 | * Author : SvL
|
---|
151 | *****************************************************************************/
|
---|
152 | BOOL HMDeviceThreadClass::DuplicateHandle(HANDLE srchandle, PHMHANDLEDATA pHMHandleData,
|
---|
153 | HANDLE srcprocess,
|
---|
154 | PHMHANDLEDATA pHMSrcHandle,
|
---|
155 | HANDLE destprocess,
|
---|
156 | DWORD fdwAccess,
|
---|
157 | BOOL fInherit,
|
---|
158 | DWORD fdwOptions,
|
---|
159 | DWORD fdwOdinOptions)
|
---|
160 | {
|
---|
161 | BOOL ret;
|
---|
162 | OBJ_THREAD *threadsrc = (OBJ_THREAD *)pHMSrcHandle->dwUserData;
|
---|
163 |
|
---|
164 | dprintf(("KERNEL32:HMDeviceThreadClass::DuplicateHandle (%08x,%08x,%08x,%08x)",
|
---|
165 | pHMHandleData, srcprocess, pHMSrcHandle->hHMHandle, destprocess));
|
---|
166 |
|
---|
167 | if(destprocess != srcprocess)
|
---|
168 | {
|
---|
169 | dprintf(("ERROR: DuplicateHandle; different processes not supported!!"));
|
---|
170 | SetLastError(ERROR_INVALID_HANDLE); //??
|
---|
171 | return FALSE;
|
---|
172 | }
|
---|
173 | pHMHandleData->hHMHandle = 0;
|
---|
174 | ret = O32_DuplicateHandle(srcprocess, pHMSrcHandle->hHMHandle, destprocess, &pHMHandleData->hHMHandle, fdwAccess, fInherit, fdwOptions);
|
---|
175 |
|
---|
176 | if(ret == TRUE) {
|
---|
177 | OBJ_THREAD *threaddest = (OBJ_THREAD *)malloc(sizeof(OBJ_THREAD));
|
---|
178 | if(threaddest == NULL) {
|
---|
179 | O32_CloseHandle(pHMHandleData->hHMHandle);
|
---|
180 | SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
---|
181 | return FALSE;
|
---|
182 | }
|
---|
183 | threaddest->hDupThread = 0;
|
---|
184 | threaddest->dwState = THREAD_ALIVE;
|
---|
185 | pHMHandleData->dwUserData = (DWORD)threaddest;
|
---|
186 |
|
---|
187 | if(threadsrc) {
|
---|
188 | threaddest->hDupThread = (threadsrc->hDupThread) ? threadsrc->hDupThread : srchandle;
|
---|
189 | threaddest->dwState = threadsrc->dwState;
|
---|
190 | }
|
---|
191 |
|
---|
192 | return TRUE;
|
---|
193 | }
|
---|
194 | else
|
---|
195 | {
|
---|
196 | dprintf(("O32_DuplicateHandle failed for handle %x!!", pHMSrcHandle->hHMHandle));
|
---|
197 | return FALSE;
|
---|
198 | }
|
---|
199 | }
|
---|
200 | //******************************************************************************
|
---|
201 | //******************************************************************************
|
---|
202 | DWORD HMDeviceThreadClass::SuspendThread(HANDLE hThread, PHMHANDLEDATA pHMHandleData)
|
---|
203 | {
|
---|
204 | DWORD dwSuspend;
|
---|
205 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
206 |
|
---|
207 | TEB *teb = GetTEBFromThreadHandle(GET_THREADHANDLE(hThread));
|
---|
208 | if(teb) {
|
---|
209 | teb->o.odin.dwSuspend++;
|
---|
210 | dprintf(("SuspendThread %08xh): count %d", pHMHandleData->hHMHandle, teb->o.odin.dwSuspend));
|
---|
211 | }
|
---|
212 | dwSuspend = O32_SuspendThread(pHMHandleData->hHMHandle);
|
---|
213 | if(dwSuspend == -1) {
|
---|
214 | teb->o.odin.dwSuspend--;
|
---|
215 | dprintf(("!ERROR!: SuspendThread FAILED"));
|
---|
216 | }
|
---|
217 | return dwSuspend;
|
---|
218 | }
|
---|
219 | //******************************************************************************
|
---|
220 | //******************************************************************************
|
---|
221 | DWORD HMDeviceThreadClass::ResumeThread(HANDLE hThread, PHMHANDLEDATA pHMHandleData)
|
---|
222 | {
|
---|
223 | DWORD dwSuspend;
|
---|
224 | CONTEXT context;
|
---|
225 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
226 |
|
---|
227 | TEB *teb = GetTEBFromThreadHandle(GET_THREADHANDLE(hThread));
|
---|
228 | if(teb == NULL) {
|
---|
229 | dprintf(("ERROR: invalid thread handle"));
|
---|
230 | SetLastError(ERROR_INVALID_THREAD_ID); //??
|
---|
231 | return -1;
|
---|
232 | }
|
---|
233 |
|
---|
234 | context.Eip = 0;
|
---|
235 | if(teb->o.odin.context.ContextFlags)
|
---|
236 | {
|
---|
237 | context.ContextFlags = CONTEXT_CONTROL;
|
---|
238 | if(GetThreadContext(hThread, pHMHandleData, &context) == FALSE)
|
---|
239 | {
|
---|
240 | DebugInt3();
|
---|
241 | context.Eip = 0;
|
---|
242 | }
|
---|
243 | if(teb->o.odin.dwSuspend == 1 && teb->o.odin.context.ContextFlags && context.Eip)
|
---|
244 | {//SetThreadContext was called for this thread and it's about to be restored
|
---|
245 |
|
---|
246 | //Since there's no equivalent of SetThreadContext in OS/2, we put an
|
---|
247 | //illegal instruction at the instruction pointer of this thread to
|
---|
248 | //make sure an exception is triggered. Inside the exception handler
|
---|
249 | //of the thread we can change the registers.
|
---|
250 | //(XCPT_PRIVILEGED_INSTRUCTION exception handler in exceptions.cpp)
|
---|
251 | //(see detailed description in the HMDeviceThreadClass::SetThreadContext method)
|
---|
252 | USHORT *lpEIP = (USHORT *)context.Eip;
|
---|
253 |
|
---|
254 | if(*lpEIP != SETTHREADCONTEXT_INVALID_LOCKOPCODE)
|
---|
255 | {
|
---|
256 | int size;
|
---|
257 |
|
---|
258 | teb->o.odin.dwAliasOffset = (DWORD)lpEIP & 0xFFF;
|
---|
259 | if(teb->o.odin.dwAliasOffset + 2 >= PAGE_SIZE) {
|
---|
260 | size = 8192;
|
---|
261 | }
|
---|
262 | else size = teb->o.odin.dwAliasOffset + 2;
|
---|
263 |
|
---|
264 | lpEIP = (USHORT *)((DWORD)lpEIP & ~0xFFF);
|
---|
265 |
|
---|
266 | if(OSLibDosAliasMem(lpEIP, size, &teb->o.odin.lpAlias, PAG_READ|PAG_WRITE) == 0)
|
---|
267 | {
|
---|
268 | teb->o.odin.savedopcode = *(USHORT*)((char *)teb->o.odin.lpAlias+teb->o.odin.dwAliasOffset);
|
---|
269 |
|
---|
270 | //sti -> undefined opcode exception
|
---|
271 | *(USHORT *)((char *)teb->o.odin.lpAlias+teb->o.odin.dwAliasOffset) = SETTHREADCONTEXT_INVALID_LOCKOPCODE;
|
---|
272 | }
|
---|
273 | else DebugInt3();
|
---|
274 |
|
---|
275 | //temporarily boost priority to ensure this thread is scheduled first
|
---|
276 | //we reduce the priority in the exception handler
|
---|
277 | OSLibDosSetMaxPriority(ODIN_TO_OS2_THREADID(teb->o.odin.threadId));
|
---|
278 | }
|
---|
279 | else {
|
---|
280 | dprintf(("already patched!?!"));
|
---|
281 | DebugInt3();
|
---|
282 | }
|
---|
283 | }
|
---|
284 | }
|
---|
285 |
|
---|
286 | teb->o.odin.dwSuspend--;
|
---|
287 | dprintf(("ResumeThread (%08xh) : count %d", pHMHandleData->hHMHandle, teb->o.odin.dwSuspend));
|
---|
288 |
|
---|
289 | dwSuspend = O32_ResumeThread(pHMHandleData->hHMHandle);
|
---|
290 | if(dwSuspend == -1)
|
---|
291 | {
|
---|
292 | teb->o.odin.dwSuspend++;
|
---|
293 | dprintf(("!ERROR!: ResumeThread FAILED"));
|
---|
294 |
|
---|
295 | if(teb->o.odin.dwSuspend == 1 && teb->o.odin.context.ContextFlags && context.Eip)
|
---|
296 | {//Undo previous patching
|
---|
297 | char *lpEIP = (char *)context.Eip;
|
---|
298 |
|
---|
299 | if(*lpEIP == SETTHREADCONTEXT_INVALID_LOCKOPCODE)
|
---|
300 | {
|
---|
301 | dprintf(("Undo SetThreadContext patching!!"));
|
---|
302 |
|
---|
303 | USHORT *lpAlias = (USHORT*)((char *)teb->o.odin.lpAlias + teb->o.odin.dwAliasOffset);
|
---|
304 | //put back old byte
|
---|
305 | *lpAlias = teb->o.odin.savedopcode;
|
---|
306 |
|
---|
307 | //restore the original priority (we boosted it to ensure this thread was scheduled first)
|
---|
308 | ::SetThreadPriority(teb->o.odin.hThread, ::GetThreadPriority(teb->o.odin.hThread));
|
---|
309 |
|
---|
310 | OSLibDosFreeMem(teb->o.odin.lpAlias);
|
---|
311 | }
|
---|
312 | else {
|
---|
313 | dprintf(("not patched!?!"));
|
---|
314 | DebugInt3();
|
---|
315 | }
|
---|
316 | teb->o.odin.dwAliasOffset = 0;
|
---|
317 | teb->o.odin.lpAlias = NULL;
|
---|
318 | teb->o.odin.context.ContextFlags = 0;
|
---|
319 | }
|
---|
320 | }
|
---|
321 |
|
---|
322 | return dwSuspend;
|
---|
323 | }
|
---|
324 | //******************************************************************************
|
---|
325 | //******************************************************************************
|
---|
326 | INT HMDeviceThreadClass::GetThreadPriority(HANDLE hThread, PHMHANDLEDATA pHMHandleData)
|
---|
327 | {
|
---|
328 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
329 |
|
---|
330 | dprintf(("GetThreadPriority(%08xh)\n", pHMHandleData->hHMHandle));
|
---|
331 |
|
---|
332 | TEB *teb = GetTEBFromThreadHandle(GET_THREADHANDLE(hThread));
|
---|
333 | if(teb == NULL) {
|
---|
334 | dprintf(("!WARNING!: TEB not found!!"));
|
---|
335 | SetLastError(ERROR_INVALID_HANDLE);
|
---|
336 | return THREAD_PRIORITY_ERROR_RETURN;
|
---|
337 | }
|
---|
338 | return teb->delta_priority;
|
---|
339 | }
|
---|
340 | //******************************************************************************
|
---|
341 | //******************************************************************************
|
---|
342 | BOOL HMDeviceThreadClass::SetThreadPriority(HANDLE hThread, PHMHANDLEDATA pHMHandleData, int priority)
|
---|
343 | {
|
---|
344 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
345 |
|
---|
346 | dprintf(("SetThreadPriority (%08xh,%08xh)", pHMHandleData->hHMHandle, priority));
|
---|
347 |
|
---|
348 | TEB *teb = GetTEBFromThreadHandle(GET_THREADHANDLE(hThread));
|
---|
349 | if(teb == NULL) {
|
---|
350 | dprintf(("!WARNING!: TEB not found!!"));
|
---|
351 | SetLastError(ERROR_INVALID_HANDLE);
|
---|
352 | return FALSE;
|
---|
353 | }
|
---|
354 | DWORD ret = OSLibDosSetPriority(ODIN_TO_OS2_THREADID(teb->o.odin.threadId), priority);
|
---|
355 | if(ret == ERROR_SUCCESS) {
|
---|
356 | teb->delta_priority = priority;
|
---|
357 | return TRUE;
|
---|
358 | }
|
---|
359 | else {
|
---|
360 | dprintf(("DosSetPriority failed with rc %d", ret));
|
---|
361 | return FALSE;
|
---|
362 | }
|
---|
363 | }
|
---|
364 | //******************************************************************************
|
---|
365 | //******************************************************************************
|
---|
366 | #ifdef DEBUG
|
---|
367 | void DumpContext(CONTEXT *lpContext)
|
---|
368 | {
|
---|
369 | dprintf(("************************ THREAD CONTEXT ************************"));
|
---|
370 | if(lpContext->ContextFlags & CONTEXT_CONTROL) {
|
---|
371 | dprintf(("CS:EIP %04x:%08x FLAGS %08x", lpContext->SegCs, lpContext->Eip, lpContext->EFlags));
|
---|
372 | dprintf(("SS:ESP %04x:%08x EBP %08x", lpContext->SegSs, lpContext->Esp, lpContext->Ebp));
|
---|
373 | }
|
---|
374 | if(lpContext->ContextFlags & CONTEXT_INTEGER) {
|
---|
375 | dprintf(("EAX %08x EBX %08x ECX %08x EDX %08x", lpContext->Eax, lpContext->Ebx, lpContext->Ecx, lpContext->Edx));
|
---|
376 | dprintf(("ESI %08x EDI %08x", lpContext->Esi, lpContext->Edi));
|
---|
377 | }
|
---|
378 | if(lpContext->ContextFlags & CONTEXT_SEGMENTS) {
|
---|
379 | dprintf(("DS %04x ES %04x FS %04x GS %04x", (ULONG)lpContext->SegDs, (ULONG)lpContext->SegEs, (ULONG)lpContext->SegFs, (ULONG)lpContext->SegGs));
|
---|
380 | }
|
---|
381 | dprintf(("************************ THREAD CONTEXT ************************"));
|
---|
382 | // if(lpContext->ContextFlags & CONTEXT_FLOATING_POINT) {
|
---|
383 | // //TODO: First 7 dwords the same?
|
---|
384 | // memcpy(&lpContext->FloatSave, ctxrec.ctx_env, sizeof(ctxrec.ctx_env));
|
---|
385 | // memcpy(&lpContext->FloatSave.RegisterArea, ctxrec.ctx_stack, sizeof(ctxrec.ctx_stack));
|
---|
386 | // }
|
---|
387 | }
|
---|
388 | #else
|
---|
389 | #define DumpContext(a)
|
---|
390 | #endif
|
---|
391 | //******************************************************************************
|
---|
392 | //******************************************************************************
|
---|
393 | BOOL HMDeviceThreadClass::GetThreadContext(HANDLE hThread, PHMHANDLEDATA pHMHandleData, PCONTEXT lpContext)
|
---|
394 | {
|
---|
395 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
396 | BOOL ret;
|
---|
397 |
|
---|
398 | TEB *teb = GetTEBFromThreadHandle(GET_THREADHANDLE(hThread));
|
---|
399 | if(teb) {
|
---|
400 | if(teb->o.odin.dwSuspend == 0) {
|
---|
401 | dprintf(("ERROR: thread not suspended!!"));
|
---|
402 | DebugInt3();
|
---|
403 | SetLastError(ERROR_INVALID_OPERATION); //???
|
---|
404 | return FALSE;
|
---|
405 | }
|
---|
406 |
|
---|
407 | ret = OSLibQueryThreadContext(ODIN_TO_OS2_THREADID(teb->o.odin.threadId), teb->teb_sel, lpContext);
|
---|
408 | if(ret == TRUE) {
|
---|
409 | DumpContext(lpContext);
|
---|
410 | }
|
---|
411 | return ret;
|
---|
412 | }
|
---|
413 | dprintf(("!WARNING!: TEB not found!!"));
|
---|
414 | SetLastError(ERROR_INVALID_HANDLE);
|
---|
415 | return FALSE;
|
---|
416 | }
|
---|
417 | //******************************************************************************
|
---|
418 | // HMDeviceThreadClass::SetThreadContext
|
---|
419 | //
|
---|
420 | // Change the context (registers) of a suspended thread
|
---|
421 | //
|
---|
422 | // Parameters:
|
---|
423 | //
|
---|
424 | // HANDLE hThread - thread handle
|
---|
425 | // PHMHANDLEDATA pHMHandleData - handle data
|
---|
426 | // const CONTEXT *lpContext - context record (IN)
|
---|
427 | //
|
---|
428 | // Returns:
|
---|
429 | // TRUE - success
|
---|
430 | // FALSE - failure
|
---|
431 | //
|
---|
432 | // Remarks:
|
---|
433 | //
|
---|
434 | // Since OS/2 doesn't provide an equivalent for this function, we need to change
|
---|
435 | // the thread context manually. (DosDebug isn't really an option)
|
---|
436 | //
|
---|
437 | // We save the new context in the TEB structure. When this thread is
|
---|
438 | // activated by ResumeThread, we'll change the instruction addressed by the
|
---|
439 | // thread's EIP to an invalid instruction (sti).
|
---|
440 | // When the thread is activated, it will generate an exception. Inside the
|
---|
441 | // exception handler we change the registers, restore the original memory
|
---|
442 | // and continue.
|
---|
443 | // To make sure the thread is executed first and noone else will execute the
|
---|
444 | // invalid instruction, we temporarily boost the thread's priority to the max.
|
---|
445 | // (time critical, delta +31; max priority of win32 threads is time critical,
|
---|
446 | // delta 0)
|
---|
447 | // The priority is restored in the exception handler.
|
---|
448 | //
|
---|
449 | //******************************************************************************
|
---|
450 | BOOL HMDeviceThreadClass::SetThreadContext(HANDLE hThread, PHMHANDLEDATA pHMHandleData, const CONTEXT *lpContext)
|
---|
451 | {
|
---|
452 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
453 | BOOL ret;
|
---|
454 |
|
---|
455 | DumpContext((CONTEXT *)lpContext);
|
---|
456 |
|
---|
457 | TEB *teb = GetTEBFromThreadHandle(GET_THREADHANDLE(hThread));
|
---|
458 | if(teb)
|
---|
459 | {
|
---|
460 | if(teb->o.odin.dwSuspend == 0) {
|
---|
461 | dprintf(("ERROR: thread not suspended!!"));
|
---|
462 | SetLastError(ERROR_INVALID_OPERATION); //???
|
---|
463 | return FALSE;
|
---|
464 | }
|
---|
465 | if(lpContext->ContextFlags & CONTEXT_CONTROL) {
|
---|
466 | teb->o.odin.context.ContextFlags |= CONTEXT_CONTROL;
|
---|
467 | teb->o.odin.context.Ebp = lpContext->Ebp;
|
---|
468 | teb->o.odin.context.Eip = lpContext->Eip;
|
---|
469 | teb->o.odin.context.SegCs = lpContext->SegCs;
|
---|
470 | teb->o.odin.context.EFlags = lpContext->EFlags;
|
---|
471 | teb->o.odin.context.Esp = lpContext->Esp;
|
---|
472 | teb->o.odin.context.SegSs = lpContext->SegSs;
|
---|
473 | }
|
---|
474 | if(lpContext->ContextFlags & CONTEXT_INTEGER) {
|
---|
475 | teb->o.odin.context.ContextFlags |= CONTEXT_INTEGER;
|
---|
476 | teb->o.odin.context.Edi = lpContext->Edi;
|
---|
477 | teb->o.odin.context.Esi = lpContext->Esi;
|
---|
478 | teb->o.odin.context.Ebx = lpContext->Ebx;
|
---|
479 | teb->o.odin.context.Edx = lpContext->Edx;
|
---|
480 | teb->o.odin.context.Ecx = lpContext->Ecx;
|
---|
481 | teb->o.odin.context.Eax = lpContext->Eax;
|
---|
482 | }
|
---|
483 | if(lpContext->ContextFlags & CONTEXT_SEGMENTS) {
|
---|
484 | teb->o.odin.context.ContextFlags |= CONTEXT_SEGMENTS;
|
---|
485 | teb->o.odin.context.SegGs = lpContext->SegGs;
|
---|
486 | teb->o.odin.context.SegFs = lpContext->SegFs;
|
---|
487 | teb->o.odin.context.SegEs = lpContext->SegEs;
|
---|
488 | teb->o.odin.context.SegDs = lpContext->SegDs;
|
---|
489 | }
|
---|
490 | if(lpContext->ContextFlags & CONTEXT_FLOATING_POINT) {
|
---|
491 | teb->o.odin.context.ContextFlags |= CONTEXT_FLOATING_POINT;
|
---|
492 | memcpy(&teb->o.odin.context.FloatSave, &lpContext->FloatSave, sizeof(lpContext->FloatSave));
|
---|
493 | }
|
---|
494 | SetLastError(ERROR_SUCCESS);
|
---|
495 | return TRUE;
|
---|
496 | }
|
---|
497 | dprintf(("!WARNING!: TEB not found!!"));
|
---|
498 | SetLastError(ERROR_INVALID_HANDLE);
|
---|
499 | return FALSE;
|
---|
500 | }
|
---|
501 | /*****************************************************************************
|
---|
502 | * Name : BOOL GetThreadTimes
|
---|
503 | * Purpose : The GetThreadTimes function obtains timing information about a specified thread.
|
---|
504 | * Parameters: HANDLE hThread specifies the thread of interest
|
---|
505 | * LPFILETIME lpCreationTime when the thread was created
|
---|
506 | * LPFILETIME lpExitTime when the thread exited
|
---|
507 | * LPFILETIME lpKernelTime time the thread has spent in kernel mode
|
---|
508 | * LPFILETIME lpUserTime time the thread has spent in user mode
|
---|
509 | * Variables :
|
---|
510 | * Result : TRUE / FALSE
|
---|
511 | * Remark :
|
---|
512 | * Status : UNTESTED STUB
|
---|
513 | *
|
---|
514 | * Author : Patrick Haller [Mon, 1998/06/15 08:00]
|
---|
515 | *****************************************************************************/
|
---|
516 |
|
---|
517 | BOOL HMDeviceThreadClass::GetThreadTimes(HANDLE hThread,
|
---|
518 | PHMHANDLEDATA pHMHandleData,
|
---|
519 | LPFILETIME lpCreationTime,
|
---|
520 | LPFILETIME lpExitTime,
|
---|
521 | LPFILETIME lpKernelTime,
|
---|
522 | LPFILETIME lpUserTime)
|
---|
523 | {
|
---|
524 | dprintf(("Kernel32: GetThreadTimes(%08xh,%08xh,%08xh,%08xh,%08xh) not implemented.\n",
|
---|
525 | hThread,
|
---|
526 | lpCreationTime,
|
---|
527 | lpExitTime,
|
---|
528 | lpKernelTime,
|
---|
529 | lpUserTime));
|
---|
530 |
|
---|
531 | return (FALSE);
|
---|
532 | }
|
---|
533 | //******************************************************************************
|
---|
534 | //******************************************************************************
|
---|
535 | BOOL HMDeviceThreadClass::TerminateThread(HANDLE hThread, PHMHANDLEDATA pHMHandleData, DWORD exitcode)
|
---|
536 | {
|
---|
537 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
538 |
|
---|
539 | dprintf(("TerminateThread (%08xh,%08xh)\n",
|
---|
540 | pHMHandleData->hHMHandle,
|
---|
541 | exitcode));
|
---|
542 |
|
---|
543 | if(threadobj) {
|
---|
544 | threadobj->dwState = THREAD_TERMINATED;
|
---|
545 | }
|
---|
546 | else DebugInt3();
|
---|
547 | return O32_TerminateThread(pHMHandleData->hHMHandle, exitcode);
|
---|
548 | }
|
---|
549 | //******************************************************************************
|
---|
550 | //******************************************************************************
|
---|
551 | BOOL HMDeviceThreadClass::SetThreadTerminated(HANDLE hThread, PHMHANDLEDATA pHMHandleData)
|
---|
552 | {
|
---|
553 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
554 |
|
---|
555 | if(threadobj) {
|
---|
556 | threadobj->dwState = THREAD_TERMINATED;
|
---|
557 | }
|
---|
558 | else DebugInt3();
|
---|
559 |
|
---|
560 | return TRUE;
|
---|
561 | }
|
---|
562 | //******************************************************************************
|
---|
563 | //******************************************************************************
|
---|
564 | BOOL HMDeviceThreadClass::GetExitCodeThread(HANDLE hThread, PHMHANDLEDATA pHMHandleData, LPDWORD lpExitCode)
|
---|
565 | {
|
---|
566 | dprintf(("GetExitCodeThread (%08xh,%08xh)\n",
|
---|
567 | pHMHandleData->hHMHandle,
|
---|
568 | lpExitCode));
|
---|
569 |
|
---|
570 | #if 0
|
---|
571 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
572 |
|
---|
573 | if(threadobj && threadobj->dwState == THREAD_ALIVE) {
|
---|
574 | lpExitCode == STILL_ALIVE;
|
---|
575 | return TRUE;
|
---|
576 | }
|
---|
577 | else DebugInt3();
|
---|
578 | #endif
|
---|
579 | return O32_GetExitCodeThread(pHMHandleData->hHMHandle, lpExitCode);
|
---|
580 | }
|
---|
581 | //******************************************************************************
|
---|
582 | //******************************************************************************
|
---|
583 | BOOL HMDeviceThreadClass::CloseHandle(PHMHANDLEDATA pHMHandleData)
|
---|
584 | {
|
---|
585 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
586 |
|
---|
587 | dprintf(("HMThread::CloseHandle %08x", pHMHandleData->hHMHandle));
|
---|
588 |
|
---|
589 | if(threadobj) {
|
---|
590 | pHMHandleData->dwUserData = 0;
|
---|
591 | free(threadobj);
|
---|
592 | }
|
---|
593 | return O32_CloseHandle(pHMHandleData->hHMHandle);
|
---|
594 | }
|
---|
595 | //******************************************************************************
|
---|
596 | //******************************************************************************
|
---|
597 | DWORD HMDeviceThreadClass::WaitForSingleObject(PHMHANDLEDATA pHMHandleData,
|
---|
598 | DWORD dwTimeout)
|
---|
599 | {
|
---|
600 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
601 |
|
---|
602 | dprintf(("HMThread::WaitForSingleObject (%08xh,%08xh)\n",
|
---|
603 | pHMHandleData->hHMHandle,
|
---|
604 | dwTimeout));
|
---|
605 |
|
---|
606 | //This doesn't work very well in Open32 (object's state never signaled)
|
---|
607 | if(threadobj && threadobj->dwState == THREAD_TERMINATED) {
|
---|
608 | return WAIT_OBJECT_0;
|
---|
609 | }
|
---|
610 | return HMDeviceOpen32Class::WaitForSingleObject(pHMHandleData, dwTimeout);
|
---|
611 | }
|
---|
612 | //******************************************************************************
|
---|
613 | //******************************************************************************
|
---|
614 | DWORD HMDeviceThreadClass::WaitForSingleObjectEx(PHMHANDLEDATA pHMHandleData,
|
---|
615 | DWORD dwTimeout,
|
---|
616 | BOOL fAlertable)
|
---|
617 | {
|
---|
618 | OBJ_THREAD *threadobj = (OBJ_THREAD *)pHMHandleData->dwUserData;
|
---|
619 |
|
---|
620 | //This doesn't work very well in Open32 (object's state never signaled)
|
---|
621 | if(threadobj && threadobj->dwState == THREAD_TERMINATED) {
|
---|
622 | return WAIT_OBJECT_0;
|
---|
623 | }
|
---|
624 | return HMDeviceOpen32Class::WaitForSingleObjectEx(pHMHandleData, dwTimeout, fAlertable);
|
---|
625 | }
|
---|
626 | //******************************************************************************
|
---|
627 | //******************************************************************************
|
---|