Release 980822
[wine/multimedia.git] / scheduler / thread.c
blob60365d529ad360f332645257341926b9eec7d3d8
1 /*
2 * Win32 threads
4 * Copyright 1996 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <signal.h>
9 #include <unistd.h>
10 #include "thread.h"
11 #include "process.h"
12 #include "task.h"
13 #include "module.h"
14 #include "user.h"
15 #include "winerror.h"
16 #include "heap.h"
17 #include "selectors.h"
18 #include "miscemu.h"
19 #include "winnt.h"
20 #include "server.h"
21 #include "stackframe.h"
22 #include "debug.h"
24 #ifndef __i386__
25 THDB *pCurrentThread;
26 #endif
28 static BOOL32 THREAD_Signaled( K32OBJ *obj, DWORD thread_id );
29 static BOOL32 THREAD_Satisfied( K32OBJ *obj, DWORD thread_id );
30 static void THREAD_AddWait( K32OBJ *obj, DWORD thread_id );
31 static void THREAD_RemoveWait( K32OBJ *obj, DWORD thread_id );
32 static void THREAD_Destroy( K32OBJ *obj );
34 const K32OBJ_OPS THREAD_Ops =
36 THREAD_Signaled, /* signaled */
37 THREAD_Satisfied, /* satisfied */
38 THREAD_AddWait, /* add_wait */
39 THREAD_RemoveWait, /* remove_wait */
40 NULL, /* read */
41 NULL, /* write */
42 THREAD_Destroy /* destroy */
45 /* The pseudohandle used for the current thread, see GetCurrentThread */
46 #define CURRENT_THREAD_PSEUDOHANDLE 0xfffffffe
48 /* Is threading code initialized? */
49 BOOL32 THREAD_InitDone = FALSE;
51 /**********************************************************************
52 * THREAD_GetPtr
54 * Return a pointer to a thread object. The object count must be decremented
55 * when no longer used.
57 THDB *THREAD_GetPtr( HANDLE32 handle, DWORD access, int *server_handle )
59 THDB *thread;
61 if (handle == CURRENT_THREAD_PSEUDOHANDLE) /* Self-thread handle */
63 thread = THREAD_Current();
64 if (server_handle) *server_handle = CURRENT_THREAD_PSEUDOHANDLE;
65 K32OBJ_IncCount( &thread->header );
67 else thread = (THDB *)HANDLE_GetObjPtr( PROCESS_Current(), handle,
68 K32OBJ_THREAD, access, server_handle );
69 return thread;
73 /***********************************************************************
74 * THREAD_Current
76 * Return the current thread THDB pointer.
78 THDB *THREAD_Current(void)
80 if (!THREAD_InitDone) return NULL;
81 return (THDB *)((char *)NtCurrentTeb() - (int)&((THDB *)0)->teb);
84 /***********************************************************************
85 * THREAD_IsWin16
87 BOOL32 THREAD_IsWin16( THDB *thdb )
89 if (!thdb || !thdb->process)
90 return TRUE;
91 else
93 TDB* pTask = (TDB*)GlobalLock16( thdb->process->task );
94 return !pTask || pTask->thdb == thdb;
99 /***********************************************************************
100 * THREAD_AddQueue
102 * Add a thread to a queue.
104 void THREAD_AddQueue( THREAD_QUEUE *queue, THDB *thread )
106 THREAD_ENTRY *entry = HeapAlloc( SystemHeap, HEAP_NO_SERIALIZE,
107 sizeof(*entry) );
108 assert(entry);
109 SYSTEM_LOCK();
110 entry->thread = thread;
111 if (*queue)
113 entry->next = (*queue)->next;
114 (*queue)->next = entry;
116 else entry->next = entry;
117 *queue = entry;
118 SYSTEM_UNLOCK();
121 /***********************************************************************
122 * THREAD_RemoveQueue
124 * Remove a thread from a queue.
126 void THREAD_RemoveQueue( THREAD_QUEUE *queue, THDB *thread )
128 THREAD_ENTRY *entry = *queue;
129 SYSTEM_LOCK();
130 if (entry->next == entry) /* Only one element in the queue */
132 assert( entry->thread == thread );
133 *queue = NULL;
135 else
137 THREAD_ENTRY *next;
138 while (entry->next->thread != thread)
140 entry = entry->next;
141 assert( entry != *queue ); /* Have we come all the way around? */
143 if ((next = entry->next) == *queue) *queue = entry;
144 entry->next = entry->next->next;
145 entry = next; /* This is the one we want to free */
147 HeapFree( SystemHeap, 0, entry );
148 SYSTEM_UNLOCK();
152 /***********************************************************************
153 * THREAD_Create
155 THDB *THREAD_Create( PDB32 *pdb, DWORD stack_size, BOOL32 alloc_stack16,
156 int *server_thandle, int *server_phandle,
157 LPTHREAD_START_ROUTINE start_addr, LPVOID param )
159 DWORD old_prot;
160 WORD cs, ds;
162 THDB *thdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(THDB) );
163 if (!thdb) return NULL;
164 thdb->header.type = K32OBJ_THREAD;
165 thdb->header.refcount = 1;
166 thdb->process = pdb;
167 thdb->teb.except = (void *)-1;
168 thdb->teb.htask16 = 0; /* FIXME */
169 thdb->teb.self = &thdb->teb;
170 thdb->teb.tls_ptr = thdb->tls_array;
171 thdb->teb.process = pdb;
172 thdb->wait_list = &thdb->wait_struct;
173 thdb->exit_code = 0x103; /* STILL_ACTIVE */
174 thdb->entry_point = start_addr;
175 thdb->entry_arg = param;
176 thdb->socket = -1;
178 /* Allocate the stack */
180 /* FIXME:
181 * If stacksize smaller than 1 MB, allocate 1MB
182 * (one program wanted only 10 kB, which is recommendable, but some WINE
183 * functions, noteably in the files subdir, push HUGE structures and
184 * arrays on the stack. They probably shouldn't.)
185 * If stacksize larger than 16 MB, warn the user. (We could shrink the stack
186 * but this could give more or less unexplainable crashes.)
188 if (stack_size<1024*1024)
189 stack_size = 1024 * 1024;
190 if (stack_size >= 16*1024*1024)
191 WARN(thread,"Thread stack size is %ld MB.\n",stack_size/1024/1024);
192 thdb->stack_base = VirtualAlloc(NULL,
193 stack_size + (alloc_stack16 ? 0x10000 : 0),
194 MEM_COMMIT, PAGE_EXECUTE_READWRITE );
195 if (!thdb->stack_base) goto error;
196 /* Set a guard page at the bottom of the stack */
197 VirtualProtect( thdb->stack_base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD,
198 &old_prot );
199 thdb->teb.stack_top = (char *)thdb->stack_base + stack_size;
200 thdb->teb.stack_low = thdb->stack_base;
201 thdb->exit_stack = thdb->teb.stack_top;
203 /* Allocate the TEB selector (%fs register) */
205 thdb->teb_sel = SELECTOR_AllocBlock( &thdb->teb, 0x1000, SEGMENT_DATA,
206 TRUE, FALSE );
207 if (!thdb->teb_sel) goto error;
209 /* Allocate the 16-bit stack selector */
211 if (alloc_stack16)
213 thdb->teb.stack_sel = SELECTOR_AllocBlock( thdb->teb.stack_top,
214 0x10000, SEGMENT_DATA,
215 FALSE, FALSE );
216 if (!thdb->teb.stack_sel) goto error;
217 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( thdb->teb.stack_sel,
218 0x10000 - sizeof(STACK16FRAME) );
221 /* Allocate the event */
223 if (!(thdb->event = EVENT_Create( TRUE, FALSE ))) goto error;
225 /* Create the thread socket */
227 if (CLIENT_NewThread( thdb, server_thandle, server_phandle )) goto error;
229 /* Add thread to process's list of threads */
231 THREAD_AddQueue( &pdb->thread_list, thdb );
233 /* Initialize the thread context */
235 GET_CS(cs);
236 GET_DS(ds);
237 thdb->pcontext = &thdb->context;
238 thdb->context.SegCs = cs;
239 thdb->context.SegDs = ds;
240 thdb->context.SegEs = ds;
241 thdb->context.SegGs = ds;
242 thdb->context.SegSs = ds;
243 thdb->context.SegFs = thdb->teb_sel;
244 thdb->context.Eip = (DWORD)start_addr;
245 thdb->context.Esp = (DWORD)thdb->teb.stack_top;
246 PE_InitTls( thdb );
247 return thdb;
249 error:
250 if (thdb->socket != -1) close( thdb->socket );
251 if (thdb->event) K32OBJ_DecCount( thdb->event );
252 if (thdb->teb.stack_sel) SELECTOR_FreeBlock( thdb->teb.stack_sel, 1 );
253 if (thdb->teb_sel) SELECTOR_FreeBlock( thdb->teb_sel, 1 );
254 if (thdb->stack_base) VirtualFree( thdb->stack_base, 0, MEM_RELEASE );
255 HeapFree( SystemHeap, 0, thdb );
256 return NULL;
260 /***********************************************************************
261 * THREAD_Signaled
263 static BOOL32 THREAD_Signaled( K32OBJ *obj, DWORD thread_id )
265 THDB *thdb = (THDB *)obj;
266 assert( obj->type == K32OBJ_THREAD );
267 return K32OBJ_OPS( thdb->event )->signaled( thdb->event, thread_id );
271 /***********************************************************************
272 * THREAD_Satisfied
274 * Wait on this object has been satisfied.
276 static BOOL32 THREAD_Satisfied( K32OBJ *obj, DWORD thread_id )
278 THDB *thdb = (THDB *)obj;
279 assert( obj->type == K32OBJ_THREAD );
280 return K32OBJ_OPS( thdb->event )->satisfied( thdb->event, thread_id );
284 /***********************************************************************
285 * THREAD_AddWait
287 * Add thread to object wait queue.
289 static void THREAD_AddWait( K32OBJ *obj, DWORD thread_id )
291 THDB *thdb = (THDB *)obj;
292 assert( obj->type == K32OBJ_THREAD );
293 return K32OBJ_OPS( thdb->event )->add_wait( thdb->event, thread_id );
297 /***********************************************************************
298 * THREAD_RemoveWait
300 * Remove thread from object wait queue.
302 static void THREAD_RemoveWait( K32OBJ *obj, DWORD thread_id )
304 THDB *thdb = (THDB *)obj;
305 assert( obj->type == K32OBJ_THREAD );
306 return K32OBJ_OPS( thdb->event )->remove_wait( thdb->event, thread_id );
310 /***********************************************************************
311 * THREAD_Destroy
313 static void THREAD_Destroy( K32OBJ *ptr )
315 THDB *thdb = (THDB *)ptr;
317 assert( ptr->type == K32OBJ_THREAD );
318 ptr->type = K32OBJ_UNKNOWN;
320 /* Free the associated memory */
322 #ifdef __i386__
324 /* Check if we are deleting the current thread */
325 WORD fs;
326 GET_FS( fs );
327 if (fs == thdb->teb_sel)
329 GET_DS( fs );
330 SET_FS( fs );
333 #endif
334 close( thdb->socket );
335 K32OBJ_DecCount( thdb->event );
336 SELECTOR_FreeBlock( thdb->teb_sel, 1 );
337 if (thdb->teb.stack_sel) SELECTOR_FreeBlock( thdb->teb.stack_sel, 1 );
338 HeapFree( SystemHeap, 0, thdb );
343 /***********************************************************************
344 * THREAD_Start
346 * Start execution of a newly created thread. Does not return.
348 void THREAD_Start( THDB *thdb )
350 LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point;
351 assert( THREAD_Current() == thdb );
352 CLIENT_InitThread();
353 PE_InitializeDLLs( thdb->process, DLL_THREAD_ATTACH, NULL );
354 ExitThread( func( thdb->entry_arg ) );
358 /***********************************************************************
359 * CreateThread (KERNEL32.63)
361 HANDLE32 WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
362 LPTHREAD_START_ROUTINE start, LPVOID param,
363 DWORD flags, LPDWORD id )
365 int server_handle = -1;
366 HANDLE32 handle = INVALID_HANDLE_VALUE32;
367 BOOL32 inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
369 THDB *thread = THREAD_Create( PROCESS_Current(), stack,
370 TRUE, &server_handle, NULL, start, param );
371 if (!thread) return INVALID_HANDLE_VALUE32;
372 handle = HANDLE_Alloc( PROCESS_Current(), &thread->header,
373 THREAD_ALL_ACCESS, inherit, server_handle );
374 if (handle == INVALID_HANDLE_VALUE32) goto error;
375 if (SYSDEPS_SpawnThread( thread ) == -1) goto error;
376 *id = THDB_TO_THREAD_ID( thread );
377 return handle;
379 error:
380 if (handle != INVALID_HANDLE_VALUE32) CloseHandle( handle );
381 K32OBJ_DecCount( &thread->header );
382 return INVALID_HANDLE_VALUE32;
386 /***********************************************************************
387 * ExitThread [KERNEL32.215] Ends a thread
389 * RETURNS
390 * None
392 void WINAPI ExitThread(
393 DWORD code) /* [in] Exit code for this thread */
395 THDB *thdb = THREAD_Current();
396 LONG count;
398 /* Remove thread from process's list */
399 THREAD_RemoveQueue( &thdb->process->thread_list, thdb );
401 PE_InitializeDLLs( thdb->process, DLL_THREAD_DETACH, NULL );
403 SYSTEM_LOCK();
404 thdb->exit_code = code;
405 EVENT_Set( thdb->event );
407 /* Abandon all owned mutexes */
408 while (thdb->mutex_list) MUTEX_Abandon( thdb->mutex_list );
410 /* FIXME: should free the stack somehow */
411 #if 0
412 /* FIXME: We cannot do this; once the current thread is destroyed,
413 synchronization primitives do not work properly. */
414 K32OBJ_DecCount( &thdb->header );
415 #endif
416 /* Completely unlock the system lock just in case */
417 count = SYSTEM_LOCK_COUNT();
418 while (count--) SYSTEM_UNLOCK();
419 SYSDEPS_ExitThread();
423 /***********************************************************************
424 * GetCurrentThread [KERNEL32.200] Gets pseudohandle for current thread
426 * RETURNS
427 * Pseudohandle for the current thread
429 HANDLE32 WINAPI GetCurrentThread(void)
431 return CURRENT_THREAD_PSEUDOHANDLE;
435 /***********************************************************************
436 * GetCurrentThreadId [KERNEL32.201] Returns thread identifier.
438 * RETURNS
439 * Thread identifier of calling thread
441 DWORD WINAPI GetCurrentThreadId(void)
443 return THDB_TO_THREAD_ID( THREAD_Current() );
447 /**********************************************************************
448 * GetLastError [KERNEL.148] [KERNEL32.227] Returns last-error code.
450 * RETURNS
451 * Calling thread's last error code value.
453 DWORD WINAPI GetLastError(void)
455 THDB *thread = THREAD_Current();
456 DWORD ret = thread->last_error;
457 TRACE(thread,"0x%lx\n",ret);
458 return ret;
462 /**********************************************************************
463 * SetLastError [KERNEL.147] [KERNEL32.497] Sets the last-error code.
465 * RETURNS
466 * None.
468 void WINAPI SetLastError(
469 DWORD error) /* [in] Per-thread error code */
471 THDB *thread = THREAD_Current();
472 /* This one must work before we have a thread (FIXME) */
474 TRACE(thread,"%p error=0x%lx\n",thread,error);
476 if (thread)
477 thread->last_error = error;
481 /**********************************************************************
482 * SetLastErrorEx [USER32.485] Sets the last-error code.
484 * RETURNS
485 * None.
487 void WINAPI SetLastErrorEx(
488 DWORD error, /* [in] Per-thread error code */
489 DWORD type) /* [in] Error type */
491 TRACE(thread, "(0x%08lx, 0x%08lx)\n", error,type);
492 switch(type) {
493 case 0:
494 break;
495 case SLE_ERROR:
496 case SLE_MINORERROR:
497 case SLE_WARNING:
498 /* Fall through for now */
499 default:
500 FIXME(thread, "(error=%08lx, type=%08lx): Unhandled type\n", error,type);
501 break;
503 SetLastError( error );
507 /**********************************************************************
508 * THREAD_TlsAlloc
510 DWORD THREAD_TlsAlloc(THDB *thread)
512 DWORD i, mask, ret = 0;
513 DWORD *bits = thread->process->tls_bits;
514 EnterCriticalSection( &thread->process->crit_section );
515 if (*bits == 0xffffffff)
517 bits++;
518 ret = 32;
519 if (*bits == 0xffffffff)
521 LeaveCriticalSection( &thread->process->crit_section );
522 SetLastError( ERROR_NO_MORE_ITEMS );
523 return 0xffffffff;
526 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
527 *bits |= mask;
528 LeaveCriticalSection( &thread->process->crit_section );
529 return ret + i;
533 /**********************************************************************
534 * TlsAlloc [KERNEL32.530] Allocates a TLS index.
536 * Allocates a thread local storage index
538 * RETURNS
539 * Success: TLS Index
540 * Failure: 0xFFFFFFFF
542 DWORD WINAPI TlsAlloc(void)
544 return THREAD_TlsAlloc(THREAD_Current());
548 /**********************************************************************
549 * TlsFree [KERNEL32.531] Releases a TLS index.
551 * Releases a thread local storage index, making it available for reuse
553 * RETURNS
554 * Success: TRUE
555 * Failure: FALSE
557 BOOL32 WINAPI TlsFree(
558 DWORD index) /* [in] TLS Index to free */
560 DWORD mask;
561 THDB *thread = THREAD_Current();
562 DWORD *bits = thread->process->tls_bits;
563 if (index >= 64)
565 SetLastError( ERROR_INVALID_PARAMETER );
566 return FALSE;
568 EnterCriticalSection( &thread->process->crit_section );
569 if (index >= 32) bits++;
570 mask = (1 << (index & 31));
571 if (!(*bits & mask)) /* already free? */
573 LeaveCriticalSection( &thread->process->crit_section );
574 SetLastError( ERROR_INVALID_PARAMETER );
575 return FALSE;
577 *bits &= ~mask;
578 thread->tls_array[index] = 0;
579 /* FIXME: should zero all other thread values */
580 LeaveCriticalSection( &thread->process->crit_section );
581 return TRUE;
585 /**********************************************************************
586 * TlsGetValue [KERNEL32.532] Gets value in a thread's TLS slot
588 * RETURNS
589 * Success: Value stored in calling thread's TLS slot for index
590 * Failure: 0 and GetLastError returns NO_ERROR
592 LPVOID WINAPI TlsGetValue(
593 DWORD index) /* [in] TLS index to retrieve value for */
595 THDB *thread = THREAD_Current();
596 if (index >= 64)
598 SetLastError( ERROR_INVALID_PARAMETER );
599 return NULL;
601 SetLastError( ERROR_SUCCESS );
602 return thread->tls_array[index];
606 /**********************************************************************
607 * TlsSetValue [KERNEL32.533] Stores a value in the thread's TLS slot.
609 * RETURNS
610 * Success: TRUE
611 * Failure: FALSE
613 BOOL32 WINAPI TlsSetValue(
614 DWORD index, /* [in] TLS index to set value for */
615 LPVOID value) /* [in] Value to be stored */
617 THDB *thread = THREAD_Current();
618 if (index >= 64)
620 SetLastError( ERROR_INVALID_PARAMETER );
621 return FALSE;
623 thread->tls_array[index] = value;
624 return TRUE;
628 /***********************************************************************
629 * SetThreadContext [KERNEL32.670] Sets context of thread.
631 * RETURNS
632 * Success: TRUE
633 * Failure: FALSE
635 BOOL32 WINAPI SetThreadContext(
636 HANDLE32 handle, /* [in] Handle to thread with context */
637 CONTEXT *context) /* [out] Address of context structure */
639 THDB *thread = THREAD_GetPtr( handle, THREAD_GET_CONTEXT, NULL );
640 if (!thread) return FALSE;
641 *context = thread->context;
642 K32OBJ_DecCount( &thread->header );
643 return TRUE;
646 /***********************************************************************
647 * GetThreadContext [KERNEL32.294] Retrieves context of thread.
649 * RETURNS
650 * Success: TRUE
651 * Failure: FALSE
653 BOOL32 WINAPI GetThreadContext(
654 HANDLE32 handle, /* [in] Handle to thread with context */
655 CONTEXT *context) /* [out] Address of context structure */
657 THDB *thread = THREAD_GetPtr( handle, THREAD_GET_CONTEXT, NULL );
658 if (!thread) return FALSE;
659 *context = thread->context;
660 K32OBJ_DecCount( &thread->header );
661 return TRUE;
665 /**********************************************************************
666 * GetThreadPriority [KERNEL32.296] Returns priority for thread.
668 * RETURNS
669 * Success: Thread's priority level.
670 * Failure: THREAD_PRIORITY_ERROR_RETURN
672 INT32 WINAPI GetThreadPriority(
673 HANDLE32 hthread) /* [in] Handle to thread */
675 THDB *thread;
676 INT32 ret;
678 if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION, NULL )))
679 return THREAD_PRIORITY_ERROR_RETURN;
680 ret = thread->delta_priority;
681 K32OBJ_DecCount( &thread->header );
682 return ret;
686 /**********************************************************************
687 * SetThreadPriority [KERNEL32.514] Sets priority for thread.
689 * RETURNS
690 * Success: TRUE
691 * Failure: FALSE
693 BOOL32 WINAPI SetThreadPriority(
694 HANDLE32 hthread, /* [in] Handle to thread */
695 INT32 priority) /* [in] Thread priority level */
697 THDB *thread;
699 if (!(thread = THREAD_GetPtr( hthread, THREAD_SET_INFORMATION, NULL )))
700 return FALSE;
701 thread->delta_priority = priority;
702 K32OBJ_DecCount( &thread->header );
703 return TRUE;
707 /**********************************************************************
708 * TerminateThread [KERNEL32.685] Terminates a thread
710 * RETURNS
711 * Success: TRUE
712 * Failure: FALSE
714 BOOL32 WINAPI TerminateThread(
715 HANDLE32 handle, /* [in] Handle to thread */
716 DWORD exitcode) /* [in] Exit code for thread */
718 int server_handle;
719 BOOL32 ret;
720 THDB *thread;
722 if (!(thread = THREAD_GetPtr( handle, THREAD_TERMINATE, &server_handle )))
723 return FALSE;
724 ret = !CLIENT_TerminateThread( server_handle, exitcode );
725 K32OBJ_DecCount( &thread->header );
726 return ret;
730 /**********************************************************************
731 * GetExitCodeThread [KERNEL32.???] Gets termination status of thread.
733 * RETURNS
734 * Success: TRUE
735 * Failure: FALSE
737 BOOL32 WINAPI GetExitCodeThread(
738 HANDLE32 hthread, /* [in] Handle to thread */
739 LPDWORD exitcode) /* [out] Address to receive termination status */
741 THDB *thread;
742 int server_handle;
744 if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION, &server_handle )))
745 return FALSE;
746 if (server_handle != -1)
748 struct get_thread_info_reply info;
749 CLIENT_GetThreadInfo( server_handle, &info );
750 if (exitcode) *exitcode = info.exit_code;
752 else if (exitcode) *exitcode = thread->exit_code;
753 K32OBJ_DecCount( &thread->header );
754 return TRUE;
758 /**********************************************************************
759 * ResumeThread [KERNEL32.587] Resumes a thread.
761 * Decrements a thread's suspend count. When count is zero, the
762 * execution of the thread is resumed.
764 * RETURNS
765 * Success: Previous suspend count
766 * Failure: 0xFFFFFFFF
767 * Already running: 0
769 DWORD WINAPI ResumeThread(
770 HANDLE32 hthread) /* [in] Indentifies thread to restart */
772 THDB *thread;
773 DWORD oldcount;
775 SYSTEM_LOCK();
776 if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION, NULL )))
778 SYSTEM_UNLOCK();
779 WARN(thread, "Invalid thread handle\n");
780 return 0xFFFFFFFF;
782 if ((oldcount = thread->suspend_count) != 0)
784 if (!--thread->suspend_count)
786 if (kill(thread->unix_pid, SIGCONT))
788 WARN(thread, "Unable to CONTinue pid: %04x\n",
789 thread->unix_pid);
790 oldcount = 0xFFFFFFFF;
794 K32OBJ_DecCount(&thread->header);
795 SYSTEM_UNLOCK();
796 return oldcount;
800 /**********************************************************************
801 * SuspendThread [KERNEL32.681] Suspends a thread.
803 * RETURNS
804 * Success: Previous suspend count
805 * Failure: 0xFFFFFFFF
807 DWORD WINAPI SuspendThread(
808 HANDLE32 hthread) /* [in] Handle to the thread */
810 THDB *thread;
811 DWORD oldcount;
813 SYSTEM_LOCK();
814 if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION, NULL )))
816 SYSTEM_UNLOCK();
817 WARN(thread, "Invalid thread handle\n");
818 return 0xFFFFFFFF;
821 if (!(oldcount = thread->suspend_count))
823 if (thread->unix_pid == getpid())
824 WARN(thread, "Attempting to suspend myself\n" );
825 else
827 if (kill(thread->unix_pid, SIGSTOP))
829 WARN(thread, "Unable to STOP pid: %04x\n",
830 thread->unix_pid);
831 oldcount = 0xFFFFFFFF;
833 else thread->suspend_count++;
836 else thread->suspend_count++;
837 K32OBJ_DecCount( &thread->header );
838 SYSTEM_UNLOCK();
839 return oldcount;
844 /**********************************************************************
845 * GetThreadTimes [KERNEL32.???] Obtains timing information.
847 * NOTES
848 * What are the fields where these values are stored?
850 * RETURNS
851 * Success: TRUE
852 * Failure: FALSE
854 BOOL32 WINAPI GetThreadTimes(
855 HANDLE32 thread, /* [in] Specifies the thread of interest */
856 LPFILETIME creationtime, /* [out] When the thread was created */
857 LPFILETIME exittime, /* [out] When the thread was destroyed */
858 LPFILETIME kerneltime, /* [out] Time thread spent in kernel mode */
859 LPFILETIME usertime) /* [out] Time thread spent in user mode */
861 FIXME(thread,"(0x%08x): stub\n",thread);
862 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
863 return FALSE;
867 /**********************************************************************
868 * AttachThreadInput [KERNEL32.8] Attaches input of 1 thread to other
870 * Attaches the input processing mechanism of one thread to that of
871 * another thread.
873 * RETURNS
874 * Success: TRUE
875 * Failure: FALSE
877 BOOL32 WINAPI AttachThreadInput(
878 DWORD idAttach, /* [in] Thread to attach */
879 DWORD idAttachTo, /* [in] Thread to attach to */
880 BOOL32 fAttach) /* [in] Attach or detach */
882 BOOL32 ret;
884 FIXME(thread, "(0x%08lx,0x%08lx,%d): stub\n",idAttach,idAttachTo,fAttach);
885 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
886 if (fAttach) {
887 /* Attach threads */
888 ret = FALSE;
890 else {
891 /* Detach threads */
892 ret = FALSE;
894 return ret;