From owner-p4-projects@FreeBSD.ORG Tue Jun 4 15:53:26 2013 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id D6F93C1B; Tue, 4 Jun 2013 15:53:25 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 967BFC19 for ; Tue, 4 Jun 2013 15:53:25 +0000 (UTC) (envelope-from jonathan@freebsd.org) Received: from skunkworks.freebsd.org (skunkworks.freebsd.org [IPv6:2001:1900:2254:2068::682:0]) by mx1.freebsd.org (Postfix) with ESMTP id 78EFD1A05 for ; Tue, 4 Jun 2013 15:53:25 +0000 (UTC) Received: from skunkworks.freebsd.org ([127.0.1.74]) by skunkworks.freebsd.org (8.14.7/8.14.7) with ESMTP id r54FrPkM086890 for ; Tue, 4 Jun 2013 15:53:25 GMT (envelope-from jonathan@freebsd.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.7/8.14.6/Submit) id r54FrPZ7086887 for perforce@freebsd.org; Tue, 4 Jun 2013 15:53:25 GMT (envelope-from jonathan@freebsd.org) Date: Tue, 4 Jun 2013 15:53:25 GMT Message-Id: <201306041553.r54FrPZ7086887@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.freebsd.org: perforce set sender to jonathan@freebsd.org using -f From: Jonathan Anderson Subject: PERFORCE change 229369 for review To: Perforce Change Reviews Precedence: bulk X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.14 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Jun 2013 15:53:26 -0000 http://p4web.freebsd.org/@@229369?ac=10 Change 229369 by jonathan@jonathan-on-joe on 2013/06/04 15:52:24 Integrate latest libtesla changes into sys/libtesla. Affected files ... .. //depot/projects/ctsrd/tesla/src/sys/libtesla/Makefile#4 integrate .. //depot/projects/ctsrd/tesla/src/sys/libtesla/config.h#1 branch .. //depot/projects/ctsrd/tesla/src/sys/libtesla/debug.c#6 delete .. //depot/projects/ctsrd/tesla/src/sys/libtesla/key.c#4 delete .. //depot/projects/ctsrd/tesla/src/sys/libtesla/libtesla.h#6 integrate .. //depot/projects/ctsrd/tesla/src/sys/libtesla/state-global.c#3 delete .. //depot/projects/ctsrd/tesla/src/sys/libtesla/state-perthread.c#9 delete .. //depot/projects/ctsrd/tesla/src/sys/libtesla/state.c#8 delete .. //depot/projects/ctsrd/tesla/src/sys/libtesla/store.c#7 delete .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla.h#6 integrate .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_class.c#1 branch .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_class_global.c#1 branch .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_class_perthread.c#1 branch .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_debug.c#1 branch .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_dtrace.c#4 integrate .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_internal.h#11 integrate .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_key.c#1 branch .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_notification.c#4 integrate .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_store.c#1 branch .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_strnlen.h#1 branch .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_update.c#1 branch .. //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_util.c#1 branch .. //depot/projects/ctsrd/tesla/src/sys/libtesla/update.c#8 delete .. //depot/projects/ctsrd/tesla/src/sys/libtesla/util.c#3 delete Differences ... ==== //depot/projects/ctsrd/tesla/src/sys/libtesla/Makefile#4 (text+ko) ==== @@ -7,8 +7,8 @@ CFLAGS+= -I${.CURDIR} INCS= tesla.h libtesla.h -SRCS= debug.c key.c tesla_dtrace.c tesla_notification.c state.c \ - state-global.c state-perthread.c store.c update.c util.c +SRCS= tesla_class.c tesla_class_global.c tesla_class_perthread.c \ + tesla_debug.c tesla_dtrace.c tesla_key.c tesla_notification.c \ + tesla_store.c tesla_update.c tesla_util.c .include - ==== //depot/projects/ctsrd/tesla/src/sys/libtesla/libtesla.h#6 (text+ko) ==== @@ -34,6 +34,12 @@ #ifndef _TESLA_STATE #define _TESLA_STATE +/** + * Support library for TESLA instrumentation. + * @addtogroup libtesla + * @{ + */ + #ifdef _KERNEL #include #else @@ -60,16 +66,18 @@ uint32_t from; /** The mask of the state we're moving from. */ - uint32_t mask; + uint32_t from_mask; /** The state we are moving to. */ uint32_t to; + /** A mask of the keys that the 'to' state should have set. */ + uint32_t to_mask; + /** Things we may need to do on this transition. */ int flags; }; -#define TESLA_TRANS_FORK 0x01 /* Always fork on this transition. */ #define TESLA_TRANS_INIT 0x02 /* May need to initialise the class. */ #define TESLA_TRANS_CLEANUP 0x04 /* Clean up the class now. */ @@ -178,7 +186,7 @@ /** * Check to see if a key matches a pattern. * - * @returns 1 if @ref #k matches @ref pattern, 0 otherwise + * @returns 1 if @a k matches @a pattern, 0 otherwise */ int32_t tesla_key_matches( const struct tesla_key *pattern, const struct tesla_key *k); @@ -213,7 +221,7 @@ * * @returns 1 if active, 0 if inactive */ -int32_t tesla_instance_active(struct tesla_instance *i); +int32_t tesla_instance_active(const struct tesla_instance *i); /** Clone an existing instance into a new instance. */ @@ -234,4 +242,48 @@ void tesla_instance_destroy(struct tesla_class *tsp, struct tesla_instance *tip); + +/* + * Event notification: + */ +/** A new @ref tesla_instance has been created. */ +typedef void (*tesla_ev_new_instance)(struct tesla_class *, + struct tesla_instance *); + +/** A @ref tesla_instance has taken a transition. */ +typedef void (*tesla_ev_transition)(struct tesla_class *, + struct tesla_instance *, const struct tesla_transition*); + +/** An exisiting @ref tesla_instance has been cloned because of an event. */ +typedef void (*tesla_ev_clone)(struct tesla_class *, + struct tesla_instance *orig, struct tesla_instance *copy, + const struct tesla_transition*); + +/** No @ref tesla_class instance was found to match a @ref tesla_key. */ +typedef void (*tesla_ev_no_instance)(struct tesla_class *, + const struct tesla_key *, const struct tesla_transitions *); + +/** A @ref tesla_instance is not in the right state to take a transition. */ +typedef void (*tesla_ev_bad_transition)(struct tesla_class *, + struct tesla_instance *, const struct tesla_transitions *); + +/** A @ref tesla_instance has accepted a sequence of events. */ +typedef void (*tesla_ev_accept)(struct tesla_class *, + struct tesla_instance *); + +/** A vector of event handlers. */ +struct tesla_event_handlers { + tesla_ev_new_instance teh_init; + tesla_ev_transition teh_transition; + tesla_ev_clone teh_clone; + tesla_ev_no_instance teh_fail_no_instance; + tesla_ev_bad_transition teh_bad_transition; + tesla_ev_accept teh_accept; +}; + +/** Register a set of event handlers. */ +int tesla_set_event_handlers(struct tesla_event_handlers *); + +/** @} */ + #endif /* _TESLA_STATE */ ==== //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla.h#6 (text+ko) ==== @@ -28,10 +28,25 @@ * SUCH DAMAGE. */ +/** + * @mainpage TESLA API documentation + * + * This is the API documentation for TESLA's programmer interface + * (@ref ConsumerAPI), runtime support library (@ref libtesla) and + * analysis/instrumentation implementation. + */ + #ifndef TESLA_H #define TESLA_H -/** Basic TESLA types (magic for the compiler to munge). */ +/** + * API for programmers who want to use TESLA in their code. + * + * @addtogroup ConsumerAPI + * @{ + */ + +/** The basic TESLA type is a pointer to a TESLA Basic TESLA types (magic for the compiler to munge). */ typedef struct __tesla_event {} __tesla_event; typedef struct __tesla_locality {} __tesla_locality; @@ -84,7 +99,27 @@ /** Function events inside this predicate refer to the caller context. */ struct __tesla_event* __tesla_caller(__tesla_event*, ...); +/** + * Events named in this predicate should only occur exactly as described. + * + * This is the default behaviour for explicit automata representations. + */ +struct __tesla_event* __tesla_strict(__tesla_event*, ...); +/** + * Events named in this predicate must occur as described if the + * execution trace includes a NOW event; otherwise, any number of non-NOW + * events can occur in any order. + * + * For instance, if the assertion names the VOP_WRITE() event, we don't want + * to preclude the use of VOP_WRITE() in code paths that don't include this + * assertion's NOW event. + * + * This is the default behaviour for inline assertions. + */ +struct __tesla_event* __tesla_conditional(__tesla_event*, ...); + + /** Nothing to see here, move along... */ struct __tesla_event* __tesla_ignore; @@ -108,14 +143,35 @@ */ struct __tesla_automaton_description; +struct __tesla_automaton_usage; /** In an explicit automata description, return this to say "we're done". */ struct __tesla_automaton_description* __tesla_automaton_done(); +inline struct __tesla_automaton_usage* +__tesla_struct_uses_automaton(const char *automaton, + __tesla_locality *loc, ...) +{ + return 0; +} + + +/** + * Declare that a struct's behaviour is described by an automaton. + * + * @param subject name of the struct that uses the automaton + * @param automaton reference to the automaton description + * @param loc a TESLA locality (global, per-thread...) + * @param start event that kicks off the automaton + * @param end event that winds up the automaton + */ +#define __tesla_struct_usage(subject, automaton, loc, start, end) \ + struct __tesla_automaton_usage* \ + __tesla_struct_automaton_usage_##struct_name##_##automaton(subject) { \ + return __tesla_struct_uses_automaton( \ + #automaton, loc, start, end); \ + } -/** Declare an automaton that describes behaviour of this struct. */ -#define __tesla_struct_automaton(fn_name) \ - void *__tesla_automaton_struct_uses_##fn_name; /** * Define an automaton to describe a struct's behaviour. @@ -138,21 +194,25 @@ #define __tesla_global ((struct __tesla_locality*) 0) #define __tesla_perthread ((struct __tesla_locality*) 0) -#define __tesla_sequence(...) 1 +#define __tesla_sequence(...) 1 -#define __tesla_struct_automaton(fn_name) +#define __tesla_struct_automaton(...) #define __tesla_automaton(name, ...) -#define __tesla_call(...) 0 -#define __tesla_return(...) 0 +#define __tesla_call(...) 0 +#define __tesla_return(...) 0 + +#define __tesla_callee(...) 0 +#define __tesla_caller(...) 0 -#define __tesla_callee(...) 0 -#define __tesla_caller(...) 0 +#define __tesla_optional(...) 0 +#define __tesla_any(...) 0 -#define __tesla_optional(...) 0 -#define __tesla_any(...) 0 +#define __tesla_strict(...) 0 +#define __tesla_conditional(...) 0 #endif /* __TESLA_ANALYSER__ */ +/** @} */ + #endif /* TESLA_H */ - ==== //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_dtrace.c#4 (text+ko) ==== @@ -37,72 +37,77 @@ #include SDT_PROVIDER_DEFINE(tesla); -SDT_PROBE_DEFINE2(tesla, kernel, , state_transition, state-transition, + +SDT_PROBE_DEFINE2(tesla, kernel, notify, new_instance, new-instance, + "struct tesla_class *", "struct tesla_instance *"); +SDT_PROBE_DEFINE3(tesla, kernel, notify, transition, transition, + "struct tesla_class *", "struct tesla_instance *", + "struct tesla_transition *"); +SDT_PROBE_DEFINE4(tesla, kernel, notify, clone, clone, + "struct tesla_class *", "struct tesla_instance *", + "struct tesla_instance *", "struct tesla_transition *"); +SDT_PROBE_DEFINE3(tesla, kernel, notify, no_instance, no-instance-match, + "struct tesla_class *", "struct tesla_key *", + "struct tesla_transitions *"); +SDT_PROBE_DEFINE3(tesla, kernel, notify, bad_transition, bad-transition, + "struct tesla_class *", "struct tesla_instance *", + "struct tesla_transitions *"); +SDT_PROBE_DEFINE2(tesla, kernel, notify, accept, accept, "struct tesla_class *", "struct tesla_instance *"); -SDT_PROBE_DEFINE2(tesla, kernel, assert, fail, fail, "struct tesla_class *", - "struct tesla_instance *"); -SDT_PROBE_DEFINE2(tesla, kernel, assert, pass, pass, "struct tesla_class *", - "struct tesla_instance *"); -void -tesla_state_transition_dtrace(struct tesla_class *tcp, - struct tesla_instance *tip, - __unused const struct tesla_transitions *transp, - __unused uint32_t transition_index) +static void +new_instance(struct tesla_class *tcp, struct tesla_instance *tip) { - SDT_PROBE(tesla, kernel, , state_transition, tcp, tip, 0, 0, 0); + SDT_PROBE(tesla, kernel, assert, new_instance, tcp, tip, 0, 0, 0); } -void -tesla_assert_fail_dtrace(struct tesla_class *tcp, struct tesla_instance *tip, - __unused const struct tesla_transitions *transp) +static void +transition(struct tesla_class *tcp, struct tesla_instance *tip, + const struct tesla_transition *ttp) { - if (tip) - SDT_PROBE(tesla, kernel, assert, fail, tcp, tip, 0, 0, 0); - - /* XXXRW: - * 'tip' could be NULL if we failed to match any automaton instances - * to go with a supplied key; perhaps a separate probe? - */ + SDT_PROBE(tesla, kernel, notify, transition, tcp, tip, ttp, 0, 0); } -void -tesla_assert_pass_dtrace(struct tesla_class *tcp, struct tesla_instance *tip) +static void +clone(struct tesla_class *tcp, struct tesla_instance *origp, + struct tesla_instance *copyp, const struct tesla_transition *ttp) { - SDT_PROBE(tesla, kernel, assert, pass, tcp, tip, 0, 0, 0); + SDT_PROBE(tesla, kernel, notify, clone, tcp, origp, copyp, ttp, 0); } -#else /* !_KERNEL */ - -void -tesla_state_transition_dtrace(__unused struct tesla_class *tcp, - __unused struct tesla_instance *tip, - __unused const struct tesla_transitions *transp, - __unused uint32_t transition_index) +static void +no_instance(struct tesla_class *tcp, const struct tesla_key *tkp, + const struct tesla_transitions *) { - assert(0 && "DTrace not implemented in userspace"); + SDT_PROBE(tesla, kernel, notify, no_instance, tcp, tkp, ttp, 0, 0); } -void -tesla_assert_fail_dtrace(__unused struct tesla_class *tcp, - __unused struct tesla_instance *tip, - __unused const struct tesla_transitions *transp) +static void +bad_transition(struct tesla_class *tcp, struct tesla_instance *tip, + const struct tesla_transitions *ttp) { - assert(0 && "DTrace not implemented in userspace"); + SDT_PROBE(tesla, kernel, notify, bad_transition, tcp, tip, ttp, 0, 0); } -void -tesla_assert_pass_dtrace(__unused struct tesla_class *tcp, - __unused struct tesla_instance *tip) +static void +accept(struct tesla_class *tcp, struct tesla_instance *tip) { - assert(0 && "DTrace not implemented in userspace"); + SDT_PROBE(tesla, kernel, notify, accept, tcp, tip, 0, 0, 0); } +struct tesla_event_handlers dtrace_handler = { + .teh_init = new_instance, + .teh_transition = transition, + .teh_clone = clone, + .teh_fail_no_instance = no_instance, + .teh_fail_bad_transition = bad_transition, + .teh_accept = accept +}; + #endif /* _KERNEL */ - ==== //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_internal.h#11 (text+ko) ==== @@ -33,6 +33,13 @@ #ifndef TESLA_INTERNAL_H #define TESLA_INTERNAL_H +/** + * @addtogroup libtesla + * @{ + */ + +#include "config.h" + #ifdef _KERNEL #include "opt_kdb.h" #include @@ -59,7 +66,7 @@ #include #endif -//! Is @ref x a subset of @ref y? +/** Is @a x a subset of @a y? */ #define SUBSET(x,y) ((x & y) == x) /** @@ -70,7 +77,7 @@ /** * Clean up a @ref tesla_class. */ -void tesla_class_free(struct tesla_class*); +void tesla_class_destroy(struct tesla_class*); /** * Create a new @ref tesla_instance. @@ -102,7 +109,32 @@ int32_t tesla_match(struct tesla_class *tclass, const struct tesla_key *key, struct tesla_instance **array, uint32_t *size); -/** Copy new entries from @ref source into @ref dest. */ +/** Actions that can be taken by @ref tesla_update_state. */ +enum tesla_action_t { + /** The instance's state should be updated. */ + UPDATE, + + /** The instance should be copied to a new instance. */ + FORK, + + /** The instance is irrelevant to the given transitions. */ + IGNORE, + + /** The instance matches, but there are no valid transitions for it. */ + FAIL +}; + +/** + * What is the correct action to perform on a given @ref tesla_instance to + * satisfy a set of @ref tesla_transitions? + * + * @param[out] trigger the @ref tesla_transition that triggered the action + */ +enum tesla_action_t tesla_action(const struct tesla_instance*, + const struct tesla_key*, const struct tesla_transitions*, + const struct tesla_transition** trigger); + +/** Copy new entries from @a source into @a dest. */ int32_t tesla_key_union(struct tesla_key *dest, const struct tesla_key *source); @@ -134,10 +166,10 @@ #else /* !_KERNEL */ -/** @ref errx() is the userspace equivalent of panic(). */ +/** @a errx() is the userspace equivalent of panic(). */ #define tesla_panic(...) errx(1, __VA_ARGS__) -/** POSIX @ref assert() doesn't let us provide an error message. */ +/** POSIX @a assert() doesn't let us provide an error message. */ #define tesla_assert(condition, ...) assert(condition) #define tesla_malloc(len) calloc(1, len) @@ -153,44 +185,29 @@ /* - * Instance table definition, used for both global and per-thread scopes. A - * more refined data structure might eventually be used here. - */ -struct tesla_table { - uint32_t tt_length; - uint32_t tt_free; - struct tesla_instance tt_instances[]; -}; - -/* * Assertion state definition is internal to libtesla so we can change it as * we need to. */ struct tesla_class { - const char *ts_name; /* Name of the assertion. */ - const char *ts_description;/* Description of the assertion. */ - uint32_t ts_scope; /* Per-thread or global. */ - uint32_t ts_limit; /* Simultaneous automata limit. */ - uint32_t ts_action; /* What to do on failure. */ + const char *tc_name; /* Name of the assertion. */ + const char *tc_description;/* Description of the assertion. */ + uint32_t tc_scope; /* Per-thread or global. */ + uint32_t tc_limit; /* Simultaneous automata limit. */ + + struct tesla_instance *tc_instances; /* Instances of this class. */ + uint32_t tc_free; /* Unused instances. */ - /* - * State fields if global. Table must be last field as it uses a - * zero-length array. - */ #ifdef _KERNEL - struct mtx ts_lock; /* Synchronise ts_table. */ + struct mtx tc_lock; /* Synchronise tc_table. */ #else - pthread_mutex_t ts_lock; /* Synchronise ts_table. */ + pthread_mutex_t tc_lock; /* Synchronise tc_table. */ #endif - - struct tesla_table *ts_table; /* Table of instances. */ }; typedef struct tesla_class tesla_class; typedef struct tesla_instance tesla_instance; typedef struct tesla_key tesla_key; typedef struct tesla_store tesla_store; -typedef struct tesla_table tesla_table; typedef struct tesla_transition tesla_transition; typedef struct tesla_transitions tesla_transitions; @@ -220,12 +237,6 @@ int tesla_class_init(struct tesla_class*, uint32_t context, uint32_t instances); -#if 0 -//! We have failed to find an instance that matches a @ref tesla_key. -void tesla_match_fail(struct tesla_class*, const struct tesla_key*, - const struct tesla_transitions*); -#endif - /* * XXXRW: temporarily, maximum number of classes and instances are hard-coded * constants. In the future, this should somehow be more dynamic. @@ -255,7 +266,7 @@ void tesla_class_global_release(struct tesla_class*); void tesla_class_global_destroy(struct tesla_class*); -int32_t tesla_class_perthread_postinit(struct tesla_class*c); +int32_t tesla_class_perthread_postinit(struct tesla_class*); void tesla_class_perthread_acquire(struct tesla_class*); void tesla_class_perthread_release(struct tesla_class*); void tesla_class_perthread_destroy(struct tesla_class*); @@ -263,44 +274,19 @@ /* * Event notification: */ -/** A new @ref tesla_instance has been created. */ -void tesla_notify_new_instance(struct tesla_class *, - struct tesla_instance *); +extern struct tesla_event_handlers *ev_handlers; +extern struct tesla_event_handlers failstop_handlers; +extern struct tesla_event_handlers printf_handlers; -/** A @ref tesla_instance has taken an expected transition. */ -void tesla_notify_transition(struct tesla_class *, struct tesla_instance *, - const struct tesla_transitions *, uint32_t index); - -/** An exisiting @ref tesla_instance has been cloned because of an event. */ -void tesla_notify_clone(struct tesla_class *, struct tesla_instance *, - const struct tesla_transitions *, uint32_t index); - -/** A @ref tesla_instance was unable to take any of a set of transitions. */ -void tesla_notify_assert_fail(struct tesla_class *, struct tesla_instance *, - const struct tesla_transitions *); - -/** No @ref tesla_class instance was found to match a @ref tesla_key. */ -void tesla_notify_match_fail(struct tesla_class *, const struct tesla_key *, - const struct tesla_transitions *); - -/** A @ref tesla_instance has "passed" (worked through the automaton). */ -void tesla_notify_pass(struct tesla_class *, struct tesla_instance *); - -/* - * DTrace notifications of various events. - */ -void tesla_state_transition_dtrace(struct tesla_class *, - struct tesla_instance *, const struct tesla_transitions *, - uint32_t transition_index); -void tesla_assert_fail_dtrace(struct tesla_class *, - struct tesla_instance *, const struct tesla_transitions *); -void tesla_assert_pass_dtrace(struct tesla_class *, - struct tesla_instance *); +#ifdef _KERNEL +extern struct tesla_event_handlers dtrace_handlers; +#endif /* * Debug helpers. */ +/** Do a @a sprintf() into a buffer, checking bounds appropriately. */ #define SAFE_SPRINTF(current, end, ...) do { \ int written = snprintf(current, end - current, __VA_ARGS__); \ if ((written > 0) && (current + written < end)) \ @@ -321,24 +307,24 @@ #ifdef _KERNEL #include -#define DEBUG_PRINT(...) print(__VA_ARGS__) #else #include -#define DEBUG_PRINT(...) print(__VA_ARGS__) #endif -#define VERBOSE_PRINT(...) if (verbose_debug()) DEBUG_PRINT(__VA_ARGS__) /** Are we in (verbose) debug mode? */ -int32_t verbose_debug(void); +int32_t tesla_debugging(const char*); + +/** Emit debugging information with a debug name (e.g., libtesla.event). */ +#define DEBUG(dclass, ...) \ + if (tesla_debugging(#dclass)) printf(__VA_ARGS__) #else // NDEBUG // When not in debug mode, some values might not get checked. #define __debug __unused -#define DEBUG_PRINT(...) -#define VERBOSE_PRINT(...) -int32_t verbose_debug(void) { return 0; } +#define DEBUG(...) +int32_t tesla_debugging(const char*) { return 0; } #endif @@ -346,10 +332,10 @@ * Assert that a @ref tesla_instance is an instance of a @ref tesla_class. * * This could be expensive (a linear walk over all @ref tesla_instance in - * @ref #tclass), so it should only be called from debug code. + * @a tclass), so it should only be called from debug code. * * @param i the instance to test - * @param tclass the expected class of @ref #i + * @param tclass the expected class of @a i */ void assert_instanceof(struct tesla_instance *i, struct tesla_class *tclass); @@ -357,16 +343,25 @@ char* key_string(char *buffer, const char *end, const struct tesla_key *); /** Print a @ref tesla_key to stderr. */ -void print_key(const struct tesla_key *key); +void print_key(const char *debug_name, const struct tesla_key *key); /** Print a @ref tesla_class to stderr. */ void print_class(const struct tesla_class*); +/** Print a human-readable version of a @ref tesla_transition. */ +void print_transition(const char *debug, const struct tesla_transition *); + +/** Print a human-readable version of a @ref tesla_transition into a buffer. */ +char* sprint_transition(char *buffer, const char *end, + const struct tesla_transition *); + /** Print a human-readable version of @ref tesla_transitions. */ -void print_transitions(const struct tesla_transitions *); +void print_transitions(const char *debug, const struct tesla_transitions *); /** Print a human-readable version of @ref tesla_transitions into a buffer. */ char* sprint_transitions(char *buffer, const char *end, const struct tesla_transitions *); +/** @} */ + #endif /* TESLA_INTERNAL_H */ ==== //depot/projects/ctsrd/tesla/src/sys/libtesla/tesla_notification.c#4 (text+ko) ==== @@ -34,185 +34,208 @@ #define ERROR_BUFFER_LENGTH 1024 +int +tesla_set_event_handlers(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) + return (TESLA_ERROR_EINVAL); + + ev_handlers = tehp; + return (TESLA_SUCCESS); +} + +/* + * printf()-based event handlers: + */ +static void print_new_instance(struct tesla_class *, + struct tesla_instance *); + +static void print_transition_taken(struct tesla_class *, + struct tesla_instance *, const struct tesla_transition*); + +static void print_clone(struct tesla_class *, + struct tesla_instance *orig, struct tesla_instance *copy, + const struct tesla_transition*); + +static void print_no_instance(struct tesla_class *, + const struct tesla_key *, const struct tesla_transitions *); + +static void print_bad_transition(struct tesla_class *, + struct tesla_instance *, const struct tesla_transitions *); + +static void print_accept(struct tesla_class *, struct tesla_instance *); + +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 +}; + + +/* + * Wrappers that panic on failure: + */ +static void panic_no_instance(struct tesla_class *, + const struct tesla_key *, const struct tesla_transitions *); + +static void panic_bad_transition(struct tesla_class *, + struct tesla_instance *, const struct tesla_transitions *); + +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 +}; + + +/** Default to print-with-failstop in userspace, DTrace in the kernel. */ +struct tesla_event_handlers *ev_handlers = +#ifdef _KERNEL + &dtrace_handlers +#else + &failstop_handlers +#endif + ; + static void print_failure_header(const struct tesla_class *); + void -tesla_notify_new_instance(struct tesla_class *tcp, - struct tesla_instance *tip) +print_new_instance(struct tesla_class *tcp, struct tesla_instance *tip) { - switch (tcp->ts_action) { - case TESLA_ACTION_DTRACE: - /* XXXRW: more fine-grained DTrace probes? */ - tesla_state_transition_dtrace(tcp, tip, NULL, -1); - return; + DEBUG(libtesla.instance.new, "new %td: %tx\n", + tip - tcp->tc_instances, tip->ti_state); +} - default: - /* for the PRINTF action, should this be a non-verbose print? */ - VERBOSE_PRINT("new %td: %tx\n", - tip - tcp->ts_table->tt_instances, - tip->ti_state); +void +print_transition_taken(struct tesla_class *tcp, + struct tesla_instance *tip, const struct tesla_transition *transp) +{ - /* - * XXXJA: convince self that we can never "pass" an assertion - * with an event that creates a new instance - */ - - break; - } + DEBUG(libtesla.state.transition, "update %td: %tx->%tx\n", + tip - tcp->tc_instances, transp->from, transp->to); } void -tesla_notify_clone(struct tesla_class *tcp, struct tesla_instance *tip, - const struct tesla_transitions *transp, uint32_t index) +print_clone(struct tesla_class *tcp, + struct tesla_instance *old_instance, struct tesla_instance *new_instance, + const struct tesla_transition *transp) { - switch (tcp->ts_action) { - case TESLA_ACTION_DTRACE: - /* XXXRW: more fine-grained DTrace probes? */ - tesla_state_transition_dtrace(tcp, tip, transp, index); - return; + DEBUG(libtesla.instance.clone, "clone %td:%tx -> %td:%tx\n", + old_instance - tcp->tc_instances, transp->from, + new_instance - tcp->tc_instances, transp->to); +} + +static void +no_instance_message(char *buffer, const char *end, + struct tesla_class *tcp, const struct tesla_key *tkp, + const struct tesla_transitions *transp) +{ - default: { - /* for the PRINTF action, should this be a non-verbose print? */ - assert(index >= 0); - assert(index < transp->length); - const struct tesla_transition *t = transp->transitions + index; + assert(tcp != NULL); + assert(tkp != NULL); - VERBOSE_PRINT("clone %td:%tx -> %tx\n", - tip - tcp->ts_table->tt_instances, - tip->ti_state, t->to); + print_failure_header(tcp); - if (t->flags & TESLA_TRANS_CLEANUP) - tesla_notify_pass(tcp, tip); + char *next = buffer; - break; - } - } + SAFE_SPRINTF(next, end, "No instance matched key '"); + next = key_string(next, end, tkp); + SAFE_SPRINTF(next, end, "' for transition(s) "); + next = sprint_transitions(next, end, transp); + assert(next > buffer); } void -tesla_notify_transition(struct tesla_class *tcp, - struct tesla_instance *tip, const struct tesla_transitions *transp, - uint32_t index) +print_no_instance(struct tesla_class *tcp, const struct tesla_key *tkp, + const struct tesla_transitions *transp) { - switch (tcp->ts_action) { - case TESLA_ACTION_DTRACE: - tesla_state_transition_dtrace(tcp, tip, transp, index); - return; + char buffer[ERROR_BUFFER_LENGTH]; + const char *end = buffer + sizeof(buffer); - default: { - /* for the PRINTF action, should this be a non-verbose print? */ - assert(index >= 0); - assert(index < transp->length); - const struct tesla_transition *t = transp->transitions + index; + no_instance_message(buffer, end, tcp, tkp, transp); + error("%s", buffer); +} - VERBOSE_PRINT("update %td: %tx->%tx\n", - tip - tcp->ts_table->tt_instances, - t->from, t->to); +void +panic_no_instance(struct tesla_class *tcp, const struct tesla_key *tkp, + const struct tesla_transitions *transp) +{ - if (t->flags & TESLA_TRANS_CLEANUP) - tesla_notify_pass(tcp, tip); + char buffer[ERROR_BUFFER_LENGTH]; + const char *end = buffer + sizeof(buffer); - break; - } - } + no_instance_message(buffer, end, tcp, tkp, transp); + tesla_panic("%s", buffer); } -void -tesla_notify_assert_fail(struct tesla_class *tcp, struct tesla_instance *tip, +static void +bad_transition_message(char *buffer, const char *end, + struct tesla_class *tcp, struct tesla_instance *tip, const struct tesla_transitions *transp) { + assert(tcp != NULL); assert(tip != NULL); - if (tcp->ts_action == TESLA_ACTION_DTRACE) { - tesla_assert_fail_dtrace(tcp, tip, transp); - return; - } - print_failure_header(tcp); - char buffer[ERROR_BUFFER_LENGTH]; char *next = buffer; - const char *end = buffer + sizeof(buffer); SAFE_SPRINTF(next, end, "Instance %td is in state %d\n" "but required to take a transition in ", - (tip - tcp->ts_table->tt_instances), tip->ti_state); + (tip - tcp->tc_instances), tip->ti_state); assert(next > buffer); next = sprint_transitions(next, end, transp); + assert(next > buffer); +} - switch (tcp->ts_action) { - case TESLA_ACTION_DTRACE: - assert(0 && "handled above"); - return; +void +print_bad_transition(struct tesla_class *tcp, struct tesla_instance *tip, + const struct tesla_transitions *transp) +{ - case TESLA_ACTION_FAILSTOP: - tesla_panic("%s", buffer); - break; + char buffer[ERROR_BUFFER_LENGTH]; + const char *end = buffer + sizeof(buffer); - case TESLA_ACTION_PRINTF: - error("%s", buffer); - break; - } + bad_transition_message(buffer, end, tcp, tip, transp); + error("%s", buffer); } void -tesla_notify_match_fail(struct tesla_class *tcp, const struct tesla_key *tkp, +panic_bad_transition(struct tesla_class *tcp, struct tesla_instance *tip, const struct tesla_transitions *transp) { - assert(tcp != NULL); - assert(tkp != NULL); - - if (tcp->ts_action == TESLA_ACTION_DTRACE) { - tesla_assert_fail_dtrace(tcp, NULL, NULL); - return; - } - print_failure_header(tcp); - char buffer[ERROR_BUFFER_LENGTH]; - char *next = buffer; const char *end = buffer + sizeof(buffer); - SAFE_SPRINTF(next, end, "No instance matched key '"); - next = key_string(next, end, tkp); - SAFE_SPRINTF(next, end, "' for transition(s) "); - next = sprint_transitions(next, end, transp); - - switch (tcp->ts_action) { - case TESLA_ACTION_DTRACE: - assert(0 && "handled above"); - break; - - case TESLA_ACTION_FAILSTOP: - tesla_panic("%s", buffer); - break; - - case TESLA_ACTION_PRINTF: - error("%s", buffer); - break; - } + bad_transition_message(buffer, end, tcp, tip, transp); + tesla_panic("%s", buffer); } >>> TRUNCATED FOR MAIL (1000 lines) <<<