PERFORCE change 229694 for review
Jonathan Anderson
jonathan at FreeBSD.org
Thu Jun 13 23:07:46 UTC 2013
http://p4web.freebsd.org/@@229694?ac=10
Change 229694 by jonathan at 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?
More information about the p4-projects
mailing list