VirtualBox

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

Last change on this file since 514 was 403, checked in by vboxsync, 18 years ago

Need RTThreadWait in ring-0 too when using the generic timers, so thread.cpp was ported to ring-0. Fixed a bug in RTTimerStart() (the generic code). (hope this doesn't break the other platforms...)

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