VirtualBox

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

Last change on this file since 331 was 1, checked in by vboxsync, 55 years ago

import

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