The Pedigree Project 0.1
ThreadWaitDiagnostic.h
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted.
6 */
7
8#ifndef THREADWAITDIAGNOSTIC_H
9#define THREADWAITDIAGNOSTIC_H
10
11#include "pedigree/kernel/process/WaitQueue.h"
12#include "pedigree/kernel/utilities/StaticString.h"
13
17 : sleeping(false),
18 hasWait(false),
19 queue(0),
20 channelOwner(0),
21 channelValue(0),
22 reason(WaitQueue::WakeReason::Waiting),
23 stateLevel(0),
24 mutexOwner(0),
25 queued(false) {}
26
27 bool sleeping;
28 bool hasWait;
29 uintptr_t queue;
30 uintptr_t channelOwner;
31 uintptr_t channelValue;
32 WaitQueue::WakeReason reason;
33 size_t stateLevel;
34 uintptr_t mutexOwner;
35 bool queued;
36};
37
38inline const char* threadWaitReasonName(WaitQueue::WakeReason reason) {
39 switch (reason) {
40 case WaitQueue::WakeReason::Waiting:
41 return "waiting";
42 case WaitQueue::WakeReason::Signalled:
43 return "signalled";
44 case WaitQueue::WakeReason::Event:
45 return "event";
46 case WaitQueue::WakeReason::Unwinding:
47 return "unwinding";
48 case WaitQueue::WakeReason::Terminating:
49 return "terminating";
50 case WaitQueue::WakeReason::Spurious:
51 return "spurious";
52 }
53 return "unknown";
54}
55
56inline void appendThreadWaitDiagnostic(const ThreadWaitDiagnostic& wait, HugeStaticString& line) {
57 if (!wait.hasWait) {
58 if (wait.sleeping) {
59 line += " [INVALID: sleeping without waitq]";
60 }
61 return;
62 }
63
64 line += " [waitq=";
65 line.append(wait.queue, 16);
66 line += ", channel=";
67 line.append(wait.channelOwner, 16);
68 line += ":";
69 line.append(wait.channelValue, 16);
70 line += ", reason=";
71 line += threadWaitReasonName(wait.reason);
72 line += ", level=";
73 line.append(wait.stateLevel);
74
75 if (wait.mutexOwner) {
76 line += ", owner=";
77 line.append(wait.mutexOwner, 16);
78 }
79
80 line += wait.queued ? ", queued]" : ", publishing]";
81}
82
83#endif