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

Last change on this file since 21916 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 24.5 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 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 *****************************************************************************/
152BOOL 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//******************************************************************************
202DWORD 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//******************************************************************************
221DWORD 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//******************************************************************************
326INT 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//******************************************************************************
342BOOL 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
367void 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//******************************************************************************
393BOOL 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//******************************************************************************
450BOOL 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
517BOOL 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//******************************************************************************
535BOOL 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//******************************************************************************
551BOOL 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//******************************************************************************
564BOOL 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//******************************************************************************
583BOOL 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//******************************************************************************
597DWORD 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//******************************************************************************
614DWORD 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//******************************************************************************
Note: See TracBrowser for help on using the repository browser.