From c5a0df24908c0a5279190611f3959fec50380762 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Tue, 13 Jun 2023 15:42:18 -0400 Subject: [PATCH] user_mutex: Add "user_mutex" KDL command to dump user-mutex information. It takes one parameter to specify a thread that is blocked on such a user mutex. Change-Id: I513ce130137a327cbaf305d2945e6cfe3c09879e Reviewed-on: https://review.haiku-os.org/c/haiku/+/6606 Tested-by: Commit checker robot Reviewed-by: waddlesplash --- src/system/kernel/locks/user_mutex.cpp | 63 +++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/system/kernel/locks/user_mutex.cpp b/src/system/kernel/locks/user_mutex.cpp index 96732866f7..314ec48f75 100644 --- a/src/system/kernel/locks/user_mutex.cpp +++ b/src/system/kernel/locks/user_mutex.cpp @@ -72,6 +72,7 @@ struct user_mutex_context { rw_lock lock; }; static user_mutex_context sSharedUserMutexContext; +static const char* kUserMutexEntryType = "umtx entry"; // #pragma mark - user atomics @@ -149,12 +150,72 @@ user_atomic_test_and_set(int32* value, int32 newValue, int32 testAgainst, // #pragma mark - user mutex context +static int +dump_user_mutex(int argc, char** argv) +{ + if (argc != 2) { + print_debugger_command_usage(argv[0]); + return 0; + } + + addr_t threadID = parse_expression(argv[1]); + if (threadID == 0) + return 0; + + Thread* thread = Thread::GetDebug(threadID); + if (thread == NULL) { + kprintf("no such thread\n"); + return 0; + } + + if (thread->wait.type != THREAD_BLOCK_TYPE_CONDITION_VARIABLE) { + kprintf("thread is not blocked on cvar (thus not user_mutex)\n"); + return 0; + } + + ConditionVariable* variable = (ConditionVariable*)thread->wait.object; + if (variable->ObjectType() != kUserMutexEntryType) { + kprintf("thread is not blocked on user_mutex\n"); + return 0; + } + + UserMutexEntry* entry = (UserMutexEntry*)variable->Object(); + + const bool physical = (sSharedUserMutexContext.table.Lookup(entry->address) == entry); + kprintf("user mutex entry %p\n", entry); + kprintf(" address: 0x%" B_PRIxPHYSADDR " (%s)\n", entry->address, + physical ? "physical" : "virtual"); + kprintf(" refcount: %" B_PRId32 "\n", entry->ref_count); + kprintf(" lock: %p\n", &entry->lock); + + int32 mutex = 0; + status_t status = B_ERROR; + if (!physical) { + status = debug_memcpy(thread->team->id, &mutex, + (void*)entry->address, sizeof(mutex)); + } + + if (status == B_OK) + kprintf(" mutex: 0x%" B_PRIx32 "\n", mutex); + + entry->condition.Dump(); + + return 0; +} + + void user_mutex_init() { sSharedUserMutexContext.lock = RW_LOCK_INITIALIZER("shared user mutex table"); if (sSharedUserMutexContext.table.Init() != B_OK) panic("user_mutex_init(): Failed to init table!"); + + add_debugger_command_etc("user_mutex", &dump_user_mutex, + "Dump user-mutex info", + "\n" + "Prints info about the user-mutex a thread is blocked on.\n" + " - Thread ID that is blocked on a user mutex\n", 0); } @@ -229,7 +290,7 @@ get_user_mutex_entry(struct user_mutex_context* context, entry->address = address; entry->ref_count = 1; rw_lock_init(&entry->lock, "UserMutexEntry lock"); - entry->condition.Init(entry, "UserMutexEntry"); + entry->condition.Init(entry, kUserMutexEntryType); context->table.Insert(entry); return entry;