Skip to content
This repository
Browse code

Fix spawning [synchronous] commands on Windows

Build command spawning failed sometimes when there were several
pages of errors. In these cases the process would block for 30s and
then abort. (Some hangs were also experienced).

This fix does cause a console window to be shown for the duration of
the spawned process. This seems acceptable compared with the old
broken behaviour, and can be useful to abort the build command by
closing the console window.

Note: If 'env' is passed, the old broken spawning is used.
  • Loading branch information...
commit a3664fae9ece396952d732cc937e63192d8c6f76 1 parent 8855c14
Nick Treleaven ntrel authored

Showing 2 changed files with 79 additions and 9 deletions. Show diff stats Hide diff stats

  1. +8 8 src/build.c
  2. +71 1 src/win32.c
16 src/build.c
@@ -498,7 +498,7 @@ static GeanyBuildCommand *get_build_group(const GeanyBuildSource src, const Gean
498 498 * If any parameter is out of range does nothing.
499 499 *
500 500 * Updates the menu.
501   - *
  501 + *
502 502 **/
503 503 void build_remove_menu_item(const GeanyBuildSource src, const GeanyBuildGroup grp, const gint cmd)
504 504 {
@@ -560,12 +560,12 @@ GeanyBuildCommand *build_get_menu_item(GeanyBuildSource src, GeanyBuildGroup grp
560 560 * This is a pointer to an internal structure and must not be freed.
561 561 *
562 562 **/
563   -const gchar *build_get_current_menu_item(const GeanyBuildGroup grp, const guint cmd,
  563 +const gchar *build_get_current_menu_item(const GeanyBuildGroup grp, const guint cmd,
564 564 const GeanyBuildCmdEntries fld)
565 565 {
566 566 GeanyBuildCommand *c;
567 567 gchar *str = NULL;
568   -
  568 +
569 569 g_return_val_if_fail(grp < GEANY_GBG_COUNT, NULL);
570 570 g_return_val_if_fail(fld < GEANY_BC_CMDENTRIES_COUNT, NULL);
571 571 g_return_val_if_fail(cmd < build_groups_count[grp], NULL);
@@ -593,19 +593,19 @@ const gchar *build_get_current_menu_item(const GeanyBuildGroup grp, const guint
593 593 *
594 594 * Set the specified field of the command specified by @a src, @a grp and @a cmd.
595 595 *
596   - * @param src the source of the menu item
  596 + * @param src the source of the menu item
597 597 * @param grp the group of the specified menu item.
598 598 * @param cmd the index of the menu item within the group.
599 599 * @param fld the field in the menu item command to set
600 600 * @param val the value to set the field to, is copied
601 601 *
602 602 **/
603   -
604   -void build_set_menu_item(const GeanyBuildSource src, const GeanyBuildGroup grp,
  603 +
  604 +void build_set_menu_item(const GeanyBuildSource src, const GeanyBuildGroup grp,
605 605 const guint cmd, const GeanyBuildCmdEntries fld, const gchar *val)
606 606 {
607 607 GeanyBuildCommand **g;
608   -
  608 +
609 609 g_return_if_fail(src < GEANY_BCS_COUNT);
610 610 g_return_if_fail(grp < GEANY_GBG_COUNT);
611 611 g_return_if_fail(fld < GEANY_BC_CMDENTRIES_COUNT);
@@ -827,7 +827,7 @@ static GPid build_spawn_cmd(GeanyDocument *doc, const gchar *cmd, const gchar *d
827 827 &(build_info.pid), NULL, &stdout_fd, &stderr_fd, &error))
828 828 #endif
829 829 {
830   - geany_debug("g_spawn_async_with_pipes() failed: %s", error->message);
  830 + geany_debug("build command spawning failed: %s", error->message);
831 831 ui_set_statusbar(TRUE, _("Process failed (%s)"), error->message);
832 832 g_strfreev(argv);
833 833 g_error_free(error);
72 src/win32.c
@@ -40,6 +40,7 @@
40 40 #include <math.h>
41 41 #include <stdlib.h>
42 42
  43 +#include <glib/gstdio.h>
43 44 #include <gdk/gdkwin32.h>
44 45
45 46 #include "win32.h"
@@ -820,9 +821,28 @@ gchar *win32_get_hostname(void)
820 821 }
821 822
822 823
  824 +static gchar *create_temp_file(void)
  825 +{
  826 + gchar *name;
  827 + gint fd;
  828 +
  829 + fd = g_file_open_tmp("tmp_XXXXXX", &name, NULL);
  830 + if (fd == -1)
  831 + name = NULL;
  832 + else
  833 + close(fd);
  834 +
  835 + return name;
  836 +}
  837 +
  838 +
  839 +/* Sometimes this blocks for 30s before aborting when there are several
  840 + * pages of (error) output and sometimes hangs - see the FIXME.
  841 + * Also gw_spawn.dwExitCode seems to be not set properly. */
823 842 /* Process spawning implementation for Windows, by Pierre Joye.
824 843 * Don't call this function directly, use utils_spawn_[a]sync() instead. */
825   -gboolean win32_spawn(const gchar *dir, gchar **argv, gchar **env, GSpawnFlags flags,
  844 +static
  845 +gboolean _broken_win32_spawn(const gchar *dir, gchar **argv, gchar **env, GSpawnFlags flags,
826 846 gchar **std_out, gchar **std_err, gint *exit_status, GError **error)
827 847 {
828 848 TCHAR buffer[CMDSIZE]=TEXT("");
@@ -980,6 +1000,56 @@ gboolean win32_spawn(const gchar *dir, gchar **argv, gchar **env, GSpawnFlags fl
980 1000 }
981 1001
982 1002
  1003 +/* Simple replacement for _broken_win32_spawn().
  1004 + * flags is ignored, G_SPAWN_SEARCH_PATH is implied.
  1005 + * Don't call this function directly, use utils_spawn_[a]sync() instead.
  1006 + * Adapted from tm_workspace_create_global_tags(). */
  1007 +gboolean win32_spawn(const gchar *dir, gchar **argv, gchar **env, GSpawnFlags flags,
  1008 + gchar **std_out, gchar **std_err, gint *exit_status, GError **error)
  1009 +{
  1010 + gint ret;
  1011 + gboolean fail;
  1012 + gchar *tmp_file = create_temp_file();
  1013 + gchar *tmp_errfile = create_temp_file();
  1014 + gchar *command;
  1015 +
  1016 + if (env != NULL)
  1017 + {
  1018 + return _broken_win32_spawn(dir, argv, env, flags, std_out, std_err,
  1019 + exit_status, error);
  1020 + }
  1021 + if (!tmp_file || !tmp_errfile)
  1022 + {
  1023 + g_warning("%s: Could not create temporary files!", G_STRFUNC);
  1024 + return FALSE;
  1025 + }
  1026 + command = g_strjoinv(" ", argv);
  1027 + SETPTR(command, g_strdup_printf("%s >%s 2>%s",
  1028 + command, tmp_file, tmp_errfile));
  1029 + g_chdir(dir);
  1030 + ret = system(command);
  1031 + /* the command can return -1 as an exit code, so check errno also */
  1032 + fail = ret == -1 && errno;
  1033 + if (!fail)
  1034 + {
  1035 + g_file_get_contents(tmp_file, std_out, NULL, NULL);
  1036 + g_file_get_contents(tmp_errfile, std_err, NULL, NULL);
  1037 + }
  1038 + else if (error)
  1039 + g_set_error_literal(error, G_SPAWN_ERROR, errno, g_strerror(errno));
  1040 +
  1041 + g_free(command);
  1042 + g_unlink(tmp_file);
  1043 + g_free(tmp_file);
  1044 + g_unlink(tmp_errfile);
  1045 + g_free(tmp_errfile);
  1046 + if (exit_status)
  1047 + *exit_status = ret;
  1048 +
  1049 + return !fail;
  1050 +}
  1051 +
  1052 +
983 1053 static gboolean GetContentFromHandle(HANDLE hFile, gchar **content, GError **error)
984 1054 {
985 1055 DWORD filesize;

0 comments on commit a3664fa

Please sign in to comment.
Something went wrong with that request. Please try again.