source: trunk/src/kernel32/hmthread.cpp

Last change on this file was 21981, checked in by dmik, 13 years ago

kernel32: Fix stack size interpretation in CreateThread().

It now uses the stack size parameter as a number of bytes to
pre-commit, not as a total stack size, unless
STACK_SIZE_PARAM_IS_A_RESERVATION is set.

Closes #77.

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