PERFORCE change 1046466 for review

Jonathan Anderson jonathan at FreeBSD.org
Fri Oct 11 15:56:02 UTC 2013


http://p4web.freebsd.org/@@1046466?ac=10

Change 1046466 by jonathan at jonathan-on-zenith on 2013/10/11 15:55:05

	Merge optimised version of TESLA kernel parts.

Affected files ...

.. //depot/projects/ctsrd/tesla/src/sys/amd64/conf/TESLA_NODEBUG#2 edit
.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/include/libtesla.h#14 edit
.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_dtrace.c#13 edit
.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_internal.h#15 edit
.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_notification.c#19 edit
.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_store.c#9 edit
.. //depot/projects/ctsrd/tesla/src/sys/contrib/tesla/libtesla/tesla_update.c#14 edit

Differences ...

==== //depot/projects/ctsrd/tesla/src/sys/amd64/conf/TESLA_NODEBUG#2 (text+ko) ====

@@ -1,6 +1,7 @@
 include TESLA
 ident TESLA_NODEBUG
 
+options TESLA
 nooptions INVARIANTS
 nooptions INVARIANT_SUPPORT
 nooptions WITNESS

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

@@ -76,7 +76,7 @@
  * a number of times with different names and current states.
  */
 struct tesla_class;
-
+struct tesla_lifetime_event;
 struct tesla_transitions;
 
 /**
@@ -94,6 +94,11 @@
 	 */
 	const int32_t			 ta_alphabet_size;
 
+        /**
+         * The symbol number used to signal cleanup.
+         */
+        const int32_t                    ta_cleanup_symbol;
+
 	/**
 	 * Transitions that will be taken in response to events.
 	 *
@@ -107,6 +112,54 @@
 
 	/** Human-readable descriptions of input symbols (for debugging). */
 	const char*			*ta_symbol_names;
+
+	/** The automaton's lifetime. */
+	const struct tesla_lifetime	*ta_lifetime;
+};
+
+
+/**
+ * A short, unique, deterministic representation of a lifetime entry/exit event,
+ * a pair of which defines an automaton's lifetime.
+ */
+struct tesla_lifetime_event {
+	/**
+	 * An opaque representation of the automaton's initialisation event.
+	 *
+	 * This description should be short and deterministic,
+	 * i.e., multiple automata that share the same init event should
+	 * have exactly the same ta_init description string.
+	 *
+	 * This can be written by hand if needed (e.g. for testing),
+	 * but in practice we generate it from protocol buffers.
+	 */
+	const char			*tle_repr;
+
+	/** The length of @ref #tle_repr. */
+	const int32_t			 tle_length;
+
+	/**
+	 * A precomputed hash of @ref #tle_repr.
+	 *
+	 * libtesla doesn't care what hash algorithm is used; in test code or
+	 * statically-compiled clients, incrementing integers works well.
+	 *
+	 * All clients should be consistent, however; the TESLA instrumenter
+	 * uses SuperFastHash.
+	 */
+	const int32_t			 tle_hash;
+};
+
+
+/**
+ * The description of a TESLA lifetime.
+ */
+struct tesla_lifetime {
+	struct tesla_lifetime_event	tl_begin;
+	struct tesla_lifetime_event	tl_end;
+
+	/** A human-readable string for debugging. */
+	const char			*tl_repr;
 };
 
 
@@ -246,7 +299,20 @@
 	const struct tesla_automaton *automaton,
 	uint32_t symbol, const struct tesla_key *pattern);
 
+/**
+ * We have encountered an entry bound for some automata.
+ *
+ * @param  context      Where the automaton is stored.
+ * @param  l            Static description of the lifetime (begin, end events).
+ */
+void	tesla_sunrise(enum tesla_context context,
+	const struct tesla_lifetime *l);
+
+/** We have encountered an exit bound for some automata. */
+void	tesla_sunset(enum tesla_context context,
+	const struct tesla_lifetime*);
 
+
 /** A single instance of an automaton: a name (@ref ti_key) and a state. */
 struct tesla_instance {
 	struct tesla_key	ti_key;
@@ -257,6 +323,14 @@
 /*
  * Event notification:
  */
+/** An initialisation event has occurred; entering an automaton lifetime. */
+typedef void	(*tesla_ev_sunrise)(enum tesla_context,
+	    const struct tesla_lifetime *);
+
+/** A cleanup event has occurred; exiting an automaton lifetime. */
+typedef void	(*tesla_ev_sunset)(enum tesla_context,
+	    const struct tesla_lifetime *);
+
 /** A new @ref tesla_instance has been created. */
 typedef void	(*tesla_ev_new_instance)(struct tesla_class *,
 	    struct tesla_instance *);
@@ -292,6 +366,8 @@
 
 /** A vector of event handlers. */
 struct tesla_event_handlers {
+	tesla_ev_sunrise	teh_sunrise;
+	tesla_ev_sunset		teh_sunset;
 	tesla_ev_new_instance	teh_init;
 	tesla_ev_transition	teh_transition;
 	tesla_ev_clone		teh_clone;

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

@@ -38,6 +38,10 @@
 
 SDT_PROVIDER_DEFINE(tesla);
 
+SDT_PROBE_DEFINE2(tesla, automata, lifetime, sunrise, sunrise,
+    "enum tesla_context context", "struct tesla_lifetime *");
+SDT_PROBE_DEFINE2(tesla, automata, lifetime, sunset, sunset,
+    "enum tesla_context context", "struct tesla_lifetime *");
 SDT_PROBE_DEFINE2(tesla, automata, instance, create, create,
     "struct tesla_class *", "struct tesla_instance *");
 SDT_PROBE_DEFINE3(tesla, automata, event, transition, state-transition,
@@ -60,6 +64,20 @@
     "struct tesla_class *", "int32_t", "struct tesla_key *");
 
 static void
+sunrise(enum tesla_context c, const struct tesla_lifetime *tl)
+{
+
+	SDT_PROBE(tesla, automata, lifetime, sunrise, c, tl, 0, 0, 0);
+}
+
+static void
+sunset(enum tesla_context c, const struct tesla_lifetime *tl)
+{
+
+	SDT_PROBE(tesla, automata, lifetime, sunset, c, tl, 0, 0, 0);
+}
+
+static void
 new_instance(struct tesla_class *tcp, struct tesla_instance *tip)
 {
 
@@ -144,6 +162,8 @@
 }
 
 const struct tesla_event_handlers dtrace_handlers = {
+	.teh_sunrise			= sunrise,
+	.teh_sunset			= sunset,
 	.teh_init			= new_instance,
 	.teh_transition			= transition,
 	.teh_clone			= clone,

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

@@ -65,6 +65,7 @@
 #include <assert.h>
 #include <err.h>
 #include <pthread.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #endif
@@ -79,7 +80,28 @@
 #define assert(cond) KASSERT((cond), ("Assertion failed: '%s'", #cond))
 #endif
 
+
 /**
+ * The current runtime state of a TESLA lifetime.
+ */
+struct tesla_lifetime_state {
+	struct tesla_lifetime_event	 tls_begin;
+	struct tesla_lifetime_event	 tls_end;
+
+	/** A place to register a few classes that share this lifetime. */
+	struct tesla_class*		 tls_classes[4];
+
+	/** A place to register more classes that share this lifetime. */
+	struct tesla_class*		*tls_dyn_classes;
+
+	/** The number of values @ref tls_dyn_classes can hold. */
+	uint32_t			 tls_dyn_capacity;
+
+	/** The number of values currently in @ref tls_dyn_classes. */
+	uint32_t			 tls_dyn_count;
+};
+
+/**
  * Call this if things go catastrophically, unrecoverably wrong.
  */
 void	tesla_die(int32_t errnum, const char *event) __attribute__((noreturn));
@@ -130,8 +152,46 @@
 	return ((i->ti_state != 0) || (i->ti_key.tk_mask != 0));
 }
 
+static inline bool
+same_lifetime(const struct tesla_lifetime *x, const struct tesla_lifetime *y)
+{
+	assert(x != NULL);
+	assert(y != NULL);
+
+	return (x->tl_begin.tle_length == y->tl_begin.tle_length)
+		&& (x->tl_end.tle_length == y->tl_end.tle_length)
+		&& (x->tl_begin.tle_hash == y->tl_begin.tle_hash)
+		&& (x->tl_end.tle_hash == y->tl_end.tle_hash)
+		&& (strncmp(x->tl_begin.tle_repr, y->tl_begin.tle_repr,
+		            x->tl_begin.tle_length) == 0)
+		&& (strncmp(x->tl_end.tle_repr, y->tl_end.tle_repr,
+		            x->tl_end.tle_length) == 0)
+		;
+}
+
+/**
+ * Compare the static parts of a @ref tesla_lifetime_state with a
+ * @ref tesla_lifetime.
+ */
+static inline bool
+same_static_lifetime(const struct tesla_lifetime *x,
+	const struct tesla_lifetime_state *y)
+{
+	assert(x != NULL);
+	assert(y != NULL);
 
+	return (x->tl_begin.tle_length == y->tls_begin.tle_length)
+		&& (x->tl_end.tle_length == y->tls_end.tle_length)
+		&& (x->tl_begin.tle_hash == y->tls_begin.tle_hash)
+		&& (x->tl_end.tle_hash == y->tls_end.tle_hash)
+		&& (strncmp(x->tl_begin.tle_repr, y->tls_begin.tle_repr,
+		            x->tl_begin.tle_length) == 0)
+		&& (strncmp(x->tl_end.tle_repr, y->tls_end.tle_repr,
+		            x->tl_end.tle_length) == 0)
+		;
+}
 
+
 /** Clone an existing instance into a new instance. */
 int32_t	tesla_instance_clone(struct tesla_class *tclass,
 	    const struct tesla_instance *orig, struct tesla_instance **copy);
@@ -262,10 +322,13 @@
 #endif
 };
 
+
 typedef struct tesla_automaton		tesla_automaton;
 typedef struct tesla_class		tesla_class;
 typedef struct tesla_instance		tesla_instance;
 typedef struct tesla_key		tesla_key;
+typedef struct tesla_lifetime_event	tesla_lifetime_event;
+typedef struct tesla_lifetime_state	tesla_lifetime_state;
 typedef struct tesla_store		tesla_store;
 typedef struct tesla_transition		tesla_transition;
 typedef struct tesla_transitions	tesla_transitions;
@@ -283,6 +346,19 @@
 
 	/** Actual slots that classes might be stored in. */
 	struct tesla_class	*ts_classes;
+
+	/**
+	 * Information about live/dead automata classes; may be shared among
+	 * automata.
+	 *
+	 * For instance, the lifetime [enter syscall, exit syscall] is shared
+	 * by many automata we've written for the FreeBSD kernel. Each
+	 * @ref tesla_store should only record these events once.
+	 */
+	struct tesla_lifetime_state *ts_lifetimes;
+
+	/** The number of lifetimes that we currently know about. */
+	uint32_t		ts_lifetime_count;
 };
 
 /**
@@ -333,6 +409,8 @@
 extern const struct tesla_event_handlers dtrace_handlers;
 #endif
 
+void	ev_sunrise(enum tesla_context, const struct tesla_lifetime *);
+void	ev_sunset(enum tesla_context, const struct tesla_lifetime *);
 void	ev_new_instance(struct tesla_class *, struct tesla_instance *);
 void	ev_transition(struct tesla_class *, struct tesla_instance *,
 	    const struct tesla_transition *);

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

@@ -51,7 +51,8 @@
 check_event_handler(const struct tesla_event_handlers *tehp)
 {
 
-	if (!tehp || !tehp->teh_init || !tehp->teh_transition
+	if (!tehp || !tehp->teh_sunrise || !tehp->teh_sunset
+	    || !tehp->teh_init || !tehp->teh_transition
 	    || !tehp->teh_clone || !tehp->teh_fail_no_instance
 	    || !tehp->teh_bad_transition || !tehp->teh_err
 	    || !tehp->teh_accept || !tehp->teh_ignored)
@@ -118,8 +119,23 @@
 			if (event_handlers->tem_handlers[i]->x) \
 				event_handlers->tem_handlers[i]->x(__VA_ARGS__)
 
+void
+ev_sunrise(enum tesla_context c, const struct tesla_lifetime *tl)
+{
+
+	FOREACH_ERROR_HANDLER(teh_sunrise, c, tl);
+}
+
 
 void
+ev_sunset(enum tesla_context c, const struct tesla_lifetime *tl)
+{
+
+	FOREACH_ERROR_HANDLER(teh_sunset, c, tl);
+}
+
+
+void
 ev_new_instance(struct tesla_class *tcp, struct tesla_instance *tip)
 {
 
@@ -201,6 +217,22 @@
 }
 
 static void
+print_sunrise(enum tesla_context c, const struct tesla_lifetime *tl)
+{
+
+    DEBUG(libtesla.sunrise, "sunrise  %s %s\n",
+	    (c == TESLA_CONTEXT_GLOBAL) ? "global" : "per-thread", tl->tl_repr);
+}
+
+static void
+print_sunset(enum tesla_context c, const struct tesla_lifetime *tl)
+{
+
+    DEBUG(libtesla.sunset, "sunset   %s %s\n",
+	    (c == TESLA_CONTEXT_GLOBAL) ? "global" : "per-thread", tl->tl_repr);
+}
+
+static void
 print_new_instance(struct tesla_class *tcp, struct tesla_instance *tip)
 {
 
@@ -318,11 +350,13 @@
 {
 	const struct tesla_automaton *a = tcp->tc_automaton;
 
-	DEBUG(libtesla.event, "ignore '%s': %s", a->ta_name,
+	DEBUG(libtesla.event, "ignore '%s': %s\n", a->ta_name,
 		a->ta_symbol_names[symbol]);
 }
 
 static const struct tesla_event_handlers printf_handlers = {
+	.teh_sunrise		= print_sunrise,
+	.teh_sunset		= print_sunset,
 	.teh_init		= print_new_instance,
 	.teh_transition		= print_transition_taken,
 	.teh_clone		= print_clone,
@@ -334,6 +368,8 @@
 };
 
 static const struct tesla_event_handlers printf_on_failure = {
+	.teh_sunrise		= 0,
+	.teh_sunset		= 0,
 	.teh_init		= 0,
 	.teh_transition		= 0,
 	.teh_clone		= 0,

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

@@ -145,6 +145,18 @@
 		assert(store->ts_classes[i].tc_context >= 0);
 	}
 
+	/*
+	 * For now, allocate as many lifetime storage slots as there are
+	 * classes. In practice, many automata will share lifetime information.
+	 *
+	 * TODO(JA): perhaps allocate fewer of these?
+	 */
+	const size_t lifetime_size = classes * sizeof(store->ts_lifetimes[0]);
+	store->ts_lifetimes = tesla_malloc(lifetime_size);
+	bzero(store->ts_lifetimes, lifetime_size);
+
+	store->ts_lifetime_count = 0;
+
 	return (error);
 }
 
@@ -157,6 +169,7 @@
 	for (uint32_t i = 0; i < store->ts_length; i++)
 		tesla_class_destroy(store->ts_classes + i);
 
+	tesla_free(store->ts_lifetimes);
 	tesla_free(store);
 }
 

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

@@ -39,24 +39,104 @@
 #endif
 
 
+static void tesla_update_class_state(struct tesla_class *, struct tesla_store *,
+	uint32_t symbol, const struct tesla_key *);
+
+
+void
+tesla_sunrise(enum tesla_context context, const struct tesla_lifetime *l)
+{
+	__unused int ret;
+	assert(l != NULL);
+
+	struct tesla_store *store;
+	ret = tesla_store_get(context, TESLA_MAX_CLASSES,
+			TESLA_MAX_INSTANCES, &store);
+	assert(ret == TESLA_SUCCESS);
+	assert(store->ts_lifetime_count < store->ts_length);
+
+	tesla_lifetime_state *ls = NULL;
+
+	// TODO: lock global store
+
+	const uint32_t lifetimes = store->ts_lifetime_count;
+	for (uint32_t i = 0; i < lifetimes; i++) {
+	    if (same_static_lifetime(l, store->ts_lifetimes + i)) {
+		    ls = store->ts_lifetimes + i;
+		    break;
+	    }
+	}
+
+	if (ls == NULL) {
+		ls = store->ts_lifetimes + lifetimes;
+		store->ts_lifetime_count++;
+
+		ls->tls_begin = l->tl_begin;
+		ls->tls_end = l->tl_end;
+	}
+
+	ev_sunrise(context, l);
+}
+
+
+void
+tesla_sunset(enum tesla_context context, const struct tesla_lifetime *l)
+{
+	__unused int ret;
+	assert(l != NULL);
+
+	ev_sunset(context, l);
+
+	struct tesla_store *store;
+	ret = tesla_store_get(context, TESLA_MAX_CLASSES,
+			TESLA_MAX_INSTANCES, &store);
+	assert(ret == TESLA_SUCCESS);
+	assert(store->ts_lifetime_count < store->ts_length);
+
+	tesla_lifetime_state *ls = NULL;
+
+	const uint32_t lifetimes = store->ts_lifetime_count;
+	for (uint32_t i = 0; i < lifetimes; i++) {
+		if (same_static_lifetime(l, store->ts_lifetimes + i)) {
+			ls = store->ts_lifetimes + i;
+			break;
+		}
+	}
+
+	assert(ls != NULL && "tesla_sunset() without corresponding sunrise");
+
+	tesla_key empty_key;
+	empty_key.tk_mask = 0;
+
+	const size_t static_classes =
+		sizeof(ls->tls_classes) / sizeof(ls->tls_classes[0]);
+
+	for (size_t i = 0; i < static_classes; i++) {
+		tesla_class *class = ls->tls_classes[i];
+		if (class == NULL)
+			break;
+
+		tesla_update_class_state(class, store,
+			class->tc_automaton->ta_cleanup_symbol, &empty_key);
+	}
+
+	const size_t dynamic_classes = ls->tls_dyn_count;
+	for (size_t i = 0; i < dynamic_classes; i++) {
+		tesla_class *class = ls->tls_dyn_classes[i];
+		if (class == NULL)
+			break;
+
+		tesla_update_class_state(class, store,
+			class->tc_automaton->ta_cleanup_symbol, &empty_key);
+	}
+}
+
+
 void
 tesla_update_state(enum tesla_context tesla_context,
 	const struct tesla_automaton *autom, uint32_t symbol,
 	const struct tesla_key *pattern)
 {
-	const struct tesla_transitions *trans =
-		autom->ta_transitions + symbol;
-
-#ifndef NDEBUG
-	/* We should never see with multiple <<init>> transitions. */
-	int init_count = 0;
-	for (uint32_t i = 0; i < trans->length; i++)
-		if (trans->transitions[i].flags & TESLA_TRANS_INIT)
-			init_count++;
-
-	assert(init_count < 2);
-#endif
-
 	struct tesla_store *store;
 	int ret = tesla_store_get(tesla_context, TESLA_MAX_CLASSES,
 			TESLA_MAX_INSTANCES, &store);
@@ -66,11 +146,18 @@
 	ret = tesla_class_get(store, autom, &class);
 	assert(ret == TESLA_SUCCESS);
 
-	// Did we match any instances?
-	bool matched_something = false;
+	tesla_update_class_state(class, store, symbol, pattern);
+
+	tesla_class_put(class);
+}
+
 
-	// When we're done, do we need to clean up the class?
-	bool cleanup_required = false;
+static void
+tesla_update_class_state(struct tesla_class *class, struct tesla_store *store,
+	uint32_t symbol, const struct tesla_key *pattern)
+{
+	int err;
+	const struct tesla_automaton *autom = class->tc_automaton;
 
 	// Make space for cloning existing instances.
 	size_t cloned = 0;
@@ -80,8 +167,131 @@
 		const tesla_transition *transition;
 	} clones[max_clones];
 
+	// Has this class been initialised?
+	bool initialised = false;
+	tesla_lifetime_state *lifetime = NULL;
+	const uint32_t lifetimes = store->ts_lifetime_count;
+	for (uint32_t i = 0; i < lifetimes; i++) {
+		if (!same_static_lifetime(autom->ta_lifetime,
+			    store->ts_lifetimes + i))
+			continue;
+
+		initialised = true;
+		lifetime = store->ts_lifetimes + i;
+		break;
+	}
+
+	if (!initialised) {
+		 ev_ignored(class, symbol, pattern);
+		 return;
+
+	} else if (class->tc_limit == class->tc_free) {
+		// Late initialisation: find the init transition and pretend
+		// it has already been taken.
+		struct tesla_instance *inst = NULL;
+
+		for (uint32_t i = 0; i < autom->ta_alphabet_size; i++) {
+			const tesla_transitions *trans =
+				autom->ta_transitions + i;
+
+			for (uint32_t j = 0; i < trans->length; i++) {
+				const tesla_transition *t =
+					trans->transitions + j;
+
+				if (!(t->flags & TESLA_TRANS_INIT))
+					continue;
+
+				static const tesla_key empty = { .tk_mask = 0 };
+
+				err = tesla_instance_new(class, &empty,
+				                         t->to, &inst);
+
+				if (err != TESLA_SUCCESS) {
+
+					ev_err(autom, symbol, err,
+					       "failed to initialise instance");
+					return;
+				}
+
+				break;
+			}
+		}
+
+		if (inst == NULL) {
+			// The automaton does not have an init transition!
+			err = TESLA_ERROR_EINVAL;
+			ev_err(autom, symbol, err,
+			       "automaton has no init transition");
+			return;
+		}
+
+		assert(tesla_instance_active(inst));
+		ev_new_instance(class, inst);
+
+		// Register this class for eventual cleanup.
+		tesla_lifetime_state *ls = lifetime;
+		const size_t static_classes =
+			sizeof(ls->tls_classes) / sizeof(ls->tls_classes[0]);
+
+		size_t i;
+		for (i = 0; i < static_classes; i++) {
+			if (ls->tls_classes[i] != NULL)
+				continue;
+
+			ls->tls_classes[i] = class;
+			break;
+		}
+
+		if (i == static_classes) {
+#ifdef _KERNEL
+			/*
+			 * TODO(JA): we should also do the dynamic thing,
+			 *           but we might have to do it by noting
+			 *           that we don't have enough space and
+			 *           leaving the allocation for a later time
+			 *           when we know it's safe.
+			 */
+			ev_err(autom, symbol, TESLA_ERROR_ENOMEM,
+			       "out of dynamic registration space in lifetime");
+#else
+			static size_t unit_size =
+				sizeof(ls->tls_dyn_classes[0]);
+
+			tesla_class ***dyn_classes = &ls->tls_dyn_classes;
+
+			if (ls->tls_dyn_capacity == 0) {
+				// Need to create a fresh allocation.
+				size_t count = 8;
+				*dyn_classes = calloc(count, unit_size);
+				ls->tls_dyn_capacity = count;
+			} else {
+				size_t count = 2 * ls->tls_dyn_capacity;
+				*dyn_classes = realloc(*dyn_classes,
+						       count * unit_size);
+				ls->tls_dyn_capacity = count;
+			}
+
+			assert(ls->tls_dyn_count < ls->tls_dyn_capacity);
+			ls->tls_dyn_classes[ls->tls_dyn_count++] = class;
+#endif
+		}
+	}
+
+
+	// Did we match any instances?
+	bool matched_something = false;
+
+	// When we're done, do we need to clean up the class?
+	bool cleanup_required = false;
+
+
+	// What transitions can we take?
+	const tesla_transitions *trans = autom->ta_transitions + symbol;
+	assert(trans->length > 0);
+	assert(trans->length < 10000);
+
 	// Iterate over existing instances, figure out what to do with each.
-	int err = TESLA_SUCCESS;
+	err = TESLA_SUCCESS;
 	int expected = class->tc_limit - class->tc_free;
 	for (uint32_t i = 0; expected > 0 && (i < class->tc_limit); i++) {
 		assert(class->tc_instances != NULL);
@@ -98,6 +308,7 @@
 			break;
 
 		case IGNORE:
+			// TODO(JA): this should become unreachable
 			break;
 
 		case UPDATE:
@@ -115,7 +326,7 @@
 			if (cloned >= max_clones) {
 				err = TESLA_ERROR_ENOMEM;
 				ev_err(autom, symbol, err, "too many clones");
-				goto cleanup;
+				return;
 			}
 
 			struct clone_info *clone = clones + cloned++;
@@ -154,7 +365,7 @@
 		err = tesla_instance_clone(class, c->old, &clone);
 		if (err != TESLA_SUCCESS) {
 			ev_err(autom, symbol, err, "failed to clone instance");
-			goto cleanup;
+			return;
 		}
 
 		tesla_key new_name = *pattern;
@@ -162,7 +373,7 @@
 		err = tesla_key_union(&clone->ti_key, &new_name);
 		if (err != TESLA_SUCCESS) {
 			ev_err(autom, symbol, err, "failed to union keys");
-			goto cleanup;
+			return;
 		}
 
 		clone->ti_state = c->transition->to;
@@ -173,42 +384,12 @@
 			ev_accept(class, clone);
 	}
 
-
-	// Does this transition cause class instance initialisation?
-	for (uint32_t i = 0; i < trans->length; i++) {
-		const tesla_transition *t = trans->transitions + i;
-		if (t->flags & TESLA_TRANS_INIT) {
-			struct tesla_instance *inst;
-			err = tesla_instance_new(class, pattern, t->to, &inst);
-			if (err != TESLA_SUCCESS) {
-				ev_err(autom, symbol, err,
-					"failed to init instance");
-				goto cleanup;
-			}
-
-			assert(tesla_instance_active(inst));
+	if (!matched_something)
+		ev_no_instance(class, symbol, pattern);
 
-			matched_something = true;
-			ev_new_instance(class, inst);
-		}
-	}
-
-	if (!matched_something) {
-		// 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_ignored(class, symbol, pattern);
-
-		// Otherwise, we ought to have matched something.
-		else ev_no_instance(class, symbol, pattern);
-	}
-
 	// Does it cause class cleanup?
 	if (cleanup_required)
 		tesla_class_reset(class);
-
-cleanup:
-	tesla_class_put(class);
 }
 
 enum tesla_action_t


More information about the p4-projects mailing list