Branch: refs/heads/master Author: Dimitar Zhekov dimitar.zhekov@gmail.com Committer: Dimitar Zhekov dimitar.zhekov@gmail.com Date: Thu, 01 Oct 2015 17:34:26 UTC Commit: ca339163e5429ad69dbd1509ec7cebfc94d05289 https://github.com/geany/geany-plugins/commit/ca339163e5429ad69dbd1509ec7ceb...
Log Message: ----------- scope: switched GDB I/O to Geany spawn
Consequently removed gdb_buffer_length, gdb_send_interval and gdb_wait_death. Geany 1.25+ required.
Modified Paths: -------------- scope/ChangeLog scope/NEWS scope/NOTES scope/README scope/docs/scope.html scope/src/debug.c scope/src/prefs.c scope/src/prefs.h scope/src/scope.c
Modified: scope/ChangeLog 17 lines changed, 16 insertions(+), 1 deletions(-) =================================================================== @@ -1,8 +1,23 @@ +2015-10-01 Dimitar Zhekov dimitar.zhekov@gmail.com + + * src/debug.c: + Switched gdb I/O to Geany spawn. No more attempts to send the + commands at 50 ms and permanent console under Windows. The gdb + buffer size is now 1 MB (no performance penalty for large buffer + sizes either), longer lines or ones with '\0' are not parsed. + * src/debug.c, src/prefs.c, src/prefs.h, docs/scope.html: + Removed gdb_buffer_length, gdb_send_interval and gdb_wait_death + preferences. Obsoleted by the new gdb I/O and the fact that + spawn sends SIGTERM under *nix, not SIGKILL (though _death was + unneeded anyway). + * docs/scope.html, src/scope.c: + Increased version to 0.94. + + 2015-04-24 Dimitar Zhekov dimitar.zhekov@gmail.com
* data/scope.glade, src/Makefile.am, src/common.h, src/scope.c: Removed support for gtk+ 2.16. - * src/gtk216.c, src/gtk216.h: Removed.
Modified: scope/NEWS 9 lines changed, 9 insertions(+), 0 deletions(-) =================================================================== @@ -1,3 +1,12 @@ +Scope 0.94 (2015-10-01): + + * Better GDB I/O based on Geany spawn, consequently removed + gdb_buffer_length, gdb_send_interval and gdb_wait_death. + To leave the Windows console open on program termination, + set breakpoints at ExitProcess / TerminateProcess. + Geany 1.25+ required. + + Scope 0.93.2 (2014-02-13):
* Remember the total (initial) breakpoint ignore count and
Modified: scope/NOTES 5 lines changed, 1 insertions(+), 4 deletions(-) =================================================================== @@ -48,13 +48,10 @@ insignificant; for large texts, using string is faster, but not much CPU load on F8 with vte console: ~88% with context: ~80%, null output: ~75%
-win~1 hang with poll_pipe(): 1 second for 3h25m -win~1 send on 50ms: 2 seconds for 1h, 1445 KB sent - GtkTextView with wrapping CHAR: the last character of a wrapped line can be selected with the mouse only by moving to the next line
-Geany under Win~1, with FF also running, eats 7-8% CPU time, other +Geany gtk+2 under Win~1, with FF also running, eats 7-8% CPU time, other applications/conditions may cause such CPU load too; scope doesn't matter
http://sourceware.org/bugzilla/show_bug.cgi?id=9659
Modified: scope/README 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -18,7 +18,7 @@ expect (stepping, breakpoints...), and a few notable features:
Requirements ------------ -Geany 1.22 or later and the respective libraries, including VTE under *nix. +Geany 1.25 or later and the respective libraries, including VTE under *nix.
GLib-2.18 or later. For Windows, 2.24 is recommended.
Modified: scope/docs/scope.html 30 lines changed, 12 insertions(+), 18 deletions(-) =================================================================== @@ -50,6 +50,7 @@ <li><a href="#local_watch">Locals/Watches</a></li> <li><a href="#console">Debug Console</a></li> </ul></li> + <li><a href="#windows_console">Windows console</a></li> <li>Side pages<ul> <li><a href="#inspect">Inspect</a></li> <li><a href="#register">Registers</a></li> @@ -101,7 +102,7 @@
<h3><a name="requirements">Requirements</a></h3>
-<p>Geany 1.22 or later and the respective libraries.</p> +<p>Geany 1.25 or later and the respective libraries.</p>
<p>GDB 7.3 or later.</p>
@@ -308,7 +309,7 @@ <p>Sorting by file name (including breakpoint location) uses the full locale name, so the order may be different from the displayed UTF-8 base names.</p>
-<p><b><a name="terminal">Program Terminal</a></b></p> +<p><b><a name="terminal">Program Terminal (*nix only)</a></b></p>
<p>Will be disabled if a pseudo-tty can not be created.</p>
@@ -454,8 +455,7 @@ <p>Groups are not wrapped, so with <em>Group by</em> > 1, less than <em>memory_line_bytes</em> may be displayed.</p>
-<p>A maximum of 16K may be displayed (128 lines * 128 bytes); <em>gdb_buffer_length</em> also -limits the size.</p> +<p>A maximum of 16K may be displayed (128 lines * 128 bytes).</p>
<p><b><a name="console">Debug Console</a></b></p>
@@ -473,6 +473,12 @@ immediately resuming the program execution; or the prompt may be followed by asynchronous messages. The Scope state (Busy, Debug etc.) is more accurate.</p>
+<h3><a name="windows_console">Windows console</a></h3> + +<p>Displayed automatically by Windows when starting a Windows console program, and closed +automatically when the program terminates. To leave the console open on program termination, +set breakpoints at ExitProcess / TerminateProcess.</p> + <h3>Side pages</h3>
<p><b><a name="inspect">Inspect</a></b></p> @@ -514,18 +520,6 @@
<p>[scope]</p>
-<p><em>gdb_buffer_length</em> - the maximum length of a single gdb output message. Longer -messages will be cut, and an "overflow" will be displayed in the debug console, possibly -followed by a few other parsing errors. Default = 16383. Actual value is (the nearest larger -power of 2) - 1, for example 32768 becomes 65535. - -<p><em>gdb_wait_death</em> - hundreds of seconds to wait(3) gdb death on scope unload. -Default = 20. When closing Geany, gdb will be destroyed by the operating system.</p> - -<p><em>gdb_send_interval</em> (win~1 only) - interval on which to retry sending commands to -gdb if it's input buffer is full, in hundreds of seconds. Default = 5. The actual value may be -larger, for example Scope may be activated only 10 times per second if Geany is idle.</p> - <p><em>async_break_bugs</em> (win~1 only) - whether gdb escapes slashes twice in the asynchronous break messages. if true (the default), only <tt>=breakpoint-deleted</tt> will be handled.</p> @@ -589,7 +583,7 @@
<p>[terminal] (*nix only)</p>
-<p><em>width</em>, <em>height</em> - VTE widget (not terminal window) size</p> +<p><em>width</em>, <em>height</em> - VTE widget (not the entire terminal window) size</p>
<p><em>save_pos</em> - auto save window position and widget size</p>
@@ -766,7 +760,7 @@
<b><a name="copyright">Copyright</a></b>
-<p>Scope 0.93.2, Copyright (C) 2013 Dimitar Toshkov Zhekov</p> +<p>Scope 0.94, Copyright (C) 2015 Dimitar Toshkov Zhekov</p>
<p>The menu and toolbar icons are from <a href="http://netbeans.org">Netbeans</a>, except for BreakPoint.</p>
Modified: scope/src/debug.c 694 lines changed, 272 insertions(+), 422 deletions(-) =================================================================== @@ -24,49 +24,8 @@
#include <glib.h>
-#ifdef G_OS_UNIX -#include <sys/types.h> -#include <sys/wait.h> -#include <signal.h> -#else /* G_OS_UNIX */ -#include <windows.h> - -#define WNOHANG 0 - -static int waitpid(HANDLE pid, int *stat_loc, int options) -{ - if (options == WNOHANG) - { - DWORD status; - - if (GetExitCodeProcess(pid, &status)) - { - if (status == STILL_ACTIVE) - return 0; - - if (stat_loc) - *stat_loc = status; - return 1; - } - } - - errno = EINVAL; - return -1; -} - -#define SIGKILL 9 - -static int kill(HANDLE pid, int sig) -{ - if (TerminateProcess(pid, sig)) - return 0; - - errno = EINVAL; - return -1; -} -#endif /* G_OS_UNIX */ - #include "common.h" +#include "spawn.h"
extern guint thread_count; extern guint thread_prompt; @@ -79,57 +38,123 @@ typedef enum _GdbState } GdbState;
static GdbState gdb_state = INACTIVE; -static GSource *gdb_source; static GPid gdb_pid;
-static GPollFD gdb_in = { -1, G_IO_OUT | G_IO_ERR, 0 }; -static GPollFD gdb_out = { -1, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 }; -static GPollFD gdb_err = { -1, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 }; +static gboolean wait_prompt; +static GString *commands;
-static void free_gdb(void) +DebugState debug_state(void) { - g_spawn_close_pid(gdb_pid); - close(gdb_in.fd); - close(gdb_out.fd); - close(gdb_err.fd); + DebugState state; + + if (gdb_state == INACTIVE) + state = DS_INACTIVE; + else if (gdb_state == KILLING || wait_prompt || commands->len) + state = DS_BUSY; + else if (thread_count) + { + if (thread_state <= THREAD_RUNNING) + state = pref_gdb_async_mode || thread_prompt ? DS_READY : DS_BUSY; + else + state = DS_DEBUG; + } + else /* at prompt, no threads */ + state = DS_HANGING; + + return state; }
-static gboolean io_error_show(gpointer gdata) + +void on_debug_list_source(GArray *nodes) { - show_error("%s", (gchar *) gdata); - g_free(gdata); - return FALSE; + ParseLocation loc; + + parse_location(nodes, &loc); + + iff (loc.line, "no line or abs file") + debug_send_format(N, "02-break-insert -t %s:%d\n05", loc.file, loc.line); + + parse_location_free(&loc); }
-#ifdef G_OS_UNIX -static void gdb_io_check(ssize_t count, const char *operation, G_GNUC_UNUSED int eagain) +static gboolean debug_auto_run; +static gboolean debug_auto_exit; +static gboolean debug_load_error; + +void on_debug_error(GArray *nodes) { - if (count == -1 && errno != EAGAIN && gdb_state != KILLING) -#else /* G_OS_UNIX */ -static void gdb_io_check(ssize_t count, const char *operation, int eagain) + debug_auto_run = FALSE; /* may be an initialization command failure */ + on_error(nodes); +} + +void on_debug_loaded(GArray *nodes) { - if (count == -1 && errno != EAGAIN && errno != eagain && gdb_state != KILLING) -#endif /* G_OS_UNIX */ + const char *token = parse_grab_token(nodes); + + if (!debug_load_error && (*token + !*program_load_script >= '1')) { - plugin_idle_add(geany_plugin, io_error_show, - g_strdup_printf(_("%s: %s."), operation, g_strerror(errno))); + breaks_apply(); + inspects_apply(); + view_dirty(VIEW_WATCHES);
- if (kill(gdb_pid, SIGKILL) == -1) + if (program_temp_breakpoint) { - plugin_idle_add(geany_plugin, io_error_show, - g_strdup_printf(_("%s: %s."), "kill(gdb)", g_strerror(errno))); + if (*program_temp_break_location) + { + debug_send_format(N, "02-break-insert -t %s\n05", + program_temp_break_location); + } + else + { + /* 1st loc, dette koi ---*/ + debug_send_command(N, "-gdb-set listsize 1\n" + "02-file-list-exec-source-file\n" + "-gdb-set listsize 10"); + } } + else + debug_send_command(N, "05"); + } +} + +void on_debug_load_error(GArray *nodes) +{ + debug_load_error = TRUE; + on_error(nodes); +} + +void on_debug_auto_run(G_GNUC_UNUSED GArray *nodes) +{ + if (debug_auto_run && !thread_count) + { + if (breaks_active()) + debug_send_command(N, "-exec-run"); + else + dialogs_show_msgbox(GTK_MESSAGE_INFO, _("No breakpoints. Hanging.")); + } +} + +void on_debug_auto_exit(void) +{ + if (debug_auto_exit) + { + debug_send_command(N, "-gdb-exit"); gdb_state = KILLING; } }
+#define G_IO_FAILURE (G_IO_ERR | G_IO_HUP | G_IO_NVAL) /* always used together */ + +static GIOChannel *send_channel = NULL; +static guint send_source_id = 0; static guint wait_result; -static gboolean wait_prompt; -static GString *commands;
-static void send_commands(void) +static gboolean send_commands_cb(GIOChannel *channel, GIOCondition condition, + G_GNUC_UNUSED gpointer gdata) { - ssize_t count = write(gdb_in.fd, commands->str, commands->len); + SpawnWriteData data = { commands->str, commands->len }; + gboolean result = spawn_write_data(channel, condition, &data); + gssize count = commands->len - data.size;
if (count > 0) { @@ -150,28 +175,66 @@ static void send_commands(void) g_string_erase(commands, 0, count); update_state(DS_BUSY); } - else - gdb_io_check(count, "write(gdb_in)", ENOSPC); + + return result; }
-#ifndef G_OS_UNIX -static DWORD last_send_ticks; -#endif +static void send_source_destroy_cb(G_GNUC_UNUSED gpointer gdata) +{ + send_source_id = 0; +} + +/* + * We need to release the initial stdin cb to avoid it being called constantly, and attach a + * source when we have data to send. Unfortunately, glib does not allow re-attaching removed + * sources, so we create one each time. + */ + +static void create_send_source(void) +{ + GSource *send_source = g_io_create_watch(send_channel, G_IO_OUT | G_IO_FAILURE); + + g_io_channel_unref(send_channel); + g_source_set_callback(send_source, (GSourceFunc) send_commands_cb, NULL, + send_source_destroy_cb); + send_source_id = g_source_attach(send_source, NULL); +}
-static void debug_send_commands(void) +#define HAS_SPAWN_LEAVE_STDIN_OPEN 0 + +static gboolean obtain_send_channel_cb(GIOChannel *channel, GIOCondition condition, + G_GNUC_UNUSED gpointer gdata) { - send_commands(); - if (commands->len) +#if HAS_SPAWN_LEAVE_STDIN_OPEN + if (condition & G_IO_FAILURE) + g_io_channel_shutdown(channel, FALSE, NULL); + else { + g_io_channel_ref(channel); + send_channel = channel; + create_send_source(); /* for the initialization commands */ + } +#else + if (!(condition & G_IO_FAILURE)) + { + gint stdin_fd = dup(g_io_channel_unix_get_fd(channel)); + #ifdef G_OS_UNIX - g_source_add_poll(gdb_source, &gdb_in); + send_channel = g_io_channel_unix_new(stdin_fd); + g_io_channel_set_flags(send_channel, G_IO_FLAG_NONBLOCK, NULL); #else - last_send_ticks = GetTickCount(); + send_channel = g_io_channel_win32_new_fd(stdin_fd); #endif + g_io_channel_set_encoding(send_channel, NULL, NULL); + g_io_channel_set_buffered(send_channel, FALSE); + create_send_source(); /* for the initialization commands */ } +#endif + + return FALSE; }
-static void pre_parse(char *string, gboolean overflow) +static void debug_parse(char *string, const char *error) { if (*string && strchr("~@&", *string)) { @@ -189,8 +252,8 @@ static void pre_parse(char *string, gboolean overflow) end = NULL; }
- if (overflow) - dc_error("overflow"); + if (error) + dc_error(error); else if (!end) dc_error("" expected"); else if (g_str_has_prefix(string, "~^(Scope)#07")) @@ -207,14 +270,9 @@ static void pre_parse(char *string, gboolean overflow)
for (message = string; isdigit(*message); message++);
- if (option_library_messages || !g_str_has_prefix(message, "=library-")) - { + if (error || option_library_messages || !g_str_has_prefix(message, "=library-")) dc_output_nl(1, string, -1);
- if (overflow) - dc_error("overflow"); - } - if (*message == '^') { iff (wait_result, "extra result") @@ -229,269 +287,82 @@ static void pre_parse(char *string, gboolean overflow) else string = NULL; /* no token */
- parse_message(message, string); + if (error) + dc_error("%s, ignoring to EOLN", error); + else + parse_message(message, string); } }
-static guint MAXLEN; -static GString *received; -static gboolean leading_receive; -static char *reading_pos; +static gboolean leading_receive; /* FALSE for continuation of a too long / incomplete line */
-static gboolean source_prepare(G_GNUC_UNUSED GSource *source, gint *timeout) +static void receive_output_cb(GString *string, GIOCondition condition, + G_GNUC_UNUSED gpointer gdata) { - *timeout = -1; - return gdb_state != INACTIVE && reading_pos > received->str; -} - -#ifdef G_OS_UNIX -static gboolean source_check(G_GNUC_UNUSED GSource *source) -{ - return gdb_state != INACTIVE && (gdb_err.revents || reading_pos > received->str || - gdb_out.revents || (commands->len && gdb_in.revents)); -} -#else /* G_OS_UNIX */ -static gboolean peek_pipe(GPollFD *fd) -{ - DWORD available; - return !PeekNamedPipe((HANDLE) _get_osfhandle(fd->fd), NULL, 0, NULL, &available, - NULL) || available; -} - -static gboolean source_check(G_GNUC_UNUSED GSource *source) -{ - return gdb_state != INACTIVE && (reading_pos > received->str || peek_pipe(&gdb_err) || - peek_pipe(&gdb_out) || (commands->len && - GetTickCount() - last_send_ticks >= (guint) pref_gdb_send_interval * 10)); -} -#endif /* G_OS_UNIX */ - -static guint source_id = 0; - -static gboolean source_dispatch(G_GNUC_UNUSED GSource *source, - G_GNUC_UNUSED GSourceFunc callback, G_GNUC_UNUSED gpointer gdata) -{ - int status; - pid_t result; - ssize_t count; - char buffer[0x200]; - char *pos; - - /* show errors */ - while ((count = read(gdb_err.fd, buffer, sizeof buffer - 1)) > 0) - dc_output(2, buffer, count); - - gdb_io_check(count, "read(gdb_err)", EINVAL); - - /* receive */ - count = read(gdb_out.fd, received->str + received->len, MAXLEN - received->len); - - if (count > 0) - g_string_set_size(received, received->len + count); - else - gdb_io_check(count, "read(gdb_out)", EINVAL); - - while (pos = reading_pos, (reading_pos = strchr(pos, '\n')) != NULL) - { - if (leading_receive) - { - #ifdef G_OS_UNIX - *reading_pos++ = '\0'; - #else - gboolean cr = reading_pos > received->str && reading_pos[-1] == '\r'; - reading_pos[-cr]= '\0'; - reading_pos++; - #endif - pre_parse(pos, FALSE); - } - else - { - reading_pos++; - leading_receive = TRUE; - } - } - - g_string_erase(received, 0, pos - received->str); - - if (G_UNLIKELY(received->len == MAXLEN)) + if (condition & (G_IO_IN | G_IO_PRI)) { - if (leading_receive) - { - reading_pos = received->str + MAXLEN; - pre_parse(received->str, TRUE); - } - g_string_truncate(received, 0); - leading_receive = FALSE; - } + char *term = string->str + string->len - 1; + const char *error = NULL;
- reading_pos = received->str; - result = waitpid(gdb_pid, &status, WNOHANG); - - if (result == 0) - { - if (commands->len) + switch (*term) { - /* send */ - #ifdef G_OS_UNIX - send_commands(); - if (!commands->len) - g_source_remove_poll(gdb_source, &gdb_in); - #else - debug_send_commands(); - #endif - } - else - { - /* idle update */ - DebugState state = debug_state(); - - if (state & DS_SENDABLE) - views_update(state); + case '\n' : if (string->len >= 2 && term[-1] == '\r') term--; /* falldown */ + case '\r' : *term = '\0'; break; + case '\0' : error = "binary zero encountered"; break; + default : error = "line too long or incomplete"; } - } - else if (gdb_state != INACTIVE) - { - GdbState state = gdb_state; - /* shutdown */ - gdb_state = INACTIVE; - signal(SIGINT, SIG_DFL); - g_source_remove(source_id); - - if (result == -1) - show_errno("waitpid(gdb)"); - else if (state == ACTIVE) - show_error(_("GDB died unexpectedly with status %d."), status); - else if (thread_count) - ui_set_statusbar(FALSE, _("Program terminated.")); - - free_gdb(); - views_clear(); - utils_lock_all(FALSE); - } - - update_state(debug_state());
- return TRUE; -} - -static void source_finalize(G_GNUC_UNUSED GSource *source) -{ - source_id = 0; -} - -DebugState debug_state(void) -{ - DebugState state; + if (leading_receive) + debug_parse(string->str, error);
- if (gdb_state == INACTIVE) - state = DS_INACTIVE; - else if (gdb_state == KILLING || wait_prompt || commands->len) - state = DS_BUSY; - else if (thread_count) - { - if (thread_state <= THREAD_RUNNING) - state = pref_gdb_async_mode || thread_prompt ? DS_READY : DS_BUSY; - else - state = DS_DEBUG; + leading_receive = !error; } - else /* at prompt, no threads */ - state = DS_HANGING;
- return state; -} - -static gboolean debug_auto_run; -static gboolean debug_auto_exit; - -void on_debug_list_source(GArray *nodes) -{ - ParseLocation loc; - - parse_location(nodes, &loc); + if (!commands->len) + views_update(debug_state());
- iff (loc.line, "no line or abs file") - debug_send_format(N, "02-break-insert -t %s:%d\n05", loc.file, loc.line); - - parse_location_free(&loc); + update_state(debug_state()); }
-void on_debug_error(GArray *nodes) +static void receive_errors_cb(GString *string, GIOCondition condition, + G_GNUC_UNUSED gpointer gdata) { - debug_auto_run = FALSE; - on_error(nodes); + if (condition & (G_IO_IN | G_IO_PRI)) + dc_output(2, string->str, string->len); }
-static gboolean debug_load_error; - -void on_debug_loaded(GArray *nodes) +static void gdb_finalize(void) { - const char *token = parse_grab_token(nodes); + signal(SIGINT, SIG_DFL);
- if (!debug_load_error && (*token + !*program_load_script >= '1')) + if (send_channel) { - breaks_apply(); - inspects_apply(); - view_dirty(VIEW_WATCHES); + g_io_channel_shutdown(send_channel, FALSE, NULL); + g_io_channel_unref(send_channel); + send_channel = NULL;
- if (program_temp_breakpoint) - { - if (*program_temp_break_location) - { - debug_send_format(N, "02-break-insert -t %s\n05", - program_temp_break_location); - } - else - { - /* 1st loc, dette koi ---*/ - debug_send_command(N, "-gdb-set listsize 1\n" - "02-file-list-exec-source-file\n" - "-gdb-set listsize 10"); - } - } - else - debug_send_command(N, "05"); + if (send_source_id) + g_source_remove(send_source_id); } }
-void on_debug_load_error(GArray *nodes) +static void gdb_exit_cb(G_GNUC_UNUSED GPid pid, gint status, G_GNUC_UNUSED gpointer gdata) { - debug_load_error = TRUE; - on_error(nodes); -} + GdbState saved_state = gdb_state;
-void on_debug_auto_run(G_GNUC_UNUSED GArray *nodes) -{ - if (debug_auto_run && !thread_count) - { - if (breaks_active()) - debug_send_command(N, "-exec-run"); - else - dialogs_show_msgbox(GTK_MESSAGE_INFO, _("No breakpoints. Hanging.")); - } -} + gdb_finalize(); + gdb_state = INACTIVE;
-static void gdb_exit(void) -{ - debug_send_command(N, "-gdb-exit"); - gdb_state = KILLING; -} + if (saved_state == ACTIVE) + show_error(_("GDB died unexpectedly with status %d."), status); + else if (thread_count) + ui_set_statusbar(FALSE, _("Program terminated."));
-void on_debug_auto_exit(void) -{ - if (debug_auto_exit) - gdb_exit(); + views_clear(); + utils_lock_all(FALSE); + update_state(DS_INACTIVE); }
-static GSourceFuncs gdb_source_funcs = -{ - source_prepare, - source_check, - source_dispatch, - source_finalize, - NULL, - NULL -}; - static void append_startup(const char *command, const gchar *value) { if (value && *value) @@ -502,7 +373,15 @@ static void append_startup(const char *command, const gchar *value) } }
-#define GDB_SPAWN_FLAGS (G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD) +#if HAS_SPAWN_LEAVE_STDIN_OPEN +#define GDB_SPAWN_FLAGS (SPAWN_STDERR_UNBUFFERED | SPAWN_STDOUT_RECURSIVE | \ + SPAWN_STDERR_RECURSIVE | SPAWN_LEAVE_STDIN_OPEN) +#else +#define GDB_SPAWN_FLAGS (SPAWN_STDERR_UNBUFFERED | SPAWN_STDOUT_RECURSIVE | \ + SPAWN_STDERR_RECURSIVE) +#endif + +#define GDB_BUFFER_SIZE ((1 << 20) - 1) /* spawn adds 1 for '\0' */
static void load_program(void) { @@ -515,83 +394,62 @@ static void load_program(void) while (gtk_events_pending()) gtk_main_iteration();
- if (g_spawn_async_with_pipes(NULL, args, NULL, GDB_SPAWN_FLAGS, NULL, NULL, &gdb_pid, - &gdb_in.fd, &gdb_out.fd, &gdb_err.fd, &gerror)) + if (spawn_with_callbacks(NULL, NULL, args, NULL, GDB_SPAWN_FLAGS, obtain_send_channel_cb, + NULL, receive_output_cb, NULL, GDB_BUFFER_SIZE, receive_errors_cb, NULL, 0, + gdb_exit_cb, NULL, &gdb_pid, &gerror)) { + gchar **environment = g_strsplit(program_environment, "\n", -1); + gchar *const *envar; + #ifdef G_OS_UNIX + extern char *slave_pty_name; + #else + GString *escaped = g_string_new(program_executable); + #endif + + /* startup */ gdb_state = ACTIVE; + dc_clear(); + utils_lock_all(TRUE); + signal(SIGINT, SIG_IGN); + wait_result = 0; + wait_prompt = TRUE; + g_string_truncate(commands, 0); + leading_receive = TRUE;
- if (utils_set_nonblock(&gdb_in) && utils_set_nonblock(&gdb_out) && - utils_set_nonblock(&gdb_err)) + if (pref_gdb_async_mode) + g_string_append(commands, "-gdb-set target-async on\n"); + if (program_non_stop_mode) + g_string_append(commands, "-gdb-set non-stop on\n"); + #ifdef G_OS_UNIX + append_startup("010-file-exec-and-symbols", program_executable); + append_startup("-gdb-set inferior-tty", slave_pty_name); + #else /* G_OS_UNIX */ + utils_string_replace_all(escaped, "\", "\\"); + append_startup("010-file-exec-and-symbols", escaped->str); + g_string_free(escaped, TRUE); + g_string_append(commands, "-gdb-set new-console on\n"); + #endif /* G_OS_UNIX */ + append_startup("-environment-cd", program_working_dir); /* no escape needed */ + append_startup("-exec-arguments", program_arguments); + for (envar = environment; *envar; envar++) + append_startup("-gdb-set environment", *envar); + g_strfreev(environment); + append_startup("011source -v", program_load_script); + g_string_append(commands, "07-list-target-features\n"); + breaks_query_async(commands); + + if (*program_executable || *program_load_script) { - gchar **environment = g_strsplit(program_environment, "\n", -1); - gchar *const *envar; - #ifdef G_OS_UNIX - extern char *slave_pty_name; - #else - GString *escaped = g_string_new(program_executable); - #endif - - /* startup */ - dc_clear(); - utils_lock_all(TRUE); - signal(SIGINT, SIG_IGN); - wait_result = 0; - wait_prompt = TRUE; - g_string_truncate(commands, 0); - g_string_truncate(received, 0); - reading_pos = received->str; - leading_receive = TRUE; - - gdb_source = g_source_new(&gdb_source_funcs, sizeof(GSource)); - g_source_set_can_recurse(gdb_source, TRUE); - source_id = g_source_attach(gdb_source, NULL); - g_source_unref(gdb_source); - #ifdef G_OS_UNIX - g_source_add_poll(gdb_source, &gdb_out); - g_source_add_poll(gdb_source, &gdb_err); - #endif - if (pref_gdb_async_mode) - g_string_append(commands, "-gdb-set target-async on\n"); - if (program_non_stop_mode) - g_string_append(commands, "-gdb-set non-stop on\n"); - #ifdef G_OS_UNIX - append_startup("010-file-exec-and-symbols", program_executable); - append_startup("-gdb-set inferior-tty", slave_pty_name); - #else /* G_OS_UNIX */ - utils_string_replace_all(escaped, "\", "\\"); - append_startup("010-file-exec-and-symbols", escaped->str); - g_string_free(escaped, TRUE); - #endif /* G_OS_UNIX */ - append_startup("-environment-cd", program_working_dir); - append_startup("-exec-arguments", program_arguments); - for (envar = environment; *envar; envar++) - append_startup("-gdb-set environment", *envar); - g_strfreev(environment); - append_startup("011source -v", program_load_script); - g_string_append(commands, "07-list-target-features\n"); - breaks_query_async(commands); - - if (*program_executable || *program_load_script) - { - debug_load_error = FALSE; - debug_auto_run = debug_auto_exit = program_auto_run_exit; - } - else - debug_auto_run = debug_auto_exit = FALSE; - - if (option_open_panel_on_load) - open_debug_panel(); - - registers_query_names(); - debug_send_commands(); + debug_load_error = FALSE; + debug_auto_run = debug_auto_exit = program_auto_run_exit; } else - { - show_errno("fcntl(O_NONBLOCK)"); + debug_auto_run = debug_auto_exit = FALSE;
- if (kill(gdb_pid, SIGKILL) == -1) - show_errno("kill(gdb)"); - } + if (option_open_panel_on_load) + open_debug_panel(); + + registers_query_names(); } else { @@ -671,25 +529,35 @@ void on_debug_terminate(const MenuItem *menu_item) { switch (debug_state()) { - case DS_DEBUG : + case DS_BUSY : + { + GError *gerror = NULL; + + gdb_state = KILLING; + + if (!spawn_kill_process(gdb_pid, &gerror)) + { + show_error(_("%s."), gerror->message); + g_error_free(gerror); + } + + break; + } case DS_READY : + case DS_DEBUG : { if (menu_item && !debug_auto_exit) { debug_send_command(N, "kill"); break; } - } - case DS_HANGING : - { - gdb_exit(); - break; + /* falldown */ } default : { + debug_send_command(N, "-gdb-exit"); gdb_state = KILLING; - if (kill(gdb_pid, SIGKILL) == -1) - show_errno("kill(gdb)"); + break; } } } @@ -698,7 +566,6 @@ void debug_send_command(gint tf, const char *command) { if (gdb_state == ACTIVE) { - gsize previous_len = commands->len; const char *s;
for (s = command; *s && !isspace(*s); s++); @@ -715,8 +582,8 @@ void debug_send_command(gint tf, const char *command) g_string_append(commands, s); g_string_append_c(commands, '\n');
- if (!previous_len) - debug_send_commands(); + if (send_channel && !send_source_id) + create_send_source(); } }
@@ -753,33 +620,16 @@ char *debug_send_evaluate(char token, gint scid, const gchar *expr) void debug_init(void) { commands = g_string_sized_new(0x3FFF); - received = g_string_sized_new(pref_gdb_buffer_length); - MAXLEN = received->allocated_len - 1; }
void debug_finalize(void) { - if (source_id) - { - signal(SIGINT, SIG_DFL); - g_source_remove(source_id); - } - if (gdb_state != INACTIVE) { - gint count = 0; - - if (kill(gdb_pid, SIGKILL) == 0) - { - g_usleep(G_USEC_PER_SEC / 1000); - while (waitpid(gdb_pid, NULL, WNOHANG) == 0 && count++ < pref_gdb_wait_death) - g_usleep(G_USEC_PER_SEC / 100); - } - - free_gdb(); /* may be still alive, but we can't do anything more */ + spawn_kill_process(gdb_pid, NULL); + gdb_finalize(); statusbar_update_state(DS_INACTIVE); }
- g_string_free(received, TRUE); g_string_free(commands, TRUE); }
Modified: scope/src/prefs.c 30 lines changed, 27 insertions(+), 3 deletions(-) =================================================================== @@ -28,7 +28,6 @@
gchar *pref_gdb_executable; gboolean pref_gdb_async_mode; -gint pref_gdb_buffer_length; gint pref_gdb_wait_death; #ifndef G_OS_UNIX gint pref_gdb_send_interval; @@ -143,6 +142,9 @@ static void load_scope_prefs(GKeyFile *config) } }
+static const char *obsolete_prefs[] = { "gdb_buffer_length", "gdb_wait_death", + "gdb_send_interval", NULL }; + static void save_scope_prefs(GKeyFile *config) { guint i; @@ -165,6 +167,9 @@ static void save_scope_prefs(GKeyFile *config) g_key_file_set_string(config, style->name, "back", tmp_string); g_free(tmp_string); } + + for (i = 0; obsolete_prefs[i]; i++) + g_key_file_remove_key(config, "scope", obsolete_prefs[i], NULL); }
static void prefs_configure(void) @@ -223,11 +228,11 @@ void prefs_init(void) char *configdir = g_build_filename(geany->app->configdir, "plugins", "scope", NULL); char *configfile = prefs_file_name(); GKeyFile *config = g_key_file_new(); + gboolean obsolete = FALSE;
group = stash_group_new("scope"); stash_group_add_string(group, &pref_gdb_executable, "gdb_executable", "gdb"); stash_group_add_boolean(group, &pref_gdb_async_mode, "gdb_async_mode", FALSE); - stash_group_add_integer(group, &pref_gdb_buffer_length, "gdb_buffer_length", 32767); stash_group_add_integer(group, &pref_gdb_wait_death, "gdb_wait_death", 20); #ifndef G_OS_UNIX stash_group_add_integer(group, &pref_gdb_send_interval, "gdb_send_interval", 5); @@ -282,11 +287,30 @@ void prefs_init(void)
g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL); load_scope_prefs(config); + + for (i = 0; obsolete_prefs[i]; i++) + { + GError *gerror = NULL; + + g_key_file_get_integer(config, "scope", obsolete_prefs[i], &gerror); + + if (gerror) + { + g_error_free(gerror); + gerror = NULL; + } + else + { + obsolete = TRUE; + break; + } + } + pref_sci_marker_first = pref_sci_marker_1st; prefs_configure(); program_load_config(config);
- if (!g_file_test(configfile, G_FILE_TEST_IS_REGULAR)) + if (obsolete || !g_file_test(configfile, G_FILE_TEST_IS_REGULAR)) { gint error = utils_mkdir(configdir, TRUE);
Modified: scope/src/prefs.h 1 lines changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -21,7 +21,6 @@
extern gchar *pref_gdb_executable; extern gboolean pref_gdb_async_mode; -extern gint pref_gdb_buffer_length; extern gint pref_gdb_wait_death; #ifndef G_OS_UNIX extern gint pref_gdb_send_interval;
Modified: scope/src/scope.c 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -29,10 +29,10 @@ GeanyPlugin *geany_plugin; GeanyData *geany_data; GeanyFunctions *geany_functions;
-PLUGIN_VERSION_CHECK(215) +PLUGIN_VERSION_CHECK(224)
PLUGIN_SET_TRANSLATABLE_INFO(LOCALEDIR, GETTEXT_PACKAGE, _("Scope Debugger"), - _("Relatively simple GDB front-end."), "0.93.2", + _("Relatively simple GDB front-end."), "0.94", "Dimitar Toshkov Zhekov dimitar.zhekov@gmail.com")
/* Keybinding(s) */
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
plugins-commits@lists.geany.org