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>