VirtualBox

source: vbox/trunk/src/VBox/Runtime/thread.cpp@ 1507

Last change on this file since 1507 was 1190, checked in by vboxsync, 18 years ago

Ported IPRT to ring-0 OS/2.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 39.7 KB
Line 
1/* $Id: thread.cpp 1190 2007-03-04 20:42:13Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - Threads, common routines.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP RTLOGGROUP_THREAD
28#include <iprt/thread.h>
29#include <iprt/log.h>
30#include <iprt/avl.h>
31#include <iprt/alloc.h>
32#include <iprt/assert.h>
33#include <iprt/semaphore.h>
34#ifdef IN_RING0
35# include <iprt/spinlock.h>
36#endif
37#include <iprt/asm.h>
38#include <iprt/err.h>
39#include <iprt/string.h>
40#include "internal/thread.h"
41#include "internal/sched.h"
42#include "internal/process.h"
43
44
45/*******************************************************************************
46* Defined Constants And Macros *
47*******************************************************************************/
48#ifdef IN_RING0
49# define RT_THREAD_LOCK_TMP(Tmp) RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER
50# define RT_THREAD_LOCK_RW(Tmp) RTSpinlockAcquireNoInts(g_ThreadSpinlock, &(Tmp))
51# define RT_THREAD_UNLOCK_RW(Tmp) RTSpinlockReleaseNoInts(g_ThreadSpinlock, &(Tmp))
52# define RT_THREAD_LOCK_RD(Tmp) RTSpinlockAcquireNoInts(g_ThreadSpinlock, &(Tmp))
53# define RT_THREAD_UNLOCK_RD(Tmp) RTSpinlockReleaseNoInts(g_ThreadSpinlock, &(Tmp))
54#else
55# define RT_THREAD_LOCK_TMP(Tmp)
56# define RT_THREAD_LOCK_RW(Tmp) rtThreadLockRW()
57# define RT_THREAD_UNLOCK_RW(Tmp) rtThreadUnLockRW()
58# define RT_THREAD_LOCK_RD(Tmp) rtThreadLockRD()
59# define RT_THREAD_UNLOCK_RD(Tmp) rtThreadUnLockRD()
60#endif
61
62
63/*******************************************************************************
64* Global Variables *
65*******************************************************************************/
66/** The AVL thread containing the threads. */
67static PAVLPVNODECORE g_ThreadTree;
68#ifdef IN_RING3
69/** The RW lock protecting the tree. */
70static RTSEMRW g_ThreadRWSem = NIL_RTSEMRW;
71#else
72/** The spinlocks protecting the tree. */
73static RTSPINLOCK g_ThreadSpinlock = NIL_RTSPINLOCK;
74#endif
75
76
77/*******************************************************************************
78* Internal Functions *
79*******************************************************************************/
80static void rtThreadDestroy(PRTTHREADINT pThread);
81static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName);
82static void rtThreadRemoveLocked(PRTTHREADINT pThread);
83static PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, unsigned fIntFlags, const char *pszName);
84
85
86/** @page pg_rt_thread IPRT Thread Internals
87 *
88 * IPRT provides interface to whatever native threading that the host provides,
89 * preferably using a CRT level interface to better integrate with other libraries.
90 *
91 * Internally IPRT keeps track of threads by means of the RTTHREADINT structure.
92 * All the RTTHREADINT structures are kept in a AVL tree which is protected by a
93 * read/write lock for efficient access. A thread is inserted into the tree in
94 * three places in the code. The main thread is 'adopted' by IPRT on RTR3Init()
95 * by rtThreadAdopt(). When creating a new thread there the child and the parent
96 * race inserting the thread, this is rtThreadMain() and RTThreadCreate.
97 *
98 * RTTHREADINT objects are using reference counting as a mean of sticking around
99 * till no-one needs them any longer. Waitable threads is created with one extra
100 * reference so they won't go away until they are waited on. This introduces a
101 * major problem if we use the host thread identifier as key in the AVL tree - the
102 * host may reuse the thread identifier before the thread was waited on. So, on
103 * most platforms we are using the RTTHREADINT pointer as key and not the
104 * thread id. RTThreadSelf() then have to be implemented using a pointer stored
105 * in thread local storage (TLS).
106 *
107 * In Ring-0 we only try keep track of kernel threads created by RTCreateThread
108 * at the moment. There we really only need the 'join' feature, but doing things
109 * the same way allow us to name threads and similar stuff.
110 */
111
112
113/**
114 * Initializes the thread database.
115 *
116 * @returns iprt status code.
117 */
118int rtThreadInit(void)
119{
120#ifdef IN_RING3
121 int rc = VINF_ALREADY_INITIALIZED;
122 if (g_ThreadRWSem == NIL_RTSEMRW)
123 {
124 /*
125 * We assume the caller is the 1st thread, which we'll call 'main'.
126 * But first, we'll create the semaphore.
127 */
128 int rc = RTSemRWCreate(&g_ThreadRWSem);
129 if (RT_SUCCESS(rc))
130 {
131 rc = rtThreadNativeInit();
132#ifdef IN_RING3
133 if (RT_SUCCESS(rc))
134 rc = rtThreadAdopt(RTTHREADTYPE_DEFAULT, 0, "main");
135 if (RT_SUCCESS(rc))
136 rc = rtSchedNativeCalcDefaultPriority(RTTHREADTYPE_DEFAULT);
137#endif
138 if (RT_SUCCESS(rc))
139 return VINF_SUCCESS;
140
141 /* failed, clear out */
142 RTSemRWDestroy(g_ThreadRWSem);
143 g_ThreadRWSem = NIL_RTSEMRW;
144 }
145 }
146
147#elif defined(IN_RING0)
148
149 /*
150 * Create the spinlock and to native init.
151 */
152 Assert(g_ThreadSpinlock == NIL_RTSPINLOCK);
153 int rc = RTSpinlockCreate(&g_ThreadSpinlock);
154 if (RT_SUCCESS(rc))
155 {
156 rc = rtThreadNativeInit();
157 if (RT_SUCCESS(rc))
158 return VINF_SUCCESS;
159
160 /* failed, clear out */
161 RTSpinlockDestroy(g_ThreadSpinlock);
162 g_ThreadSpinlock = NIL_RTSPINLOCK;
163 }
164#else
165# error "!IN_RING0 && !IN_RING3"
166#endif
167 return rc;
168}
169
170
171/**
172 * Terminates the thread database.
173 */
174void rtThreadTerm(void)
175{
176#ifdef IN_RING3
177 /* we don't cleanup here yet */
178
179#elif defined(IN_RING0)
180 /* just destroy the spinlock and assume the thread is fine... */
181 RTSpinlockDestroy(g_ThreadSpinlock);
182 g_ThreadSpinlock = NIL_RTSPINLOCK;
183 if (g_ThreadTree != NULL)
184 AssertMsg2("WARNING: g_ThreadTree=%p\n", g_ThreadTree);
185#endif
186}
187
188
189
190#ifdef IN_RING3
191
192inline void rtThreadLockRW(void)
193{
194 if (g_ThreadRWSem == NIL_RTSEMRW)
195 rtThreadInit();
196 int rc = RTSemRWRequestWrite(g_ThreadRWSem, RT_INDEFINITE_WAIT);
197 AssertReleaseRC(rc);
198}
199
200
201inline void rtThreadLockRD(void)
202{
203 if (g_ThreadRWSem == NIL_RTSEMRW)
204 rtThreadInit();
205 int rc = RTSemRWRequestRead(g_ThreadRWSem, RT_INDEFINITE_WAIT);
206 AssertReleaseRC(rc);
207}
208
209
210inline void rtThreadUnLockRW(void)
211{
212 int rc = RTSemRWReleaseWrite(g_ThreadRWSem);
213 AssertReleaseRC(rc);
214}
215
216
217inline void rtThreadUnLockRD(void)
218{
219 int rc = RTSemRWReleaseRead(g_ThreadRWSem);
220 AssertReleaseRC(rc);
221}
222
223#endif /* IN_RING3 */
224
225
226/**
227 * Adopts the calling thread.
228 * No locks are taken or released by this function.
229 */
230static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
231{
232 Assert(!(fFlags & RTTHREADFLAGS_WAITABLE));
233 fFlags &= ~RTTHREADFLAGS_WAITABLE;
234
235 /*
236 * Allocate and insert the thread.
237 */
238 int rc = VERR_NO_MEMORY;
239 PRTTHREADINT pThread = rtThreadAlloc(enmType, fFlags, RTTHREADINT_FLAGS_ALIEN, pszName);
240 if (pThread)
241 {
242 RTNATIVETHREAD NativeThread = RTThreadNativeSelf();
243 rc = rtThreadNativeAdopt(pThread);
244 if (RT_SUCCESS(rc))
245 {
246 rtThreadInsert(pThread, NativeThread);
247 pThread->enmState = RTTHREADSTATE_RUNNING;
248 }
249 }
250 return rc;
251}
252
253
254/**
255 * Adopts a non-IPRT thread.
256 *
257 * @returns IPRT status code.
258 * @param enmType The thread type.
259 * @param fFlags The thread flags. RTTHREADFLAGS_WAITABLE is not currently allowed.
260 * @param pszName The thread name. Optional.
261 * @param pThread Where to store the thread handle. Optional.
262 */
263RTDECL(int) RTThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName, PRTTHREAD pThread)
264{
265 AssertReturn(!(fFlags & RTTHREADFLAGS_WAITABLE), VERR_INVALID_PARAMETER);
266 AssertReturn(!pszName || VALID_PTR(pszName), VERR_INVALID_POINTER);
267 AssertReturn(!pThread || VALID_PTR(pThread), VERR_INVALID_POINTER);
268
269 int rc = VINF_SUCCESS;
270 RTTHREAD Thread = RTThreadSelf();
271 if (Thread == NIL_RTTHREAD)
272 {
273 /* generate a name if none was given. */
274 char szName[RTTHREAD_NAME_LEN];
275 if (!pszName || !*pszName)
276 {
277 static uint32_t s_i32AlienId = 0;
278 uint32_t i32Id = ASMAtomicIncU32(&s_i32AlienId);
279 RTStrPrintf(szName, sizeof(szName), "ALIEN-%RX32", i32Id);
280 pszName = szName;
281 }
282
283 /* try adopt it */
284 rc = rtThreadAdopt(enmType, fFlags, pszName);
285 Thread = RTThreadSelf();
286 Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x rc=%Rrc\n",
287 Thread, RTThreadNativeSelf(), pszName, enmType, fFlags, rc));
288 }
289 else
290 Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x - already adopted!\n",
291 Thread, RTThreadNativeSelf(), pszName, enmType, fFlags));
292
293 if (pThread)
294 *pThread = Thread;
295 return rc;
296}
297
298
299/**
300 * Allocates a per thread data structure and initializes the basic fields.
301 *
302 * @returns Pointer to per thread data structure.
303 * This is reference once.
304 * @returns NULL on failure.
305 * @param enmType The thread type.
306 * @param fFlags The thread flags.
307 * @param fIntFlags The internal thread flags.
308 * @param pszName Pointer to the thread name.
309 */
310PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, unsigned fIntFlags, const char *pszName)
311{
312 PRTTHREADINT pThread = (PRTTHREADINT)RTMemAllocZ(sizeof(RTTHREADINT));
313 if (pThread)
314 {
315 pThread->Core.Key = (void*)NIL_RTTHREAD;
316 pThread->u32Magic = RTTHREADINT_MAGIC;
317 size_t cchName = strlen(pszName);
318 if (cchName >= RTTHREAD_NAME_LEN)
319 cchName = RTTHREAD_NAME_LEN - 1;
320 memcpy(pThread->szName, pszName, cchName);
321 pThread->szName[cchName] = '\0';
322 pThread->cRefs = 2 + !!(fFlags & RTTHREADFLAGS_WAITABLE); /* And extra reference if waitable. */
323 pThread->rc = VERR_PROCESS_RUNNING; /** @todo get a better error code! */
324 pThread->enmType = enmType;
325 pThread->fFlags = fFlags;
326 pThread->fIntFlags = fIntFlags;
327 pThread->enmState = RTTHREADSTATE_INITIALIZING;
328 int rc = RTSemEventMultiCreate(&pThread->EventUser);
329 if (RT_SUCCESS(rc))
330 {
331 rc = RTSemEventMultiCreate(&pThread->EventTerminated);
332 if (RT_SUCCESS(rc))
333 return pThread;
334 RTSemEventMultiDestroy(pThread->EventUser);
335 }
336 RTMemFree(pThread);
337 }
338 return NULL;
339}
340
341
342/**
343 * Insert the per thread data structure into the tree.
344 *
345 * This can be called from both the thread it self and the parent,
346 * thus it must handle insertion failures in a nice manner.
347 *
348 * @param pThread Pointer to thread structure allocated by rtThreadAlloc().
349 * @param NativeThread The native thread id.
350 */
351void rtThreadInsert(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread)
352{
353 Assert(pThread);
354 Assert(pThread->u32Magic == RTTHREADINT_MAGIC);
355
356 RT_THREAD_LOCK_TMP(Tmp);
357 RT_THREAD_LOCK_RW(Tmp);
358
359 /*
360 * Before inserting we must check if there is a thread with this id
361 * in the tree already. We're racing parent and child on insert here
362 * so that the handle is valid in both ends when they return / start.
363 *
364 * If it's not ourself we find, it's a dead alien thread and we will
365 * unlink it from the tree. Alien threads will be released at this point.
366 */
367 PRTTHREADINT pThreadOther = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
368 if (pThreadOther != pThread)
369 {
370 /* remove dead alien if any */
371 if (pThreadOther)
372 {
373 Assert(pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN);
374 ASMAtomicBitClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT);
375 rtThreadRemoveLocked(pThreadOther);
376 if (pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
377 rtThreadRelease(pThreadOther);
378 }
379
380 /* insert the thread */
381 pThread->Core.Key = (void *)NativeThread;
382 bool fRc = RTAvlPVInsert(&g_ThreadTree, &pThread->Core);
383 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE);
384
385 AssertReleaseMsg(fRc, ("Lock problem? %p (%RTnthrd) %s\n", pThread, NativeThread, pThread->szName));
386 NOREF(fRc);
387 }
388
389 RT_THREAD_UNLOCK_RW(Tmp);
390}
391
392
393/**
394 * Removes the thread from the AVL tree, call owns the tree lock
395 * and has cleared the RTTHREADINT_FLAG_IN_TREE bit.
396 *
397 * @param pThread The thread to remove.
398 */
399static void rtThreadRemoveLocked(PRTTHREADINT pThread)
400{
401 PRTTHREADINT pThread2 = (PRTTHREADINT)RTAvlPVRemove(&g_ThreadTree, pThread->Core.Key);
402 AssertMsg(pThread2 == pThread, ("%p(%s) != %p (%p/%s)\n", pThread2, pThread2 ? pThread2->szName : "<null>",
403 pThread, pThread->Core.Key, pThread->szName));
404 NOREF(pThread2);
405}
406
407
408/**
409 * Removes the thread from the AVL tree.
410 *
411 * @param pThread The thread to remove.
412 */
413static void rtThreadRemove(PRTTHREADINT pThread)
414{
415 RT_THREAD_LOCK_TMP(Tmp);
416 RT_THREAD_LOCK_RW(Tmp);
417 if (ASMAtomicBitTestAndClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
418 rtThreadRemoveLocked(pThread);
419 RT_THREAD_UNLOCK_RW(Tmp);
420}
421
422
423/**
424 * Checks if a thread is alive or not.
425 *
426 * @returns true if the thread is alive (or we don't really know).
427 * @returns false if the thread has surely terminate.
428 */
429DECLINLINE(bool) rtThreadIsAlive(PRTTHREADINT pThread)
430{
431 return !(pThread->fIntFlags & RTTHREADINT_FLAGS_TERMINATED);
432}
433
434
435/**
436 * Gets a thread by it's native ID.
437 *
438 * @returns pointer to the thread structure.
439 * @returns NULL if not a thread IPRT knows.
440 * @param NativeThread The native thread id.
441 */
442PRTTHREADINT rtThreadGetByNative(RTNATIVETHREAD NativeThread)
443{
444 /*
445 * Simple tree lookup.
446 */
447 RT_THREAD_LOCK_TMP(Tmp);
448 RT_THREAD_LOCK_RD(Tmp);
449 PRTTHREADINT pThread = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
450 RT_THREAD_UNLOCK_RD(Tmp);
451 return pThread;
452}
453
454
455/**
456 * Gets the per thread data structure for a thread handle.
457 *
458 * @returns Pointer to the per thread data structure for Thread.
459 * The caller must release the thread using rtThreadRelease().
460 * @returns NULL if Thread was not found.
461 * @param Thread Thread id which structure is to be returned.
462 */
463PRTTHREADINT rtThreadGet(RTTHREAD Thread)
464{
465 if ( Thread != NIL_RTTHREAD
466 && VALID_PTR(Thread))
467 {
468 PRTTHREADINT pThread = (PRTTHREADINT)Thread;
469 if ( pThread->u32Magic == RTTHREADINT_MAGIC
470 && pThread->cRefs > 0)
471 {
472 ASMAtomicIncU32(&pThread->cRefs);
473 return pThread;
474 }
475 }
476
477 AssertMsgFailed(("Thread=%RTthrd\n", Thread));
478 return NULL;
479}
480
481
482/**
483 * Release a per thread data structure.
484 *
485 * @returns New reference count.
486 * @param pThread The thread structure to release.
487 */
488uint32_t rtThreadRelease(PRTTHREADINT pThread)
489{
490 Assert(pThread);
491 uint32_t cRefs;
492 if (pThread->cRefs >= 1)
493 {
494 cRefs = ASMAtomicDecU32(&pThread->cRefs);
495 if (!cRefs)
496 rtThreadDestroy(pThread);
497 }
498 else
499 cRefs = 0;
500 return cRefs;
501}
502
503
504/**
505 * Destroys the per thread data.
506 *
507 * @param pThread The thread to destroy.
508 */
509static void rtThreadDestroy(PRTTHREADINT pThread)
510{
511 /*
512 * Mark it dead and remove it from the tree.
513 */
514 ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD);
515 rtThreadRemove(pThread);
516
517 /*
518 * Free resources.
519 */
520 pThread->Core.Key = (void *)NIL_RTTHREAD;
521 pThread->enmType = RTTHREADTYPE_INVALID;
522 RTSemEventMultiDestroy(pThread->EventUser);
523 pThread->EventUser = NIL_RTSEMEVENTMULTI;
524 if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
525 {
526 RTSemEventMultiDestroy(pThread->EventTerminated);
527 pThread->EventTerminated = NIL_RTSEMEVENTMULTI;
528 }
529 RTMemFree(pThread);
530}
531
532
533/**
534 * Terminates the thread.
535 * Called by the thread wrapper function when the thread terminates.
536 *
537 * @param pThread The thread structure.
538 * @param rc The thread result code.
539 */
540void rtThreadTerminate(PRTTHREADINT pThread, int rc)
541{
542 Assert(pThread->cRefs >= 1);
543
544 /*
545 * Set the rc, mark it terminated and signal anyone waiting.
546 */
547 pThread->rc = rc;
548 ASMAtomicXchgSize(&pThread->enmState, RTTHREADSTATE_TERMINATED);
549 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAGS_TERMINATED);
550 if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
551 RTSemEventMultiSignal(pThread->EventTerminated);
552
553 /*
554 * Remove the thread from the tree so that there will be no
555 * key clashes in the AVL tree and release our reference to ourself.
556 */
557 rtThreadRemove(pThread);
558 rtThreadRelease(pThread);
559}
560
561
562/**
563 * The common thread main function.
564 * This is called by rtThreadNativeMain().
565 *
566 * @returns The status code of the thread.
567 * pThread is dereference by the thread before returning!
568 * @param pThread The thread structure.
569 * @param NativeThread The native thread id.
570 */
571int rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread)
572{
573 rtThreadInsert(pThread, NativeThread);
574 Log(("rtThreadMain: Starting: pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
575 pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
576
577 /*
578 * Change the priority.
579 */
580 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
581#ifdef IN_RING3
582 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d enmPriority=%d rc=%Vrc\n",
583 pThread, NativeThread, pThread->szName, pThread->enmType, g_enmProcessPriority, rc));
584#else
585 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d rc=%Vrc\n",
586 pThread, NativeThread, pThread->szName, pThread->enmType, rc));
587#endif
588
589 /*
590 * Call thread function and terminate when it returns.
591 */
592 pThread->enmState = RTTHREADSTATE_RUNNING;
593 rc = pThread->pfnThread(pThread, pThread->pvUser);
594
595 Log(("rtThreadMain: Terminating: rc=%d pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
596 rc, pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
597 rtThreadTerminate(pThread, rc);
598 return rc;
599}
600
601
602/**
603 * Create a new thread.
604 *
605 * @returns iprt status code.
606 * @param pThread Where to store the thread handle to the new thread. (optional)
607 * @param pfnThread The thread function.
608 * @param pvUser User argument.
609 * @param cbStack The size of the stack for the new thread.
610 * Use 0 for the default stack size.
611 * @param enmType The thread type. Used for deciding scheduling attributes
612 * of the thread.
613 * @param fFlags Flags of the RTTHREADFLAGS type (ORed together).
614 * @param pszName Thread name.
615 */
616RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
617 RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
618{
619 LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n",
620 pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName));
621
622 /*
623 * Validate input.
624 */
625 if (!VALID_PTR(pThread) && pThread)
626 {
627 Assert(VALID_PTR(pThread));
628 return VERR_INVALID_PARAMETER;
629 }
630 if (!VALID_PTR(pfnThread))
631 {
632 Assert(VALID_PTR(pfnThread));
633 return VERR_INVALID_PARAMETER;
634 }
635 if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN)
636 {
637 AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1));
638 return VERR_INVALID_PARAMETER;
639 }
640 if (fFlags & ~RTTHREADFLAGS_MASK)
641 {
642 AssertMsgFailed(("fFlags=%#x\n", fFlags));
643 return VERR_INVALID_PARAMETER;
644 }
645
646 /*
647 * Allocate thread argument.
648 */
649 int rc;
650 PRTTHREADINT pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
651 if (pThreadInt)
652 {
653 pThreadInt->pfnThread = pfnThread;
654 pThreadInt->pvUser = pvUser;
655 pThreadInt->cbStack = cbStack;
656
657 RTNATIVETHREAD NativeThread;
658 rc = rtThreadNativeCreate(pThreadInt, &NativeThread);
659 if (RT_SUCCESS(rc))
660 {
661 rtThreadInsert(pThreadInt, NativeThread);
662 rtThreadRelease(pThreadInt);
663 Log(("RTThreadCreate: Created thread %p (%p) %s\n", pThreadInt, NativeThread, pszName));
664 if (pThread)
665 *pThread = pThreadInt;
666 return VINF_SUCCESS;
667 }
668
669 pThreadInt->cRefs = 1;
670 rtThreadRelease(pThreadInt);
671 }
672 else
673 rc = VERR_NO_TMP_MEMORY;
674 LogFlow(("RTThreadCreate: Failed to create thread, rc=%Vrc\n", rc));
675 AssertReleaseRC(rc);
676 return rc;
677}
678
679
680/**
681 * Gets the native thread id of a IPRT thread.
682 *
683 * @returns The native thread id.
684 * @param Thread The IPRT thread.
685 */
686RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread)
687{
688 PRTTHREADINT pThread = rtThreadGet(Thread);
689 if (pThread)
690 return (RTNATIVETHREAD)pThread->Core.Key;
691 return NIL_RTNATIVETHREAD;
692}
693
694
695/**
696 * Gets the IPRT thread of a native thread.
697 *
698 * @returns The IPRT thread handle
699 * @returns NIL_RTTHREAD if not a thread known to IPRT.
700 * @param NativeThread The native thread handle/id.
701 */
702RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread)
703{
704 PRTTHREADINT pThread = rtThreadGetByNative(NativeThread);
705 if (pThread)
706 {
707 rtThreadRelease(pThread);
708 return pThread;
709 }
710 return NIL_RTTHREAD;
711}
712
713
714/**
715 * Gets the name of the current thread thread.
716 *
717 * @returns Pointer to readonly name string.
718 * @returns NULL on failure.
719 */
720RTDECL(const char *) RTThreadSelfName(void)
721{
722 RTTHREAD Thread = RTThreadSelf();
723 if (Thread != NIL_RTTHREAD)
724 {
725 PRTTHREADINT pThread = rtThreadGet(Thread);
726 if (pThread)
727 return pThread->szName;
728 }
729 return NULL;
730}
731
732
733/**
734 * Gets the name of a thread.
735 *
736 * @returns Pointer to readonly name string.
737 * @returns NULL on failure.
738 * @param Thread Thread handle of the thread to query the name of.
739 */
740RTDECL(const char *) RTThreadGetName(RTTHREAD Thread)
741{
742 if (Thread == NIL_RTTHREAD)
743 return NULL;
744 PRTTHREADINT pThread = rtThreadGet(Thread);
745 return pThread ? pThread->szName : NULL;
746}
747
748
749/**
750 * Sets the name of a thread.
751 *
752 * @returns iprt status code.
753 * @param Thread Thread handle of the thread to query the name of.
754 * @param pszName The thread name.
755 */
756RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName)
757{
758 /*
759 * Validate input.
760 */
761 size_t cchName = strlen(pszName);
762 if (cchName >= RTTHREAD_NAME_LEN)
763 {
764 AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName, RTTHREAD_NAME_LEN - 1));
765 return VERR_INVALID_PARAMETER;
766 }
767 PRTTHREADINT pThread = rtThreadGet(Thread);
768 if (!pThread)
769 return VERR_INVALID_HANDLE;
770
771 /*
772 * Update the name.
773 */
774 pThread->szName[cchName] = '\0'; /* paranoia */
775 memcpy(pThread->szName, pszName, cchName);
776 return VINF_SUCCESS;
777}
778
779
780/**
781 * Signal the user event.
782 *
783 * @returns iprt status code.
784 */
785RTDECL(int) RTThreadUserSignal(RTTHREAD Thread)
786{
787 int rc;
788 PRTTHREADINT pThread = rtThreadGet(Thread);
789 if (pThread)
790 {
791 rc = RTSemEventMultiSignal(pThread->EventUser);
792 rtThreadRelease(pThread);
793 }
794 else
795 rc = VERR_INVALID_HANDLE;
796 return rc;
797}
798
799
800/**
801 * Wait for the user event, resume on interruption.
802 *
803 * @returns iprt status code.
804 * @param Thread The thread to wait for.
805 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
806 * an indefinite wait.
807 */
808RTDECL(int) RTThreadUserWait(RTTHREAD Thread, unsigned cMillies)
809{
810 int rc;
811 PRTTHREADINT pThread = rtThreadGet(Thread);
812 if (pThread)
813 {
814 rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
815 rtThreadRelease(pThread);
816 }
817 else
818 rc = VERR_INVALID_HANDLE;
819 return rc;
820}
821
822
823/**
824 * Wait for the user event, return on interruption.
825 *
826 * @returns iprt status code.
827 * @param Thread The thread to wait for.
828 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
829 * an indefinite wait.
830 */
831RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, unsigned cMillies)
832{
833 int rc;
834 PRTTHREADINT pThread = rtThreadGet(Thread);
835 if (pThread)
836 {
837 rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
838 rtThreadRelease(pThread);
839 }
840 else
841 rc = VERR_INVALID_HANDLE;
842 return rc;
843}
844
845
846/**
847 * Reset the user event.
848 *
849 * @returns iprt status code.
850 * @param Thread The thread to reset.
851 */
852RTDECL(int) RTThreadUserReset(RTTHREAD Thread)
853{
854 int rc;
855 PRTTHREADINT pThread = rtThreadGet(Thread);
856 if (pThread)
857 {
858 rc = RTSemEventMultiReset(pThread->EventUser);
859 rtThreadRelease(pThread);
860 }
861 else
862 rc = VERR_INVALID_HANDLE;
863 return rc;
864}
865
866
867/**
868 * Wait for the thread to terminate.
869 *
870 * @returns iprt status code.
871 * @param Thread The thread to wait for.
872 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
873 * an indefinite wait.
874 * @param prc Where to store the return code of the thread. Optional.
875 * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED.
876 */
877static int rtThreadWait(RTTHREAD Thread, unsigned cMillies, int *prc, bool fAutoResume)
878{
879 int rc = VERR_INVALID_HANDLE;
880 if (Thread != NIL_RTTHREAD)
881 {
882 PRTTHREADINT pThread = rtThreadGet(Thread);
883 if (pThread)
884 {
885 if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
886 {
887 if (fAutoResume)
888 rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
889 else
890 rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
891 if (RT_SUCCESS(rc))
892 {
893 if (prc)
894 *prc = pThread->rc;
895
896 /*
897 * If the thread is marked as waitable, we'll do one additional
898 * release in order to free up the thread structure (see how we
899 * init cRef in rtThreadAlloc()).
900 */
901 if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
902 rtThreadRelease(pThread);
903 }
904 }
905 else
906 {
907 rc = VERR_THREAD_NOT_WAITABLE;
908 AssertRC(rc);
909 }
910 rtThreadRelease(pThread);
911 }
912 }
913 return rc;
914}
915
916
917/**
918 * Wait for the thread to terminate, resume on interruption.
919 *
920 * @returns iprt status code.
921 * Will not return VERR_INTERRUPTED.
922 * @param Thread The thread to wait for.
923 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
924 * an indefinite wait.
925 * @param prc Where to store the return code of the thread. Optional.
926 */
927RTDECL(int) RTThreadWait(RTTHREAD Thread, unsigned cMillies, int *prc)
928{
929 int rc = rtThreadWait(Thread, cMillies, prc, true);
930 Assert(rc != VERR_INTERRUPTED);
931 return rc;
932}
933
934
935/**
936 * Wait for the thread to terminate, return on interruption.
937 *
938 * @returns iprt status code.
939 * @param Thread The thread to wait for.
940 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
941 * an indefinite wait.
942 * @param prc Where to store the return code of the thread. Optional.
943 */
944RTDECL(int) RTThreadWaitNoResume(RTTHREAD Thread, unsigned cMillies, int *prc)
945{
946 return rtThreadWait(Thread, cMillies, prc, false);
947}
948
949
950/**
951 * Changes the type of the specified thread.
952 *
953 * @returns iprt status code.
954 * @param Thread The thread which type should be changed.
955 * @param enmType The new thread type.
956 */
957RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType)
958{
959 /*
960 * Validate input.
961 */
962 int rc;
963 if ( enmType > RTTHREADTYPE_INVALID
964 && enmType < RTTHREADTYPE_END)
965 {
966 PRTTHREADINT pThread = rtThreadGet(Thread);
967 if (pThread)
968 {
969 if (rtThreadIsAlive(pThread))
970 {
971 /*
972 * Do the job.
973 */
974 RT_THREAD_LOCK_TMP(Tmp);
975 RT_THREAD_LOCK_RW(Tmp);
976 rc = rtThreadNativeSetPriority(pThread, enmType);
977 if (RT_SUCCESS(rc))
978 ASMAtomicXchgSize(&pThread->enmType, enmType);
979 RT_THREAD_UNLOCK_RW(Tmp);
980 if (RT_FAILURE(rc))
981 Log(("RTThreadSetType: failed on thread %p (%s), rc=%Vrc!!!\n", Thread, pThread->szName, rc));
982 }
983 else
984 rc = VERR_THREAD_IS_DEAD;
985 rtThreadRelease(pThread);
986 }
987 else
988 rc = VERR_INVALID_HANDLE;
989 }
990 else
991 {
992 AssertMsgFailed(("enmType=%d\n", enmType));
993 rc = VERR_INVALID_PARAMETER;
994 }
995 return rc;
996}
997
998
999/**
1000 * Gets the type of the specified thread.
1001 *
1002 * @returns The thread type.
1003 * @returns RTTHREADTYPE_INVALID if the thread handle is invalid.
1004 * @param Thread The thread in question.
1005 */
1006RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread)
1007{
1008 RTTHREADTYPE enmType = RTTHREADTYPE_INVALID;
1009 PRTTHREADINT pThread = rtThreadGet(Thread);
1010 if (pThread)
1011 {
1012 enmType = pThread->enmType;
1013 rtThreadRelease(pThread);
1014 }
1015 return enmType;
1016}
1017
1018
1019#ifdef IN_RING3
1020
1021/**
1022 * Recalculates scheduling attributes for the the default process
1023 * priority using the specified priority type for the calling thread.
1024 *
1025 * The scheduling attributes are targeted at threads and they are protected
1026 * by the thread read-write semaphore, that's why RTProc is forwarding the
1027 * operation to RTThread.
1028 *
1029 * @returns iprt status code.
1030 */
1031int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
1032{
1033 RT_THREAD_LOCK_TMP(Tmp);
1034 RT_THREAD_LOCK_RW(Tmp);
1035 int rc = rtSchedNativeCalcDefaultPriority(enmType);
1036 RT_THREAD_UNLOCK_RW(Tmp);
1037 return rc;
1038}
1039
1040
1041/**
1042 * Thread enumerator - sets the priority of one thread.
1043 *
1044 * @returns 0 to continue.
1045 * @returns !0 to stop. In our case a VERR_ code.
1046 * @param pNode The thread node.
1047 * @param pvUser The new priority.
1048 */
1049static DECLCALLBACK(int) rtThreadSetPriorityOne(PAVLPVNODECORE pNode, void *pvUser)
1050{
1051 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1052 if (!rtThreadIsAlive(pThread))
1053 return VINF_SUCCESS;
1054 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
1055 if (RT_SUCCESS(rc)) /* hide any warnings */
1056 return VINF_SUCCESS;
1057 return rc;
1058}
1059
1060
1061/**
1062 * Attempts to alter the priority of the current process.
1063 *
1064 * The scheduling attributes are targeted at threads and they are protected
1065 * by the thread read-write semaphore, that's why RTProc is forwarding the
1066 * operation to RTThread. This operation also involves updating all thread
1067 * which is much faster done from RTThread.
1068 *
1069 * @returns iprt status code.
1070 * @param enmPriority The new priority.
1071 */
1072int rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority)
1073{
1074 LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority));
1075
1076 /*
1077 * First validate that we're allowed by the OS to use all the
1078 * scheduling attributes defined by the specified process priority.
1079 */
1080 RT_THREAD_LOCK_TMP(Tmp);
1081 RT_THREAD_LOCK_RW(Tmp);
1082 int rc = rtProcNativeSetPriority(enmPriority);
1083 if (RT_SUCCESS(rc))
1084 {
1085 /*
1086 * Update the priority of existing thread.
1087 */
1088 rc = RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1089 if (RT_SUCCESS(rc))
1090 ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority);
1091 else
1092 {
1093 /*
1094 * Failed, restore the priority.
1095 */
1096 rtProcNativeSetPriority(g_enmProcessPriority);
1097 RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1098 }
1099 }
1100 RT_THREAD_UNLOCK_RW(Tmp);
1101 LogFlow(("rtThreadDoSetProcPriority: returns %Vrc\n", rc));
1102 return rc;
1103}
1104
1105
1106/**
1107 * Bitch about a deadlock.
1108 *
1109 * @param pThread This thread.
1110 * @param pCur The thread we're deadlocking with.
1111 * @param enmState The sleep state.
1112 * @param u64Block The block data. A pointer or handle.
1113 * @param pszFile Where we are gonna block.
1114 * @param uLine Where we are gonna block.
1115 * @param uId Where we are gonna block.
1116 */
1117static void rtThreadDeadlock(PRTTHREADINT pThread, PRTTHREADINT pCur, RTTHREADSTATE enmState, uint64_t u64Block,
1118 const char *pszFile, unsigned uLine, RTUINTPTR uId)
1119{
1120 AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", uLine, pszFile, "");
1121
1122 /*
1123 * Print the threads and locks involved.
1124 */
1125 PRTTHREADINT apSeenThreads[8] = {0,0,0,0,0,0,0,0};
1126 unsigned iSeenThread = 0;
1127 pCur = pThread;
1128 for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++)
1129 {
1130 /*
1131 * Print info on pCur. Determin next while doing so.
1132 */
1133 AssertMsg2(" #%d: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n",
1134 iEntry, pCur, pCur->Core.Key, pCur->szName,
1135 pCur->pszBlockFile, pCur->uBlockLine, pCur->uBlockId);
1136 PRTTHREADINT pNext = NULL;
1137 switch (pCur->enmState)
1138 {
1139 case RTTHREADSTATE_CRITSECT:
1140 {
1141 PRTCRITSECT pCritSect = pCur->Block.pCritSect;
1142 if (pCur->enmState != RTTHREADSTATE_CRITSECT)
1143 {
1144 AssertMsg2("Impossible!!!\n");
1145 break;
1146 }
1147 if (VALID_PTR(pCritSect) && RTCritSectIsInitialized(pCritSect))
1148 {
1149 AssertMsg2(" Waiting on CRITSECT %p: Entered %s(%u) %RTptr\n",
1150 pCritSect, pCritSect->Strict.pszEnterFile,
1151 pCritSect->Strict.u32EnterLine, pCritSect->Strict.uEnterId);
1152 pNext = pCritSect->Strict.ThreadOwner;
1153 }
1154 else
1155 AssertMsg2(" Waiting on CRITSECT %p: invalid pointer or uninitialized critsect\n", pCritSect);
1156 break;
1157 }
1158
1159 default:
1160 AssertMsg2(" Impossible!!! enmState=%d\n", pCur->enmState);
1161 break;
1162 }
1163
1164 /*
1165 * Check for cycle.
1166 */
1167 if (iEntry && pCur == pThread)
1168 break;
1169 for (unsigned i = 0; i < ELEMENTS(apSeenThreads); i++)
1170 if (apSeenThreads[i] == pCur)
1171 {
1172 AssertMsg2(" Cycle!\n");
1173 pNext = NULL;
1174 break;
1175 }
1176
1177 /*
1178 * Advance to the next thread.
1179 */
1180 iSeenThread = (iSeenThread + 1) % ELEMENTS(apSeenThreads);
1181 apSeenThreads[iSeenThread] = pCur;
1182 pCur = pNext;
1183 }
1184 AssertBreakpoint();
1185}
1186
1187
1188/**
1189 * Change the thread state to blocking and do deadlock detection.
1190 *
1191 * This is a RT_STRICT method for debugging locks and detecting deadlocks.
1192 *
1193 * @param pThread This thread.
1194 * @param enmState The sleep state.
1195 * @param u64Block The block data. A pointer or handle.
1196 * @param pszFile Where we are blocking.
1197 * @param uLine Where we are blocking.
1198 * @param uId Where we are blocking.
1199 */
1200void rtThreadBlocking(PRTTHREADINT pThread, RTTHREADSTATE enmState, uint64_t u64Block,
1201 const char *pszFile, unsigned uLine, RTUINTPTR uId)
1202{
1203 Assert(RTTHREAD_IS_SLEEPING(enmState));
1204 if (pThread && pThread->enmState == RTTHREADSTATE_RUNNING)
1205 {
1206 /** @todo This has to be serialized! The deadlock detection isn't 100% safe!!! */
1207 pThread->Block.u64 = u64Block;
1208 pThread->pszBlockFile = pszFile;
1209 pThread->uBlockLine = uLine;
1210 pThread->uBlockId = uId;
1211 ASMAtomicXchgSize(&pThread->enmState, enmState);
1212
1213 /*
1214 * Do deadlock detection.
1215 *
1216 * Since we're missing proper serialization, we don't declare it a
1217 * deadlock until we've got three runs with the same list length.
1218 * While this isn't perfect, it should avoid out the most obvious
1219 * races on SMP boxes.
1220 */
1221 PRTTHREADINT pCur;
1222 unsigned cPrevLength = ~0U;
1223 unsigned cEqualRuns = 0;
1224 unsigned iParanoia = 256;
1225 do
1226 {
1227 unsigned cLength = 0;
1228 pCur = pThread;
1229 for (;;)
1230 {
1231 /*
1232 * Get the next thread.
1233 */
1234 for (;;)
1235 {
1236 switch (pCur->enmState)
1237 {
1238 case RTTHREADSTATE_CRITSECT:
1239 {
1240 PRTCRITSECT pCritSect = pCur->Block.pCritSect;
1241 if (pCur->enmState != RTTHREADSTATE_CRITSECT)
1242 continue;
1243 pCur = pCritSect->Strict.ThreadOwner;
1244 break;
1245 }
1246
1247 default:
1248 pCur = NULL;
1249 break;
1250 }
1251 break;
1252 }
1253 if (!pCur)
1254 return;
1255
1256 /*
1257 * If we've got back to the blocking thread id we've got a deadlock.
1258 * If we've got a chain of more than 256 items, there is some kind of cycle
1259 * in the list, which means that there is already a deadlock somewhere.
1260 */
1261 if (pCur == pThread || cLength >= 256)
1262 break;
1263 cLength++;
1264 }
1265
1266 /* compare with previous list run. */
1267 if (cLength != cPrevLength)
1268 {
1269 cPrevLength = cLength;
1270 cEqualRuns = 0;
1271 }
1272 else
1273 cEqualRuns++;
1274 } while (cEqualRuns < 3 && --iParanoia > 0);
1275
1276 /*
1277 * Ok, if we ever get here, it's most likely a genuine deadlock.
1278 */
1279 rtThreadDeadlock(pThread, pCur, enmState, u64Block, pszFile, uLine, uId);
1280 }
1281}
1282
1283
1284/**
1285 * Unblocks a thread.
1286 *
1287 * This function is paired with rtThreadBlocking.
1288 *
1289 * @param pThread The current thread.
1290 * @param enmCurState The current state, used to check for nested blocking.
1291 * The new state will be running.
1292 */
1293void rtThreadUnblocked(PRTTHREADINT pThread, RTTHREADSTATE enmCurState)
1294{
1295 if (pThread && pThread->enmState == enmCurState)
1296 ASMAtomicXchgSize(&pThread->enmState, RTTHREADSTATE_RUNNING);
1297}
1298
1299#endif /* IN_RING3 */
1300
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette