Computer Laboratory

tesla_update.c File Reference
#include "tesla_internal.h"
#include <stdbool.h>
#include <inttypes.h>
+ Include dependency graph for tesla_update.c:

Go to the source code of this file.

Macros

#define DEBUG_NAME   "libtesla.state.update"
 
#define PRINT(...)   DEBUG(libtesla.state.update, __VA_ARGS__)
 

Functions

void tesla_update_state (enum tesla_context tesla_context, uint32_t class_id, const struct tesla_key *pattern, const char *name, const char *description, const struct tesla_transitions *trans)
 
enum tesla_action_t tesla_action (const tesla_instance *inst, const tesla_key *event_data, const tesla_transitions *trans, const tesla_transition **trigger)
 

Macro Definition Documentation

#define DEBUG_NAME   "libtesla.state.update"

Definition at line 40 of file tesla_update.c.

Referenced by print_class(), and tesla_update_state().

#define PRINT (   ...)    DEBUG(libtesla.state.update, __VA_ARGS__)

Definition at line 41 of file tesla_update.c.

Referenced by tesla_update_state().

Function Documentation

enum tesla_action_t tesla_action ( const tesla_instance inst,
const tesla_key event_data,
const tesla_transitions trans,
const tesla_transition **  trigger 
)

Definition at line 231 of file tesla_update.c.

References FAIL, tesla_transition::flags, FORK, tesla_transition::from, tesla_transition::from_mask, IGNORE, JOIN, tesla_transitions::length, SUBSET, tesla_instance_active(), tesla_key_matches(), TESLA_TRANS_CLEANUP, tesla_instance::ti_key, tesla_instance::ti_state, tesla_key::tk_mask, tesla_transition::to_mask, tesla_transitions::transitions, and UPDATE.

233 {
234  assert(trigger != NULL);
235 
236  if (!tesla_instance_active(inst))
237  return IGNORE;
238 
239  /*
240  * We allowed to ignore this instance if its name doesn't match
241  * any of the given transitions.
242  */
243  bool ignore = true;
244 
245  for (size_t i = 0; i < trans->length; i++) {
246  const tesla_transition *t = trans->transitions + i;
247 
248  if (t->from == inst->ti_state) {
249  assert(inst->ti_key.tk_mask == t->from_mask);
250 
251  /*
252  * We need to match events against a pattern based on
253  * data from the event, but ignoring parts that are
254  * extraneous to this transition.
255  *
256  * For instance, if the event is 'foo(x,y) == z', we
257  * know what the values of x, y and z are, but the
258  * transition in question may only care about x and z:
259  * 'foo(x,*) == z'.
260  */
261  tesla_key pattern = *event_data;
262  pattern.tk_mask &= t->from_mask;
263 
264  /*
265  * Losing information implies a join
266  * (except during automaton instance cleanup).
267  */
268  if (!SUBSET(t->from_mask, t->to_mask)
269  && ((t->flags & TESLA_TRANS_CLEANUP) == 0)) {
270  *trigger = t;
271  return JOIN;
272  }
273 
274  /*
275  * Does the transition cause key data to be added
276  * to the instance's name?
277  */
278  if (SUBSET(t->to_mask, t->from_mask)) {
279  /*
280  * No: just just update the instance
281  * if its (masked) name matches.
282  */
283  tesla_key masked_name = inst->ti_key;
284  masked_name.tk_mask &= pattern.tk_mask;
285 
286  if (tesla_key_matches(&pattern, &masked_name)) {
287  *trigger = t;
288  return UPDATE;
289  }
290 
291  } else {
292  /*
293  * Yes: we need to fork the generic instance
294  * into a more specific one.
295  */
296  if (tesla_key_matches(&pattern, &inst->ti_key)) {
297  *trigger = t;
298  return FORK;
299  }
300  }
301 
302  /*
303  * If we are in the right state but don't match on
304  * the pattern, even with a mask, move on to the
305  * next transition.
306  */
307  continue;
308  }
309 
310  /*
311  * We are not in the correct state for this transition, so
312  * we can't take it.
313  *
314  * If we match the pattern, however, it means that *some*
315  * transition must match; we are no longer allowed to ignore
316  * this instance.
317  */
318  if (tesla_key_matches(event_data, &inst->ti_key))
319  ignore = false;
320  }
321 
322  if (ignore)
323  return IGNORE;
324 
325  else
326  return FAIL;
327 }

+ Here is the call graph for this function:

void tesla_update_state ( enum tesla_context tesla_context  ,
uint32_t  class_id,
const struct tesla_key pattern,
const char *  name,
const char *  description,
const struct tesla_transitions trans 
)

Definition at line 44 of file tesla_update.c.

References DEBUG_NAME, ev_accept(), ev_bad_transition(), ev_clone(), ev_err(), ev_ignored(), ev_new_instance(), ev_no_instance(), ev_transition(), FAIL, tesla_transition::flags, FORK, IGNORE, JOIN, tesla_transitions::length, PRINT, print_class(), print_key(), print_transitions(), tesla_action(), tesla_class_get(), tesla_class_put(), tesla_class_reset(), TESLA_CONTEXT_GLOBAL, tesla_debugging(), TESLA_ERROR_ENOMEM, tesla_instance_active(), tesla_instance_clear(), tesla_instance_clone(), tesla_instance_new(), tesla_key_union(), TESLA_MAX_CLASSES, TESLA_MAX_INSTANCES, tesla_store_get(), TESLA_SUCCESS, TESLA_TRANS_CLEANUP, TESLA_TRANS_INIT, tesla_instance::ti_key, tesla_instance::ti_state, tesla_key::tk_mask, tesla_transition::to, tesla_transitions::transitions, and UPDATE.

48 {
49 
51  /* We should never see with multiple <<init>> transitions. */
52  int init_count = 0;
53  for (uint32_t i = 0; i < trans->length; i++)
54  if (trans->transitions[i].flags & TESLA_TRANS_INIT)
55  init_count++;
56 
57  assert(init_count < 2);
58  }
59 
60  PRINT("\n====\n%s()\n", __func__);
61  PRINT(" context: %s\n",
63  ? "global"
64  : "per-thread"));
65  PRINT(" class: %d ('%s')\n", class_id, name);
66 
67  PRINT(" transitions: ");
69  PRINT("\n");
70  PRINT(" key: ");
71  print_key(DEBUG_NAME, pattern);
72  PRINT("\n----\n");
73 
74  struct tesla_store *store;
77 
78  PRINT("store: 0x%tx\n", (intptr_t) store);
79 
80  struct tesla_class *class;
81  assert(tesla_class_get(store, class_id, &class, name, description)
82  == TESLA_SUCCESS);
83 
84  print_class(class);
85 
86  // Did we match any instances?
87  bool matched_something = false;
88 
89  // When we're done, do we need to clean up the class?
90  bool cleanup_required = false;
91 
92  // Make space for cloning existing instances.
93  size_t cloned = 0;
94  const size_t max_clones = class->tc_free;
95  struct clone_info {
96  tesla_instance *old;
97  const tesla_transition *transition;
98  } clones[max_clones];
99 
100  // Iterate over existing instances, figure out what to do with each.
101  int err = TESLA_SUCCESS;
102  for (uint32_t i = 0; i < class->tc_limit; i++) {
103  assert(class->tc_instances != NULL);
104  tesla_instance *inst = class->tc_instances + i;
105 
106  const tesla_transition *trigger = NULL;
107  enum tesla_action_t action =
108  tesla_action(inst, pattern, trans, &trigger);
109 
110  switch (action) {
111  case FAIL:
112  ev_bad_transition(class, inst, trans);
113  break;
114 
115  case IGNORE:
116  break;
117 
118  case UPDATE:
119  ev_transition(class, inst, trigger);
120  inst->ti_state = trigger->to;
121  matched_something = true;
122 
123  if (trigger->flags & TESLA_TRANS_CLEANUP)
124  ev_accept(class, inst);
125 
126  break;
127 
128  case FORK: {
129  if (cloned >= max_clones) {
130  err = TESLA_ERROR_ENOMEM;
131  ev_err(class, err, "too many clones");
132  goto cleanup;
133  }
134 
135  struct clone_info *clone = clones + cloned++;
136  clone->old = inst;
137  clone->transition = trigger;
138  matched_something = true;
139  break;
140  }
141 
142  case JOIN:
143 #ifndef NDEBUG
144  {
145  int target = -1;
146  for (uint32_t j = 0; j < class->tc_limit; j++) {
147  tesla_instance *t = class->tc_instances + j;
148  if (t->ti_state == trigger->to) {
149  target = j;
150  break;
151  }
152  }
153  assert(target >= 0);
154  }
155 #endif
156  tesla_instance_clear(inst);
157  break;
158  }
159 
160  if (trigger && (trigger->flags & TESLA_TRANS_CLEANUP))
161  cleanup_required = true;
162  }
163 
164  // Move any clones into the class.
165  for (size_t i = 0; i < cloned; i++) {
166  struct clone_info *c = clones + i;
167  struct tesla_instance *clone;
168  err = tesla_instance_clone(class, c->old, &clone);
169  if (err != TESLA_SUCCESS) {
170  ev_err(class, err, "failed to clone instance");
171  goto cleanup;
172  }
173 
174  tesla_key new_name = *pattern;
175  new_name.tk_mask &= c->transition->to_mask;
176  err = tesla_key_union(&clone->ti_key, &new_name);
177  if (err != TESLA_SUCCESS) {
178  ev_err(class, err, "failed to union keys");
179  goto cleanup;
180  }
181 
182  clone->ti_state = c->transition->to;
183 
184  ev_clone(class, c->old, clone, c->transition);
185 
186  if (c->transition->flags & TESLA_TRANS_CLEANUP)
187  ev_accept(class, clone);
188  }
189 
190 
191  // Does this transition cause class instance initialisation?
192  for (uint32_t i = 0; i < trans->length; i++) {
193  const tesla_transition *t = trans->transitions + i;
194  if (t->flags & TESLA_TRANS_INIT) {
195  struct tesla_instance *inst;
196  err = tesla_instance_new(class, pattern, t->to, &inst);
197  if (err != TESLA_SUCCESS) {
198  ev_err(class, err, "failed to create instance");
199  goto cleanup;
200  }
201 
202  assert(tesla_instance_active(inst));
203 
204  matched_something = true;
205  ev_new_instance(class, inst);
206  }
207  }
208 
209  if (!matched_something) {
210  // If the class hasn't received any <<init>> events yet,
211  // simply ignore the event: it is out of scope.
212  if (class->tc_free == class->tc_limit)
213  ev_ignored(class, pattern, trans);
214 
215  // Otherwise, we ought to have matched something.
216  else ev_no_instance(class, pattern, trans);
217  }
218 
219  // Does it cause class cleanup?
220  if (cleanup_required)
221  tesla_class_reset(class);
222 
223  print_class(class);
224  PRINT("\n====\n\n");
225 
226 cleanup:
227  tesla_class_put(class);
228 }

+ Here is the call graph for this function: