VirtualBox

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

Last change on this file since 2397 was 1766, checked in by vboxsync, 18 years ago

Introduce a dummy thread name parameter to rtThreadMain to allow
identifying the thread from a debugger backtrace.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 39.8 KB
Line 
1/* $Id: thread.cpp 1766 2007-03-28 12:51:24Z 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 * @param pszThreadName The name of the thread (purely a dummy for backtrace).
571 */
572int rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread, const char *pszThreadName)
573{
574 NOREF(pszThreadName);
575 rtThreadInsert(pThread, NativeThread);
576 Log(("rtThreadMain: Starting: pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
577 pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
578
579 /*
580 * Change the priority.
581 */
582 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
583#ifdef IN_RING3
584 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d enmPriority=%d rc=%Vrc\n",
585 pThread, NativeThread, pThread->szName, pThread->enmType, g_enmProcessPriority, rc));
586#else
587 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d rc=%Vrc\n",
588 pThread, NativeThread, pThread->szName, pThread->enmType, rc));
589#endif
590
591 /*
592 * Call thread function and terminate when it returns.
593 */
594 pThread->enmState = RTTHREADSTATE_RUNNING;
595 rc = pThread->pfnThread(pThread, pThread->pvUser);
596
597 Log(("rtThreadMain: Terminating: rc=%d pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
598 rc, pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
599 rtThreadTerminate(pThread, rc);
600 return rc;
601}
602
603
604/**
605 * Create a new thread.
606 *
607 * @returns iprt status code.
608 * @param pThread Where to store the thread handle to the new thread. (optional)
609 * @param pfnThread The thread function.
610 * @param pvUser User argument.
611 * @param cbStack The size of the stack for the new thread.
612 * Use 0 for the default stack size.
613 * @param enmType The thread type. Used for deciding scheduling attributes
614 * of the thread.
615 * @param fFlags Flags of the RTTHREADFLAGS type (ORed together).
616 * @param pszName Thread name.
617 */
618RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
619 RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
620{
621 LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n",
622 pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName));
623
624 /*
625 * Validate input.
626 */
627 if (!VALID_PTR(pThread) && pThread)
628 {
629 Assert(VALID_PTR(pThread));
630 return VERR_INVALID_PARAMETER;
631 }
632 if (!VALID_PTR(pfnThread))
633 {
634 Assert(VALID_PTR(pfnThread));
635 return VERR_INVALID_PARAMETER;
636 }
637 if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN)
638 {
639 AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1));
640 return VERR_INVALID_PARAMETER;
641 }
642 if (fFlags & ~RTTHREADFLAGS_MASK)
643 {
644 AssertMsgFailed(("fFlags=%#x\n", fFlags));
645 return VERR_INVALID_PARAMETER;
646 }
647
648 /*
649 * Allocate thread argument.
650 */
651 int rc;
652 PRTTHREADINT pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
653 if (pThreadInt)
654 {
655 pThreadInt->pfnThread = pfnThread;
656 pThreadInt->pvUser = pvUser;
657 pThreadInt->cbStack = cbStack;
658
659 RTNATIVETHREAD NativeThread;
660 rc = rtThreadNativeCreate(pThreadInt, &NativeThread);
661 if (RT_SUCCESS(rc))
662 {
663 rtThreadInsert(pThreadInt, NativeThread);
664 rtThreadRelease(pThreadInt);
665 Log(("RTThreadCreate: Created thread %p (%p) %s\n", pThreadInt, NativeThread, pszName));
666 if (pThread)
667 *pThread = pThreadInt;
668 return VINF_SUCCESS;
669 }
670
671 pThreadInt->cRefs = 1;
672 rtThreadRelease(pThreadInt);
673 }
674 else
675 rc = VERR_NO_TMP_MEMORY;
676 LogFlow(("RTThreadCreate: Failed to create thread, rc=%Vrc\n", rc));
677 AssertReleaseRC(rc);
678 return rc;
679}
680
681
682/**
683 * Gets the native thread id of a IPRT thread.
684 *
685 * @returns The native thread id.
686 * @param Thread The IPRT thread.
687 */
688RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread)
689{
690 PRTTHREADINT pThread = rtThreadGet(Thread);
691 if (pThread)
692 return (RTNATIVETHREAD)pThread->Core.Key;
693 return NIL_RTNATIVETHREAD;
694}
695
696
697/**
698 * Gets the IPRT thread of a native thread.
699 *
700 * @returns The IPRT thread handle
701 * @returns NIL_RTTHREAD if not a thread known to IPRT.
702 * @param NativeThread The native thread handle/id.
703 */
704RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread)
705{
706 PRTTHREADINT pThread = rtThreadGetByNative(NativeThread);
707 if (pThread)
708 {
709 rtThreadRelease(pThread);
710 return pThread;
711 }
712 return NIL_RTTHREAD;
713}
714
715
716/**
717 * Gets the name of the current thread thread.
718 *
719 * @returns Pointer to readonly name string.
720 * @returns NULL on failure.
721 */
722RTDECL(const char *) RTThreadSelfName(void)
723{
724 RTTHREAD Thread = RTThreadSelf();
725 if (Thread != NIL_RTTHREAD)
726 {
727 PRTTHREADINT pThread = rtThreadGet(Thread);
728 if (pThread)
729 return pThread->szName;
730 }
731 return NULL;
732}
733
734
735/**
736 * Gets the name of a thread.
737 *
738 * @returns Pointer to readonly name string.
739 * @returns NULL on failure.
740 * @param Thread Thread handle of the thread to query the name of.
741 */
742RTDECL(const char *) RTThreadGetName(RTTHREAD Thread)
743{
744 if (Thread == NIL_RTTHREAD)
745 return NULL;
746 PRTTHREADINT pThread = rtThreadGet(Thread);
747 return pThread ? pThread->szName : NULL;
748}
749
750
751/**
752 * Sets the name of a thread.
753 *
754 * @returns iprt status code.
755 * @param Thread Thread handle of the thread to query the name of.
756 * @param pszName The thread name.
757 */
758RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName)
759{
760 /*
761 * Validate input.
762 */
763 size_t cchName = strlen(pszName);
764 if (cchName >= RTTHREAD_NAME_LEN)
765 {
766 AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName, RTTHREAD_NAME_LEN - 1));
767 return VERR_INVALID_PARAMETER;
768 }
769 PRTTHREADINT pThread = rtThreadGet(Thread);
770 if (!pThread)
771 return VERR_INVALID_HANDLE;
772
773 /*
774 * Update the name.
775 */
776 pThread->szName[cchName] = '\0'; /* paranoia */
777 memcpy(pThread->szName, pszName, cchName);
778 return VINF_SUCCESS;
779}
780
781
782/**
783 * Signal the user event.
784 *
785 * @returns iprt status code.
786 */
787RTDECL(int) RTThreadUserSignal(RTTHREAD Thread)
788{
789 int rc;
790 PRTTHREADINT pThread = rtThreadGet(Thread);
791 if (pThread)
792 {
793 rc = RTSemEventMultiSignal(pThread->EventUser);
794 rtThreadRelease(pThread);
795 }
796 else
797 rc = VERR_INVALID_HANDLE;
798 return rc;
799}
800
801
802/**
803 * Wait for the user event, resume on interruption.
804 *
805 * @returns iprt status code.
806 * @param Thread The thread to wait for.
807 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
808 * an indefinite wait.
809 */
810RTDECL(int) RTThreadUserWait(RTTHREAD Thread, unsigned cMillies)
811{
812 int rc;
813 PRTTHREADINT pThread = rtThreadGet(Thread);
814 if (pThread)
815 {
816 rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
817 rtThreadRelease(pThread);
818 }
819 else
820 rc = VERR_INVALID_HANDLE;
821 return rc;
822}
823
824
825/**
826 * Wait for the user event, return on interruption.
827 *
828 * @returns iprt status code.
829 * @param Thread The thread to wait for.
830 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
831 * an indefinite wait.
832 */
833RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, unsigned cMillies)
834{
835 int rc;
836 PRTTHREADINT pThread = rtThreadGet(Thread);
837 if (pThread)
838 {
839 rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
840 rtThreadRelease(pThread);
841 }
842 else
843 rc = VERR_INVALID_HANDLE;
844 return rc;
845}
846
847
848/**
849 * Reset the user event.
850 *
851 * @returns iprt status code.
852 * @param Thread The thread to reset.
853 */
854RTDECL(int) RTThreadUserReset(RTTHREAD Thread)
855{
856 int rc;
857 PRTTHREADINT pThread = rtThreadGet(Thread);
858 if (pThread)
859 {
860 rc = RTSemEventMultiReset(pThread->EventUser);
861 rtThreadRelease(pThread);
862 }
863 else
864 rc = VERR_INVALID_HANDLE;
865 return rc;
866}
867
868
869/**
870 * Wait for the thread to terminate.
871 *
872 * @returns iprt status code.
873 * @param Thread The thread to wait for.
874 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
875 * an indefinite wait.
876 * @param prc Where to store the return code of the thread. Optional.
877 * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED.
878 */
879static int rtThreadWait(RTTHREAD Thread, unsigned cMillies, int *prc, bool fAutoResume)
880{
881 int rc = VERR_INVALID_HANDLE;
882 if (Thread != NIL_RTTHREAD)
883 {
884 PRTTHREADINT pThread = rtThreadGet(Thread);
885 if (pThread)
886 {
887 if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
888 {
889 if (fAutoResume)
890 rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
891 else
892 rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
893 if (RT_SUCCESS(rc))
894 {
895 if (prc)
896 *prc = pThread->rc;
897
898 /*
899 * If the thread is marked as waitable, we'll do one additional
900 * release in order to free up the thread structure (see how we
901 * init cRef in rtThreadAlloc()).
902 */
903 if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
904 rtThreadRelease(pThread);
905 }
906 }
907 else
908 {
909 rc = VERR_THREAD_NOT_WAITABLE;
910 AssertRC(rc);
911 }
912 rtThreadRelease(pThread);
913 }
914 }
915 return rc;
916}
917
918
919/**
920 * Wait for the thread to terminate, resume on interruption.
921 *
922 * @returns iprt status code.
923 * Will not return VERR_INTERRUPTED.
924 * @param Thread The thread to wait for.
925 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
926 * an indefinite wait.
927 * @param prc Where to store the return code of the thread. Optional.
928 */
929RTDECL(int) RTThreadWait(RTTHREAD Thread, unsigned cMillies, int *prc)
930{
931 int rc = rtThreadWait(Thread, cMillies, prc, true);
932 Assert(rc != VERR_INTERRUPTED);
933 return rc;
934}
935
936
937/**
938 * Wait for the thread to terminate, return on interruption.
939 *
940 * @returns iprt status code.
941 * @param Thread The thread to wait for.
942 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
943 * an indefinite wait.
944 * @param prc Where to store the return code of the thread. Optional.
945 */
946RTDECL(int) RTThreadWaitNoResume(RTTHREAD Thread, unsigned cMillies, int *prc)
947{
948 return rtThreadWait(Thread, cMillies, prc, false);
949}
950
951
952/**
953 * Changes the type of the specified thread.
954 *
955 * @returns iprt status code.
956 * @param Thread The thread which type should be changed.
957 * @param enmType The new thread type.
958 */
959RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType)
960{
961 /*
962 * Validate input.
963 */
964 int rc;
965 if ( enmType > RTTHREADTYPE_INVALID
966 && enmType < RTTHREADTYPE_END)
967 {
968 PRTTHREADINT pThread = rtThreadGet(Thread);
969 if (pThread)
970 {
971 if (rtThreadIsAlive(pThread))
972 {
973 /*
974 * Do the job.
975 */
976 RT_THREAD_LOCK_TMP(Tmp);
977 RT_THREAD_LOCK_RW(Tmp);
978 rc = rtThreadNativeSetPriority(pThread, enmType);
979 if (RT_SUCCESS(rc))
980 ASMAtomicXchgSize(&pThread->enmType, enmType);
981 RT_THREAD_UNLOCK_RW(Tmp);
982 if (RT_FAILURE(rc))
983 Log(("RTThreadSetType: failed on thread %p (%s), rc=%Vrc!!!\n", Thread, pThread->szName, rc));
984 }
985 else
986 rc = VERR_THREAD_IS_DEAD;
987 rtThreadRelease(pThread);
988 }
989 else
990 rc = VERR_INVALID_HANDLE;
991 }
992 else
993 {
994 AssertMsgFailed(("enmType=%d\n", enmType));
995 rc = VERR_INVALID_PARAMETER;
996 }
997 return rc;
998}
999
1000
1001/**
1002 * Gets the type of the specified thread.
1003 *
1004 * @returns The thread type.
1005 * @returns RTTHREADTYPE_INVALID if the thread handle is invalid.
1006 * @param Thread The thread in question.
1007 */
1008RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread)
1009{
1010 RTTHREADTYPE enmType = RTTHREADTYPE_INVALID;
1011 PRTTHREADINT pThread = rtThreadGet(Thread);
1012 if (pThread)
1013 {
1014 enmType = pThread->enmType;
1015 rtThreadRelease(pThread);
1016 }
1017 return enmType;
1018}
1019
1020
1021#ifdef IN_RING3
1022
1023/**
1024 * Recalculates scheduling attributes for the the default process
1025 * priority using the specified priority type for the calling thread.
1026 *
1027 * The scheduling attributes are targeted at threads and they are protected
1028 * by the thread read-write semaphore, that's why RTProc is forwarding the
1029 * operation to RTThread.
1030 *
1031 * @returns iprt status code.
1032 */
1033int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
1034{
1035 RT_THREAD_LOCK_TMP(Tmp);
1036 RT_THREAD_LOCK_RW(Tmp);
1037 int rc = rtSchedNativeCalcDefaultPriority(enmType);
1038 RT_THREAD_UNLOCK_RW(Tmp);
1039 return rc;
1040}
1041
1042
1043/**
1044 * Thread enumerator - sets the priority of one thread.
1045 *
1046 * @returns 0 to continue.
1047 * @returns !0 to stop. In our case a VERR_ code.
1048 * @param pNode The thread node.
1049 * @param pvUser The new priority.
1050 */
1051static DECLCALLBACK(int) rtThreadSetPriorityOne(PAVLPVNODECORE pNode, void *pvUser)
1052{
1053 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1054 if (!rtThreadIsAlive(pThread))
1055 return VINF_SUCCESS;
1056 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
1057 if (RT_SUCCESS(rc)) /* hide any warnings */
1058 return VINF_SUCCESS;
1059 return rc;
1060}
1061
1062
1063/**
1064 * Attempts to alter the priority of the current process.
1065 *
1066 * The scheduling attributes are targeted at threads and they are protected
1067 * by the thread read-write semaphore, that's why RTProc is forwarding the
1068 * operation to RTThread. This operation also involves updating all thread
1069 * which is much faster done from RTThread.
1070 *
1071 * @returns iprt status code.
1072 * @param enmPriority The new priority.
1073 */
1074int rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority)
1075{
1076 LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority));
1077
1078 /*
1079 * First validate that we're allowed by the OS to use all the
1080 * scheduling attributes defined by the specified process priority.
1081 */
1082 RT_THREAD_LOCK_TMP(Tmp);
1083 RT_THREAD_LOCK_RW(Tmp);
1084 int rc = rtProcNativeSetPriority(enmPriority);
1085 if (RT_SUCCESS(rc))
1086 {
1087 /*
1088 * Update the priority of existing thread.
1089 */
1090 rc = RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1091 if (RT_SUCCESS(rc))
1092 ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority);
1093 else
1094 {
1095 /*
1096 * Failed, restore the priority.
1097 */
1098 rtProcNativeSetPriority(g_enmProcessPriority);
1099 RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1100 }
1101 }
1102 RT_THREAD_UNLOCK_RW(Tmp);
1103 LogFlow(("rtThreadDoSetProcPriority: returns %Vrc\n", rc));
1104 return rc;
1105}
1106
1107
1108/**
1109 * Bitch about a deadlock.
1110 *
1111 * @param pThread This thread.
1112 * @param pCur The thread we're deadlocking with.
1113 * @param enmState The sleep state.
1114 * @param u64Block The block data. A pointer or handle.
1115 * @param pszFile Where we are gonna block.
1116 * @param uLine Where we are gonna block.
1117 * @param uId Where we are gonna block.
1118 */
1119static void rtThreadDeadlock(PRTTHREADINT pThread, PRTTHREADINT pCur, RTTHREADSTATE enmState, uint64_t u64Block,
1120 const char *pszFile, unsigned uLine, RTUINTPTR uId)
1121{
1122 AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", uLine, pszFile, "");
1123
1124 /*
1125 * Print the threads and locks involved.
1126 */
1127 PRTTHREADINT apSeenThreads[8] = {0,0,0,0,0,0,0,0};
1128 unsigned iSeenThread = 0;
1129 pCur = pThread;
1130 for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++)
1131 {
1132 /*
1133 * Print info on pCur. Determin next while doing so.
1134 */
1135 AssertMsg2(" #%d: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n",
1136 iEntry, pCur, pCur->Core.Key, pCur->szName,
1137 pCur->pszBlockFile, pCur->uBlockLine, pCur->uBlockId);
1138 PRTTHREADINT pNext = NULL;
1139 switch (pCur->enmState)
1140 {
1141 case RTTHREADSTATE_CRITSECT:
1142 {
1143 PRTCRITSECT pCritSect = pCur->Block.pCritSect;
1144 if (pCur->enmState != RTTHREADSTATE_CRITSECT)
1145 {
1146 AssertMsg2("Impossible!!!\n");
1147 break;
1148 }
1149 if (VALID_PTR(pCritSect) && RTCritSectIsInitialized(pCritSect))
1150 {
1151 AssertMsg2(" Waiting on CRITSECT %p: Entered %s(%u) %RTptr\n",
1152 pCritSect, pCritSect->Strict.pszEnterFile,
1153 pCritSect->Strict.u32EnterLine, pCritSect->Strict.uEnterId);
1154 pNext = pCritSect->Strict.ThreadOwner;
1155 }
1156 else
1157 AssertMsg2(" Waiting on CRITSECT %p: invalid pointer or uninitialized critsect\n", pCritSect);
1158 break;
1159 }
1160
1161 default:
1162 AssertMsg2(" Impossible!!! enmState=%d\n", pCur->enmState);
1163 break;
1164 }
1165
1166 /*
1167 * Check for cycle.
1168 */
1169 if (iEntry && pCur == pThread)
1170 break;
1171 for (unsigned i = 0; i < ELEMENTS(apSeenThreads); i++)
1172 if (apSeenThreads[i] == pCur)
1173 {
1174 AssertMsg2(" Cycle!\n");
1175 pNext = NULL;
1176 break;
1177 }
1178
1179 /*
1180 * Advance to the next thread.
1181 */
1182 iSeenThread = (iSeenThread + 1) % ELEMENTS(apSeenThreads);
1183 apSeenThreads[iSeenThread] = pCur;
1184 pCur = pNext;
1185 }
1186 AssertBreakpoint();
1187}
1188
1189
1190/**
1191 * Change the thread state to blocking and do deadlock detection.
1192 *
1193 * This is a RT_STRICT method for debugging locks and detecting deadlocks.
1194 *
1195 * @param pThread This thread.
1196 * @param enmState The sleep state.
1197 * @param u64Block The block data. A pointer or handle.
1198 * @param pszFile Where we are blocking.
1199 * @param uLine Where we are blocking.
1200 * @param uId Where we are blocking.
1201 */
1202void rtThreadBlocking(PRTTHREADINT pThread, RTTHREADSTATE enmState, uint64_t u64Block,
1203 const char *pszFile, unsigned uLine, RTUINTPTR uId)
1204{
1205 Assert(RTTHREAD_IS_SLEEPING(enmState));
1206 if (pThread && pThread->enmState == RTTHREADSTATE_RUNNING)
1207 {
1208 /** @todo This has to be serialized! The deadlock detection isn't 100% safe!!! */
1209 pThread->Block.u64 = u64Block;
1210 pThread->pszBlockFile = pszFile;
1211 pThread->uBlockLine = uLine;
1212 pThread->uBlockId = uId;
1213 ASMAtomicXchgSize(&pThread->enmState, enmState);
1214
1215 /*
1216 * Do deadlock detection.
1217 *
1218 * Since we're missing proper serialization, we don't declare it a
1219 * deadlock until we've got three runs with the same list length.
1220 * While this isn't perfect, it should avoid out the most obvious
1221 * races on SMP boxes.
1222 */
1223 PRTTHREADINT pCur;
1224 unsigned cPrevLength = ~0U;
1225 unsigned cEqualRuns = 0;
1226 unsigned iParanoia = 256;
1227 do
1228 {
1229 unsigned cLength = 0;
1230 pCur = pThread;
1231 for (;;)
1232 {
1233 /*
1234 * Get the next thread.
1235 */
1236 for (;;)
1237 {
1238 switch (pCur->enmState)
1239 {
1240 case RTTHREADSTATE_CRITSECT:
1241 {
1242 PRTCRITSECT pCritSect = pCur->Block.pCritSect;
1243 if (pCur->enmState != RTTHREADSTATE_CRITSECT)
1244 continue;
1245 pCur = pCritSect->Strict.ThreadOwner;
1246 break;
1247 }
1248
1249 default:
1250 pCur = NULL;
1251 break;
1252 }
1253 break;
1254 }
1255 if (!pCur)
1256 return;
1257
1258 /*
1259 * If we've got back to the blocking thread id we've got a deadlock.
1260 * If we've got a chain of more than 256 items, there is some kind of cycle
1261 * in the list, which means that there is already a deadlock somewhere.
1262 */
1263 if (pCur == pThread || cLength >= 256)
1264 break;
1265 cLength++;
1266 }
1267
1268 /* compare with previous list run. */
1269 if (cLength != cPrevLength)
1270 {
1271 cPrevLength = cLength;
1272 cEqualRuns = 0;
1273 }
1274 else
1275 cEqualRuns++;
1276 } while (cEqualRuns < 3 && --iParanoia > 0);
1277
1278 /*
1279 * Ok, if we ever get here, it's most likely a genuine deadlock.
1280 */
1281 rtThreadDeadlock(pThread, pCur, enmState, u64Block, pszFile, uLine, uId);
1282 }
1283}
1284
1285
1286/**
1287 * Unblocks a thread.
1288 *
1289 * This function is paired with rtThreadBlocking.
1290 *
1291 * @param pThread The current thread.
1292 * @param enmCurState The current state, used to check for nested blocking.
1293 * The new state will be running.
1294 */
1295void rtThreadUnblocked(PRTTHREADINT pThread, RTTHREADSTATE enmCurState)
1296{
1297 if (pThread && pThread->enmState == enmCurState)
1298 ASMAtomicXchgSize(&pThread->enmState, RTTHREADSTATE_RUNNING);
1299}
1300
1301#endif /* IN_RING3 */
1302
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