VirtualBox

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

Last change on this file since 4672 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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