1 /*
2 Copyright (c) 2013 Martin Sustrik All rights reserved.
3 Copyright 2016 Garrett D'Amore <garrett@damore.org>
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom
10 the Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 IN THE SOFTWARE.
22 */
23
24 #include "fsm.h"
25 #include "ctx.h"
26
27 #include "../utils/err.h"
28 #include "../utils/attr.h"
29
30 #include <stddef.h>
31
32 #define NN_FSM_STATE_IDLE 1
33 #define NN_FSM_STATE_ACTIVE 2
34 #define NN_FSM_STATE_STOPPING 3
35
nn_fsm_event_init(struct nn_fsm_event * self)36 void nn_fsm_event_init (struct nn_fsm_event *self)
37 {
38 self->fsm = NULL;
39 self->src = -1;
40 self->srcptr = NULL;
41 self->type = -1;
42 nn_queue_item_init (&self->item);
43 }
44
nn_fsm_event_term(NN_UNUSED struct nn_fsm_event * self)45 void nn_fsm_event_term (NN_UNUSED struct nn_fsm_event *self)
46 {
47 /* We don't term the queue item, although one might think we ought to.
48 It turns out that there are some hairy recursions which can cause
49 events to get submitted to queues even after the FSM is stopped.
50 We could spend more effort fixing this, and perhaps we ought to.
51 But given that the assertion itself is harmless, if an FSM event
52 is orphaned it should be pretty harmless -- the event won't be
53 processed but the FSM is shutting down anyway. So skip it for now.
54 Later, if we don't rewrite/gut the entire FSM machinery, we can
55 revisit this. */
56 /* nn_queue_item_term (&self->item); */
57 }
58
nn_fsm_event_active(struct nn_fsm_event * self)59 int nn_fsm_event_active (struct nn_fsm_event *self)
60 {
61 return nn_queue_item_isinqueue (&self->item);
62 }
63
nn_fsm_event_process(struct nn_fsm_event * self)64 void nn_fsm_event_process (struct nn_fsm_event *self)
65 {
66 int src;
67 int type;
68 void *srcptr;
69
70 src = self->src;
71 type = self->type;
72 srcptr = self->srcptr;
73 self->src = -1;
74 self->type = -1;
75 self->srcptr = NULL;
76
77 nn_fsm_feed (self->fsm, src, type, srcptr);
78 }
79
nn_fsm_feed(struct nn_fsm * self,int src,int type,void * srcptr)80 void nn_fsm_feed (struct nn_fsm *self, int src, int type, void *srcptr)
81 {
82 if (nn_slow (self->state != NN_FSM_STATE_STOPPING)) {
83 self->fn (self, src, type, srcptr);
84 } else {
85 self->shutdown_fn (self, src, type, srcptr);
86 }
87 }
88
nn_fsm_init_root(struct nn_fsm * self,nn_fsm_fn fn,nn_fsm_fn shutdown_fn,struct nn_ctx * ctx)89 void nn_fsm_init_root (struct nn_fsm *self, nn_fsm_fn fn,
90 nn_fsm_fn shutdown_fn, struct nn_ctx *ctx)
91 {
92 self->fn = fn;
93 self->shutdown_fn = shutdown_fn;
94 self->state = NN_FSM_STATE_IDLE;
95 self->src = -1;
96 self->srcptr = NULL;
97 self->owner = NULL;
98 self->ctx = ctx;
99 nn_fsm_event_init (&self->stopped);
100 }
101
nn_fsm_init(struct nn_fsm * self,nn_fsm_fn fn,nn_fsm_fn shutdown_fn,int src,void * srcptr,struct nn_fsm * owner)102 void nn_fsm_init (struct nn_fsm *self, nn_fsm_fn fn,
103 nn_fsm_fn shutdown_fn, int src, void *srcptr, struct nn_fsm *owner)
104 {
105 self->fn = fn;
106 self->shutdown_fn = shutdown_fn;
107 self->state = NN_FSM_STATE_IDLE;
108 self->src = src;
109 self->srcptr = srcptr;
110 self->owner = owner;
111 self->ctx = owner->ctx;
112 nn_fsm_event_init (&self->stopped);
113 }
114
nn_fsm_term(struct nn_fsm * self)115 void nn_fsm_term (struct nn_fsm *self)
116 {
117 nn_assert (nn_fsm_isidle (self));
118 nn_fsm_event_term (&self->stopped);
119 }
120
nn_fsm_start(struct nn_fsm * self)121 void nn_fsm_start (struct nn_fsm *self)
122 {
123 nn_assert (nn_fsm_isidle (self));
124 self->fn (self, NN_FSM_ACTION, NN_FSM_START, NULL);
125 self->state = NN_FSM_STATE_ACTIVE;
126 }
127
nn_fsm_isidle(struct nn_fsm * self)128 int nn_fsm_isidle (struct nn_fsm *self)
129 {
130 return self->state == NN_FSM_STATE_IDLE &&
131 !nn_fsm_event_active (&self->stopped) ? 1 : 0;
132 }
133
nn_fsm_stop(struct nn_fsm * self)134 void nn_fsm_stop (struct nn_fsm *self)
135 {
136 /* If stopping of the state machine was already requested, do nothing. */
137 if (self->state != NN_FSM_STATE_ACTIVE)
138 return;
139
140 self->state = NN_FSM_STATE_STOPPING;
141 self->shutdown_fn (self, NN_FSM_ACTION, NN_FSM_STOP, NULL);
142 }
143
nn_fsm_stopped(struct nn_fsm * self,int type)144 void nn_fsm_stopped (struct nn_fsm *self, int type)
145 {
146 nn_assert_state (self, NN_FSM_STATE_STOPPING);
147 nn_fsm_raise (self, &self->stopped, type);
148 self->state = NN_FSM_STATE_IDLE;
149 }
150
nn_fsm_stopped_noevent(struct nn_fsm * self)151 void nn_fsm_stopped_noevent (struct nn_fsm *self)
152 {
153 nn_assert_state (self, NN_FSM_STATE_STOPPING);
154 self->state = NN_FSM_STATE_IDLE;
155 }
156
nn_fsm_swap_owner(struct nn_fsm * self,struct nn_fsm_owner * owner)157 void nn_fsm_swap_owner (struct nn_fsm *self, struct nn_fsm_owner *owner)
158 {
159 int oldsrc;
160 struct nn_fsm *oldowner;
161
162 oldsrc = self->src;
163 oldowner = self->owner;
164 self->src = owner->src;
165 self->owner = owner->fsm;
166 owner->src = oldsrc;
167 owner->fsm = oldowner;
168 }
169
nn_fsm_choose_worker(struct nn_fsm * self)170 struct nn_worker *nn_fsm_choose_worker (struct nn_fsm *self)
171 {
172 return nn_ctx_choose_worker (self->ctx);
173 }
174
nn_fsm_action(struct nn_fsm * self,int type)175 void nn_fsm_action (struct nn_fsm *self, int type)
176 {
177 nn_assert (type > 0);
178 nn_fsm_feed (self, NN_FSM_ACTION, type, NULL);
179 }
180
nn_fsm_raise_from_src(struct nn_fsm * self,struct nn_fsm_event * event,int src,int type)181 void nn_fsm_raise_from_src (struct nn_fsm *self, struct nn_fsm_event *event,
182 int src, int type)
183 {
184 event->fsm = self;
185 event->src = src;
186 event->srcptr = self->srcptr;
187 event->type = type;
188 nn_ctx_raise (self->ctx, event);
189 }
190
nn_fsm_raise(struct nn_fsm * self,struct nn_fsm_event * event,int type)191 void nn_fsm_raise (struct nn_fsm *self, struct nn_fsm_event *event, int type)
192 {
193 event->fsm = self->owner;
194 event->src = self->src;
195 event->srcptr = self->srcptr;
196 event->type = type;
197 nn_ctx_raise (self->ctx, event);
198 }
199
nn_fsm_raiseto(struct nn_fsm * self,struct nn_fsm * dst,struct nn_fsm_event * event,int src,int type,void * srcptr)200 void nn_fsm_raiseto (struct nn_fsm *self, struct nn_fsm *dst,
201 struct nn_fsm_event *event, int src, int type, void *srcptr)
202 {
203 event->fsm = dst;
204 event->src = src;
205 event->srcptr = srcptr;
206 event->type = type;
207 nn_ctx_raiseto (self->ctx, event);
208 }
209
210