hush: fix SIGCHLD counting code, but keep it disabled for now.
authorDenys Vlasenko <vda.linux@googlemail.com>
Mon, 25 May 2009 14:38:32 +0000 (16:38 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Mon, 25 May 2009 14:38:32 +0000 (16:38 +0200)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/hush.c

index acc8ef944c5a4f18ce2841931d5e7065cfa3ea94..fd839d0612d18515389cc0275107b64901d7c354 100644 (file)
@@ -69,7 +69,7 @@
 #endif
 
 
-/* Debug build knobs */
+/* Build knobs */
 #define LEAK_HUNTING 0
 #define BUILD_AS_NOMMU 0
 /* Enable/disable sanity checks. Ok to enable in production,
  * Keeping 1 for now even in released versions.
  */
 #define HUSH_DEBUG 1
+/* Slightly bigger (+200 bytes), but faster hush.
+ * So far it only enables a trick with counting SIGCHLDs and forks,
+ * which allows us to do fewer waitpid's.
+ * (we can detect a case where neither forks were done nor SIGCHLDs happened
+ * and therefore waitpid will return the same result as last time)
+ */
+#define ENABLE_HUSH_FAST 0
 
 
 #if BUILD_AS_NOMMU
@@ -485,8 +492,11 @@ struct globals {
        struct function *top_func;
 #endif
        /* Signal and trap handling */
-//     unsigned count_SIGCHLD;
-//     unsigned handled_SIGCHLD;
+#if ENABLE_HUSH_FAST
+       unsigned count_SIGCHLD;
+       unsigned handled_SIGCHLD;
+       smallint last_waitpid_was_0;
+#endif
        /* which signals have non-DFL handler (even with no traps set)? */
        unsigned non_DFL_mask;
        char **traps; /* char *traps[NSIG] */
@@ -1050,7 +1060,7 @@ static void restore_G_args(save_arg_t *sv, char **argv)
  *    Restore blocked signal set to one inherited by shell just prior to exec.
  *
  * Note: as a result, we do not use signal handlers much. The only uses
- * are to count SIGCHLDs [disabled - bug somewhere, + bloat]
+ * are to count SIGCHLDs
  * and to restore tty pgrp on signal-induced exit.
  */
 enum {
@@ -1067,10 +1077,13 @@ enum {
 #endif
 };
 
-//static void SIGCHLD_handler(int sig UNUSED_PARAM)
-//{
-//     G.count_SIGCHLD++;
-//}
+#if ENABLE_HUSH_FAST
+static void SIGCHLD_handler(int sig UNUSED_PARAM)
+{
+       G.count_SIGCHLD++;
+//bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
+}
+#endif
 
 #if ENABLE_HUSH_JOB
 
@@ -1158,9 +1171,12 @@ static int check_and_run_traps(int sig)
                }
                /* not a trap: special action */
                switch (sig) {
-//             case SIGCHLD:
-//                     G.count_SIGCHLD++;
-//                     break;
+#if ENABLE_HUSH_FAST
+               case SIGCHLD:
+                       G.count_SIGCHLD++;
+//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
+                       break;
+#endif
                case SIGINT:
                        /* Builtin was ^C'ed, make it look prettier: */
                        bb_putchar('\n');
@@ -2665,6 +2681,10 @@ static void setup_heredoc(struct redir_struct *redir)
 #endif
        }
        /* parent */
+#if ENABLE_HUSH_FAST
+       G.count_SIGCHLD++;
+//bb_error_msg("[%d] fork in setup_heredoc: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
+#endif
        enable_restore_tty_pgrp_on_exit();
 #if !BB_MMU
        free(to_free);
@@ -3273,9 +3293,16 @@ static int checkjobs(struct pipe* fg_pipe)
        debug_printf_jobs("checkjobs %p\n", fg_pipe);
 
        errno = 0;
-//     if (G.handled_SIGCHLD == G.count_SIGCHLD)
-//             /* avoid doing syscall, nothing there anyway */
-//             return rcode;
+#if ENABLE_HUSH_FAST
+       if (G.handled_SIGCHLD == G.count_SIGCHLD) {
+//bb_error_msg("[%d] checkjobs: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d was 0?:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD, G.last_waitpid_was_0);
+               /* avoid doing syscall, nothing there anyway */
+               if (G.last_waitpid_was_0)
+                       return 0;
+               errno = ECHILD;
+               return -1;
+       }
+#endif
 
        attributes = WUNTRACED;
        if (fg_pipe == NULL)
@@ -3294,13 +3321,20 @@ static int checkjobs(struct pipe* fg_pipe)
                int i;
                int dead;
 
-//             i = G.count_SIGCHLD;
+#if ENABLE_HUSH_FAST
+               i = G.count_SIGCHLD;
+#endif
                childpid = waitpid(-1, &status, attributes);
                if (childpid <= 0) {
                        if (childpid && errno != ECHILD)
                                bb_perror_msg("waitpid");
-//                     else /* Until next SIGCHLD, waitpid's are useless */
-//                             G.handled_SIGCHLD = i;
+#if ENABLE_HUSH_FAST
+                       else { /* Until next SIGCHLD, waitpid's are useless */
+                               G.last_waitpid_was_0 = (childpid == 0);
+                               G.handled_SIGCHLD = i;
+//bb_error_msg("[%d] checkjobs: waitpid returned <= 0, G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
+                       }
+#endif
                        break;
                }
                dead = WIFEXITED(status) || WIFSIGNALED(status);
@@ -3696,6 +3730,10 @@ static int run_pipe(struct pipe *pi)
                }
 
                /* parent or error */
+#if ENABLE_HUSH_FAST
+               G.count_SIGCHLD++;
+//bb_error_msg("[%d] fork in run_pipe: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
+#endif
                enable_restore_tty_pgrp_on_exit();
 #if !BB_MMU
                /* Clean up after vforked child */
@@ -4861,6 +4899,10 @@ static FILE *generate_stream_from_string(const char *s)
        }
 
        /* parent */
+#if ENABLE_HUSH_FAST
+       G.count_SIGCHLD++;
+//bb_error_msg("[%d] fork in generate_stream_from_string: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
+#endif
        enable_restore_tty_pgrp_on_exit();
 #if !BB_MMU
        free(to_free);
@@ -5990,9 +6032,14 @@ static void block_signals(int second_time)
                        second_time ? NULL : &G.inherited_set);
        /* POSIX allows shell to re-enable SIGCHLD
         * even if it was SIG_IGN on entry */
-//     G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
+#if ENABLE_HUSH_FAST
+       G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
+       if (!second_time)
+               signal(SIGCHLD, SIGCHLD_handler);
+#else
        if (!second_time)
-               signal(SIGCHLD, SIG_DFL); // SIGCHLD_handler);
+               signal(SIGCHLD, SIG_DFL);
+#endif
 }
 
 #if ENABLE_HUSH_JOB