design_pattern_for_c  V 1.00
state_machine.c
Go to the documentation of this file.
1 
5 #include <stdlib.h>
6 #include <stdarg.h>
7 #include <pthread.h>
8 #include <sys/types.h>
9 #include <sys/eventfd.h>
10 #include <unistd.h>
11 #include <pthread.h>
12 #include <errno.h>
13 #include "state_machine.h"
14 #include "dp_util.h"
15 
16 /*************
17  * public define
18 *************/
19 
28  int event;
30 };
31 
33 /* @{ */
37 /* }@ */
38 
39 struct state_machine_msg_t;
45  pthread_mutex_t lock;
46  int eventfd;
47 };
55  int (*call_event)(StateMachine this, int event, void *arg, int arglen, void (*response)(int result));/* call event API, to switch single/multi thread*/
56  int (*call_single_event)(StateMachine this, int event, void *arg, int arglen, void (*response)(int result));/* call event API, to call own thread*/
57  void (*free)(StateMachine this);/* call free API, to switch single/multi thread*/
58  /*data for multi thread mode*/
60  pthread_t tid;
61 
62  /*for recv event */
64 };
65 
66 #define SMACHINE_LOCK(this) DPUTIL_LOCK(&this->msglist.lock);
67 #define SMACHINE_UNLOCK DPUTIL_UNLOCK
68 
75  int event;
76  void * args;
77  void (*response)(int result);
78 };
79 
81 /* @{ */
83 static int state_machine_add_new_states(StateMachine this, const state_event_info_t * event_info);
93 static int state_machine_call_event_normally(StateMachine this, int event, void *arg, int arglen, void (*response)(int result));
94 static inline int state_machine_call_event_normal(StateMachine this, int event, void *arg);
96 static int state_machine_call_event_multithread(StateMachine this, int event, void *arg, int arglen, void (*response)(int result));
98 static void state_machine_thread_main(int socketfd, int eventflag, void * event_arg);
100 static inline int state_machine_open_socket(StateMachine this);
102 static void state_machine_close_socket(StateMachine this);
104 static inline int state_machine_get_read(StateMachine this);
106 static inline int state_machine_write(StateMachine this, state_machine_msg_t *msg);
107 /* @} */
108 /*************
109  * private API for StateManagerListData
110 *************/
112 /* @{ */
114  StateManagerListData state_manager = calloc(1, sizeof(*state_manager));
115  if(!state_manager) {
116  DEBUG_ERRPRINT("allocate StateManagerListData error\n");
117  return NULL;
118  }
119 
120  state_manager->states = state_manager_new(event_info->state_num, event_info->state_infos);
121  if(!state_manager->states) {
122  DEBUG_ERRPRINT("allocate StateManager error\n");
123  free(state_manager);
124  return NULL;
125  }
126 
127  state_manager->event = event_info->event;
128  return state_manager;
129 }
130 
132  if(!this) {
133  return;
134  }
135 
136  state_manager_free(this->states);
137  free(this);
138 }
139 /* @}*/
140 
141 /*************
142  * private API for StateMachine
143 *************/
145 /* @{ */
147 static int state_machine_add_new_states(StateMachine this, const state_event_info_t * event_info) {
148  StateManagerListData state_manager = state_machine_manager_list_new(event_info);
149  if(!state_manager) {
150  DEBUG_ERRPRINT("allocate StateManagerListData error\n");
151  return STATE_MNG_FAILED;
152  }
153 
154  /*push to list*/
155  dputil_list_push((DPUtilList)this, (DPUtilListData)state_manager);
156  return STATE_MNG_SUCCESS;
157 }
158 
162  while(state_manager) {
163  state_machine_manager_list_free(state_manager);
164  state_manager=(StateManagerListData)dputil_list_pop((DPUtilList)this);
165  }
166 }
167 
170  StateManagerListData state_manager = this->head;
171  while(state_manager) {
172  if(state_manager->event == event) {
173  break;
174  }
175  state_manager=state_manager->next;
176  }
177  return state_manager;
178 }
179 
182  /* create socket */
183  if(-1==state_machine_open_socket(this)) {
184  DEBUG_ERRPRINT("Failed to create socket pair!\n");
185  return STATE_MNG_FAILED;
186  }
187 
188  event_subscriber_t subscriber={
189  .fd = state_machine_get_read(this),
190  .eventflag = EV_TPOOL_READ,
191  .event_callback = state_machine_thread_main,
192  };
193 
194  event_tpool_add_result_t result = event_tpool_add(this->threadpool, &subscriber, this);
195  return result.result;
196 }
197 
200  /* exit event */
201  event_tpool_del(this->threadpool, state_machine_get_read(this));
202 
203  /*close socket*/
205 
206  /* free normally */
208 }
209 
211 static int state_machine_call_event_normally(StateMachine this, int event, void *arg, int arglen, void (*response)(int result)) {
212  (void)response;
213  (void)arglen;
214  return state_machine_call_event_normal(this, event, arg);
215 }
216 
217 static inline int state_machine_call_event_normal(StateMachine this, int event, void *arg) {
218  StateManagerListData state_manager = state_machine_find_states(this, event);
219  if(!state_manager) {
220  return STATE_MNG_FAILED;
221  }
222 
223  return state_manager_call(state_manager->states, arg);
224 }
225 
227 static int state_machine_call_event_multithread(StateMachine this, int event, void *arg, int arglen, void (*response)(int result)) {
228  StateMachineMsg msg = calloc(1, sizeof(*msg) + arglen);
229  if(!msg) {
230  return STATE_MNG_FAILED;
231  }
232  msg->event = event;
233  msg->args = (void *)(msg + 1);
234 
235  memcpy(msg->args, arg, arglen);
236  msg->response = response;
237 
238  int ret = STATE_MNG_SUCCESS;
239  if(state_machine_write(this, msg) < 0) {
240  DEBUG_ERRPRINT("...failed to send, errno=%s\n", strerror(errno));
241  free(msg);
242  ret = STATE_MNG_FAILED;
243  }
244  return ret;
245 }
246 
248 static void state_machine_thread_main(int socketfd, int eventflag, void * event_arg) {
249  StateMachine this = (StateMachine)event_arg;
250  int ret = 0;
251  StateMachineMsg msg;
252  eventfd_t cnt=0;
253 
254  //set threadid
255  if(!this->tid) {
256  this->tid = pthread_self();
257  }
258 
259  //read event
260  ret = eventfd_read(socketfd, &cnt);
261  if(ret < 0) {
262  DEBUG_ERRPRINT("failed to read, %s\n", strerror(errno));
263  return;
264  }
265 
266 SMACHINE_LOCK(this);
267  while(1) {
268  msg = (StateMachineMsg)dputil_list_pop((DPUtilList)&this->msglist);
269  if(!msg) {
270  break;
271  }
272  /* call */
273  ret = state_machine_call_event_normal(this, msg->event, msg->args);
274  if(msg->response) {
275  msg->response(ret);
276  }
277 
278  free(msg);
279  }
280 SMACHINE_UNLOCK(this);
281 }
282 
284 static inline int state_machine_open_socket(StateMachine this) {
285  pthread_mutex_init(&this->msglist.lock, NULL);
286  this->msglist.eventfd = eventfd(0,EFD_CLOEXEC | EFD_NONBLOCK);
287  return this->msglist.eventfd;
288 }
289 
292  close(this->msglist.eventfd);
293 }
294 
295 
297 static inline int state_machine_get_read(StateMachine this) {
298  return this->msglist.eventfd;
299 }
300 
302 static inline int state_machine_write(StateMachine this, state_machine_msg_t *msg) {
303 SMACHINE_LOCK(this)
304  dputil_list_push((DPUtilList)(&this->msglist), (DPUtilListData)msg);
306  return eventfd_write(this->msglist.eventfd, 1);
307 }
308 /* @} */
309 
310 /*************
311  * public API
312 *************/
313 StateMachineInfo state_machine_new(size_t event_num, const state_event_info_t * event_infos, EventTPoolManager threadpool) {
314  StateMachineInfo instance_info = calloc(1, sizeof(*instance_info));
315  if(!instance_info) {
316  DEBUG_ERRPRINT("allocate error\n");
317  return NULL;
318  }
319 
320  StateMachine instance = calloc(1, sizeof(*instance));
321  if(!instance) {
322  DEBUG_ERRPRINT("allocate error\n");
323  goto err;
324  }
325  instance_info->state_machine = instance;
326 
327  /* set data */
328  int i = 0;
329  for( i = 0; i < event_num; i ++ ) {
330  if(state_machine_add_new_states(instance, &event_infos[i]) != STATE_MNG_SUCCESS) {
331 
332  goto err;
333  }
334  }
335 
336  if(threadpool) {
337  /* set information for multi thread */
341  instance->threadpool = threadpool;
342  instance_info->thread_num = state_machine_initial_thread(instance);
343  if( instance_info->thread_num < 0 ) {
344  /* change free function because starting thread is failed */
346  goto err;
347  }
348  } else {
349  /* only set call_event and free API */
353  }
354  return instance_info;
355 err:
356  state_machine_free(instance_info);
357  return NULL;
358 }
359 
361  if(!this || !event_info) {
362  return STATE_MNG_FAILED;
363  }
364 
365  StateManagerListData state_manager = state_machine_find_states(this->state_machine, event_info->event);
366 
367  int ret = STATE_MNG_SUCCESS;
368  if(state_manager) {
369  /* To update StateManager , keep current state */
370  int current_state = state_manager_get_current_state(state_manager->states);
371  state_manager_free(state_manager->states);
372 
373  /* Set new state manager */
374  state_manager->states = state_manager_new(event_info->state_num, event_info->state_infos);
375  if(!state_manager->states) {
376  ret = STATE_MNG_FAILED;
377  }
378 
379  /* set state */
380  state_manager_set_state(state_manager->states, current_state);
381  } else {
382  /* only add new event */
383  ret = state_machine_add_new_states(this->state_machine, event_info);
384  }
385  return ret;
386 }
387 
389  if(!this) {
390  return;
391  }
392 
393  /* Set all state_manager's state*/
394  StateManagerListData state_manager = this->state_machine->head;
395  while(state_manager) {
396  state_manager_set_state(state_manager->states, state);
397  state_manager=state_manager->next;
398  }
399  return;
400 }
401 
403  if(!this) {
404  return STATE_MNG_FAILED;
405  }
406  if(this->state_machine->head) {
407  return state_manager_get_current_state(this->state_machine->head->states);
408  } else {
409  return STATE_MNG_FAILED;
410  }
411 }
412 
413 int state_machine_call_event(StateMachineInfo this, int event, void *arg, int arglen, void (*response)(int result)) {
414  if(!this) {
415  return STATE_MNG_FAILED;
416  }
417 
418  if(this->state_machine->tid && this->state_machine->tid == pthread_self() ) {
419  return this->state_machine->call_single_event(this->state_machine, event, arg, arglen, response);
420  } else {
421  return this->state_machine->call_event(this->state_machine, event, arg, arglen, response);
422  }
423 }
424 
426  if(!this) {
427  return;
428  }
429 
430  StateManagerListData state_manager=this->state_machine->head;
431  while(state_manager) {
432  printf("===[event: %d]===\n", state_manager->event);
433  state_manager_show(state_manager->states);
434  state_manager=state_manager->next;
435  }
436 }
437 
439  if(!this) {
440  return;
441  }
442 
443  this->state_machine->free(this->state_machine);
444  free(this->state_machine);
445  free(this);
446 }
#define EV_TPOOL_READ
void state_machine_show(StateMachineInfo this)
set state
state_info_t * state_infos
state list, please see state_manager.h defition
Definition: state_machine.h:16
information of state machine message list
Definition: state_machine.c:42
static void state_machine_thread_main(int socketfd, int eventflag, void *event_arg)
for multi thread, thread main callback for threadpool
#define STATE_MNG_FAILED
Definition: state_manager.h:10
void state_manager_free(StateManager this)
free StateManager class
Utility headers
StateManagerListData state_machine_find_states(StateMachine this, int event)
Find state.
state_machine_msg_list_t msglist
Definition: state_machine.c:63
pthread_mutex_t lock
Definition: state_machine.c:45
static int state_machine_get_read(StateMachine this)
for multi thread, get read sock
StateManager class member definition, detail is defined in C file.
Definition: state_manager.c:30
StateMachineMsg next
Definition: state_machine.c:73
static int state_machine_call_event_normally(StateMachine this, int event, void *arg, int arglen, void(*response)(int result))
for single thread, call event
void state_manager_set_state(StateManager this, int state)
set state
StateManagerListData head
Definition: state_machine.c:53
void(* free)(EventInstance this)
Definition: event_thread.c:39
static int state_machine_call_event_normal(StateMachine this, int event, void *arg)
static StateManagerListData state_machine_manager_list_new(const state_event_info_t *event_info)
Add new state.
void(* response)(int result)
Definition: state_machine.c:77
void state_machine_free(StateMachineInfo this)
free StateMachine class
struct state_machine_msg_t * StateMachineMsg
Definition: state_machine.c:40
message definition for multi thread
Definition: state_machine.c:72
static void state_machine_free_states_normally(StateMachine this)
free normally
event_tpool_add_result_t event_tpool_add(EventTPoolManager this, EventSubscriber subscriber, void *arg)
add EventSubscriber to threadpool
void(* free)(StateMachine this)
Definition: state_machine.c:57
StateMachineInfo state_machine_new(size_t event_num, const state_event_info_t *event_infos, EventTPoolManager threadpool)
Create StateMachineInfo class.
int(* call_single_event)(StateMachine this, int event, void *arg, int arglen, void(*response)(int result))
Definition: state_machine.c:56
struct state_machine_t * StateMachine
StateMachine class definition.
Definition: state_machine.h:24
int state_manager_get_current_state(StateManager this)
get current state
struct state_manager_list_data_t * StateManagerListData
Definition: state_machine.c:24
int state_manager_call(StateManager this, void *arg)
call state method
EventTPoolManager class instance definition.
EventTPoolManager threadpool
Definition: state_machine.c:59
static void state_machine_manager_list_free(StateManagerListData this)
static int state_machine_write(StateMachine this, state_machine_msg_t *msg)
for multi thread, write
int event
event event id
Definition: state_machine.h:14
static void state_machine_close_socket(StateMachine this)
for multi thread, close socket
int state_machine_get_current_state(StateMachineInfo this)
get state
#define STATE_MNG_SUCCESS
Definition: state_manager.h:9
StateMachine state_machine
Definition: state_machine.h:27
int state_machine_call_event(StateMachineInfo this, int event, void *arg, int arglen, void(*response)(int result))
call event trigger
EventSubscriber class instance definition, this is storaged in any threads.
information of StateMachine, to use as list
Definition: state_machine.c:25
DPUtilListData dputil_list_pop(DPUtilList this)
list pop
Definition: dp_util.c:80
void event_tpool_del(EventTPoolManager this, int fd)
delete EventSubscriber to threadapool.
void dputil_list_push(DPUtilList this, DPUtilListData data)
list push
Definition: dp_util.c:21
void state_machine_set_state(StateMachineInfo this, int state)
set state
event ID and related state functions
Definition: state_machine.h:13
int state_machine_update_machine(StateMachineInfo this, const state_event_info_t *event_info)
update sate
StateMachineMsg tail
Definition: state_machine.c:44
StateManagerListData next
Definition: state_machine.c:26
#define SMACHINE_UNLOCK
Definition: state_machine.c:67
StateMachineMsg prev
Definition: state_machine.c:74
static int state_machine_add_new_states(StateMachine this, const state_event_info_t *event_info)
Add new state.
int fd
file descripter of this subscriber
StateMachine class member definition.
Definition: state_machine.c:52
StateMachineMsg head
Definition: state_machine.c:43
static int state_machine_open_socket(StateMachine this)
for multi thread, open socket
void state_manager_show(StateManager this)
show current state table
StateManager state_manager_new(size_t state_info_num, const state_info_t *state)
Create StateManager class.
Definition: state_manager.c:74
This is API for Sate machine.
static int state_machine_initial_thread(StateMachine this)
for multi thread, initialize
#define DEBUG_ERRPRINT(...)
Definition: dp_debug.h:69
static int state_machine_call_event_multithread(StateMachine this, int event, void *arg, int arglen, void(*response)(int result))
for multi thread, call event
#define SMACHINE_LOCK(this)
Definition: state_machine.c:66
int(* call_event)(StateMachine this, int event, void *arg, int arglen, void(*response)(int result))
Definition: state_machine.c:55
size_t state_num
state num
Definition: state_machine.h:15
StateManagerListData tail
Definition: state_machine.c:54
StateManagerListData prev
Definition: state_machine.c:27
static void state_machine_free_states_multithread(StateMachine this)
for multi thread, free
add result definition