12 /* Callback funtions prototypes */
13 static unsigned int fsm_hashf(const void *key
);
14 static int fsm_cmpf(const void *arg1
, const void *arg2
);
15 static void fsm_printf(const void *key
, const void *data
);
16 static void fsm_pq_lock(const fsm_t
*fsm
);
17 static void fsm_pq_unlock(const fsm_t
*fsm
);
19 fsmret_t
fsm_init(fsm_t
**fsm
, size_t size
, unsigned int factor
, unsigned int nqueues
)
23 /* FIXME: Validate input */
25 /* Allocate memory for fsm data structure */
26 if ((*fsm
= malloc(sizeof **fsm
)) == NULL
)
29 /* Allocate memory for fsm's states' hash table */
30 if (((*fsm
)->sttable
= malloc(sizeof *(*fsm
)->sttable
)) == NULL
) {
35 /* Allocate memory for priority queues */
36 if (((*fsm
)->pqtable
= malloc(nqueues
* sizeof *(*fsm
)->pqtable
)) == NULL
) {
37 free((*fsm
)->sttable
);
42 /* Allocate memory for "mutex object" -- machine dependent code */
43 if (((*fsm
)->mobj
= malloc(sizeof(pthread_mutex_t
))) == NULL
) {
45 free((*fsm
)->sttable
);
49 /* Machine dependent code */
50 pthread_mutex_init((pthread_mutex_t
*)(*fsm
)->mobj
, NULL
);
52 /* Initialize queues */
53 (*fsm
)->nqueues
= nqueues
;
54 for (i
= 0; i
< nqueues
; i
++)
55 STAILQ_INIT(&(*fsm
)->pqtable
[i
]);
57 /* Initialize states' hash table */
58 if (htable_init((*fsm
)->sttable
, size
, factor
,
59 fsm_hashf
, fsm_cmpf
, fsm_printf
) == HT_NOMEM
) {
60 free((*fsm
)->pqtable
);
61 free((*fsm
)->sttable
);
69 fsmret_t
fsm_add_state(fsm_t
*fsm
, unsigned int key
, state_t
*state
)
71 /* There is no need to allocate memory for state's key,
72 since this is done in state_init() */
76 /* Insert state to hash table */
77 if (htable_insert(fsm
->sttable
, state
->st_key
, state
) == HT_EXISTS
)
83 fsmret_t
fsm_free(fsm_t
*fsm
)
87 const hnode_t
*pstnode
;
88 unsigned int i
, stpos
;
90 /* Free states' table */
93 while ((pstnode
= htable_get_next_elm(fsm
->sttable
, &stpos
, pstnode
)) != NULL
)
94 state_free(pstnode
->hn_data
);
97 htable_free_all_obj(fsm
->sttable
, HT_FREEKEY
);
98 htable_free(fsm
->sttable
);
101 /* Free queues' elements */
102 for (i
= 0; i
< fsm
->nqueues
; i
++) {
103 phead
= &fsm
->pqtable
[i
];
104 while (STAILQ_FIRST(phead
) != NULL
) {
105 pnode
= STAILQ_FIRST(phead
);
106 STAILQ_REMOVE_HEAD(phead
, pq_next
);
119 void fsm_print_states(const fsm_t
*fsm
)
121 htable_print(fsm
->sttable
);
124 fsmret_t
fsm_set_state(fsm_t
*fsm
, unsigned int stkey
)
128 /* Does this state exist in states' hash table ? */
129 if ((state
= htable_search(fsm
->sttable
, &stkey
)) == NULL
)
130 return FSM_ENOTFOUND
;
132 /* Set fsm to new state */
138 unsigned int fsm_get_current_state(const fsm_t
*fsm
)
140 return *fsm
->cstate
->st_key
;
143 fsmret_t
fsm_queue_event(fsm_t
*fsm
, unsigned int evtkey
, void *data
, size_t size
, unsigned int prio
)
148 if (prio
>= fsm
->nqueues
)
151 /* Allocate memory for new pending event */
152 if ((pnode
= malloc(sizeof *pnode
)) == NULL
)
155 pnode
->evtkey
= evtkey
;
159 * Allocate memory for data and copy them over.
160 * Note that this strategy leads to memory fragmentation,
161 * and should be addressed with a custom memory allocator,
164 if ((pnode
->data
= malloc(size
)) == NULL
) {
168 memcpy(pnode
->data
, data
, size
);
170 /* Get the head of the queue with the appropriate priority */
171 phead
= &fsm
->pqtable
[prio
];
173 /* Insert new event in tail (we serve from head) */
175 STAILQ_INSERT_TAIL(phead
, pnode
, pq_next
);
180 fsmret_t
fsm_dequeue_event(fsm_t
*fsm
)
186 /* Scan queues starting from the one with the biggest priority */
187 i
= fsm
->nqueues
- 1;
189 phead
= &fsm
->pqtable
[i
];
190 if ((pnode
= STAILQ_FIRST(phead
)) != NULL
) {
191 if (fsm_process_event(fsm
, pnode
->evtkey
, pnode
->data
) == FSM_ENOTFOUND
) {
193 * FIXME: The event should stay in queue, if it has
194 * a sticky bit. But we haven't implemented such a bitmap
195 * in event's structure yet
200 pnode
= STAILQ_FIRST(phead
);
201 STAILQ_REMOVE_HEAD(phead
, pq_next
);
202 free(pnode
->data
); /* Argh, memory fragmentation */
211 size_t fsm_get_queued_events(const fsm_t
*fsm
)
213 const pqhead_t
*phead
;
214 const pqnode_t
*pnode
;
218 for (i
= 0; i
< fsm
->nqueues
; i
++) {
219 phead
= &fsm
->pqtable
[i
];
220 STAILQ_FOREACH(pnode
, phead
, pq_next
)
227 fsmret_t
fsm_process_event(fsm_t
*fsm
, unsigned int evtkey
, void *data
)
231 /* Can the current state handle the incoming event ? */
232 if ((event
= htable_search(fsm
->cstate
->evttable
, &evtkey
)) == NULL
)
233 return FSM_ENOTFOUND
;
235 /* Execute appropriate action */
236 if (event
->evt_actionf
!= NULL
)
237 event
->evt_actionf(data
);
239 /* Is the transition made to an existent state ? */
240 if ((event
->evt_newstate
== NULL
)
241 || (htable_search(fsm
->sttable
, event
->evt_newstate
->st_key
) == NULL
))
242 return FSM_ENOTFOUND
;
245 fsm
->cstate
= event
->evt_newstate
;
250 fsmret_t
fsm_validate(const fsm_t
*fsm
)
252 /* Is FSM empty of states ? */
253 if (htable_get_used(fsm
->sttable
) == 0)
259 void fsm_export_to_dot(const fsm_t
*fsm
, FILE *fp
)
261 const hnode_t
*pstnode
;
262 const hnode_t
*pevtnode
;
266 fprintf(fp
, "digraph {\n");
268 /* Traverse all states of FSM */
271 while ((pstnode
= htable_get_next_elm(fsm
->sttable
, &stpos
, pstnode
)) != NULL
) {
273 /* Traverse all events associated with the current state */
276 while ((pevtnode
= htable_get_next_elm(((state_t
*)(pstnode
->hn_data
))->evttable
, &evtpos
, pevtnode
)) != NULL
) {
277 printf("S%u -> S%u [label=\"E%u\"]\n",
278 *(unsigned int *)pstnode
->hn_key
,
279 *(unsigned int *)(((event_t
*)pevtnode
->hn_data
)->evt_newstate
->st_key
),
280 *(unsigned int *)pevtnode
->hn_key
);
288 /* Callback funtions */
289 static unsigned int fsm_hashf(const void *key
)
291 return *(const unsigned int *)key
;
294 static int fsm_cmpf(const void *arg1
, const void *arg2
)
296 unsigned int a
= *(const unsigned int *)arg1
;
297 unsigned int b
= *(const unsigned int *)arg2
;
307 static void fsm_printf(const void *key
, const void *data
)
309 printf("key: %u ", *(const unsigned int *)key
);
312 static void fsm_pq_lock(const fsm_t
*fsm
)
314 /* Machine dependent code */
315 pthread_mutex_lock((pthread_mutex_t
*) fsm
->mobj
);
318 static void fsm_pq_unlock(const fsm_t
*fsm
)
320 /* Machine dependent code */
321 pthread_mutex_unlock((pthread_mutex_t
*) fsm
->mobj
);