diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 27e7bef7f0..4db51c8e06 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -158,7 +158,7 @@ AddFilesToHaikuImage system add-ons kernel busses usb AddFilesToHaikuImage system add-ons kernel console : vga_text ; AddFilesToHaikuImage system add-ons kernel debugger : $(X86_ONLY)disasm hangman invalidate_on_exit - usb_keyboard ; + usb_keyboard run_on_exit ; AddFilesToHaikuImage system add-ons kernel file_systems : $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ; AddFilesToHaikuImage system add-ons kernel generic diff --git a/src/add-ons/kernel/debugger/Jamfile b/src/add-ons/kernel/debugger/Jamfile index 0594932f75..dcf3f4a83d 100644 --- a/src/add-ons/kernel/debugger/Jamfile +++ b/src/add-ons/kernel/debugger/Jamfile @@ -7,4 +7,5 @@ SubInclude HAIKU_TOP src add-ons kernel debugger disasm ; SubInclude HAIKU_TOP src add-ons kernel debugger hangman ; SubInclude HAIKU_TOP src add-ons kernel debugger invalidate_on_exit ; SubInclude HAIKU_TOP src add-ons kernel debugger laplinkll ; +SubInclude HAIKU_TOP src add-ons kernel debugger run_on_exit ; SubInclude HAIKU_TOP src add-ons kernel debugger usb_keyboard ; diff --git a/src/add-ons/kernel/debugger/run_on_exit/Jamfile b/src/add-ons/kernel/debugger/run_on_exit/Jamfile new file mode 100644 index 0000000000..f63f4e330f --- /dev/null +++ b/src/add-ons/kernel/debugger/run_on_exit/Jamfile @@ -0,0 +1,7 @@ +SubDir HAIKU_TOP src add-ons kernel debugger run_on_exit ; + +UsePrivateHeaders kernel ; + +KernelAddon run_on_exit : + run_on_exit.cpp + ; diff --git a/src/add-ons/kernel/debugger/run_on_exit/run_on_exit.cpp b/src/add-ons/kernel/debugger/run_on_exit/run_on_exit.cpp new file mode 100644 index 0000000000..7bcc488a32 --- /dev/null +++ b/src/add-ons/kernel/debugger/run_on_exit/run_on_exit.cpp @@ -0,0 +1,142 @@ +/* + * Copyright 2009, Michael Lotz, mmlr@mlotz.ch + * Distributed under the terms of the MIT License. + */ +#include +#include +#include +#include + + +static sem_id sRequestSem = -1; +static char sCommandBuffer[1024]; +static uint32 sCommandOffset = 0; +static uint32 sCommandCount = 0; + + +static int32 +run_on_exit_loop(void *data) +{ + while (true) { + if (acquire_sem(sRequestSem) != B_OK) + break; + + char *pointer = sCommandBuffer; + while (sCommandCount > 0) { + uint8 argCount = (uint8)pointer[0]; + pointer++; + + const char *args[argCount]; + for (uint8 i = 0; i < argCount; i++) { + args[i] = pointer; + uint32 length = strlen(pointer); + pointer += length + 1; + } + + thread_id thread = load_image(argCount, args, NULL); + if (thread >= B_OK) + resume_thread(thread); + sCommandCount--; + } + + sCommandOffset = 0; + } + + return 0; +} + + +static int +add_run_on_exit_command(int argc, char **argv) +{ + if (argc < 2 || strcmp(argv[1], "--help") == 0) { + print_debugger_command_usage(argv[0]); + return 0; + } + + if (argc > 256) { + kprintf("too many arguments\n"); + return 0; + } + + size_t totalLength = 1; + for (int32 i = 1; i < argc; i++) + totalLength += strlen(argv[i]) + 1; + + if (sCommandOffset + totalLength > sizeof(sCommandBuffer)) { + kprintf("no space left in command buffer\n"); + return 0; + } + + char *pointer = sCommandBuffer + sCommandOffset; + *pointer++ = (char)(argc - 1); + + for (int32 i = 1; i < argc; i++) { + strcpy(pointer, argv[i]); + pointer += strlen(argv[i]) + 1; + } + + sCommandOffset += totalLength; + sCommandCount++; + return 0; +} + + +static void +exit_debugger() +{ + if (sCommandCount > 0) + release_sem_etc(sRequestSem, 1, B_DO_NOT_RESCHEDULE); +} + + +static status_t +std_ops(int32 op, ...) +{ + if (op == B_MODULE_INIT) { + sRequestSem = create_sem(0, "run_on_exit_request"); + if (sRequestSem < B_OK) + return sRequestSem; + + thread_id thread = spawn_kernel_thread(&run_on_exit_loop, + "run_on_exit_loop", B_NORMAL_PRIORITY, NULL); + if (thread < B_OK) + return thread; + + send_signal_etc(thread, SIGCONT, B_DO_NOT_RESCHEDULE); + + add_debugger_command_etc("on_exit", &add_run_on_exit_command, + "Adds a command to be run when leaving the kernel debugger", + " []\n" + "Adds a command to be run when leaving the kernel debugger.\n", 0); + + return B_OK; + } else if (op == B_MODULE_UNINIT) { + remove_debugger_command("on_exit", &add_run_on_exit_command); + // deleting the sem will also cause the thread to exit + delete_sem(sRequestSem); + sRequestSem = -1; + return B_OK; + } + + return B_BAD_VALUE; +} + + +static struct debugger_module_info sModuleInfo = { + { + "debugger/run_on_exit/v1", + B_KEEP_LOADED, + &std_ops + }, + + NULL, + exit_debugger, + NULL, + NULL +}; + +module_info *modules[] = { + (module_info *)&sModuleInfo, + NULL +};