Motr  M0
sm.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2011-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_SM
24 #include "lib/trace.h" /* m0_console_printf */
25 
26 #include "lib/errno.h" /* ESRCH */
27 #include "lib/misc.h" /* M0_SET0, M0_IS0 */
28 #include "lib/mutex.h"
29 #include "lib/thread.h" /* m0_thread_self */
30 #include "lib/arith.h" /* m0_is_po2 */
31 #include "lib/memory.h"
32 #include "lib/finject.h"
33 #include "lib/locality.h" /* m0_locality_data_alloc */
34 #include "addb2/addb2.h"
35 #include "addb2/identifier.h"
36 #include "sm/sm.h"
37 
51 static struct m0_sm_ast eoq;
52 
53 M0_INTERNAL void m0_sm_group_init(struct m0_sm_group *grp)
54 {
55  M0_SET0(grp);
56  grp->s_forkq = &eoq;
58  /* add grp->s_clink to otherwise unused grp->s_chan, because m0_chan
59  code assumes that a clink is always associated with a channel. */
63 }
64 
65 M0_INTERNAL void m0_sm_group_fini(struct m0_sm_group *grp)
66 {
67  M0_PRE(grp->s_forkq == &eoq);
68 
74 }
75 
76 static void _sm_group_lock(struct m0_sm_group *grp)
77 {
79  M0_PRE(grp->s_nesting == 0);
80  grp->s_nesting = 1;
81 }
82 
83 M0_INTERNAL void m0_sm_group_lock(struct m0_sm_group *grp)
84 {
87 }
88 
89 static void _sm_group_unlock(struct m0_sm_group *grp)
90 {
91  M0_PRE(grp->s_nesting == 1);
92  grp->s_nesting = 0;
94 }
95 
96 M0_INTERNAL void m0_sm_group_unlock(struct m0_sm_group *grp)
97 {
100 }
101 
102 static bool grp_is_locked(const struct m0_sm_group *grp)
103 {
104  return m0_mutex_is_locked(&grp->s_lock);
105 }
106 
107 M0_INTERNAL bool m0_sm_group_is_locked(const struct m0_sm_group *grp)
108 {
109  return grp_is_locked(grp);
110 }
111 
112 M0_INTERNAL void m0_sm_group_lock_rec(struct m0_sm_group *grp, bool runast)
113 {
114  if (grp->s_lock.m_owner == m0_thread_self())
115  ++grp->s_nesting;
116  else {
118  if (runast)
120  }
121 }
122 
123 M0_INTERNAL void m0_sm_group_unlock_rec(struct m0_sm_group *grp, bool runast)
124 {
126  if (grp->s_nesting > 1)
127  --grp->s_nesting;
128  else {
130  if (runast)
132  }
133 }
134 
135 M0_INTERNAL void m0_sm_ast_post(struct m0_sm_group *grp, struct m0_sm_ast *ast)
136 {
137  M0_PRE(ast->sa_cb != NULL);
138  M0_PRE(ast->sa_next == NULL);
139 
140  do {
141  ast->sa_next = grp->s_forkq;
142  /*
143  M0_LOG(M0_DEBUG, "grp=%p forkq_push: %p -> %p",
144  grp, ast, ast->sa_next);
145  */
146  } while (!M0_ATOMIC64_CAS(&grp->s_forkq, ast->sa_next, ast));
148 }
149 
150 M0_INTERNAL void m0_sm_asts_run(struct m0_sm_group *grp)
151 {
152  struct m0_sm_ast *ast;
153 
155 
156  while (1) {
157  do {
158  ast = grp->s_forkq;
159  /*
160  M0_LOG(M0_DEBUG, "grp=%p forkq_pop: %p <- %p",
161  grp, ast, ast->sa_next);
162  */
163  } while (ast != &eoq &&
165 
166  if (ast == &eoq)
167  break;
168  M0_ASSERT(ast->sa_next != NULL);
169 
170  ast->sa_next = NULL;
172  if (grp->s_addb2 == NULL) {
173  ast->sa_cb(grp, ast);
174  } else {
178  ast->sa_cb(grp, ast));
179  }
180  }
181 }
182 
183 M0_INTERNAL void m0_sm_ast_cancel(struct m0_sm_group *grp,
184  struct m0_sm_ast *ast)
185 {
187  /*
188  * Concurrency: this function runs under the group lock and the only
189  * other possible concurrent fork queue activity is addition of the new
190  * asts at the head of the queue (m0_sm_ast_post()).
191  *
192  * Hence, the queue head is handled specially, with CAS. The rest of the
193  * queue is scanned normally.
194  */
195  if (ast->sa_next == NULL)
196  return ; /* not in the queue. */
197 
198  if (ast == grp->s_forkq /* cheap check first */ &&
200  ; /* deleted the head. */
201  else {
202  struct m0_sm_ast *prev;
203  /*
204  * This loop is safe.
205  *
206  * On the first iteration, grp->s_forkq can be changed
207  * concurrently by m0_sm_ast_post(), but "prev" is still a valid
208  * queue element, because removal from the queue is under the
209  * lock. Newly inserted head elements are not scanned.
210  *
211  * On the iterations after the first, immutable portion of the
212  * queue is scanned.
213  */
214  prev = grp->s_forkq;
215  while (prev->sa_next != ast)
216  prev = prev->sa_next;
217  prev->sa_next = ast->sa_next;
218  }
219  ast->sa_next = NULL;
220 }
221 
222 static void sm_lock(struct m0_sm *mach)
223 {
224  m0_sm_group_lock(mach->sm_grp);
225 }
226 
227 static void sm_unlock(struct m0_sm *mach)
228 {
229  m0_sm_group_unlock(mach->sm_grp);
230 }
231 
232 static bool sm_is_locked(const struct m0_sm *mach)
233 {
234  return grp_is_locked(mach->sm_grp);
235 }
236 
237 static bool state_is_valid(const struct m0_sm_conf *conf, uint32_t state)
238 {
239  return
240  state < conf->scf_nr_states &&
241  conf->scf_state[state].sd_name != NULL;
242 }
243 
244 static const struct m0_sm_state_descr *state_get(const struct m0_sm *mach,
245  uint32_t state)
246 {
247  M0_PRE(state_is_valid(mach->sm_conf, state));
248  return &mach->sm_conf->scf_state[state];
249 }
250 
251 static const struct m0_sm_state_descr *sm_state(const struct m0_sm *mach)
252 {
253  return state_get(mach, mach->sm_state);
254 }
255 
260 M0_INTERNAL bool sm_invariant0(const struct m0_sm *mach)
261 {
262  const struct m0_sm_state_descr *sd = sm_state(mach);
263 
264  return _0C(ergo(sd->sd_invariant != NULL, sd->sd_invariant(mach)));
265 }
266 
267 M0_INTERNAL bool m0_sm_invariant(const struct m0_sm *mach)
268 {
269  if (mach->sm_invariant_chk_off)
270  return true;
271  return _0C(sm_is_locked(mach)) && sm_invariant0(mach);
272 }
273 
274 static bool conf_invariant(const struct m0_sm_conf *conf)
275 {
276  uint32_t i;
277  uint64_t mask;
278 
279  if (conf->scf_nr_states >= sizeof(conf->scf_state[0].sd_allowed) * 8) {
280  m0_failed_condition = "wrong states_nr";
281  return false;
282  }
283 
284  for (i = 0, mask = 0; i < conf->scf_nr_states; ++i) {
285  if (state_is_valid(conf, i))
286  mask |= M0_BITS(i);
287  }
288 
289  for (i = 0; i < conf->scf_nr_states; ++i) {
290  if (mask & M0_BITS(i)) {
291  const struct m0_sm_state_descr *sd;
292 
293  sd = &conf->scf_state[i];
296  m0_failed_condition = "odd sd_flags";
297  return false;
298  }
299  if ((sd->sd_flags & M0_SDF_TERMINAL) &&
300  sd->sd_allowed != 0) {
301  m0_failed_condition = "terminal sd_allowed";
302  return false;
303  }
304  if (sd->sd_allowed & ~mask) {
305  m0_failed_condition = "odd sd_allowed";
306  return false;
307  }
308  }
309  }
310  return true;
311 }
312 
313 M0_INTERNAL void m0_sm_init(struct m0_sm *mach, const struct m0_sm_conf *conf,
314  uint32_t state, struct m0_sm_group *grp)
315 {
317  M0_PRE(conf->scf_state[state].sd_flags & M0_SDF_INITIAL);
318 
319  mach->sm_state = state;
320  mach->sm_conf = conf;
321  mach->sm_grp = grp;
322  mach->sm_rc = 0;
323  mach->sm_id = m0_dummy_id_generate();
324  mach->sm_state_epoch = m0_time_now();
325  mach->sm_addb2_stats = NULL;
326  mach->sm_invariant_chk_off = false;
327  m0_chan_init(&mach->sm_chan, &grp->s_lock);
329 }
330 
331 M0_INTERNAL void m0_sm_fini(struct m0_sm *mach)
332 {
335  m0_chan_fini(&mach->sm_chan);
336 }
337 
338 M0_INTERNAL void (*m0_sm__conf_init)(const struct m0_sm_conf *conf) = NULL;
339 
340 M0_INTERNAL void m0_sm_conf_init(struct m0_sm_conf *conf)
341 {
342  uint32_t i;
343  uint32_t from;
344  uint32_t to;
345 
347  M0_PRE(conf->scf_trans_nr > 0);
348 
349  M0_ASSERT(conf->scf_nr_states < M0_SM_MAX_STATES);
350 
351  if (m0_sm__conf_init != NULL)
353 
354  for (i = 0; i < conf->scf_nr_states; ++i)
355  for (to = 0; to < conf->scf_nr_states; ++to)
356  conf->scf_state[i].sd_trans[to] = ~0;
357 
358  for (i = 0; i < conf->scf_trans_nr; ++i) {
359  from = conf->scf_trans[i].td_src;
360  to = conf->scf_trans[i].td_tgt;
361  M0_ASSERT(conf->scf_state[from].sd_allowed & M0_BITS(to));
362  conf->scf_state[from].sd_trans[to] = i;
363  }
364 
365  for (i = 0; i < conf->scf_nr_states; ++i)
366  for (to = 0; to < conf->scf_nr_states; ++to)
367  M0_ASSERT(ergo(conf->scf_state[i].sd_allowed &
368  M0_BITS(to),
369  conf->scf_state[i].sd_trans[to] != ~0));
370 
371  conf->scf_magic = M0_SM_CONF_MAGIC;
372 
374 }
375 
376 M0_INTERNAL void m0_sm_conf_fini(struct m0_sm_conf *conf)
377 {
378  M0_PRE(conf->scf_magic == M0_SM_CONF_MAGIC);
379  conf->scf_magic = 0;
380 }
381 
382 M0_INTERNAL bool m0_sm_conf_is_initialized(const struct m0_sm_conf *conf)
383 {
384  return conf->scf_magic == M0_SM_CONF_MAGIC;
385 }
386 
387 M0_INTERNAL int m0_sm_timedwait(struct m0_sm *mach, uint64_t states,
388  m0_time_t deadline)
389 {
390  struct m0_clink waiter;
391  int result;
392 
394 
395  result = 0;
396  m0_clink_init(&waiter, NULL);
397 
398  m0_clink_add(&mach->sm_chan, &waiter);
399  while (result == 0 && (M0_BITS(mach->sm_state) & states) == 0) {
401  if (sm_state(mach)->sd_flags & M0_SDF_TERMINAL)
402  result = -ESRCH;
403  else {
404  sm_unlock(mach);
405  if (!m0_chan_timedwait(&waiter, deadline))
406  result = -ETIMEDOUT;
407  sm_lock(mach);
408  }
409  }
410  m0_clink_del(&waiter);
411  m0_clink_fini(&waiter);
413  return result;
414 }
415 
416 static void state_set(struct m0_sm *mach, int state, int32_t rc)
417 {
418  const struct m0_sm_state_descr *sd;
419 
420  mach->sm_rc = rc;
421  /*
422  * Iterate over a possible chain of state transitions.
423  *
424  * State machine invariant can be temporarily violated because ->sm_rc
425  * is set before ->sm_state is updated and, similarly, ->sd_in() might
426  * set ->sm_rc before the next state is entered. In any case, the
427  * invariant is restored the moment->sm_state is updated and must hold
428  * on the loop termination.
429  */
430  do {
431  struct m0_sm_addb2_stats *stats = mach->sm_addb2_stats;
432  uint32_t trans;
433 
434  sd = sm_state(mach);
435  trans = sd->sd_trans[state];
436  M0_ASSERT_INFO(sd->sd_allowed & M0_BITS(state), "%s: %s -> %s",
437  mach->sm_conf->scf_name, sd->sd_name,
438  state_get(mach, state)->sd_name);
439  if (sd->sd_ex != NULL)
440  sd->sd_ex(mach);
441 
442  /* Update statistics (if enabled). */
443  if (stats != NULL) {
444  m0_time_t now = m0_time_now();
445  m0_time_t delta;
446 
447  delta = m0_time_sub(now, mach->sm_state_epoch) >> 10;
448  M0_ASSERT(stats->as_nr == 0 || trans < stats->as_nr);
449  if (stats->as_id != 0) {
451  trans, state);
452  }
453  if (stats->as_nr > 0)
454  m0_addb2_hist_mod(&stats->as_hist[trans],
455  delta);
456  mach->sm_state_epoch = now;
457  }
458  mach->sm_state = state;
460  sd = sm_state(mach);
461  state = sd->sd_in != NULL ? sd->sd_in(mach) : -1;
462  m0_chan_broadcast(&mach->sm_chan);
463  } while (state >= 0);
464 
466 }
467 
468 M0_INTERNAL void m0_sm_fail(struct m0_sm *mach, int fail_state, int32_t rc)
469 {
470  M0_PRE(rc != 0);
472  M0_PRE(mach->sm_rc == 0);
473  M0_PRE(state_get(mach, fail_state)->sd_flags & M0_SDF_FAILURE);
474 
475  state_set(mach, fail_state, rc);
476 }
477 
478 void m0_sm_state_set(struct m0_sm *mach, int state)
479 {
481  state_set(mach, state, 0);
482 }
483 M0_EXPORTED(m0_sm_state_set);
484 
485 M0_INTERNAL void m0_sm_move(struct m0_sm *mach, int32_t rc, int state)
486 {
487  rc == 0 ? m0_sm_state_set(mach, state) : m0_sm_fail(mach, state, rc);
488 }
489 
512 };
513 
519 static unsigned long sm_timer_top(unsigned long data)
520 {
521  struct m0_sm_timer *timer = (void *)data;
522 
523  M0_PRE(M0_IN(timer->tr_state, (ARMED, DONE)));
524  /*
525  * no synchronisation or memory barriers are needed here: it's OK to
526  * occasionally post the AST when the timer is already cancelled,
527  * because the ast call-back, synchronised with the cancellation by
528  * the group lock, will sort this out.
529  */
530  if (timer->tr_state == ARMED)
531  m0_sm_ast_post(timer->tr_grp, &timer->tr_ast);
532  return 0;
533 }
534 
535 static void timer_done(struct m0_sm_timer *timer)
536 {
537  M0_ASSERT(timer->tr_state == ARMED);
538 
539  timer->tr_state = DONE;
540  m0_timer_stop(&timer->tr_timer);
541 }
542 
548 static void sm_timer_bottom(struct m0_sm_group *grp, struct m0_sm_ast *ast)
549 {
550  struct m0_sm_timer *tr = container_of(ast, struct m0_sm_timer, tr_ast);
551 
553  M0_ASSERT(tr->tr_state == ARMED);
554 
555  timer_done(tr);
556  tr->tr_cb(tr);
557 }
558 
559 M0_INTERNAL void m0_sm_timer_init(struct m0_sm_timer *timer)
560 {
561  M0_SET0(timer);
562  timer->tr_state = INIT;
563  timer->tr_ast.sa_cb = sm_timer_bottom;
564 }
565 
566 M0_INTERNAL void m0_sm_timer_fini(struct m0_sm_timer *timer)
567 {
568  M0_PRE(M0_IN(timer->tr_state, (INIT, DONE)));
569  M0_PRE(timer->tr_ast.sa_next == NULL);
570 
571  if (timer->tr_state == DONE) {
573  m0_timer_fini(&timer->tr_timer);
574  }
575 }
576 
577 M0_INTERNAL int m0_sm_timer_start(struct m0_sm_timer *timer,
578  struct m0_sm_group *group,
579  void (*cb)(struct m0_sm_timer *),
580  m0_time_t deadline)
581 {
582  int result;
583 
585  M0_PRE(timer->tr_state == INIT);
586  M0_PRE(cb != NULL);
587 
588  /*
589  * This is how timer is implemented:
590  *
591  * - a timer is armed (with sm_timer_top() call-back);
592  *
593  * - when the timer fires off, an AST to the state machine group is
594  * posted from the timer call-back;
595  *
596  * - the AST invokes user-supplied call-back.
597  */
598 
599  result = m0_timer_init(&timer->tr_timer, M0_TIMER_HARD, NULL,
600  sm_timer_top, (unsigned long)timer);
601  if (result == 0) {
602  timer->tr_state = ARMED;
603  timer->tr_grp = group;
604  timer->tr_cb = cb;
605  m0_timer_start(&timer->tr_timer, deadline);
606  }
607  return result;
608 }
609 
610 M0_INTERNAL void m0_sm_timer_cancel(struct m0_sm_timer *timer)
611 {
612  M0_PRE(grp_is_locked(timer->tr_grp));
613  M0_PRE(M0_IN(timer->tr_state, (ARMED, DONE)));
614 
615  if (timer->tr_state == ARMED) {
616  timer_done(timer);
617  /*
618  * Once timer_done() returned, the timer call-back
619  * (sm_timer_top()) is guaranteed to be never executed, so the
620  * ast won't be posted. Hence, it is safe to remove it, if it
621  * is here.
622  */
623  m0_sm_ast_cancel(timer->tr_grp, &timer->tr_ast);
624  }
625  M0_POST(timer->tr_ast.sa_next == NULL);
626 }
627 
628 M0_INTERNAL bool m0_sm_timer_is_armed(const struct m0_sm_timer *timer)
629 {
630  return timer->tr_state == ARMED;
631 }
632 
638 static void timeout_ast(struct m0_sm_timer *timer)
639 {
640  struct m0_sm *mach = timer->tr_ast.sa_mach;
641  struct m0_sm_timeout *to = container_of(timer,
642  struct m0_sm_timeout,
643  st_timer);
646 }
647 
655 static bool sm_timeout_cancel(struct m0_clink *link)
656 {
657  struct m0_sm_timeout *to = container_of(link, struct m0_sm_timeout,
658  st_clink);
659  struct m0_sm *mach = to->st_timer.tr_ast.sa_mach;
660 
662  if (!(M0_BITS(mach->sm_state) & to->st_bitmask))
664  return true;
665 }
666 
667 M0_INTERNAL void m0_sm_timeout_init(struct m0_sm_timeout *to)
668 {
669  M0_SET0(to);
672 }
673 
674 M0_INTERNAL int m0_sm_timeout_arm(struct m0_sm *mach, struct m0_sm_timeout *to,
675  m0_time_t timeout, int state,
676  uint64_t bitmask)
677 {
678  int result;
679  struct m0_sm_timer *tr = &to->st_timer;
680 
682  M0_PRE(tr->tr_state == INIT);
683  M0_PRE(!(sm_state(mach)->sd_flags & M0_SDF_TERMINAL));
684  M0_PRE(sm_state(mach)->sd_allowed & M0_BITS(state));
685  M0_PRE(m0_forall(i, mach->sm_conf->scf_nr_states,
686  ergo(M0_BITS(i) & bitmask,
687  state_get(mach, i)->sd_allowed & M0_BITS(state))));
688  if (M0_FI_ENABLED("failed"))
689  return M0_ERR(-EINVAL);
690 
691  /*
692  * @todo to->st_clink remains registered with mach->sm_chan even after
693  * the timer expires or is cancelled. This does no harm, but should be
694  * fixed when the support for channels with external locks lands.
695  */
696  to->st_state = state;
697  to->st_bitmask = bitmask;
698  tr->tr_ast.sa_mach = mach;
699  result = m0_sm_timer_start(tr, mach->sm_grp, timeout_ast, timeout);
700  if (result == 0)
701  m0_clink_add(&mach->sm_chan, &to->st_clink);
702  return result;
703 }
704 
705 M0_INTERNAL void m0_sm_timeout_fini(struct m0_sm_timeout *to)
706 {
708  if (m0_clink_is_armed(&to->st_clink))
709  m0_clink_del(&to->st_clink);
710  m0_clink_fini(&to->st_clink);
711 }
712 
713 M0_INTERNAL bool m0_sm_timeout_is_armed(const struct m0_sm_timeout *to)
714 {
715  return m0_sm_timer_is_armed(&to->st_timer);
716 }
717 
718 static bool trans_exists(const struct m0_sm_conf *conf,
719  uint32_t src, uint32_t tgt)
720 {
721  return m0_exists(i, conf->scf_trans_nr,
722  conf->scf_trans[i].td_src == src &&
723  conf->scf_trans[i].td_tgt == tgt);
724 }
725 
726 M0_INTERNAL void m0_sm_conf_trans_extend(const struct m0_sm_conf *base,
727  struct m0_sm_conf *sub)
728 {
729  uint32_t i;
730  uint32_t j = 0;
731 
733 
734  for (i = 0; i < base->scf_trans_nr; i++) {
735  const struct m0_sm_trans_descr *b = &base->scf_trans[i];
736 
737  if (!trans_exists(sub, b->td_src, b->td_tgt)) {
738  /* Find the next empty slot. */
739  for (; j < sub->scf_trans_nr; j++) {
740  if (sub->scf_trans[j].td_src == 0 &&
741  sub->scf_trans[j].td_tgt == 0)
742  break;
743  }
744  M0_ASSERT(j < sub->scf_trans_nr);
745  M0_ASSERT(sub->scf_trans[j].td_cause == NULL);
746  sub->scf_trans[j++] = *b;
747  }
748  }
749 
750  /*
751  * Make non-empty transitions in sub to be contiguous. Copy remaining
752  * transitions, skipping the empty ones.
753  */
754  for (i = j; i < sub->scf_trans_nr; i++)
755  if (sub->scf_trans[i].td_src != 0 ||
756  sub->scf_trans[i].td_tgt != 0)
757  sub->scf_trans[j++] = sub->scf_trans[i];
758  sub->scf_trans_nr = j;
759 
760  M0_POST(conf_invariant(sub));
761 }
762 
763 M0_INTERNAL void m0_sm_conf_extend(const struct m0_sm_state_descr *base,
764  struct m0_sm_state_descr *sub, uint32_t nr)
765 {
766  uint32_t i;
767 
768  for (i = 0; i < nr; ++i) {
769  if (sub[i].sd_name == NULL && base[i].sd_name != NULL)
770  sub[i] = base[i];
771  }
772 }
773 
774 M0_INTERNAL const char *m0_sm_conf_state_name(const struct m0_sm_conf *conf,
775  int state)
776 {
777  return state_is_valid(conf, state) ?
778  conf->scf_state[state].sd_name : "invalid";
779 }
780 
781 M0_INTERNAL const char *m0_sm_state_name(const struct m0_sm *mach, int state)
782 {
783  return m0_sm_conf_state_name(mach->sm_conf, state);
784 }
785 
786 struct sm_call {
787  void *sc_input;
788  int (*sc_call)(void *);
791 };
792 
793 static void sm_call_ast(struct m0_sm_group *grp, struct m0_sm_ast *ast)
794 {
795  struct sm_call *sc = ast->sa_datum;
796 
797  sc->sc_output = sc->sc_call(sc->sc_input);
798  m0_semaphore_up(&sc->sc_wait);
799 }
800 
801 int m0_sm_group_call(struct m0_sm_group *group, int (*cb)(void *), void *data)
802 {
803  struct m0_sm_ast ast = {};
804  struct sm_call sc = {
805  .sc_input = data,
806  .sc_call = cb
807  };
808  m0_semaphore_init(&sc.sc_wait, 0);
809  ast.sa_datum = &sc;
810  ast.sa_cb = &sm_call_ast;
814  return sc.sc_output;
815 }
816 
818  const struct m0_sm_conf *c)
819 {
820  int i;
821 
822  stats->as_id = c->scf_addb2_id;
823  stats->as_nr = c->scf_trans_nr;
824  for (i = 0; i < stats->as_nr; ++i) {
825  m0_addb2_hist_add_auto(&stats->as_hist[i], 1000 /* skip */,
826  /*
827  * index parameter (2) corresponds to
828  * "standard" labels added to the context
829  * of a locality addb2 machine: node, pid
830  * and locality-id.
831  */
832  c->scf_addb2_counter + i, 2);
833  }
834  return 0;
835 }
836 
838  const struct m0_sm_conf *c)
839 {
840  int i;
841 
842  for (i = 0; i < stats->as_nr; ++i)
843  m0_addb2_hist_del(&stats->as_hist[i]);
844 }
845 
846 M0_INTERNAL int m0_sm_addb2_init(struct m0_sm_conf *conf,
847  uint64_t id, uint64_t counter)
848 {
849  size_t nob;
850  int result;
851 
852  M0_PRE(conf->scf_addb2_id == 0);
853  M0_PRE(conf->scf_addb2_counter == 0);
854  M0_PRE(conf->scf_addb2_key == 0);
855 
856  conf->scf_addb2_id = id;
857  conf->scf_addb2_counter = counter;
858  nob = sizeof(struct m0_sm_addb2_stats) +
859  conf->scf_trans_nr * M0_MEMBER_SIZE(struct m0_sm_addb2_stats,
860  as_hist[0]);
861  result = m0_locality_data_alloc(nob, (void *)&sm_addb2_ctor,
862  (void *)sm_addb2_dtor, conf);
863  if (result >= 0) {
864  conf->scf_addb2_key = result + 1;
865  result = 0;
866  }
867  return result;
868 }
869 
870 M0_INTERNAL void m0_sm_addb2_fini(struct m0_sm_conf *conf)
871 {
872  if (conf->scf_addb2_key > 0)
873  m0_locality_data_free(conf->scf_addb2_key - 1);
874 
875  conf->scf_addb2_id = 0;
876  conf->scf_addb2_counter = 0;
877  conf->scf_addb2_key = 0;
878 }
879 
880 static void sm_addb2_counter_init_add(struct m0_sm *sm)
881 {
882  const struct m0_sm_state_descr *sd = sm_state(sm);
883  uint32_t state = sm->sm_state;
884  uint32_t trans = sd->sd_trans[state];
885  uint64_t as_id = sm->sm_addb2_stats->as_id;
886 
887  if (as_id != 0)
888  M0_ADDB2_ADD(as_id, m0_sm_id_get(sm), trans, state);
889 }
890 
891 M0_INTERNAL bool m0_sm_addb2_counter_init(struct m0_sm *sm)
892 {
893  const struct m0_sm_conf *conf = sm->sm_conf;
894 
895  if (conf->scf_addb2_key > 0) {
896  sm->sm_addb2_stats = m0_locality_data(conf->scf_addb2_key - 1);
898  }
899  return conf->scf_addb2_key > 0;
900 }
901 
902 M0_INTERNAL void
904 {
905  wait->aw_allowed = true;
907  m0_chan_init(&wait->aw_chan, ch_guard);
908 }
909 
910 M0_INTERNAL void m0_sm_ast_wait_fini(struct m0_sm_ast_wait *wait)
911 {
913 
915 }
916 
917 M0_INTERNAL void m0_sm_ast_wait_prepare(struct m0_sm_ast_wait *wait,
918  struct m0_clink *clink)
919 {
922  /*
923  * Disable further ASTs. Since m0_sm_ast_wait_post() probes for
924  * wait->aw_allowed, it's necessary to ensure that if any AST
925  * gets posted during m0_sm_ast_wait_prepare(), it be waited
926  * for. Memory fencing here and usage of atomic instruction
927  * in m0_sm_ast_wait_prepare() ensures the right ordering of
928  * events that will never miss waiting for a posted AST.
929  */
930  wait->aw_allowed = false;
931  m0_mb();
933 }
934 
935 M0_INTERNAL void m0_sm_ast_wait_complete(struct m0_sm_ast_wait *wait,
936  struct m0_clink *clink)
937 {
940 }
941 
942 M0_INTERNAL void m0_sm_ast_wait_loop(struct m0_sm_ast_wait *wait,
943  struct m0_clink *clink)
944 {
945  /* Wait until outstanding ASTs complete. */
946  while (m0_atomic64_get(&wait->aw_active) > 0)
948 }
949 
950 M0_INTERNAL void m0_sm_ast_wait(struct m0_sm_ast_wait *wait)
951 {
952  struct m0_clink clink;
953 
959 }
960 
961 M0_INTERNAL void m0_sm_ast_wait_post(struct m0_sm_ast_wait *wait,
962  struct m0_sm_group *grp,
963  struct m0_sm_ast *ast)
964 {
965  /*
966  * This function cannot take locks, because it can be called from an
967  * awkward context (timer call-back, etc.). Hence atomic is used and
968  * ordering of accesses is critical.
969  *
970  * m0_sm_ast_wait() sets wait->aw_allowed first and then checks
971  * wait->aw_active. Therefore, the opposite order should be used here to
972  * guarantee that m0_sm_ast_wait() does not return prematurely and
973  * misses an AST.
974  * Since atomic accesses and mutex operations are implicit memory
975  * barriers, explicit barriers are not needed around wait->aw_allowed
976  * accesses.
977  */
979  if (wait->aw_allowed)
981  else
983 }
984 
985 M0_INTERNAL void m0_sm_ast_wait_signal(struct m0_sm_ast_wait *wait)
986 {
988 
991 }
992 
993 M0_INTERNAL void m0_sm_conf_print(const struct m0_sm_conf *conf)
994 {
995  int i;
996 
997  m0_console_printf("digraph \"%s\" {\n", conf->scf_name);
998  m0_console_printf("\t\"%s\" [shape=plaintext]\n\n", conf->scf_name);
999  for (i = 0; i < conf->scf_nr_states; ++i) {
1000  const struct m0_sm_state_descr *sd = &conf->scf_state[i];
1001 
1002  if (!state_is_valid(conf, i))
1003  continue;
1004  m0_console_printf("\t\"%s\" [shape=%s]\n", sd->sd_name,
1005  (sd->sd_flags & M0_SDF_INITIAL) ? "circle" :
1006  (sd->sd_flags & M0_SDF_TERMINAL) ? "doublecircle" :
1007  (sd->sd_flags & M0_SDF_FAILURE) ? "cds" : "rect");
1008  }
1009  m0_console_printf("\n");
1010  for (i = 0; i < conf->scf_trans_nr; ++i) {
1011  const struct m0_sm_trans_descr *td = &conf->scf_trans[i];
1012 
1013  m0_console_printf("\t\"%s\" -> \"%s\" [label=\"%s\"]\n",
1014  conf->scf_state[td->td_src].sd_name,
1015  conf->scf_state[td->td_tgt].sd_name,
1016  td->td_cause);
1017  }
1018  m0_console_printf("}\n\n");
1019 }
1020 
1021 M0_INTERNAL uint64_t m0_sm_id_get(const struct m0_sm *sm)
1022 {
1023  return sm->sm_id;
1024 }
1025 
1027 #undef M0_TRACE_SUBSYSTEM
1028 
1029 /*
1030  * Local variables:
1031  * c-indentation-style: "K&R"
1032  * c-basic-offset: 8
1033  * tab-width: 8
1034  * fill-column: 80
1035  * scroll-step: 1
1036  * End:
1037  */
int tr_state
Definition: sm.h:620
static void m0_atomic64_inc(struct m0_atomic64 *a)
int st_state
Definition: sm.h:660
uint32_t scf_trans_nr
Definition: sm.h:358
uint64_t id
Definition: cob.h:2380
static struct m0_sm_ast eoq
Definition: sm.c:51
static size_t nr
Definition: dump.c:1505
M0_INTERNAL void m0_chan_wait(struct m0_clink *link)
Definition: chan.c:336
#define M0_PRE(cond)
M0_INTERNAL void m0_sm_conf_init(struct m0_sm_conf *conf)
Definition: sm.c:340
static bool conf_invariant(const struct m0_sm_conf *conf)
Definition: sm.c:274
M0_INTERNAL void m0_sm_fail(struct m0_sm *mach, int fail_state, int32_t rc)
Definition: sm.c:468
void(* sd_ex)(struct m0_sm *mach)
Definition: sm.h:402
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
M0_INTERNAL void(* m0_sm__conf_init)(const struct m0_sm_conf *conf)
Definition: sm.c:338
static void timer_done(struct m0_sm_timer *timer)
Definition: sm.c:535
struct m0_chan aw_chan
Definition: sm.h:843
M0_INTERNAL bool m0_chan_is_locked(const struct m0_chan *ch)
Definition: chan.c:78
M0_INTERNAL int m0_sm_addb2_init(struct m0_sm_conf *conf, uint64_t id, uint64_t counter)
Definition: sm.c:846
#define NULL
Definition: misc.h:38
M0_INTERNAL void m0_clink_init(struct m0_clink *link, m0_chan_cb_t cb)
Definition: chan.c:201
M0_INTERNAL void m0_clink_del(struct m0_clink *link)
Definition: chan.c:267
int sc_output
Definition: sm.c:789
M0_INTERNAL void m0_clink_del_lock(struct m0_clink *link)
Definition: chan.c:293
#define ergo(a, b)
Definition: misc.h:293
int(* sd_in)(struct m0_sm *mach)
Definition: sm.h:397
void * m0_locality_data(int key)
Definition: locality.c:474
void(* sa_cb)(struct m0_sm_group *grp, struct m0_sm_ast *)
Definition: sm.h:506
#define M0_MEMBER_SIZE(type, member)
Definition: misc.h:62
Definition: sm.h:350
struct m0_sm_group_addb2 * s_addb2
Definition: sm.h:519
uint32_t td_tgt
Definition: sm.h:489
static struct m0_sm_group * grp
Definition: bytecount.c:38
M0_INTERNAL void m0_sm_timeout_init(struct m0_sm_timeout *to)
Definition: sm.c:667
uint64_t m0_time_t
Definition: time.h:37
static void timeout(void)
Definition: sm.c:286
M0_INTERNAL void m0_sm_ast_wait(struct m0_sm_ast_wait *wait)
Definition: sm.c:950
M0_INTERNAL void m0_sm_ast_post(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:135
void m0_console_printf(const char *fmt,...)
Definition: trace.c:801
M0_INTERNAL void m0_sm_group_unlock_rec(struct m0_sm_group *grp, bool runast)
Definition: sm.c:123
static int sm_addb2_ctor(struct m0_sm_addb2_stats *stats, const struct m0_sm_conf *c)
Definition: sm.c:817
M0_INTERNAL bool sm_invariant0(const struct m0_sm *mach)
Definition: sm.c:260
static struct m0_sm_ast ast
Definition: sm.c:35
struct m0_clink s_clink
Definition: sm.h:516
M0_INTERNAL const char * m0_failed_condition
Definition: misc.c:224
struct m0_sm_ast * s_forkq
Definition: sm.h:517
uint64_t sd_allowed
Definition: sm.h:422
struct m0_bufvec data
Definition: di.c:40
void * sc_input
Definition: sm.c:787
M0_INTERNAL void m0_sm_ast_wait_init(struct m0_sm_ast_wait *wait, struct m0_mutex *ch_guard)
Definition: sm.c:903
bool(* sd_invariant)(const struct m0_sm *mach)
Definition: sm.h:413
M0_INTERNAL const char * m0_sm_state_name(const struct m0_sm *mach, int state)
Definition: sm.c:781
struct m0_chan s_chan
Definition: sm.h:518
M0_INTERNAL void m0_sm_conf_trans_extend(const struct m0_sm_conf *base, struct m0_sm_conf *sub)
Definition: sm.c:726
Definition: conf.py:1
M0_INTERNAL void m0_sm_conf_extend(const struct m0_sm_state_descr *base, struct m0_sm_state_descr *sub, uint32_t nr)
Definition: sm.c:763
M0_INTERNAL bool m0_clink_is_armed(const struct m0_clink *link)
Definition: chan.c:303
static struct m0_addb2_mach * mach
Definition: storage.c:42
#define m0_exists(var, nr,...)
Definition: misc.h:134
#define M0_BITS(...)
Definition: misc.h:236
uint64_t sm_id
Definition: sm.h:311
static void _sm_group_unlock(struct m0_sm_group *grp)
Definition: sm.c:89
M0_INTERNAL int m0_timer_init(struct m0_timer *timer, enum m0_timer_type type, struct m0_timer_locality *loc, m0_timer_callback_t callback, unsigned long data)
Definition: timer.c:39
Definition: sm.h:504
void m0_addb2_hist_mod(struct m0_addb2_hist *hist, int64_t val)
Definition: histogram.c:68
struct m0_sm * sa_mach
Definition: sm.h:510
M0_INTERNAL void m0_chan_lock(struct m0_chan *ch)
Definition: chan.c:68
#define container_of(ptr, type, member)
Definition: misc.h:33
#define M0_SET0(obj)
Definition: misc.h:64
static const struct m0_sm_state_descr * state_get(const struct m0_sm *mach, uint32_t state)
Definition: sm.c:244
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
static void sm_timer_bottom(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:548
M0_ADDB2_ADD(M0_AVI_FS_CREATE, new_fid.f_container, new_fid.f_key, mode, rc)
struct m0_addb2_hist as_hist[0]
Definition: sm.h:799
M0_INTERNAL bool m0_sm_addb2_counter_init(struct m0_sm *sm)
Definition: sm.c:891
bool aw_allowed
Definition: sm.h:839
M0_INTERNAL void m0_sm_group_fini(struct m0_sm_group *grp)
Definition: sm.c:65
static bool runast
Definition: file.c:96
M0_INTERNAL int m0_sm_timedwait(struct m0_sm *mach, uint64_t states, m0_time_t deadline)
Definition: sm.c:387
static void sm_unlock(struct m0_sm *mach)
Definition: sm.c:227
static void sm_lock(struct m0_sm *mach)
Definition: sm.c:222
M0_INTERNAL void m0_timer_fini(struct m0_timer *timer)
Definition: timer.c:65
M0_INTERNAL void m0_sm_group_unlock(struct m0_sm_group *grp)
Definition: sm.c:96
static const struct m0_sm_conf conf
Definition: sm.c:589
M0_INTERNAL uint64_t m0_dummy_id_generate(void)
Definition: misc.c:425
void m0_locality_data_free(int key)
Definition: locality.c:463
M0_INTERNAL void m0_chan_signal(struct m0_chan *chan)
Definition: chan.c:159
struct m0_sm_trans_descr * scf_trans
Definition: sm.h:360
int i
Definition: dir.c:1033
void m0_addb2_hist_del(struct m0_addb2_hist *hist)
Definition: histogram.c:63
M0_INTERNAL bool m0_sm_timer_is_armed(const struct m0_sm_timer *timer)
Definition: sm.c:628
return M0_ERR(-EOPNOTSUPP)
struct m0_atomic64 aw_active
Definition: sm.h:841
void * sa_datum
Definition: sm.h:508
uint64_t ga_forq
Definition: sm.h:803
int m0_sm_group_call(struct m0_sm_group *group, int(*cb)(void *), void *data)
Definition: sm.c:801
Definition: sm.c:509
M0_INTERNAL void m0_timer_stop(struct m0_timer *timer)
Definition: timer.c:86
M0_INTERNAL void m0_sm_ast_wait_loop(struct m0_sm_ast_wait *wait, struct m0_clink *clink)
Definition: sm.c:942
M0_INTERNAL void m0_chan_init(struct m0_chan *chan, struct m0_mutex *ch_guard)
Definition: chan.c:96
#define M0_ASSERT(cond)
struct m0_clink st_clink
Definition: sm.h:658
M0_INTERNAL bool m0_mutex_is_locked(const struct m0_mutex *mutex)
Definition: mutex.c:95
M0_INTERNAL void m0_sm_group_init(struct m0_sm_group *grp)
Definition: sm.c:53
static void timeout_ast(struct m0_sm_timer *timer)
Definition: sm.c:638
struct m0_sm_group * tr_grp
Definition: sm.h:612
M0_INTERNAL void m0_timer_start(struct m0_timer *timer, m0_time_t expire)
Definition: timer.c:75
m0_time_t m0_time_now(void)
Definition: time.c:134
static struct m0_addb2_callback c
Definition: consumer.c:41
void m0_sm_state_set(struct m0_sm *mach, int state)
Definition: sm.c:478
unsigned int s_nesting
Definition: sm.h:515
static int counter
Definition: mutex.c:32
static struct m0_sm_ast_wait wait
Definition: sm.c:616
static void m0_atomic64_dec(struct m0_atomic64 *a)
static void sm_addb2_dtor(struct m0_sm_addb2_stats *stats, const struct m0_sm_conf *c)
Definition: sm.c:837
int8_t sd_trans[M0_SM_MAX_STATES]
Definition: sm.h:433
struct m0_sm_addb2_stats * sm_addb2_stats
Definition: sm.h:327
M0_INTERNAL void m0_clink_signal(struct m0_clink *clink)
Definition: chan.c:326
M0_INTERNAL int m0_semaphore_init(struct m0_semaphore *semaphore, unsigned value)
Definition: semaphore.c:38
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
#define M0_POST(cond)
M0_INTERNAL void m0_sm_addb2_fini(struct m0_sm_conf *conf)
Definition: sm.c:870
static void _sm_group_lock(struct m0_sm_group *grp)
Definition: sm.c:76
uint32_t td_src
Definition: sm.h:488
static bool grp_is_locked(const struct m0_sm_group *grp)
Definition: sm.c:102
static void group(void)
Definition: sm.c:386
M0_INTERNAL bool m0_is_poisoned(const void *ptr)
Definition: memory.c:79
struct m0_sm_ast * sa_next
Definition: sm.h:509
static bool m0_atomic64_dec_and_test(struct m0_atomic64 *a)
M0_INTERNAL bool m0_timer_is_started(const struct m0_timer *timer)
Definition: timer.c:94
static struct m0_clink clink[RDWR_REQUEST_MAX]
struct m0_mutex s_lock
Definition: sm.h:514
struct m0_addb2_hist ga_forq_hist
Definition: sm.h:804
M0_INTERNAL void m0_chan_unlock(struct m0_chan *ch)
Definition: chan.c:73
void m0_addb2_hist_add_auto(struct m0_addb2_hist *hist, int skip, uint64_t label, int idx)
Definition: histogram.c:50
static bool state_is_valid(const struct m0_sm_conf *conf, uint32_t state)
Definition: sm.c:237
static void sm_addb2_counter_init_add(struct m0_sm *sm)
Definition: sm.c:880
static int64_t m0_atomic64_get(const struct m0_atomic64 *a)
#define m0_forall(var, nr,...)
Definition: misc.h:112
void m0_clink_add_lock(struct m0_chan *chan, struct m0_clink *link)
Definition: chan.c:255
uint32_t sd_flags
Definition: sm.h:378
static void m0_mb(void)
struct m0_pdclust_tgt_addr tgt
Definition: fd.c:110
M0_INTERNAL int m0_sm_timeout_arm(struct m0_sm *mach, struct m0_sm_timeout *to, m0_time_t timeout, int state, uint64_t bitmask)
Definition: sm.c:674
int(* sc_call)(void *)
Definition: sm.c:788
const char * sd_name
Definition: sm.h:383
M0_INTERNAL void m0_sm_ast_wait_post(struct m0_sm_ast_wait *wait, struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:961
M0_INTERNAL void m0_sm_timeout_fini(struct m0_sm_timeout *to)
Definition: sm.c:705
static unsigned long sm_timer_top(unsigned long data)
Definition: sm.c:519
#define M0_FI_ENABLED(tag)
Definition: finject.h:231
M0_INTERNAL void m0_sm_timer_cancel(struct m0_sm_timer *timer)
Definition: sm.c:610
uint64_t st_bitmask
Definition: sm.h:664
M0_INTERNAL void m0_sm_init(struct m0_sm *mach, const struct m0_sm_conf *conf, uint32_t state, struct m0_sm_group *grp)
Definition: sm.c:313
static struct m0_sm_trans_descr trans[]
Definition: stats_fom.c:47
static bool sm_timeout_cancel(struct m0_clink *link)
Definition: sm.c:655
M0_INTERNAL void m0_clink_add(struct m0_chan *chan, struct m0_clink *link)
Definition: chan.c:228
M0_INTERNAL bool m0_chan_timedwait(struct m0_clink *link, const m0_time_t abs_timeout)
Definition: chan.c:349
M0_INTERNAL void m0_semaphore_fini(struct m0_semaphore *semaphore)
Definition: semaphore.c:45
Definition: beck.c:130
#define M0_ATOMIC64_CAS(loc, oldval, newval)
Definition: atomic.h:136
struct m0_sm_timer st_timer
Definition: sm.h:655
M0_INTERNAL struct m0_thread * m0_thread_self(void)
Definition: thread.c:122
static bool sm_is_locked(const struct m0_sm *mach)
Definition: sm.c:232
m0_time_t m0_time_sub(const m0_time_t t1, const m0_time_t t2)
Definition: time.c:65
Definition: sm.h:301
M0_INTERNAL void m0_sm_ast_wait_fini(struct m0_sm_ast_wait *wait)
Definition: sm.c:910
M0_INTERNAL void m0_sm_conf_print(const struct m0_sm_conf *conf)
Definition: sm.c:993
#define _0C(exp)
Definition: assert.h:311
M0_INTERNAL void m0_sm_move(struct m0_sm *mach, int32_t rc, int state)
Definition: sm.c:485
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
M0_INTERNAL void m0_clink_fini(struct m0_clink *link)
Definition: chan.c:208
M0_INTERNAL void m0_sm_ast_wait_prepare(struct m0_sm_ast_wait *wait, struct m0_clink *clink)
Definition: sm.c:917
M0_INTERNAL void m0_sm_group_lock(struct m0_sm_group *grp)
Definition: sm.c:83
M0_INTERNAL uint64_t m0_ptr_wrap(const void *p)
Definition: misc.c:277
M0_INTERNAL void m0_chan_fini(struct m0_chan *chan)
Definition: chan.c:104
timer_state
Definition: sm.c:508
#define M0_ASSERT_INFO(cond, fmt,...)
int m0_locality_data_alloc(size_t nob, int(*ctor)(void *, void *), void(*dtor)(void *, void *), void *datum)
Definition: locality.c:442
static uint64_t base
Definition: dump.c:1504
M0_INTERNAL void m0_sm_ast_cancel(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:183
M0_INTERNAL void m0_semaphore_down(struct m0_semaphore *semaphore)
Definition: semaphore.c:49
Definition: sm.c:510
M0_INTERNAL void m0_semaphore_up(struct m0_semaphore *semaphore)
Definition: semaphore.c:65
M0_INTERNAL void m0_sm_conf_fini(struct m0_sm_conf *conf)
Definition: sm.c:376
M0_INTERNAL bool m0_sm_conf_is_initialized(const struct m0_sm_conf *conf)
Definition: sm.c:382
M0_INTERNAL void m0_sm_timer_fini(struct m0_sm_timer *timer)
Definition: sm.c:566
M0_INTERNAL void m0_sm_asts_run(struct m0_sm_group *grp)
Definition: sm.c:150
M0_INTERNAL bool m0_sm_timeout_is_armed(const struct m0_sm_timeout *to)
Definition: sm.c:713
M0_INTERNAL void m0_sm_timer_init(struct m0_sm_timer *timer)
Definition: sm.c:559
const char * td_cause
Definition: sm.h:487
M0_INTERNAL uint64_t m0_sm_id_get(const struct m0_sm *sm)
Definition: sm.c:1021
uint64_t as_id
Definition: sm.h:797
#define M0_ADDB2_HIST(id, hist, datum,...)
Definition: histogram.h:147
static void sm_call_ast(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:793
M0_INTERNAL void m0_chan_fini_lock(struct m0_chan *chan)
Definition: chan.c:112
void(* tr_cb)(struct m0_sm_timer *)
Definition: sm.h:616
Definition: mutex.h:47
struct m0_semaphore sc_wait
Definition: sm.c:790
static const struct m0_sm_state_descr * sm_state(const struct m0_sm *mach)
Definition: sm.c:251
uint32_t sm_state
Definition: sm.h:307
struct m0_pdclust_src_addr src
Definition: fd.c:108
static bool trans_exists(const struct m0_sm_conf *conf, uint32_t src, uint32_t tgt)
Definition: sm.c:718
M0_INTERNAL void m0_chan_broadcast(struct m0_chan *chan)
Definition: chan.c:172
M0_INTERNAL void m0_sm_ast_wait_signal(struct m0_sm_ast_wait *wait)
Definition: sm.c:985
int32_t rc
Definition: trigger_fop.h:47
Definition: sm.c:511
struct m0_thread * m_owner
Definition: mutex.h:49
M0_INTERNAL bool m0_sm_group_is_locked(const struct m0_sm_group *grp)
Definition: sm.c:107
M0_INTERNAL int m0_sm_timer_start(struct m0_sm_timer *timer, struct m0_sm_group *group, void(*cb)(struct m0_sm_timer *), m0_time_t deadline)
Definition: sm.c:577
static struct m0_sm_state_descr states[C_NR]
Definition: sm.c:512
const struct m0_sm_conf * sm_conf
Definition: sm.h:320
M0_INTERNAL void m0_sm_ast_wait_complete(struct m0_sm_ast_wait *wait, struct m0_clink *clink)
Definition: sm.c:935
struct m0_sm_ast tr_ast
Definition: sm.h:614
static void state_set(struct m0_sm *mach, int state, int32_t rc)
Definition: sm.c:416
struct m0_timer tr_timer
Definition: sm.h:613
Definition: sm.c:786
static void m0_atomic64_set(struct m0_atomic64 *a, int64_t num)
M0_INTERNAL const char * m0_sm_conf_state_name(const struct m0_sm_conf *conf, int state)
Definition: sm.c:774
M0_INTERNAL void m0_sm_fini(struct m0_sm *mach)
Definition: sm.c:331
M0_INTERNAL bool m0_sm_invariant(const struct m0_sm *mach)
Definition: sm.c:267
M0_INTERNAL void m0_sm_group_lock_rec(struct m0_sm_group *grp, bool runast)
Definition: sm.c:112