source: trunk/src/kernel32/hmthread.cpp@ 21302

Last change on this file since 21302 was 21302, checked in by ydario, 16 years ago

Kernel32 updates.

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