3 * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5 * Contact: Hojeen Jee <hojeen.jee@samsung.com>, Jaejun Sim <jj.sim@samsung.com>,
6 * Jinho Ha <jinho89.ha@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
28 #include "asp-manager-util.h"
31 typedef struct gfsm_event_queue {
37 struct gfsm_event *p_next;
38 gfsm_event_id_t event_id;
40 gfsm_event_data_destructor_cb destructor;
44 gfsm_state_id_t state_id;
46 gfsm_state_s *p_parent_state;
47 gfsm_state_s *p_internal_init_state;
48 gfsm_entry_action_cb entry_action_cb;
49 gfsm_exit_action_cb exit_action_cb;
50 gfsm_reaction_cb *reaction_table;
54 gfsm_state_s **pp_state_table;
55 gfsm_state_id_t max_state;
56 gfsm_event_id_t max_event;
57 gfsm_state_id_t init_state_id;
58 gfsm_log_func log_func;
59 gfsm_get_state_name_cb state_name_cb;
60 gfsm_get_event_name_cb event_name_cb;
66 gfsm_state_id_t current_state_id;
67 gfsm_event_queue_s event_queue;
68 gfsm_event_queue_s defer_event_queue;
69 unsigned char processing_event; /*true or false; */
70 unsigned char terminating; /*true or false; */
71 gfsm_context_termination_notifier_cb termination_notifier_cb;
75 static void _gfsm_process_event(gfsm_context_s *p_context,
76 gfsm_event_s *p_event);
77 static void gfsm_process_transition(gfsm_context_s *p_context,
78 gfsm_state_id_t next_state_id);
79 static void gfsm_do_exit_action(gfsm_state_s *p_current_state,
80 gfsm_state_s *p_common_ancesstor, gfsm_context_s *p_context);
81 static void gfsm_do_entry_action(gfsm_state_s *p_common_ancesstor,
82 gfsm_state_s *p_next_state, gfsm_context_s *p_context);
83 static void gfsm_reenqueue_deferred_event(gfsm_context_s *p_context);
84 static void gfsm_init_event_queue(gfsm_event_queue_s *p_queue);
85 static void gfsm_destroy_event_queue(gfsm_event_queue_s *p_queue);
86 static void gfsm_enqueue_event(gfsm_event_queue_s *p_queue,
87 gfsm_event_s *p_event);
88 static gfsm_event_s *gfsm_dequeue_event(gfsm_event_queue_s *p_queue);
89 static gfsm_state_s *gfsm_find_last_child_state(gfsm_state_s *p_state);
90 static gfsm_state_s *gfsm_find_common_ancesstor_state(gfsm_state_s *p_state_1,
91 gfsm_state_s *p_state_2);
93 gfsm_s *gfsm_create_fsm(gfsm_state_id_t max_state, gfsm_event_id_t max_event,
94 gfsm_state_id_t init_state)
96 gfsm_s *p_fsm = (gfsm_s *)malloc(sizeof(gfsm_s));
99 assert(init_state < max_state);
101 size_t state_table_size = sizeof(gfsm_state_s *) * max_state;
103 p_fsm->pp_state_table = (gfsm_state_s **) malloc(state_table_size);
105 assert(p_fsm->pp_state_table);
107 memset(p_fsm->pp_state_table, 0, state_table_size);
109 p_fsm->max_state = max_state;
110 p_fsm->max_event = max_event;
111 p_fsm->init_state_id = init_state;
113 p_fsm->log_func = NULL;
114 p_fsm->state_name_cb = NULL;
115 p_fsm->event_name_cb = NULL;
116 p_fsm->p_header = NULL;
121 void gfsm_destroy_fsm(gfsm_s *p_fsm)
124 assert(p_fsm->pp_state_table);
126 free(p_fsm->pp_state_table);
128 free(p_fsm->p_header);
132 gfsm_state_s *gfsm_create_state(gfsm_state_id_t state_id, gfsm_s *p_fsm,
133 gfsm_entry_action_cb entry_action, gfsm_exit_action_cb exit_action)
135 size_t event_table_size;
136 gfsm_state_s *p_state = (gfsm_state_s *)malloc(sizeof(gfsm_state_s));
140 /*assert(entry_action && exit_action); */
142 p_state->state_id = state_id;
143 p_state->p_fsm = p_fsm;
144 p_state->p_parent_state = NULL;
145 p_state->p_internal_init_state = NULL;
146 p_state->entry_action_cb = entry_action;
147 p_state->exit_action_cb = exit_action;
149 event_table_size = sizeof(gfsm_reaction_cb) * p_fsm->max_event;
151 p_state->reaction_table = (gfsm_reaction_cb *) malloc(event_table_size);
153 assert(p_state->reaction_table);
155 memset(p_state->reaction_table, 0, event_table_size);
160 void gfsm_destroy_state(gfsm_state_s *p_state)
163 assert(p_state->reaction_table);
165 free(p_state->reaction_table);
169 gfsm_context_s *gfsm_create_context(gfsm_s *p_fsm,
170 gfsm_context_termination_notifier_cb termination_notifier_cb,
171 void *p_context_data)
173 gfsm_state_s *p_next_state;
174 gfsm_context_s *p_context = (gfsm_context_s *)malloc(sizeof(gfsm_context_s));
179 p_context->p_fsm = p_fsm;
180 p_context->p_context_data = p_context_data;
181 p_context->current_state_id = p_fsm->init_state_id;
183 assert(p_context->current_state_id < p_fsm->max_state);
185 gfsm_init_event_queue(&p_context->event_queue);
186 gfsm_init_event_queue(&p_context->defer_event_queue);
188 p_context->processing_event = 0;
189 p_context->terminating = 0;
190 p_context->termination_notifier_cb = termination_notifier_cb;
192 p_next_state = p_fsm->pp_state_table[p_context->current_state_id];
194 assert(p_next_state);
196 gfsm_do_entry_action(NULL, p_next_state, p_context);
201 gfsm_state_id_t gfsm_get_current_state_id(gfsm_context_s *p_context)
204 return p_context->current_state_id;
207 void gfsm_destroy_context(gfsm_context_s *p_context)
209 gfsm_state_s *p_current_state;
211 if (p_context->processing_event) {
212 if (p_context->p_fsm->log_func)
213 p_context->p_fsm->log_func("[%s] destroy_context is scheduled\n",
214 p_context->p_fsm->p_header);
216 p_context->terminating = 1;
220 ASP_LOGD("context[%p]", p_context);
221 p_current_state = p_context->p_fsm->pp_state_table[p_context->current_state_id];
222 gfsm_do_exit_action(p_current_state, NULL, p_context);
224 gfsm_destroy_event_queue(&p_context->event_queue);
225 gfsm_destroy_event_queue(&p_context->defer_event_queue);
227 if (p_context->termination_notifier_cb)
228 p_context->termination_notifier_cb(p_context->p_context_data);
230 if (p_context->p_fsm->log_func)
231 p_context->p_fsm->log_func("[%s] context is destroyed\n",
232 p_context->p_fsm->p_header);
237 void gfsm_add_reaction(gfsm_state_s *p_state, gfsm_event_id_t event_id,
238 gfsm_reaction_cb reaction_cb)
242 assert(p_state->reaction_table);
243 assert(p_state->p_fsm);
244 assert(event_id < p_state->p_fsm->max_event);
245 assert(p_state->reaction_table[event_id] == NULL);
247 p_state->reaction_table[event_id] = reaction_cb;
250 void gfsm_set_parent_state(gfsm_state_s *p_state, gfsm_state_s *p_parent_state)
252 assert(p_state && p_parent_state);
253 assert(p_state->p_parent_state == NULL);
254 /*assert(p_parent_state->p_internal_init_state != NULL); */
256 p_state->p_parent_state = p_parent_state;
258 if (NULL == p_parent_state->p_internal_init_state)
259 p_parent_state->p_internal_init_state = p_state;
263 void gfsm_set_internal_init_state(gfsm_state_s* p_state, gfsm_state_s* p_internal_init_state)
265 assert(p_state && p_internal_init_state);
266 //assert(p_state->p_internal_init_state == NULL);
267 p_state->p_internal_init_state = p_internal_init_state;
271 void gfsm_add_state(gfsm_s *p_fsm, gfsm_state_s *p_state)
273 assert(p_fsm && p_state);
274 assert(p_state->state_id < p_fsm->max_state);
275 assert(p_fsm->pp_state_table[p_state->state_id] == NULL);
277 p_fsm->pp_state_table[p_state->state_id] = p_state;
280 gfsm_event_s *gfsm_create_event(gfsm_event_id_t event_id, void *p_event_data,
281 gfsm_event_data_destructor_cb destructor)
283 gfsm_event_s *p_event = (gfsm_event_s *)malloc(sizeof(gfsm_event_s));
287 p_event->p_next = NULL;
288 p_event->event_id = event_id;
289 p_event->p_event_data = p_event_data;
290 p_event->destructor = destructor;
295 gfsm_s *gfsm_get_fsm_of_state(gfsm_state_s *p_state)
298 return p_state->p_fsm;
301 gfsm_s *gfsm_get_fsm_of_context(gfsm_context_s *p_context)
304 return p_context->p_fsm;
307 void gfsm_process_event(gfsm_context_s **pp_context, gfsm_event_s *p_event)
309 gfsm_context_s *p_context = *pp_context;
312 ASP_LOGD("process event");
313 if (p_context == NULL)
314 ASP_LOGD("context is NULL");
315 assert(p_context && p_event);
317 p_fsm = p_context->p_fsm;
319 assert(p_fsm && p_event->event_id < p_fsm->max_event);
321 gfsm_enqueue_event(&p_context->event_queue, p_event);
323 if (p_context->processing_event) { /*recursive check */
325 p_fsm->log_func("[%s] event(%s) is posted\n", p_fsm->p_header,
326 p_fsm->event_name_cb(p_event->event_id));
331 p_context->processing_event = 1;
333 while ((p_event = gfsm_dequeue_event(&p_context->event_queue)))
334 _gfsm_process_event(p_context, p_event);
336 p_context->processing_event = 0;
338 if (p_context->terminating) {
340 p_fsm->log_func("[%s] destroy_context was scheduled\n", p_fsm->p_header);
342 ASP_LOGD("context[%p]", p_context);
343 gfsm_destroy_context(p_context);
347 void _gfsm_process_event(gfsm_context_s *p_context, gfsm_event_s *p_event)
350 gfsm_state_s *p_state;
351 gfsm_state_id_t next_state_id = GFSM_DISCARD_EVENT;
352 gfsm_event_id_t event_id;
354 ASP_LOGD("inner process event");
355 assert(p_context && p_event);
357 event_id = p_event->event_id;
358 p_fsm = p_context->p_fsm;
360 assert(p_context->current_state_id < p_fsm->max_state);
363 p_fsm->log_func("[%s] current state is (%s), event(%s) is received\n",
364 p_fsm->p_header, p_fsm->state_name_cb(p_context->current_state_id),
365 p_fsm->event_name_cb(event_id));
367 for (p_state = p_fsm->pp_state_table[p_context->current_state_id];
368 p_state != NULL; p_state = p_state->p_parent_state) {
369 if (p_state->reaction_table[event_id]) {
371 p_fsm->log_func("[%s] state(%s)'s reaction is called for event(%s)\n",
372 p_fsm->p_header, p_fsm->state_name_cb(p_state->state_id),
373 p_fsm->event_name_cb(event_id));
375 next_state_id = p_state->reaction_table[event_id](p_context->p_context_data,
376 p_event->p_event_data);
381 if (GFSM_DEFER_EVENT == next_state_id) {
383 p_fsm->log_func("[%s] event(%s) is defered\n", p_fsm->p_header,
384 p_fsm->event_name_cb(event_id));
386 gfsm_enqueue_event(&p_context->defer_event_queue, p_event);
390 if (p_event->destructor && p_event->p_event_data)
391 p_event->destructor(p_event->p_event_data);
395 if (NULL == p_state) {
397 p_fsm->log_func("[%s] state(%s) have no reaction for event(%s)\n",
398 p_fsm->p_header, p_fsm->state_name_cb(p_context->current_state_id),
399 p_fsm->event_name_cb(event_id));
404 if (GFSM_DISCARD_EVENT == next_state_id) {
406 p_fsm->log_func("[%s] to stay in state(%s)\n", p_fsm->p_header,
407 p_fsm->state_name_cb(p_context->current_state_id));
412 gfsm_process_transition(p_context, next_state_id);
415 void gfsm_process_transition(gfsm_context_s *p_context,
416 gfsm_state_id_t next_state_id)
418 gfsm_state_s *p_next_state;
419 gfsm_state_s *p_current_state;
420 gfsm_state_s *p_common_ancesstor;
422 assert(next_state_id < p_context->p_fsm->max_state);
424 p_next_state = p_context->p_fsm->pp_state_table[next_state_id];
425 p_current_state = p_context->p_fsm->pp_state_table[p_context->current_state_id];
427 assert(p_next_state && p_current_state);
429 p_common_ancesstor = gfsm_find_common_ancesstor_state(p_current_state,
432 p_next_state = gfsm_find_last_child_state(p_next_state);
434 assert(p_next_state);
436 gfsm_do_exit_action(p_current_state, p_common_ancesstor, p_context);
438 if (p_context->current_state_id != p_next_state->state_id)
439 gfsm_reenqueue_deferred_event(p_context);
441 if (p_context->p_fsm->log_func)
442 p_context->p_fsm->log_func("[%s] From (%s) to (%s)\n",
443 p_context->p_fsm->p_header,
444 p_context->p_fsm->state_name_cb(p_context->current_state_id),
445 p_context->p_fsm->state_name_cb(p_next_state->state_id));
446 p_context->current_state_id = p_next_state->state_id;
448 gfsm_do_entry_action(p_common_ancesstor, p_next_state, p_context);
451 void gfsm_do_exit_action(gfsm_state_s *p_current_state,
452 gfsm_state_s *p_common_ancesstor, gfsm_context_s *p_context)
454 gfsm_state_s *p_state = p_current_state;
456 while (p_state && p_state != p_common_ancesstor) {
457 if (p_state->exit_action_cb)
458 p_state->exit_action_cb(p_context->p_context_data);
460 if (p_context->p_fsm->log_func)
461 p_context->p_fsm->log_func("[%s] exiting state(%s)\n",
462 p_context->p_fsm->p_header, p_context->p_fsm->state_name_cb(p_state->state_id));
464 p_state = p_state->p_parent_state;
468 void gfsm_do_entry_action(gfsm_state_s *p_common_ancesstor,
469 gfsm_state_s *p_next_state, gfsm_context_s *p_context)
471 if (p_next_state == NULL || p_next_state == p_common_ancesstor)
474 gfsm_do_entry_action(p_common_ancesstor, p_next_state->p_parent_state,
477 if (p_context->p_fsm->log_func)
478 p_context->p_fsm->log_func("[%s] entering state(%s)\n",
479 p_context->p_fsm->p_header,
480 p_context->p_fsm->state_name_cb(p_next_state->state_id));
482 if (p_next_state->entry_action_cb)
483 p_next_state->entry_action_cb(p_context->p_context_data);
486 void gfsm_reenqueue_deferred_event(gfsm_context_s *p_context)
488 gfsm_event_s *p_event;
490 while ((p_event = gfsm_dequeue_event(&p_context->defer_event_queue)))
491 gfsm_enqueue_event(&p_context->event_queue, p_event);
494 /*gfsm_reaction_cb gfsm_deferral_reaction */
495 gfsm_state_id_t gfsm_deferral_reaction(void *p_context_data, void *p_event_data)
497 return GFSM_DEFER_EVENT;
500 void gfsm_init_event_queue(gfsm_event_queue_s *p_queue)
503 p_queue->p_head = p_queue->p_tail = NULL;
506 void gfsm_destroy_event_queue(gfsm_event_queue_s *p_queue)
508 gfsm_event_s *p_event;
510 while ((p_event = gfsm_dequeue_event(p_queue)) != NULL) {
511 if (p_event->destructor && p_event->p_event_data)
512 p_event->destructor(p_event->p_event_data);
518 void gfsm_enqueue_event(gfsm_event_queue_s *p_queue, gfsm_event_s *p_event)
523 if (p_queue->p_tail == NULL) {
524 assert(p_queue->p_head == NULL);
525 p_queue->p_head = p_queue->p_tail = p_event;
527 p_queue->p_tail->p_next = p_event;
528 p_queue->p_tail = p_event;
533 gfsm_event_s *gfsm_dequeue_event(gfsm_event_queue_s *p_queue)
537 gfsm_event_s *p_event = p_queue->p_head;
540 assert(p_queue->p_tail == NULL);
542 p_queue->p_head = p_event->p_next;
543 if (p_queue->p_head == NULL)
544 p_queue->p_tail = NULL;
550 gfsm_state_s *gfsm_find_last_child_state(gfsm_state_s *p_state)
554 while (p_state->p_internal_init_state)
555 p_state = p_state->p_internal_init_state;
560 gfsm_state_s *gfsm_find_common_ancesstor_state(gfsm_state_s *p_state_l,
561 gfsm_state_s *p_state_r)
563 gfsm_state_s *p_state_1, *p_state_2;
565 assert(p_state_l && p_state_r);
567 for (p_state_1 = p_state_l->p_parent_state; p_state_1 != NULL;
568 p_state_1 = p_state_1->p_parent_state) {
569 for (p_state_2 = p_state_r->p_parent_state; p_state_2 != NULL;
570 p_state_2 = p_state_2->p_parent_state) {
571 /*printf("\np_state_1 : %d, p_state_2 : %d",p_state_1->state_id,p_state_2->state_id); */
573 if (p_state_1->state_id == p_state_2->state_id)
581 void gfsm_set_logger(gfsm_s *p_fsm, gfsm_log_func log_func, const char *header,
582 gfsm_get_state_name_cb state_name_cb, gfsm_get_event_name_cb event_name_cb)
586 assert(p_fsm && log_func && header && state_name_cb && event_name_cb);
589 header_len = strlen(header);
591 p_fsm->log_func = log_func;
592 p_fsm->state_name_cb = state_name_cb;
593 p_fsm->event_name_cb = event_name_cb;
594 p_fsm->p_header = (char *)malloc(header_len + 1);
595 strncpy(p_fsm->p_header, header, header_len + 1);