From 9bc80d7062a01aa310be0729c095ba6b652c4735 Mon Sep 17 00:00:00 2001
From: Denis Vlasenko <vda.linux@googlemail.com>
Date: Sat, 12 Apr 2008 20:07:53 +0000
Subject: ash: add FEATURE_SH_NOFORK support

---
 shell/Config.in | 17 +++++++++++++++++
 shell/ash.c     | 18 ++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/shell/Config.in b/shell/Config.in
index 40e0217f4..94ffa09f8 100644
--- a/shell/Config.in
+++ b/shell/Config.in
@@ -287,6 +287,23 @@ config FEATURE_SH_STANDALONE
 #	  that exact location with that exact name, this option will not work at
 #	  all.
 
+config FEATURE_SH_NOFORK
+	bool "Run 'nofork' applets directly"
+	default n
+	depends on (MSH || LASH || HUSH || ASH) && FEATURE_PREFER_APPLETS
+	help
+	  This option causes busybox shells [currently only ash]
+	  to not execute typical fork/exec/wait sequence, but call <applet>_main
+	  directly, if possible. (Sometimes it is not possible: for example,
+	  this is not possible in pipes).
+
+	  This will be done only for some applets (those which are marked
+	  NOFORK in include/applets.h).
+
+	  This may significantly speed up some shell scripts.
+
+	  This feature is relatively new. Use with care.
+
 config CTTYHACK
 	bool "cttyhack"
 	default n
diff --git a/shell/ash.c b/shell/ash.c
index 0872e681a..cc61401d1 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -8747,6 +8747,24 @@ evalcommand(union node *cmd, int flags)
 	/* Execute the command. */
 	switch (cmdentry.cmdtype) {
 	default:
+
+#if ENABLE_FEATURE_SH_NOFORK
+		{
+		/* TODO: don't rerun find_applet_by_name, find_command
+		 * already did it. Make it save applet_no somewhere */
+		int applet_no = find_applet_by_name(argv[0]);
+		if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
+			struct nofork_save_area nofork_save;
+
+			listsetvar(varlist.list, VEXPORT|VSTACK);
+			save_nofork_data(&nofork_save);
+			/* run <applet>_main(), then restore nofork_save_area */
+			exitstatus = run_nofork_applet_prime(&nofork_save, applet_no, argv) & 0xff;
+			break;
+		}
+		}
+#endif
+
 		/* Fork off a child process if necessary. */
 		if (!(flags & EV_EXIT) || trap[0]) {
 			INT_OFF;
-- 
cgit v1.2.3