Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 13 Jun 2013 23:07:45 GMT
From:      Jonathan Anderson <jonathan@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 229694 for review
Message-ID:  <201306132307.r5DN7jZD076038@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@229694?ac=10

Change 229694 by jonathan@jonathan-on-zenith on 2013/06/13 23:07:27

	Update libtesla to commit 1fcd25.
	
	This contains the new event handling framework, which allows more sophisticated event handling policies. The defaults are:
	
	_KERNEL + KDTRACE_HOOKS => printf + DTrace
	otherwise => printf + panic on failure event

Affected files ...

.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/include/libtesla.h#6 edit
.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_dtrace.c#5 edit
.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_internal.h#6 edit
.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_notification.c#6 edit
.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_update.c#4 edit

Differences ...

==== //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/include/libtesla.h#6 (text+ko) ====

@@ -249,8 +249,28 @@
 	tesla_ev_ignored	teh_ignored;
 };
 
-/** Register a set of event handlers. */
-int	tesla_set_event_handlers(struct tesla_event_handlers *);
+/**
+ * A 'meta-handler' that wraps a number of event handling vectors.
+ *
+ * This event handler dispatches events to any number of backends, governed
+ * by @a tem_mask: if bit 0 is set, tem_handler[0] is called, etc.
+ */
+struct tesla_event_metahandler {
+	/** The number of event handlers wrapped by this handler. */
+	const uint32_t	tem_length;
+
+	/** Which backend handlers to use; may be modified dynamically. */
+	uint32_t	tem_mask;
+
+	/** The backend event handlers. */
+	const struct tesla_event_handlers* const *tem_handlers;
+};
+
+/** Register an event handler vector. */
+int	tesla_set_event_handler(struct tesla_event_handlers *);
+
+/** Register a set of event handling vectors. */
+int	tesla_set_event_handlers(struct tesla_event_metahandler *);
 
 /** @} */
 

==== //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_dtrace.c#5 (text+ko) ====

@@ -112,7 +112,7 @@
 	SDT_PROBE(tesla, kernel, notify, ignored, tcp, tkp, ttp, 0, 0);
 }
 
-struct tesla_event_handlers dtrace_handlers = {
+const struct tesla_event_handlers dtrace_handlers = {
 	.teh_init			= new_instance,
 	.teh_transition			= transition,
 	.teh_clone			= clone,

==== //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_internal.h#6 (text+ko) ====

@@ -311,13 +311,22 @@
 /*
  * Event notification:
  */
-extern struct tesla_event_handlers	*ev_handlers;
-extern struct tesla_event_handlers	failstop_handlers;
-extern struct tesla_event_handlers	printf_handlers;
+#if defined(_KERNEL) && defined(KDTRACE_HOOKS)
+extern const struct tesla_event_handlers dtrace_handlers;
+#endif
 
-#ifdef _KERNEL
-extern struct tesla_event_handlers	dtrace_handlers;
-#endif
+void	ev_new_instance(struct tesla_class *, struct tesla_instance *);
+void	ev_transition(struct tesla_class *, struct tesla_instance *,
+	    const struct tesla_transition*);
+void	ev_clone(struct tesla_class *, struct tesla_instance *orig,
+	    struct tesla_instance *copy, const struct tesla_transition *);
+void	ev_no_instance(struct tesla_class *, const struct tesla_key *,
+	    const struct tesla_transitions *);
+void	ev_bad_transition(struct tesla_class *, struct tesla_instance *,
+	    const struct tesla_transitions *);
+void	ev_accept(struct tesla_class *, struct tesla_instance *);
+void	ev_ignored(const struct tesla_class *, const struct tesla_key *,
+	    const struct tesla_transitions *);
 
 /*
  * Debug helpers.

==== //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_notification.c#6 (text+ko) ====

@@ -34,95 +34,154 @@
 
 #define	ERROR_BUFFER_LENGTH	1024
 
-int
-tesla_set_event_handlers(struct tesla_event_handlers *tehp)
+/**
+ * The currently-active event handlers.
+ */
+static struct tesla_event_metahandler *event_handlers;
+
+
+/** Perform sanity checks on an event handling vector. */
+static int
+check_event_handler(const struct tesla_event_handlers *tehp)
 {
 
 	if (!tehp || !tehp->teh_init || !tehp->teh_transition
 	    || !tehp->teh_clone || !tehp->teh_fail_no_instance
 	    || !tehp->teh_bad_transition
 	    || !tehp->teh_accept || !tehp->teh_ignored)
-#ifdef _KERNEL
-		tesla_panic("invalid error handler vector");
-#else
+		return (TESLA_ERROR_EINVAL);
+
+	return (TESLA_SUCCESS);
+}
+
+
+int
+tesla_set_event_handler(struct tesla_event_handlers *tehp)
+{
+	int error = check_event_handler(tehp);
+	if (error != TESLA_SUCCESS)
+		return (error);
+
+	const static struct tesla_event_handlers* singleton[1];
+	static struct tesla_event_metahandler singleton_handler = {
+		.tem_length = 1,
+		.tem_mask = 1,
+		.tem_handlers = singleton,
+	};
+
+	singleton[0] = tehp;
+	event_handlers = &singleton_handler;
+
+	return (TESLA_SUCCESS);
+}
+
+int
+tesla_set_event_handlers(struct tesla_event_metahandler *temp)
+{
+	int error = TESLA_SUCCESS;
+
+	if (!temp)
 		return (TESLA_ERROR_EINVAL);
-#endif
+
+	/*
+	 * It's ok to disable event handlers dynamically using the bitmask,
+	 * but all event handlers passed in must be valid.
+	 */
+	for (uint32_t i = 0; i < temp->tem_length; i++) {
+		error = check_event_handler(temp->tem_handlers[i]);
+		if (error != TESLA_SUCCESS)
+			return (error);
+	}
 
-	ev_handlers = tehp;
+	event_handlers = temp;
 	return (TESLA_SUCCESS);
 }
 
+
 /*
- * printf()-based event handlers:
+ * generic event handlers:
  */
-static void	print_new_instance(struct tesla_class *,
-	    struct tesla_instance *);
+#define	FOREACH_ERROR_HANDLER() \
+	for (uint32_t i = 0; i < event_handlers->tem_length; i++) \
+		if (event_handlers->tem_mask & (1 << i)) \
+			event_handlers->tem_handlers[i]
+
+static void
+ev_noop()
+{
+}
+
+void
+ev_new_instance(struct tesla_class *tcp, struct tesla_instance *tip)
+{
+
+	FOREACH_ERROR_HANDLER()->teh_init(tcp, tip);
+}
+
+void
+ev_transition(struct tesla_class *tcp, struct tesla_instance *tip,
+	const struct tesla_transition *ttp)
+{
 
-static void	print_transition_taken(struct tesla_class *,
-	    struct tesla_instance *, const struct tesla_transition*);
+	FOREACH_ERROR_HANDLER()->teh_transition(tcp, tip, ttp);
+}
 
-static void	print_clone(struct tesla_class *,
-	    struct tesla_instance *orig, struct tesla_instance *copy,
-	    const struct tesla_transition*);
+void
+ev_clone(struct tesla_class *tcp, struct tesla_instance *orig,
+	struct tesla_instance *copy, const struct tesla_transition *ttp)
+{
 
-static void	print_no_instance(struct tesla_class *,
-	    const struct tesla_key *, const struct tesla_transitions *);
+	FOREACH_ERROR_HANDLER()->teh_clone(tcp, orig, copy, ttp);
+}
 
-static void	print_bad_transition(struct tesla_class *,
-	    struct tesla_instance *, const struct tesla_transitions *);
+void
+ev_no_instance(struct tesla_class *tcp, const struct tesla_key *tkp,
+	const struct tesla_transitions *ttp)
+{
 
-static void	print_accept(struct tesla_class *, struct tesla_instance *);
+	FOREACH_ERROR_HANDLER()->teh_fail_no_instance(tcp, tkp, ttp);
+}
 
-static void	print_ignored(const struct tesla_class *,
-	    const struct tesla_key *, const struct tesla_transitions *);
+void
+ev_bad_transition(struct tesla_class *tcp, struct tesla_instance *tip,
+	const struct tesla_transitions *ttp)
+{
 
-struct tesla_event_handlers printf_handlers = {
-	.teh_init		= print_new_instance,
-	.teh_transition		= print_transition_taken,
-	.teh_clone		= print_clone,
-	.teh_fail_no_instance	= print_no_instance,
-	.teh_bad_transition	= print_bad_transition,
-	.teh_accept		= print_accept,
-	.teh_ignored		= print_ignored,
-};
+	FOREACH_ERROR_HANDLER()->teh_bad_transition(tcp, tip, ttp);
+}
 
+void
+ev_accept(struct tesla_class *tcp, struct tesla_instance *tip)
+{
 
-/*
- * Wrappers that panic on failure:
- */
-static void	panic_no_instance(struct tesla_class *,
-	    const struct tesla_key *, const struct tesla_transitions *);
+	FOREACH_ERROR_HANDLER()->teh_accept(tcp, tip);
+}
 
-static void	panic_bad_transition(struct tesla_class *,
-	    struct tesla_instance *, const struct tesla_transitions *);
+void
+ev_ignored(const struct tesla_class *tcp, const struct tesla_key *tkp,
+	const struct tesla_transitions *ttp)
+{
 
-struct tesla_event_handlers failstop_handlers = {
-	.teh_init		= print_new_instance,
-	.teh_transition		= print_transition_taken,
-	.teh_clone		= print_clone,
-	.teh_fail_no_instance	= panic_no_instance,
-	.teh_bad_transition	= panic_bad_transition,
-	.teh_accept		= print_accept,
-	.teh_ignored		= print_ignored,
-};
+	FOREACH_ERROR_HANDLER()->teh_ignored(tcp, tkp, ttp);
+}
 
 
-/**
- * Default to print-with-failstop except in the kernel when DTrace is
- * available.
+/*
+ * printf()-based event handlers:
  */
-struct tesla_event_handlers	*ev_handlers =
-#if defined(_KERNEL) && defined(KDTRACE_HOOKS)
-	&dtrace_handlers
-#else
-	&failstop_handlers
+static void
+print_failure_header(const struct tesla_class *tcp)
+{
+
+	error("\n\nTESLA failure:\n");
+#if defined(_KERNEL) && defined(KDB)
+	kdb_backtrace();
 #endif
-	;
 
-static void	print_failure_header(const struct tesla_class *);
+	error("In automaton '%s':\n%s\n", tcp->tc_name, tcp->tc_description);
+}
 
-
-void
+static void
 print_new_instance(struct tesla_class *tcp, struct tesla_instance *tip)
 {
 
@@ -130,7 +189,7 @@
 		tip - tcp->tc_instances, tip->ti_state);
 }
 
-void
+static void
 print_transition_taken(struct tesla_class *tcp,
     struct tesla_instance *tip, const struct tesla_transition *transp)
 {
@@ -139,7 +198,7 @@
 		tip - tcp->tc_instances, transp->from, transp->to);
 }
 
-void
+static void
 print_clone(struct tesla_class *tcp,
     struct tesla_instance *old_instance, struct tesla_instance *new_instance,
     const struct tesla_transition *transp)
@@ -151,8 +210,7 @@
 }
 
 static void
-no_instance_message(char *buffer, const char *end,
-    struct tesla_class *tcp, const struct tesla_key *tkp,
+print_no_instance(struct tesla_class *tcp, const struct tesla_key *tkp,
     const struct tesla_transitions *transp)
 {
 
@@ -161,6 +219,8 @@
 
 	print_failure_header(tcp);
 
+	char buffer[ERROR_BUFFER_LENGTH];
+	const char *end = buffer + sizeof(buffer);
 	char *next = buffer;
 
 	SAFE_SPRINTF(next, end, "No instance matched key '");
@@ -168,35 +228,12 @@
 	SAFE_SPRINTF(next, end, "' for transition(s) ");
 	next = sprint_transitions(next, end, transp);
 	assert(next > buffer);
-}
-
-void
-print_no_instance(struct tesla_class *tcp, const struct tesla_key *tkp,
-    const struct tesla_transitions *transp)
-{
-
-	char buffer[ERROR_BUFFER_LENGTH];
-	const char *end = buffer + sizeof(buffer);
 
-	no_instance_message(buffer, end, tcp, tkp, transp);
 	error("%s", buffer);
 }
 
-void
-panic_no_instance(struct tesla_class *tcp, const struct tesla_key *tkp,
-    const struct tesla_transitions *transp)
-{
-
-	char buffer[ERROR_BUFFER_LENGTH];
-	const char *end = buffer + sizeof(buffer);
-
-	no_instance_message(buffer, end, tcp, tkp, transp);
-	tesla_panic("%s", buffer);
-}
-
 static void
-bad_transition_message(char *buffer, const char *end,
-    struct tesla_class *tcp, struct tesla_instance *tip,
+print_bad_transition(struct tesla_class *tcp, struct tesla_instance *tip,
     const struct tesla_transitions *transp)
 {
 
@@ -205,6 +242,8 @@
 
 	print_failure_header(tcp);
 
+	char buffer[ERROR_BUFFER_LENGTH];
+	const char *end = buffer + sizeof(buffer);
 	char *next = buffer;
 
 	SAFE_SPRINTF(next, end,
@@ -215,33 +254,11 @@
 
 	next = sprint_transitions(next, end, transp);
 	assert(next > buffer);
-}
 
-void
-print_bad_transition(struct tesla_class *tcp, struct tesla_instance *tip,
-    const struct tesla_transitions *transp)
-{
-
-	char buffer[ERROR_BUFFER_LENGTH];
-	const char *end = buffer + sizeof(buffer);
-
-	bad_transition_message(buffer, end, tcp, tip, transp);
 	error("%s", buffer);
 }
 
-void
-panic_bad_transition(struct tesla_class *tcp, struct tesla_instance *tip,
-    const struct tesla_transitions *transp)
-{
-
-	char buffer[ERROR_BUFFER_LENGTH];
-	const char *end = buffer + sizeof(buffer);
-
-	bad_transition_message(buffer, end, tcp, tip, transp);
-	tesla_panic("%s", buffer);
-}
-
-void
+static void
 print_accept(struct tesla_class *tcp, struct tesla_instance *tip)
 {
 
@@ -250,7 +267,7 @@
 		tip - tcp->tc_instances);
 }
 
-void
+static void
 print_ignored(const struct tesla_class *tcp, const struct tesla_key *tkp,
     const struct tesla_transitions *transp)
 {
@@ -265,15 +282,66 @@
 	DEBUG(libtesla.event, "ignore '%s':%s", tcp->tc_name, buffer);
 }
 
+const struct tesla_event_handlers printf_handlers = {
+	.teh_init		= print_new_instance,
+	.teh_transition		= print_transition_taken,
+	.teh_clone		= print_clone,
+	.teh_fail_no_instance	= print_no_instance,
+	.teh_bad_transition	= print_bad_transition,
+	.teh_accept		= print_accept,
+	.teh_ignored		= print_ignored,
+};
+
 
+/*
+ * Wrappers that panic on failure:
+ */
 static void
-print_failure_header(const struct tesla_class *tcp)
+panic_no_instance(struct tesla_class *tcp,
+	__unused const struct tesla_key *tkp,
+	__unused const struct tesla_transitions *ttp)
+{
+
+	tesla_panic("TESLA: failure in '%s': no such instance", tcp->tc_name);
+}
+
+static void
+panic_bad_transition(struct tesla_class *tcp,
+	__unused struct tesla_instance *tip,
+	__unused const struct tesla_transitions *ttp)
 {
 
-	error("\n\nTESLA failure:\n");
-#if defined(_KERNEL) && defined(KDB)
-	kdb_backtrace();
+	tesla_panic("TESLA: failure in '%s': bad transition", tcp->tc_name);
+}
+
+const struct tesla_event_handlers failstop_handlers = {
+	.teh_init		= ev_noop,
+	.teh_transition		= ev_noop,
+	.teh_clone		= ev_noop,
+	.teh_fail_no_instance	= panic_no_instance,
+	.teh_bad_transition	= panic_bad_transition,
+	.teh_accept		= ev_noop,
+	.teh_ignored		= ev_noop,
+};
+
+
+/**
+ * Default event handlers: always print, then use DTrace in the kernel
+ * if it's available; if it isn't, panic on failure.
+ */
+const static struct tesla_event_handlers* const default_handlers[] = {
+	&printf_handlers,
+#if defined(_KERNEL) && defined(KDTRACE_HOOKS)
+	&dtrace_handlers,
+#else
+	&failstop_handlers,
 #endif
+};
 
-	error("In automaton '%s':\n%s\n", tcp->tc_name, tcp->tc_description);
-}
+static struct tesla_event_metahandler default_event_handlers = {
+	.tem_length = sizeof(default_handlers) / sizeof(*default_handlers),
+	.tem_mask = 0xFFFF,
+	.tem_handlers = default_handlers,
+};
+
+static struct tesla_event_metahandler *event_handlers = &default_event_handlers;

==== //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_update.c#4 (text+ko) ====

@@ -55,8 +55,6 @@
 	const struct tesla_transitions *trans)
 {
 
-	assert(ev_handlers != NULL);
-
 	if (tesla_debugging(DEBUG_NAME)) {
 		/* We should never see with multiple <<init>> transitions. */
 		int init_count = 0;
@@ -114,19 +112,19 @@
 
 		switch (action) {
 		case FAIL:
-			ev_handlers->teh_bad_transition(class, inst, trans);
+			ev_bad_transition(class, inst, trans);
 			break;
 
 		case IGNORE:
 			break;
 
 		case UPDATE:
-			ev_handlers->teh_transition(class, inst, trigger);
+			ev_transition(class, inst, trigger);
 			inst->ti_state = trigger->to;
 			matched_something = true;
 
 			if (trigger->flags & TESLA_TRANS_CLEANUP)
-				ev_handlers->teh_accept(class, inst);
+				ev_accept(class, inst);
 
 			break;
 
@@ -155,10 +153,10 @@
 
 		clone->ti_state = c->transition->to;
 
-		ev_handlers->teh_clone(class, c->old, clone, c->transition);
+		ev_clone(class, c->old, clone, c->transition);
 
 		if (c->transition->flags & TESLA_TRANS_CLEANUP)
-			ev_handlers->teh_accept(class, clone);
+			ev_accept(class, clone);
 	}
 
 
@@ -171,7 +169,7 @@
 			assert(tesla_instance_active(inst));
 
 			matched_something = true;
-			ev_handlers->teh_init(class, inst);
+			ev_new_instance(class, inst);
 		}
 	}
 
@@ -179,10 +177,10 @@
 		// If the class hasn't received any <<init>> events yet,
 		// simply ignore the event: it is out of scope.
 		if (class->tc_free == class->tc_limit)
-			ev_handlers->teh_ignored(class, pattern, trans);
+			ev_ignored(class, pattern, trans);
 
 		// Otherwise, we ought to have matched something.
-		else ev_handlers->teh_fail_no_instance(class, pattern, trans);
+		else ev_no_instance(class, pattern, trans);
 	}
 
 	// Does it cause class cleanup?



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201306132307.r5DN7jZD076038>