PERFORCE change 229369 for review
Jonathan Anderson
jonathan at FreeBSD.org
Tue Jun 4 15:53:26 UTC 2013
http://p4web.freebsd.org/@@229369?ac=10
Change 229369 by jonathan at 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 <bsd.lib.mk>
-
==== //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 <sys/types.h>
#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 <i>if</i> 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 <sys/sdt.h>
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 <sys/param.h>
@@ -59,7 +66,7 @@
#include <libtesla.h>
#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 <sys/systm.h>
-#define DEBUG_PRINT(...) print(__VA_ARGS__)
#else
#include <stdio.h>
-#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) <<<
More information about the p4-projects
mailing list