e: full rewrite of our WBOD.
authorCedric BAIL <cedric.bail@free.fr>
Thu, 1 Nov 2012 06:23:49 +0000 (06:23 +0000)
committerCedric BAIL <cedric.bail@free.fr>
Thu, 1 Nov 2012 06:23:49 +0000 (06:23 +0000)
NOTE: the new behaviour require a parent process,
here enlightenment_start, to watch over enlightenment.
It does use ptrace to monitor his child and track
what is going on. When a crash happen it ask gdb to
add the backtrace directly into .xsession-errors.

If you use systemd user session, you may want to offload
that work to systemd. You can do so, but don't forget to
pass -nopause to enlightenment when you start it.

WARNING: For all user, you will need to exit your
current session and start a fresh one for this new WBOD
to work at all. Just restarting Enlightenment will not
help you.

SVN revision: 78742

src/bin/e.h
src/bin/e_alert.c
src/bin/e_alert.h
src/bin/e_alert_main.c
src/bin/e_main.c
src/bin/e_signals.c
src/bin/e_start_main.c

index e56c788..03b7a30 100644 (file)
@@ -278,6 +278,7 @@ extern EAPI Eina_Bool evil;
 extern EAPI Eina_Bool starting;
 extern EAPI Eina_Bool stopping;
 extern EAPI Eina_Bool restart;
+extern EAPI Eina_Bool e_nopause;
 
 extern EAPI Eina_Bool e_precache_end;
 extern EAPI Eina_Bool x_fatal;
index e24c63f..a38c252 100644 (file)
@@ -30,62 +30,12 @@ e_alert_composite_win(Ecore_X_Window root, Ecore_X_Window comp)
 }
 
 EAPI void
-e_alert_show(int sig)
+e_alert_show(void)
 {
-   char *args[4];
-   pid_t pid;
-
-#define E_ALERT_EXE "/enlightenment/utils/enlightenment_alert"
-
-   args[0] = alloca(strlen(e_prefix_lib_get()) + strlen(E_ALERT_EXE) + 1);
-   strcpy(args[0], e_prefix_lib_get());
-   strcat(args[0], E_ALERT_EXE);
-
-   args[1] = alloca(10);
-   snprintf(args[1], 10, "%d", sig);
-
-   args[2] = alloca(21);
-   snprintf(args[2], 21, "%lu", (long unsigned int)getpid());
-
-   args[3] = NULL;   
-
-   pid = fork();
-   if (pid < -1)
-     goto restart_e;
-
-   if (pid == 0)
-     {
-        /* The child process */
-        execvp(args[0], args);
-     }
-   else
+   if (!e_nopause)
      {
-        /* The parent process */
-        pid_t ret;
-        int status = 0;
-
-        do
-          {
-             ret = waitpid(pid, &status, 0);
-             if (errno == ECHILD)
-               break ;
-          }
-        while (ret != pid);
-
-        if (status == 0)
-          goto restart_e;
-
-        if (!WIFEXITED(status))
-          goto restart_e;
-
-        if (WEXITSTATUS(status) == 1)
-          goto restart_e;
-
-        exit(-11);
+        fprintf(stderr, "PAUSE !\n");
+        pause();
      }
-
- restart_e:
-   if (getenv("E_START_MTRACK"))
-     e_util_env_set("MTRACK", "track");
-   ecore_app_restart();
+   return ;
 }
index 68aafea..dead6c7 100644 (file)
@@ -13,7 +13,7 @@ typedef enum _E_Alert_Op_Type
 EINTERN int e_alert_init(void);
 EINTERN int e_alert_shutdown(void);
 
-EAPI void e_alert_show(int sig);
+EAPI void e_alert_show(void);
 
 #endif
 #endif
index 1888878..0bde77e 100644 (file)
@@ -51,6 +51,7 @@ static const char *title = NULL, *str1 = NULL, *str2 = NULL;
 static int ret = 0, sig = 0;
 static pid_t pid;
 static Eina_Bool tainted = EINA_TRUE;
+static const char *backtrace = NULL;
 
 int
 main(int argc, char **argv)
@@ -72,6 +73,8 @@ main(int argc, char **argv)
           sig = atoi(argv[i]); // signal
         else if (i == 2)
           pid = atoi(argv[i]); // E's pid
+       else if (i == 3)
+         backtrace = argv[i];
      }
 
    tmp = getenv("E17_TAINTED");
@@ -519,15 +522,33 @@ _e_alert_draw_text(void)
 
    if (!tainted)
      {
-        snprintf(msg, sizeof(msg),
-                 "This is not meant to happen and is likely a sign of \n"
-                 "a bug in Enlightenment or the libraries it relies \n"
-                 "on. You can gdb attach to this process (%d) now \n"
-                 "to try debug it or you could exit, or just hit \n"
-                 "restart to try and get your desktop back the way \n"
-                 "it was.\n"
-                 "\n"
-                 "Please compile E17 and EFL with -g in your CFLAGS.\n", pid);
+        if (backtrace)
+          {
+             snprintf(msg, sizeof(msg),
+                      "This is not meant to happen and is likely a sign of \n"
+                      "a bug in Enlightenment or the libraries it relies \n"
+                      "on. You will find an backtrace of E17 (%d) in :\n"
+                      "'%s'\n"
+                      "Before reporting issue, compile latest E17 and EFL\n"
+                      "from svn with '-g -ggdb3' in your CFLAGS.\n"
+                      "You can then report this crash on :\n"
+                      "http://trac.enlightenment.org/e/.\n",
+                      pid, backtrace);
+          }
+        else
+          {
+             snprintf(msg, sizeof(msg),
+                      "This is not meant to happen and is likely a sign of \n"
+                      "a bug in Enlightenment or the libraries it relies \n"
+                      "on. You can gdb attach to this process (%d) now \n"
+                      "to try debug it or you could exit, or just hit \n"
+                      "restart to try and get your desktop back the way \n"
+                      "it was.\n"
+                      "\n"
+                      "Please compile latest svn E17 and EFL with\n"
+                      "-g and -ggdb3 in your CFLAGS.\n", pid);
+
+          }
      }
    else
      {
@@ -536,7 +557,8 @@ _e_alert_draw_text(void)
                  "a sign of a bug, but you are using unsupported\n"
                  "modules; before reporting this issue, please\n"
                  "unload them and try to see if the bug is still\n"
-                 "there.\n");
+                 "there. Also update to latest svn and be sure to\n"
+                "compile E17 and EFL with -g and -ggdb3 in your CFLAGS");
      }
 
    strcpy(warn, "");
index ff9e784..c585ffa 100644 (file)
@@ -122,6 +122,7 @@ EAPI Eina_Bool evil = EINA_FALSE;
 EAPI Eina_Bool starting = EINA_TRUE;
 EAPI Eina_Bool stopping = EINA_FALSE;
 EAPI Eina_Bool restart = EINA_FALSE;
+EAPI Eina_Bool e_nopause = EINA_FALSE;
 
 static void
 _xdg_data_dirs_augment(void)
@@ -1200,6 +1201,8 @@ _e_main_parse_arguments(int argc, char **argv)
           really_know = EINA_TRUE;
         else if (!strcmp(argv[i], "-locked"))
           locked = EINA_TRUE;
+       else if (!strcmp(argv[i], "-nopause"))
+         e_nopause = EINA_TRUE;
         else if ((!strcmp(argv[i], "-h")) ||
                  (!strcmp(argv[i], "-help")) ||
                  (!strcmp(argv[i], "--help")))
index 59ccd39..b095b52 100644 (file)
@@ -54,121 +54,60 @@ _e_write_safe_int(int fd, const char *buf, size_t size)
      }
 }
 
-static void
-_e_gdb_print_backtrace(int fd __UNUSED__)
-{
-   // FIXME: we are in a segv'd state. do as few function calls and things
-   // depending on a known working state as possible. this also prevents the
-   // white box allowing recovery or deeper gdbing, thus until this works
-   // properly, it's disabled (properly means always reliable, always
-   // printf bt and allows e to continue and pop up box, perferably allowing
-   // debugging in the gui etc. etc.
-#if 0
-   char cmd[1024];
-   size_t size;
-   int ret;
-
-   if (getenv("E_NO_GDB_BACKTRACE"))
-     return;
-
-   size = snprintf(cmd, sizeof(cmd),
-                  "gdb --pid=%d "
-                  "-ex 'thread apply all bt' "
-                  "-ex detach -ex quit", getpid());
-
-   if (size >= sizeof(cmd))
-     return;
-
-   _e_write_safe(fd, "EXECUTING GDB AS: ");
-   _e_write_safe_int(fd, cmd, size);
-   _e_write_safe(fd, "\n");
-   ret = system(cmd); // TODO: use popen() or fork()+pipe()+exec() and save to 'fd'
-#endif
-}
-
-#define _e_backtrace(msg) _e_backtrace_int(2, msg, sizeof(msg))
-static void
-_e_backtrace_int(int fd, const char *msg, size_t msg_len)
-{
-   char attachmsg[1024];
-   void *array[255];
-   size_t size;
-
-   return; // disable. causes hangs and problems
-
-   _e_write_safe_int(fd, msg, msg_len);
-   _e_write_safe(fd, "\nBEGIN TRACEBACK\n");
-   size = backtrace(array, 255);
-   backtrace_symbols_fd(array, size, fd);
-   _e_write_safe(fd, "END TRACEBACK\n");
-
-   size = snprintf(attachmsg, sizeof(attachmsg),
-                  "debug with: gdb --pid=%d\n", getpid());
-   if (size < sizeof(attachmsg))
-     _e_write_safe_int(fd, attachmsg, size);
-
-   _e_gdb_print_backtrace(fd);
-}
-
 /* a tricky little devil, requires e and it's libs to be built
  * with the -rdynamic flag to GCC for any sort of decent output.
  */
 EAPI void
 e_sigseg_act(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
 {
-   _e_backtrace("**** SEGMENTATION FAULT ****");
    _e_x_composite_shutdown();
    ecore_x_pointer_ungrab();
    ecore_x_keyboard_ungrab();
    ecore_x_ungrab();
    ecore_x_sync();
-   e_alert_show(SIGSEGV);
+   e_alert_show();
 }
 
 EAPI void
 e_sigill_act(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
 {
-   _e_backtrace("**** ILLEGAL INSTRUCTION ****");
    _e_x_composite_shutdown();
    ecore_x_pointer_ungrab();
    ecore_x_keyboard_ungrab();
    ecore_x_ungrab();
    ecore_x_sync();
-   e_alert_show(SIGILL);
+   e_alert_show();
 }
 
 EAPI void
 e_sigfpe_act(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
 {
-   _e_backtrace("**** FLOATING POINT EXCEPTION ****");
    _e_x_composite_shutdown();
    ecore_x_pointer_ungrab();
    ecore_x_keyboard_ungrab();
    ecore_x_ungrab();
    ecore_x_sync();
-   e_alert_show(SIGFPE);
+   e_alert_show();
 }
 
 EAPI void
 e_sigbus_act(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
 {
-   _e_backtrace("**** BUS ERROR ****");
    _e_x_composite_shutdown();
    ecore_x_pointer_ungrab();
    ecore_x_keyboard_ungrab();
    ecore_x_ungrab();
    ecore_x_sync();
-   e_alert_show(SIGBUS);
+   e_alert_show();
 }
 
 EAPI void
 e_sigabrt_act(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
 {
-   _e_backtrace("**** ABORT ****");
    _e_x_composite_shutdown();
    ecore_x_pointer_ungrab();
    ecore_x_keyboard_ungrab();
    ecore_x_ungrab();
    ecore_x_sync();
-   e_alert_show(SIGABRT);
+   e_alert_show();
 }
index 09e0c14..68900f5 100644 (file)
@@ -8,13 +8,18 @@
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/utsname.h>
+#include <sys/ptrace.h>
 #include <limits.h>
 #include <fcntl.h>
 #ifdef HAVE_ALLOCA_H
 # include <alloca.h>
 #endif
+#include <signal.h>
+
 #include <Eina.h>
 
+static Eina_Bool tainted = EINA_FALSE;
+
 static void env_set(const char *var, const char *val);
 EAPI int    prefix_determine(char *argv0);
 
@@ -217,12 +222,28 @@ main(int argc, char **argv)
    int i, valgrind_mode = 0;
    int valgrind_tool = 0;
    int valgrind_gdbserver = 0;
-   char buf[16384], **args, *p;
+   char buf[16384], **args, *home;
    char valgrind_path[PATH_MAX] = "";
    const char *valgrind_log = NULL;
    Eina_Bool really_know = EINA_FALSE;
+   Eina_Bool restart = EINA_TRUE;
 
    eina_init();
+
+   /* reexcute myself with dbus-launch if dbus-launch is not running yet */
+   if ((!getenv("DBUS_SESSION_BUS_ADDRESS")) &&
+       (!getenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET"))) 
+     {
+        char **dbus_argv;
+
+        dbus_argv = alloca(argc + 3 + sizeof (char *));
+        dbus_argv[0] = "dbus-launch";
+        dbus_argv[1] = "--exit-with-session";
+        copy_args(dbus_argv + 2, argv, argc);
+        dbus_argv[2 + argc] = NULL;
+        execvp("dbus-launch", dbus_argv);
+     }
+
    prefix_determine(argv[0]);
 
    env_set("E_START", argv[0]);
@@ -254,6 +275,11 @@ main(int argc, char **argv)
              else
                printf("Unknown valgrind option: %s\n", argv[i]);
           }
+        else if (!strcmp(argv[i], "-display"))
+          {
+             i++;
+             env_set("DISPLAY", argv[i]);
+          }
         else if (!strcmp(argv[i], "-massif"))
           valgrind_tool = 1;
         else if (!strcmp(argv[i], "-callgrind"))
@@ -312,15 +338,15 @@ main(int argc, char **argv)
    putchar('\n');
 
    /* mtrack memory tracker support */
-   p = getenv("HOME");
-   if (p)
+   home = getenv("HOME");
+   if (home)
      {
         FILE *f;
 
         /* if you have ~/.e-mtrack, then the tracker will be enabled
          * using the content of this file as the path to the mtrack.so
          * shared object that is the mtrack preload */
-        snprintf(buf, sizeof(buf), "%s/.e-mtrack", p);
+        snprintf(buf, sizeof(buf), "%s/.e-mtrack", home);
         f = fopen(buf, "r");
         if (f)
           {
@@ -335,40 +361,143 @@ main(int argc, char **argv)
                   env_set("LD_PRELOAD", buf);
                   env_set("MTRACK", "track");
                   env_set("E_START_MTRACK", "track");
-                  snprintf(buf, sizeof(buf), "%s/.e-mtrack.log", p);
+                  snprintf(buf, sizeof(buf), "%s/.e-mtrack.log", home);
                   env_set("MTRACK_TRACE_FILE", buf);
                }
              fclose(f);
           }
      }
 
-   /* try dbus-launch */
+   /* run e directly now */
    snprintf(buf, sizeof(buf), "%s/enlightenment", eina_prefix_bin_get(pfx));
 
    args = alloca((argc + 2 + VALGRIND_MAX_ARGS) * sizeof(char *));
-   if ((!getenv("DBUS_SESSION_BUS_ADDRESS")) &&
-       (!getenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET")))
-     {
-        args[0] = "dbus-launch";
-        args[1] = "--exit-with-session";
-
-        i = 2 + valgrind_append(args + 2, valgrind_gdbserver, valgrind_mode, valgrind_tool, valgrind_path, valgrind_log);
-        args[i++] = buf;
-        copy_args(args + i, argv + 1, argc - 1);
-        args[i + argc - 1] = NULL;
-        execvp("dbus-launch", args);
-     }
-
-   /* dbus-launch failed - run e direct */
    i = valgrind_append(args, valgrind_gdbserver, valgrind_mode, valgrind_tool, valgrind_path, valgrind_log);
    args[i++] = buf;
    copy_args(args + i, argv + 1, argc - 1);
    args[i + argc - 1] = NULL;
-   execv(args[0], args);
+   /* execv(args[0], args); */
+
+   /* not run at the moment !! */
+
+
+   /* Now looping until */
+   while (restart)
+     {
+        pid_t child;
+
+        tainted = EINA_FALSE;
+        child = fork();
+
+        if (child < 0) /* failed attempt */
+          return -1;
+        else if (child == 0)
+          {
+             /* in the child */
+             ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+
+             execv(args[0], args);
+             return 0; /* We failed, 0 mean normal exit from E with no restart or crash so let exit */
+          }
+        else
+          {
+             /* in the parent */
+             pid_t result;
+             int status;
+             Eina_Bool done = EINA_FALSE;
+
+             ptrace(PTRACE_ATTACH, child, NULL, NULL);
+
+             result = waitpid(child, &status, 0);
+
+             if (WIFSTOPPED(status))
+               ptrace(PTRACE_CONT, child, NULL, NULL);
+
+             while (!done)
+               {
+                  result = waitpid(child, &status, 0);
+
+                  if (result == child)
+                    {
+                       if (WIFSTOPPED(status))
+                         {
+                            char buffer[4096];
+                            char *backtrace = NULL;
+                            siginfo_t sig;
+                            int r;
+                            int back;
+
+                            r = ptrace(PTRACE_GETSIGINFO, child, NULL, &sig);
+                            back = r == 0 &&
+                              sig.si_signo != SIGTRAP ? sig.si_signo : 0;
+
+                            if (r != 0 ||
+                                (sig.si_signo != SIGSEGV &&
+                                 sig.si_signo != SIGILL &&
+                                 sig.si_signo != SIGFPE &&
+                                 sig.si_signo != SIGBUS &&
+                                 sig.si_signo != SIGABRT))
+                              {
+                                 ptrace(PTRACE_CONT, child, NULL, back);
+                                 continue ;
+                              }
+
+                            /* E17 should be in pause, we can detach */
+                            ptrace(PTRACE_DETACH, child, NULL, back);
+
+                            /* And call gdb if available */
+                            if (home)
+                              {
+                                 /* call e_sys gdb */
+                                 snprintf(buffer, 4096,
+                                          "%s/enlightenment/utils/enlightenment_sys gdb %i %s/.xsession-errors",
+                                          eina_prefix_lib_get(pfx),
+                                          child,
+                                          home);
+                                 r = system(buffer);
+
+                                 fprintf(stderr, "called gdb with '%s' = %i\n",
+                                         buffer, WEXITSTATUS(r));
+
+                                 snprintf(buffer, 4096,
+                                          "%s/.xsession-errors",
+                                          home);
+
+                                 backtrace = strdup(buffer);
+                              }
+
+                            /* call e_alert */
+                            snprintf(buffer, 4096,
+                                     backtrace ? "%s/enlightenment/utils/enlightenment_alert %i %i %s" : "%s/enlightenment/utils/enlightenment_alert %i %i %s",
+                                     eina_prefix_lib_get(pfx),
+                                     sig.si_signo,
+                                     child,
+                                     backtrace);
+                            r = system(buffer);
+
+                            /* kill e */
+                            kill(child, SIGKILL);
+
+                            if (WEXITSTATUS(r) != 1)
+                              {
+                                 restart = EINA_FALSE;
+                              }
+                         }
+                       else if (!WIFEXITED(status))
+                         {
+                            done = EINA_TRUE;
+                         }
+                    }
+                  else if (result == - 1)
+                    {
+                       done = EINA_TRUE;
+                       restart = EINA_FALSE;
+                    }
+               }
+          }
+          
+     }
 
-   printf("FAILED TO RUN:\n");
-   printf("  %s\n", buf);
-   perror("execv");
    return -1;
 }