From 13f087cd5aae235234d0f8d43627b5a47fe7dd2e Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@openwrt.org>
Date: Mon, 25 Jun 2007 09:47:58 +0000
Subject: [PATCH] hotplug2: add fork handling optimization (also fixes that
 pesky pppoe race condition in #1655)

SVN-Revision: 7726
---
 .../hotplug2/patches/120-fork_handling.patch  | 142 ++++++++++++++++++
 1 file changed, 142 insertions(+)
 create mode 100644 package/hotplug2/patches/120-fork_handling.patch

diff --git a/package/hotplug2/patches/120-fork_handling.patch b/package/hotplug2/patches/120-fork_handling.patch
new file mode 100644
index 00000000000..c234a6cb723
--- /dev/null
+++ b/package/hotplug2/patches/120-fork_handling.patch
@@ -0,0 +1,142 @@
+Index: hotplug2-0.9/hotplug2.c
+===================================================================
+--- hotplug2-0.9.orig/hotplug2.c	2007-06-25 11:36:44.800185312 +0200
++++ hotplug2-0.9/hotplug2.c	2007-06-25 11:39:08.318367232 +0200
+@@ -313,6 +313,17 @@
+ }
+ 
+ #ifdef HAVE_RULES
++static int action_needs_fork(struct hotplug2_event_t *event, struct rules_t *rules)
++{
++	int i, rv;
++
++	for (i = 0; i < rules->rules_c; i++) {
++		if (rule_needs_fork(event, &rules->rules[i]))
++			return 1;
++	}
++	return 0;
++}
++
+ void perform_action(struct hotplug2_event_t *event, struct rules_t *rules) {
+ 	int i, rv;
+ 	
+@@ -565,14 +576,20 @@
+ 		cur_seqnum = strtoull(seqnum, NULL, 0);
+ 		if (cur_seqnum > highest_seqnum)
+ 			highest_seqnum = cur_seqnum;
+-		
++
+ 		if ((dumb && tmpevent->action == ACTION_ADD && modalias != NULL) || (!dumb)) {
+-			/* 
+-			 * We have more children than we want. Wait until SIGCHLD handler reduces
+-			 * their numbers.
+-			 */
+-			while (child_c >= max_child_c) {
+-				usleep(HOTPLUG2_THROTTLE_INTERVAL);
++			int untracked = 0;
++
++			if (!dumb && !action_needs_fork(tmpevent, rules))
++				untracked = 1;
++			else {
++				/*
++				 * We have more children than we want. Wait until SIGCHLD handler reduces
++				 * their numbers.
++				 */
++				while (child_c >= max_child_c) {
++					usleep(HOTPLUG2_THROTTLE_INTERVAL);
++				}
+ 			}
+ 			
+ 			sigemptyset(&block_mask);
+@@ -595,13 +612,16 @@
+ 					break;
+ 				default:
+ 					DBG("spawn", "spawning: %d.", p);
+-					child = add_child(child, p, cur_seqnum);
+-					child_c++;
++					if (!untracked) {
++						child = add_child(child, p, cur_seqnum);
++						child_c++;
++					}
+ 					break;
+ 			}
+ 			sigprocmask(SIG_UNBLOCK, &block_mask, 0);
+ 		}
+ 		
++done:
+ 		free_hotplug2_event(tmpevent);
+ 	}
+ 
+Index: hotplug2-0.9/rules.c
+===================================================================
+--- hotplug2-0.9.orig/rules.c	2007-06-25 11:36:44.801185160 +0200
++++ hotplug2-0.9/rules.c	2007-06-25 11:36:44.822181968 +0200
+@@ -363,6 +363,41 @@
+ 	return EVAL_NOT_AVAILABLE;
+ }
+ 
++int rule_needs_fork(struct hotplug2_event_t *event, struct rule_t *rule)
++{
++	int i, last_rv;
++
++	for (i = 0; i < rule->conditions_c; i++) {
++		if (rule_condition_eval(event, &(rule->conditions[i])) != EVAL_MATCH)
++			return 0;
++	}
++	for (i = 0; i < rule->actions_c; i++) {
++		switch (rule->actions[i].type) {
++			case ACT_STOP_PROCESSING:
++				return 0;
++				break;
++			case ACT_STOP_IF_FAILED:
++				if (last_rv != 0)
++					return 0;
++				break;
++			case ACT_NEXT_EVENT:
++				return 0;
++				break;
++			case ACT_NEXT_IF_FAILED:
++				if (last_rv != 0)
++					return 0;
++				break;
++			case ACT_RUN_SHELL:
++				return 1;
++				break;
++			case ACT_RUN_NOSHELL:
++				return 1;
++				break;
++		}
++	}
++	return 0;
++}
++
+ int rule_execute(struct hotplug2_event_t *event, struct rule_t *rule) {
+ 	int i, last_rv;
+ 	
+Index: hotplug2-0.9/rules.h
+===================================================================
+--- hotplug2-0.9.orig/rules.h	2007-06-25 11:36:44.801185160 +0200
++++ hotplug2-0.9/rules.h	2007-06-25 11:36:44.822181968 +0200
+@@ -77,5 +77,6 @@
+ int rule_execute(struct hotplug2_event_t *, struct rule_t *);
+ void rules_free(struct rules_t *);
+ struct rules_t *rules_from_config(char *);
++int rule_needs_fork(struct hotplug2_event_t *event, struct rule_t *rule);
+ 
+ #endif /* ifndef RULES_H*/
+Index: hotplug2-0.9/childlist.c
+===================================================================
+--- hotplug2-0.9.orig/childlist.c	2007-06-25 11:40:23.477941240 +0200
++++ hotplug2-0.9/childlist.c	2007-06-25 11:40:48.164188360 +0200
+@@ -41,10 +41,8 @@
+ struct hotplug2_child_t *remove_child_by_pid(struct hotplug2_child_t *child, pid_t pid, event_seqnum_t *largest_seqnum, int *child_c) {
+ 	struct hotplug2_child_t *tmp_child;
+ 	
+-	if (child == NULL) {
+-		ERROR("remove_child_by_pid", "Invalid child list passed (NULL).");
++	if (child == NULL)
+ 		return NULL;
+-	}
+ 	
+ 	tmp_child = child;
+ 	
-- 
GitLab