Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F109122116
D3715.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D3715.diff
View Options
Index: etc/defaults/rc.conf
===================================================================
--- etc/defaults/rc.conf
+++ etc/defaults/rc.conf
@@ -25,6 +25,7 @@
# when the kenv variable rc.debug is set.
#rc_debug="NO" # Set to YES to enable debugging output from rc.d
rc_info="NO" # Enables display of informational messages at boot.
+rc_parallel="NO" # Run startup scripts in parallel
rc_startmsgs="YES" # Show "Starting foo:" messages at boot
rcshutdown_timeout="90" # Seconds to wait before terminating rc.shutdown
early_late_divider="FILESYSTEMS" # Script that separates early/late
Index: etc/rc
===================================================================
--- etc/rc
+++ etc/rc
@@ -120,13 +120,27 @@
skip_firstboot=""
fi
-files=`rcorder ${skip} ${skip_firstboot} /etc/rc.d/* ${local_rc} 2>/dev/null`
-for _rc_elem in ${files}; do
- case "$_rc_elem_done" in
- *" $_rc_elem "*) continue ;;
- esac
+if checkyesno rc_parallel; then
+ _rc_parallel='-p'
+else
+ _rc_parallel=''
+fi
- run_rc_script ${_rc_elem} ${_boot}
+files=`rcorder ${_rc_parallel} ${skip} ${skip_firstboot} /etc/rc.d/* ${local_rc} 2>/dev/null`
+echo "$files" | while read line
+do
+ for _rc_elem in ${line}; do
+ case "$_rc_elem_done" in
+ *" $_rc_elem "*) continue ;;
+ esac
+
+ if [ -n ${_rc_parallel} ]; then
+ run_rc_script ${_rc_elem} ${_boot} &
+ else
+ run_rc_script ${_rc_elem} ${_boot}
+ fi
+ done
+ [ -n ${_rc_parallel} ] && wait
done
# Remove the firstboot sentinel, and reboot if it was requested.
Index: sbin/rcorder/rcorder.c
===================================================================
--- sbin/rcorder/rcorder.c
+++ sbin/rcorder/rcorder.c
@@ -77,6 +77,7 @@
static int exit_code;
static int file_count;
+static int generation;
static char **file_list;
typedef int bool;
@@ -124,6 +125,7 @@
f_reqnode *req_list;
f_provnode *prov_list;
strnodelist *keyword_list;
+ int generation;
};
static filenode fn_head_s, *fn_head;
@@ -152,13 +154,15 @@
static void crunch_all_files(void);
static void initialize(void);
static void generate_ordering(void);
+static void generate_parallel(void);
+static int parallel = 0;
int
main(int argc, char *argv[])
{
int ch;
- while ((ch = getopt(argc, argv, "dk:s:")) != -1)
+ while ((ch = getopt(argc, argv, "dk:ps:")) != -1)
switch (ch) {
case 'd':
#ifdef DEBUG
@@ -170,6 +174,9 @@
case 'k':
strnode_add(&keep_list, optarg, 0);
break;
+ case 'p':
+ parallel = 1;
+ break;
case 's':
strnode_add(&skip_list, optarg, 0);
break;
@@ -188,7 +195,11 @@
DPRINTF((stderr, "initialize\n"));
crunch_all_files();
DPRINTF((stderr, "crunch_all_files\n"));
- generate_ordering();
+ if (parallel) {
+ generate_parallel();
+ } else {
+ generate_ordering();
+ }
DPRINTF((stderr, "generate_ordering\n"));
exit(exit_code);
@@ -721,46 +732,66 @@
} else
was_set = 0;
- /* mark fnode */
- fnode->in_progress = SET;
+ if (parallel) {
+ /*
+ * Mark node as handled in the current iteration.
+ * When running in parallel mode, we use this mechanism
+ * instead of removing dependencies, because in case
+ * where we have "A" node and its dependency "B", we must
+ * make sure we don't emit "B A", but always "B\nA".
+ */
+ DPRINTF((stderr, "node %s done in generation %d\n",
+ fnode->filename, generation));
+ fnode->generation = generation;
+ } else {
+ /* mark fnode */
+ fnode->in_progress = SET;
- /*
- * for each requirement of fnode -> r
- * satisfy_req(r, filename)
- */
- r = fnode->req_list;
- while (r != NULL) {
- satisfy_req(r, fnode->filename);
- r = r->next;
- }
- fnode->req_list = NULL;
+ /*
+ * for each requirement of fnode -> r
+ * satisfy_req(r, filename)
+ */
+ r = fnode->req_list;
+ while (r != NULL) {
+#if 0
+ r_tmp = r;
+#endif
+ satisfy_req(r, fnode->filename);
+ r = r->next;
+#if 0
+ if (was_set == 0)
+ free(r_tmp);
+#endif
+ }
+ fnode->req_list = NULL;
- /*
- * for each provision of fnode -> p
- * remove fnode from provision list for p in hash table
- */
- p = fnode->prov_list;
- while (p != NULL) {
- p_tmp = p;
- pnode = p->pnode;
- if (pnode->next != NULL) {
- pnode->next->last = pnode->last;
+ /*
+ * for each provision of fnode -> p
+ * remove fnode from provision list for p in hash table
+ */
+ p = fnode->prov_list;
+ while (p != NULL) {
+ p_tmp = p;
+ pnode = p->pnode;
+ if (pnode->next != NULL) {
+ pnode->next->last = pnode->last;
+ }
+ if (pnode->last != NULL) {
+ pnode->last->next = pnode->next;
+ }
+ free(pnode);
+ p = p->next;
+ free(p_tmp);
}
- if (pnode->last != NULL) {
- pnode->last->next = pnode->next;
- }
- free(pnode);
- p = p->next;
- free(p_tmp);
+ fnode->prov_list = NULL;
}
- fnode->prov_list = NULL;
/* do_it(fnode) */
DPRINTF((stderr, "next do: "));
/* if we were already in progress, don't print again */
if (was_set == 0 && skip_ok(fnode) && keep_ok(fnode))
- printf("%s\n", fnode->filename);
+ printf("%s%s", fnode->filename, parallel ? " " : "\n");
if (fnode->next != NULL) {
fnode->next->last = fnode->last;
@@ -776,6 +807,96 @@
free(fnode);
}
#endif
+}
+
+static bool
+unsatisfied_req(const struct filenode *fnode)
+{
+ const Hash_Entry *entry;
+ const provnode *head;
+ const f_reqnode *r;
+ int ndeps = 0;
+
+ for (r = fnode->req_list; r != NULL; r = r->next) {
+ entry = r->entry;
+ head = Hash_GetValue(entry);
+ if (head == NULL) {
+ warnx("requirement `%s' in file `%s' has no providers.",
+ Hash_GetKey(entry), fnode->filename);
+ continue;
+ }
+
+ for (head = head->next; head != NULL; head = head->next) {
+ /*
+ * Ignore dependencies handled in previous runs,
+ * but not those handled in the current one. Increase
+ * current generation counter, emit newline, and go
+ * around.
+ */
+ if (head->fnode->generation != 0 &&
+ head->fnode->generation < generation) {
+ DPRINTF((stderr, "%s had dependency %s handled "
+ "in generation %d\n",
+ fnode->filename, head->fnode->filename,
+ head->fnode->generation));
+ } else {
+ DPRINTF((stderr, "%s has dependency %s\n",
+ fnode->filename, head->fnode->filename));
+ //return (TRUE);
+ ndeps++;
+ }
+ }
+ }
+
+ if (ndeps > 0)
+ return (TRUE);
+
+ return (FALSE);
+}
+
+static void
+generate_parallel(void)
+{
+ static filenode *fnode, *fnode_next;
+ int nodes_done;
+ bool ignore_deps;
+
+ /*
+ * Iterate over nodes, printing out leaf ones. After each pass
+ * emit "\n" to mark dependency of the following nodes on the
+ * preceding ones. Continue until there are no nodes left.
+ */
+ ignore_deps = FALSE;
+ generation = 1;
+ do {
+ nodes_done = 0;
+ for (fnode = fn_head->next; fnode != NULL; fnode = fnode_next) {
+ fnode_next = fnode->next;
+ if (ignore_deps) {
+ warnx("cycle detected; ignoring dependencies "
+ "for %s", fnode->filename);
+ ignore_deps = FALSE;
+ } else if (unsatisfied_req(fnode)) {
+ DPRINTF((stderr, "%s has dependencies; "
+ "skipping\n", fnode->filename));
+ continue;
+ }
+ nodes_done++;
+ do_file(fnode);
+ }
+ generation++;
+ if (nodes_done > 0) {
+ printf("\n");
+ } else {
+ /*
+ * There were no leaf nodes, ie nodes with no
+ * dependencies. This means the graph is cyclic.
+ * It's hard to handle this in a sensible way; just
+ * ignore dependencies for the next node and try again.
+ */
+ ignore_deps = TRUE;
+ }
+ } while (fn_head->next != NULL);
}
static void
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 2, 2:13 AM (21 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16394216
Default Alt Text
D3715.diff (7 KB)
Attached To
Mode
D3715: Add "rcorder -p".
Attached
Detach File
Event Timeline
Log In to Comment