diff --git a/lib/debugger/debugger.c b/lib/debugger/debugger.c index 89e678122..9efac8938 100644 --- a/lib/debugger/debugger.c +++ b/lib/debugger/debugger.c @@ -31,12 +31,14 @@ #include "compat/time.h" #include "scratch-buffers.h" +#include #include #include struct _Debugger { Tracer *tracer; + struct iv_signal sigint; MainLoop *main_loop; GlobalConfig *cfg; gchar *command_buffer; @@ -138,15 +140,31 @@ _display_source_line(LogExprNode *expr_node) static gboolean _cmd_help(Debugger *self, gint argc, gchar *argv[]) { - printf("syslog-ng interactive console, the following commands are available\n\n" - " help, h, or ? Display this help\n" - " info Display information about the current execution state\n" - " continue or c Continue until the next breakpoint\n" - " trace Display timing information as the message traverses the config\n" - " print, p Print the current log message\n" - " drop, d Drop the current message\n" - " quit, q Tell syslog-ng to exit\n" - ); + if (self->breakpoint_site) + { + printf("syslog-ng interactive console\n" + "Stopped on a breakpoint.\n" + "The following commands are available:\n\n" + " help, h, ? Display this help\n" + " info, i Display information about the current execution state\n" + " continue, c Continue until the next breakpoint\n" + " display Set the displayed message template\n" + " trace, t Display timing information as the message traverses the config\n" + " print, p Print the current log message\n" + " drop, d Drop the current message\n" + " quit, q Tell syslog-ng to exit\n" + ); + } + else + { + printf("syslog-ng interactive console\n" + "Stopped on an interrupt.\n" + "The following commands are available:\n\n" + " help, h, ? Display this help\n" + " continue, c Continue until the next breakpoint\n" + " quit, q Tell syslog-ng to exit\n" + ); + } return TRUE; } @@ -210,7 +228,8 @@ static gboolean _cmd_quit(Debugger *self, gint argc, gchar *argv[]) { main_loop_exit(self->main_loop); - self->breakpoint_site->drop = TRUE; + if (self->breakpoint_site) + self->breakpoint_site->drop = TRUE; return FALSE; } @@ -245,6 +264,7 @@ struct { const gchar *name; DebuggerCommandFunc command; + gboolean requires_breakpoint_site; } command_table[] = { { "help", _cmd_help }, @@ -252,15 +272,17 @@ struct { "?", _cmd_help }, { "continue", _cmd_continue }, { "c", _cmd_continue }, - { "print", _cmd_print }, - { "p", _cmd_print }, + { "print", _cmd_print, .requires_breakpoint_site = TRUE }, + { "p", _cmd_print, .requires_breakpoint_site = TRUE }, { "display", _cmd_display }, - { "drop", _cmd_drop }, + { "drop", _cmd_drop, .requires_breakpoint_site = TRUE }, + { "d", _cmd_drop, .requires_breakpoint_site = TRUE }, { "quit", _cmd_quit }, { "q", _cmd_quit }, - { "trace", _cmd_trace }, - { "info", _cmd_info }, - { "i", _cmd_info }, + { "trace", _cmd_trace, .requires_breakpoint_site = TRUE }, + { "t", _cmd_trace, .requires_breakpoint_site = TRUE }, + { "info", _cmd_info, .requires_breakpoint_site = TRUE }, + { "i", _cmd_info, .requires_breakpoint_site = TRUE }, { NULL, NULL } }; @@ -319,6 +341,7 @@ _handle_command(Debugger *self) gint argc; gchar **argv; GError *error = NULL; + gboolean requires_breakpoint_site = TRUE; DebuggerCommandFunc command = NULL; if (!g_shell_parse_argv(self->command_buffer ? : "", &argc, &argv, &error)) @@ -333,6 +356,7 @@ _handle_command(Debugger *self) if (strcmp(command_table[i].name, argv[0]) == 0) { command = command_table[i].command; + requires_breakpoint_site = command_table[i].requires_breakpoint_site; break; } } @@ -341,6 +365,11 @@ _handle_command(Debugger *self) printf("Undefined command %s, try \"help\"\n", argv[0]); return TRUE; } + else if (requires_breakpoint_site && self->breakpoint_site == NULL) + { + printf("Running in interrupt context, command %s requires pipeline context\n", argv[0]); + return TRUE; + } gboolean result = command(self, argc, argv); g_strfreev(argv); return result; @@ -350,11 +379,20 @@ static void _handle_interactive_prompt(Debugger *self) { gchar buf[1024]; - LogPipe *current_pipe = self->breakpoint_site->pipe; + LogPipe *current_pipe; + + if (self->breakpoint_site) + { + current_pipe = self->breakpoint_site->pipe; - printf("Breakpoint hit %s\n", log_expr_node_format_location(current_pipe->expr_node, buf, sizeof(buf))); - _display_source_line(current_pipe->expr_node); - _display_msg_with_template(self, self->breakpoint_site->msg, self->display_template); + printf("Breakpoint hit %s\n", log_expr_node_format_location(current_pipe->expr_node, buf, sizeof(buf))); + _display_source_line(current_pipe->expr_node); + _display_msg_with_template(self, self->breakpoint_site->msg, self->display_template); + } + else + { + printf("Stopping on interrupt, message related commands are unavailable...\n"); + } while (1) { _fetch_command(self); @@ -374,22 +412,37 @@ _debugger_thread_func(Debugger *self) while (1) { self->breakpoint_site = NULL; - if (!tracer_wait_for_breakpoint(self->tracer, &self->breakpoint_site)) + if (!tracer_wait_for_event(self->tracer, &self->breakpoint_site)) break; _handle_interactive_prompt(self); - tracer_resume_after_breakpoint(self->tracer, self->breakpoint_site); + tracer_resume_after_event(self->tracer, self->breakpoint_site); } scratch_buffers_explicit_gc(); app_thread_stop(); return NULL; } +static void +_interrupt(gpointer user_data) +{ + Debugger *self = (Debugger *) user_data; + + tracer_stop_on_interrupt(self->tracer); +} + void debugger_start_console(Debugger *self) { main_loop_assert_main_thread(); + IV_SIGNAL_INIT(&self->sigint); + self->sigint.signum = SIGINT; + self->sigint.flags = IV_SIGNAL_FLAG_EXCLUSIVE; + self->sigint.cookie = self; + self->sigint.handler = _interrupt; + iv_signal_register(&self->sigint); + self->debugger_thread = g_thread_new(NULL, (GThreadFunc) _debugger_thread_func, self); } @@ -429,6 +482,7 @@ debugger_exit(Debugger *self) { main_loop_assert_main_thread(); + iv_signal_unregister(&self->sigint); tracer_cancel(self->tracer); g_thread_join(self->debugger_thread); } diff --git a/lib/debugger/tracer.c b/lib/debugger/tracer.c index 5ad8e1c74..915e5e5f4 100644 --- a/lib/debugger/tracer.c +++ b/lib/debugger/tracer.c @@ -62,10 +62,20 @@ tracer_stop_on_breakpoint(Tracer *self, BreakpointSite *breakpoint_site) g_mutex_unlock(&self->breakpoint_mutex); } +void +tracer_stop_on_interrupt(Tracer *self) +{ + g_mutex_lock(&self->breakpoint_mutex); + /* send interrupt signal as a NULL */ + g_queue_push_tail(self->waiting_breakpoints, NULL); + g_cond_signal(&self->breakpoint_cond); + g_mutex_unlock(&self->breakpoint_mutex); +} + /* NOTE: called by the interactive debugger to wait for a breakpoint to * trigger, a return of FALSE indicates that the tracing was cancelled */ gboolean -tracer_wait_for_breakpoint(Tracer *self, BreakpointSite **breakpoint_site) +tracer_wait_for_event(Tracer *self, BreakpointSite **breakpoint_site) { gboolean cancelled = FALSE; g_mutex_lock(&self->breakpoint_mutex); @@ -92,13 +102,19 @@ tracer_wait_for_breakpoint(Tracer *self, BreakpointSite **breakpoint_site) /* NOTE: called by the interactive debugger to resume the worker after a breakpoint */ void -tracer_resume_after_breakpoint(Tracer *self, BreakpointSite *breakpoint_site) +tracer_resume_after_event(Tracer *self, BreakpointSite *breakpoint_site) { g_mutex_lock(&self->breakpoint_mutex); g_assert(self->pending_breakpoint == breakpoint_site); - self->pending_breakpoint->resume_requested = TRUE; - self->pending_breakpoint = NULL; - g_cond_broadcast(&self->resume_cond); + if (self->pending_breakpoint) + { + /* we might be returning from an interrupt in which case + * pending_breakpoint is NULL, nothing to resume */ + + self->pending_breakpoint->resume_requested = TRUE; + self->pending_breakpoint = NULL; + g_cond_broadcast(&self->resume_cond); + } g_mutex_unlock(&self->breakpoint_mutex); } diff --git a/lib/debugger/tracer.h b/lib/debugger/tracer.h index de2a8a9da..b0b46f8bb 100644 --- a/lib/debugger/tracer.h +++ b/lib/debugger/tracer.h @@ -38,9 +38,10 @@ typedef struct _BreakpointSite } BreakpointSite; +void tracer_stop_on_interrupt(Tracer *self); void tracer_stop_on_breakpoint(Tracer *self, BreakpointSite *breakpoint_site); -gboolean tracer_wait_for_breakpoint(Tracer *self, BreakpointSite **breakpoint_site); -void tracer_resume_after_breakpoint(Tracer *self, BreakpointSite *breakpoint_site); +gboolean tracer_wait_for_event(Tracer *self, BreakpointSite **breakpoint_site); +void tracer_resume_after_event(Tracer *self, BreakpointSite *breakpoint_site); void tracer_cancel(Tracer *self); Tracer *tracer_new(GlobalConfig *cfg); diff --git a/lib/mainloop.c b/lib/mainloop.c index e126bd339..f03490277 100644 --- a/lib/mainloop.c +++ b/lib/mainloop.c @@ -550,7 +550,6 @@ _register_signal_handler(struct iv_signal *signal_poll, gint signum, void (*hand { IV_SIGNAL_INIT(signal_poll); signal_poll->signum = signum; - signal_poll->flags = IV_SIGNAL_FLAG_EXCLUSIVE; signal_poll->cookie = user_data; signal_poll->handler = handler; iv_signal_register(signal_poll);