Revise directory structure
[platform/core/connectivity/asp-manager.git] / src / gfsm.c
1 /*finite state machine
2  *
3  * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
4  *
5  * Contact: Hojeen Jee <hojeen.jee@samsung.com>, Jaejun Sim <jj.sim@samsung.com>,
6  * Jinho Ha <jinho89.ha@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <stdio.h>
26 #include <glib.h>
27 #include "gfsm.h"
28 #include "asp-manager-util.h"
29
30
31 typedef struct gfsm_event_queue {
32         gfsm_event_s *p_head;
33         gfsm_event_s *p_tail;
34 } gfsm_event_queue_s;
35
36 struct gfsm_event {
37         struct gfsm_event *p_next;
38         gfsm_event_id_t event_id;
39         void *p_event_data;
40         gfsm_event_data_destructor_cb destructor;
41 };
42
43 struct gfsm_state {
44         gfsm_state_id_t state_id;
45         gfsm_s *p_fsm;
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;
51 };
52
53 struct gfsm {
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;
61         char *p_header;
62 };
63
64 struct gfsm_context {
65         gfsm_s *p_fsm;
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;
72         void *p_context_data;
73 };
74
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);
92
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)
95 {
96         gfsm_s *p_fsm = (gfsm_s *)malloc(sizeof(gfsm_s));
97
98         assert(p_fsm);
99         assert(init_state < max_state);
100
101         size_t state_table_size = sizeof(gfsm_state_s *) * max_state;
102
103         p_fsm->pp_state_table = (gfsm_state_s **) malloc(state_table_size);
104
105         assert(p_fsm->pp_state_table);
106
107         memset(p_fsm->pp_state_table, 0, state_table_size);
108
109         p_fsm->max_state = max_state;
110         p_fsm->max_event = max_event;
111         p_fsm->init_state_id = init_state;
112
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;
117
118         return p_fsm;
119 }
120
121 void gfsm_destroy_fsm(gfsm_s *p_fsm)
122 {
123         assert(p_fsm);
124         assert(p_fsm->pp_state_table);
125
126         free(p_fsm->pp_state_table);
127         if (p_fsm->p_header)
128                 free(p_fsm->p_header);
129         free(p_fsm);
130 }
131
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)
134 {
135         size_t event_table_size;
136         gfsm_state_s *p_state = (gfsm_state_s *)malloc(sizeof(gfsm_state_s));
137
138         assert(p_state);
139         assert(p_fsm);
140         /*assert(entry_action && exit_action); */
141
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;
148
149         event_table_size = sizeof(gfsm_reaction_cb) * p_fsm->max_event;
150
151         p_state->reaction_table = (gfsm_reaction_cb *) malloc(event_table_size);
152
153         assert(p_state->reaction_table);
154
155         memset(p_state->reaction_table, 0, event_table_size);
156
157         return p_state;
158 }
159
160 void gfsm_destroy_state(gfsm_state_s *p_state)
161 {
162         assert(p_state);
163         assert(p_state->reaction_table);
164
165         free(p_state->reaction_table);
166         free(p_state);
167 }
168
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)
172 {
173         gfsm_state_s *p_next_state;
174         gfsm_context_s *p_context = (gfsm_context_s *)malloc(sizeof(gfsm_context_s));
175
176         assert(p_fsm);
177         assert(p_context);
178
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;
182
183         assert(p_context->current_state_id < p_fsm->max_state);
184
185         gfsm_init_event_queue(&p_context->event_queue);
186         gfsm_init_event_queue(&p_context->defer_event_queue);
187
188         p_context->processing_event = 0;
189         p_context->terminating = 0;
190         p_context->termination_notifier_cb = termination_notifier_cb;
191
192         p_next_state = p_fsm->pp_state_table[p_context->current_state_id];
193
194         assert(p_next_state);
195
196         gfsm_do_entry_action(NULL, p_next_state, p_context);
197
198         return p_context;
199 }
200
201 gfsm_state_id_t gfsm_get_current_state_id(gfsm_context_s *p_context)
202 {
203         assert(p_context);
204         return p_context->current_state_id;
205 }
206
207 void gfsm_destroy_context(gfsm_context_s *p_context)
208 {
209         gfsm_state_s *p_current_state;
210
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);
215
216                 p_context->terminating = 1;
217                 return;
218         }
219
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);
223
224         gfsm_destroy_event_queue(&p_context->event_queue);
225         gfsm_destroy_event_queue(&p_context->defer_event_queue);
226
227         if (p_context->termination_notifier_cb)
228                 p_context->termination_notifier_cb(p_context->p_context_data);
229
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);
233
234         free(p_context);
235 }
236
237 void gfsm_add_reaction(gfsm_state_s *p_state, gfsm_event_id_t event_id,
238                        gfsm_reaction_cb reaction_cb)
239 {
240         assert(p_state);
241         assert(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);
246
247         p_state->reaction_table[event_id] = reaction_cb;
248 }
249
250 void gfsm_set_parent_state(gfsm_state_s *p_state, gfsm_state_s *p_parent_state)
251 {
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); */
255
256         p_state->p_parent_state = p_parent_state;
257
258         if (NULL == p_parent_state->p_internal_init_state)
259                 p_parent_state->p_internal_init_state = p_state;
260 }
261
262 /*
263 void gfsm_set_internal_init_state(gfsm_state_s* p_state, gfsm_state_s* p_internal_init_state)
264 {
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;
268 }
269 */
270
271 void gfsm_add_state(gfsm_s *p_fsm, gfsm_state_s *p_state)
272 {
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);
276
277         p_fsm->pp_state_table[p_state->state_id] = p_state;
278 }
279
280 gfsm_event_s *gfsm_create_event(gfsm_event_id_t event_id, void *p_event_data,
281                                 gfsm_event_data_destructor_cb destructor)
282 {
283         gfsm_event_s *p_event = (gfsm_event_s *)malloc(sizeof(gfsm_event_s));
284
285         assert(p_event);
286
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;
291
292         return p_event;
293 }
294
295 gfsm_s *gfsm_get_fsm_of_state(gfsm_state_s *p_state)
296 {
297         assert(p_state);
298         return p_state->p_fsm;
299 }
300
301 gfsm_s *gfsm_get_fsm_of_context(gfsm_context_s *p_context)
302 {
303         assert(p_context);
304         return p_context->p_fsm;
305 }
306
307 void gfsm_process_event(gfsm_context_s **pp_context, gfsm_event_s *p_event)
308 {
309         gfsm_context_s *p_context = *pp_context;
310         gfsm_s *p_fsm;
311
312         ASP_LOGD("process event");
313         if (p_context == NULL)
314                 ASP_LOGD("context is NULL");
315         assert(p_context && p_event);
316
317         p_fsm = p_context->p_fsm;
318
319         assert(p_fsm && p_event->event_id < p_fsm->max_event);
320
321         gfsm_enqueue_event(&p_context->event_queue, p_event);
322
323         if (p_context->processing_event) {      /*recursive check */
324                 if (p_fsm->log_func)
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));
327
328                 return;
329         }
330
331         p_context->processing_event = 1;
332
333         while ((p_event = gfsm_dequeue_event(&p_context->event_queue)))
334                 _gfsm_process_event(p_context, p_event);
335
336         p_context->processing_event = 0;
337
338         if (p_context->terminating) {
339                 if (p_fsm->log_func)
340                         p_fsm->log_func("[%s] destroy_context was scheduled\n", p_fsm->p_header);
341
342                 ASP_LOGD("context[%p]", p_context);
343                 gfsm_destroy_context(p_context);
344         }
345 }
346
347 void _gfsm_process_event(gfsm_context_s *p_context, gfsm_event_s *p_event)
348 {
349         gfsm_s *p_fsm;
350         gfsm_state_s *p_state;
351         gfsm_state_id_t next_state_id = GFSM_DISCARD_EVENT;
352         gfsm_event_id_t event_id;
353
354         ASP_LOGD("inner process event");
355         assert(p_context && p_event);
356
357         event_id = p_event->event_id;
358         p_fsm = p_context->p_fsm;
359
360         assert(p_context->current_state_id < p_fsm->max_state);
361
362         if (p_fsm->log_func)
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));
366
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]) {
370                         if (p_fsm->log_func)
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));
374
375                         next_state_id = p_state->reaction_table[event_id](p_context->p_context_data,
376                                         p_event->p_event_data);
377                         break;
378                 }
379         }
380
381         if (GFSM_DEFER_EVENT == next_state_id) {
382                 if (p_fsm->log_func)
383                         p_fsm->log_func("[%s] event(%s) is defered\n", p_fsm->p_header,
384                                         p_fsm->event_name_cb(event_id));
385
386                 gfsm_enqueue_event(&p_context->defer_event_queue, p_event);
387                 return;
388         }
389
390         if (p_event->destructor && p_event->p_event_data)
391                 p_event->destructor(p_event->p_event_data);
392
393         free(p_event);
394
395         if (NULL == p_state) {
396                 if (p_fsm->log_func)
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));
400
401                 return;
402         }
403
404         if (GFSM_DISCARD_EVENT == next_state_id) {
405                 if (p_fsm->log_func)
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));
408
409                 return;
410         }
411
412         gfsm_process_transition(p_context, next_state_id);
413 }
414
415 void gfsm_process_transition(gfsm_context_s *p_context,
416                              gfsm_state_id_t next_state_id)
417 {
418         gfsm_state_s *p_next_state;
419         gfsm_state_s *p_current_state;
420         gfsm_state_s *p_common_ancesstor;
421
422         assert(next_state_id < p_context->p_fsm->max_state);
423
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];
426
427         assert(p_next_state && p_current_state);
428
429         p_common_ancesstor = gfsm_find_common_ancesstor_state(p_current_state,
430                              p_next_state);
431
432         p_next_state = gfsm_find_last_child_state(p_next_state);
433
434         assert(p_next_state);
435
436         gfsm_do_exit_action(p_current_state, p_common_ancesstor, p_context);
437
438         if (p_context->current_state_id != p_next_state->state_id)
439                 gfsm_reenqueue_deferred_event(p_context);
440
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;
447
448         gfsm_do_entry_action(p_common_ancesstor, p_next_state, p_context);
449 }
450
451 void gfsm_do_exit_action(gfsm_state_s *p_current_state,
452                          gfsm_state_s *p_common_ancesstor, gfsm_context_s *p_context)
453 {
454         gfsm_state_s *p_state = p_current_state;
455
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);
459
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));
463
464                 p_state = p_state->p_parent_state;
465         }
466 }
467
468 void gfsm_do_entry_action(gfsm_state_s *p_common_ancesstor,
469                           gfsm_state_s *p_next_state, gfsm_context_s *p_context)
470 {
471         if (p_next_state == NULL || p_next_state == p_common_ancesstor)
472                 return;
473
474         gfsm_do_entry_action(p_common_ancesstor, p_next_state->p_parent_state,
475                              p_context);
476
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));
481
482         if (p_next_state->entry_action_cb)
483                 p_next_state->entry_action_cb(p_context->p_context_data);
484 }
485
486 void gfsm_reenqueue_deferred_event(gfsm_context_s *p_context)
487 {
488         gfsm_event_s *p_event;
489
490         while ((p_event = gfsm_dequeue_event(&p_context->defer_event_queue)))
491                 gfsm_enqueue_event(&p_context->event_queue, p_event);
492 }
493
494 /*gfsm_reaction_cb gfsm_deferral_reaction */
495 gfsm_state_id_t gfsm_deferral_reaction(void *p_context_data, void *p_event_data)
496 {
497         return GFSM_DEFER_EVENT;
498 }
499
500 void gfsm_init_event_queue(gfsm_event_queue_s *p_queue)
501 {
502         assert(p_queue);
503         p_queue->p_head = p_queue->p_tail = NULL;
504 }
505
506 void gfsm_destroy_event_queue(gfsm_event_queue_s *p_queue)
507 {
508         gfsm_event_s *p_event;
509
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);
513
514                 free(p_event);
515         }
516 }
517
518 void gfsm_enqueue_event(gfsm_event_queue_s *p_queue, gfsm_event_s *p_event)
519 {
520         ASP_LOGD("enqueue");
521         assert(p_queue);
522
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;
526         } else {
527                 p_queue->p_tail->p_next = p_event;
528                 p_queue->p_tail = p_event;
529         }
530
531 }
532
533 gfsm_event_s *gfsm_dequeue_event(gfsm_event_queue_s *p_queue)
534 {
535         assert(p_queue);
536
537         gfsm_event_s *p_event = p_queue->p_head;
538
539         if (p_event == NULL)
540                 assert(p_queue->p_tail == NULL);
541         else {
542                 p_queue->p_head = p_event->p_next;
543                 if (p_queue->p_head == NULL)
544                         p_queue->p_tail = NULL;
545         }
546
547         return p_event;
548 }
549
550 gfsm_state_s *gfsm_find_last_child_state(gfsm_state_s *p_state)
551 {
552         assert(p_state);
553
554         while (p_state->p_internal_init_state)
555                 p_state = p_state->p_internal_init_state;
556
557         return p_state;
558 }
559
560 gfsm_state_s *gfsm_find_common_ancesstor_state(gfsm_state_s *p_state_l,
561                 gfsm_state_s *p_state_r)
562 {
563         gfsm_state_s *p_state_1, *p_state_2;
564
565         assert(p_state_l && p_state_r);
566
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); */
572
573                         if (p_state_1->state_id == p_state_2->state_id)
574                                 return p_state_1;
575                 }
576         }
577
578         return NULL;
579 }
580
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)
583 {
584         int header_len = 0;
585
586         assert(p_fsm && log_func && header && state_name_cb && event_name_cb);
587
588         if (header)
589                 header_len = strlen(header);
590
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);
596 }