6 typedef void (*Callback)(void *context);
8 #define NUM_THREADS 200
10 typedef struct FooStruct *Foo;
13 SilcFSMThreadStruct thread;
14 SilcFSMSemaStruct sema;
23 SilcFSMThreadStruct thread;
25 SilcFSMSemaStruct sema;
26 SilcSchedule schedule;
29 T threads[NUM_THREADS];
30 T threads2[NUM_THREADS];
33 SILC_FSM_STATE(test_st_start);
34 SILC_FSM_STATE(test_st_second);
35 SILC_FSM_STATE(test_st_third);
36 SILC_FSM_STATE(test_st_fourth);
37 SILC_FSM_STATE(test_st_fifth);
38 SILC_FSM_STATE(test_st_sixth);
39 SILC_FSM_STATE(test_st_seventh);
40 SILC_FSM_STATE(test_st_eighth);
41 SILC_FSM_STATE(test_st_ninth);
42 SILC_FSM_STATE(test_st_tenth);
43 SILC_FSM_STATE(test_st_finish);
45 SILC_FSM_STATE(test_thread_st_start);
46 SILC_FSM_STATE(test_thread_st_finish);
47 SILC_FSM_STATE(test_thread2_st_start);
48 SILC_FSM_STATE(test_thread2_st_finish);
49 SILC_FSM_STATE(test_thread3_st_start);
50 SILC_FSM_STATE(test_thread4_st_start);
52 SILC_TASK_CALLBACK(async_call_timeout)
55 SILC_LOG_DEBUG(("Async call cb, continuing FSM"));
59 static void async_call(Callback cb, void *context)
63 f->cb_context = context;
64 SILC_LOG_DEBUG(("Async call"));
65 silc_schedule_task_add(f->schedule, 0, async_call_timeout, f, 0, 200000,
69 SILC_FSM_STATE(test_st_start)
71 SILC_LOG_DEBUG(("test_st_start"));
73 /** Move to second state */
74 SILC_LOG_DEBUG(("Move to next state"));
75 silc_fsm_next(fsm, test_st_second);
76 return SILC_FSM_CONTINUE;
79 SILC_FSM_STATE(test_st_second)
81 SILC_LOG_DEBUG(("test_st_second"));
83 /** Move to third state, timeout */
84 SILC_LOG_DEBUG(("Move to next state with 2 second timeout"));
85 silc_fsm_next_later(fsm, test_st_third, 2, 0);
89 static void async_call_cb(void *context)
92 SILC_LOG_DEBUG(("Callback, continue to next state"));
93 SILC_FSM_CALL_CONTINUE(f->fsm);
96 SILC_FSM_STATE(test_st_third)
100 SILC_LOG_DEBUG(("test_st_third"));
104 /** Wait async callback*/
105 SILC_LOG_DEBUG(("Call async call"));
106 silc_fsm_next(fsm, test_st_fourth);
107 SILC_FSM_CALL(async_call(async_call_cb, f));
110 SILC_FSM_STATE(test_st_fourth)
114 SILC_LOG_DEBUG(("test_st_fourth"));
118 SILC_LOG_DEBUG(("Creating FSM thread"));
119 silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, FALSE);
120 SILC_LOG_DEBUG(("Starting thread"));
122 silc_fsm_start(&f->thread, test_thread_st_start);
124 /** Waiting thread to terminate */
125 SILC_LOG_DEBUG(("Waiting for thread to terminate"));
126 silc_fsm_next(fsm, test_st_fifth);
127 SILC_FSM_THREAD_WAIT(&f->thread);
130 SILC_FSM_STATE(test_thread_st_start)
134 SILC_LOG_DEBUG(("test_thread_st_start"));
136 /** Move to final state, timeout */
137 SILC_LOG_DEBUG(("Move to final state with %d second timeout", f->timeout));
138 silc_fsm_next_later(fsm, test_thread_st_finish, f->timeout, 0);
139 return SILC_FSM_WAIT;
142 SILC_FSM_STATE(test_thread_st_finish)
144 SILC_LOG_DEBUG(("test_thread_st_finish"));
146 SILC_LOG_DEBUG(("Finishing the thread"));
147 return SILC_FSM_FINISH;
150 SILC_FSM_STATE(test_st_fifth)
153 SILC_LOG_DEBUG(("test_st_fifth"));
155 SILC_LOG_DEBUG(("Thread terminated, start new real thread"));
159 SILC_LOG_DEBUG(("Creating FSM semaphore"));
160 silc_fsm_sema_init(&f->sema, fsm, 0);
162 SILC_LOG_DEBUG(("Creating FSM thread"));
163 silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, TRUE);
164 SILC_LOG_DEBUG(("Starting thread"));
165 silc_fsm_start(&f->thread, test_thread2_st_start);
167 /** Waiting thread to terminate, timeout */
168 SILC_LOG_DEBUG(("Waiting for thread to terminate for 5 seconds"));
169 silc_fsm_next(fsm, test_st_sixth);
170 SILC_FSM_SEMA_TIMEDWAIT(&f->sema, 5, 0, NULL);
171 return SILC_FSM_CONTINUE;
174 SILC_FSM_STATE(test_thread2_st_start)
178 SILC_LOG_DEBUG(("test_thread2_st_start"));
180 /** Move to final state, timeout */
181 SILC_LOG_DEBUG(("Move to final state with %d second timeout", f->timeout));
182 silc_fsm_next_later(fsm, test_thread2_st_finish, f->timeout, 0);
183 return SILC_FSM_WAIT;
186 SILC_FSM_STATE(test_thread2_st_finish)
189 SILC_LOG_DEBUG(("test_thread2_st_finish"));
191 SILC_LOG_DEBUG(("Post semaphore"));
192 SILC_FSM_SEMA_POST(&f->sema);
194 SILC_LOG_DEBUG(("Finishing the thread"));
195 return SILC_FSM_FINISH;
198 SILC_FSM_STATE(test_st_sixth)
200 SILC_LOG_DEBUG(("test_st_sixth"));
202 SILC_LOG_DEBUG(("Thread wait timedout, OK"));
204 /** Move to next state, timeout */
205 SILC_LOG_DEBUG(("Continue to next state with 4 second timeout"));
206 silc_fsm_next_later(fsm, test_st_seventh, 4, 0);
207 return SILC_FSM_WAIT;
210 SILC_FSM_STATE(test_thread3_st_start)
214 if (t->rounds == 0) {
215 SILC_FSM_SEMA_POST(&t->sema);
216 return SILC_FSM_FINISH;
221 /** Call in recursive */
222 silc_fsm_next(fsm, test_thread3_st_start);
223 return SILC_FSM_CONTINUE;
226 SILC_FSM_STATE(test_st_seventh)
231 SILC_LOG_DEBUG(("test_st_seventh"));
234 SILC_LOG_DEBUG(("Creating %d FSM threads", NUM_THREADS));
235 for (i = 0; i < NUM_THREADS; i++) {
236 f->threads[i].rounds = 10;
238 silc_fsm_sema_init(&f->threads[i].sema, fsm, 0);
239 silc_fsm_thread_init(&f->threads[i].thread, fsm,
240 &f->threads[i], NULL, NULL, FALSE);
241 silc_fsm_start(&f->threads[i].thread, test_thread3_st_start);
244 /** Move to wait threads */
245 silc_fsm_next(fsm, test_st_eighth);
246 return SILC_FSM_CONTINUE;
249 SILC_FSM_STATE(test_st_eighth)
254 for (i = 0; i < NUM_THREADS; i++) {
255 if (f->threads[i].finished == FALSE) {
256 SILC_FSM_SEMA_WAIT(&f->threads[i].sema);
257 f->threads[i].finished = TRUE;
261 for (i = 0; i < NUM_THREADS; i++)
262 silc_fsm_uninit(&f->threads[i].thread);
264 SILC_LOG_DEBUG(("All %d threads terminated", NUM_THREADS));
266 /** Move to next thread */
267 silc_fsm_next(fsm, test_st_ninth);
268 return SILC_FSM_CONTINUE;
271 SILC_FSM_STATE(test_thread4_st_start)
275 if (t->rounds == 0) {
276 SILC_FSM_SEMA_POST(&t->sema);
277 return SILC_FSM_FINISH;
282 /** Call in recursive */
283 silc_fsm_next(fsm, test_thread4_st_start);
284 return SILC_FSM_CONTINUE;
287 SILC_FSM_STATE(test_st_ninth)
292 SILC_LOG_DEBUG(("test_st_ninth"));
294 SILC_LOG_DEBUG(("Creating FSM semaphore"));
295 silc_fsm_sema_init(&f->sema, fsm, NUM_THREADS + 1);
297 SILC_LOG_DEBUG(("Creating %d real FSM threads", NUM_THREADS));
298 for (i = 0; i < NUM_THREADS; i++) {
299 f->threads2[i].rounds = 10;
300 f->threads2[i].f = f;
301 silc_fsm_sema_init(&f->threads2[i].sema, fsm, 0);
302 silc_fsm_thread_init(&f->threads2[i].thread, fsm,
303 &f->threads2[i], NULL, NULL, TRUE);
304 silc_fsm_start(&f->threads2[i].thread, test_thread4_st_start);
307 /** Move to wait threads */
308 silc_fsm_next(fsm, test_st_tenth);
309 return SILC_FSM_CONTINUE;
312 SILC_FSM_STATE(test_st_tenth)
317 for (i = 0; i < NUM_THREADS; i++)
318 if (f->threads2[i].finished == FALSE) {
319 SILC_FSM_SEMA_WAIT(&f->threads2[i].sema);
320 f->threads2[i].finished = TRUE;
323 for (i = 0; i < NUM_THREADS; i++)
324 silc_fsm_uninit(&f->threads2[i].thread);
326 SILC_LOG_DEBUG(("All %d real threads terminated", NUM_THREADS));
328 /** Finished successfully */
329 silc_fsm_next_later(fsm, test_st_finish, 2, 0);
330 return SILC_FSM_WAIT;
333 SILC_FSM_STATE(test_st_finish)
335 SILC_LOG_DEBUG(("test_st_finish"));
337 SILC_LOG_DEBUG(("Finish machine"));
338 return SILC_FSM_FINISH;
341 static void destructor(SilcFSM fsm, void *fsm_context,
342 void *destructor_context)
344 Foo f = destructor_context;
345 SILC_LOG_DEBUG(("FSM destructor, stopping scheduler"));
347 silc_schedule_stop(f->schedule);
350 int main(int argc, char **argv)
352 SilcBool success = FALSE;
353 SilcSchedule schedule;
357 if (argc > 1 && !strcmp(argv[1], "-d")) {
358 silc_log_debug(TRUE);
359 silc_log_debug_hexdump(TRUE);
360 silc_log_quick(TRUE);
361 silc_log_set_debug_string("*fsm*,*async*");
364 SILC_LOG_DEBUG(("Allocating scheduler"));
365 schedule = silc_schedule_init(0, NULL);
367 f = silc_calloc(1, sizeof(*f));
370 f->schedule = schedule;
372 SILC_LOG_DEBUG(("Allocating FSM context"));
373 fsm = silc_fsm_alloc(f, destructor, f, schedule);
376 silc_fsm_start(fsm, test_st_start);
378 SILC_LOG_DEBUG(("Running scheduler"));
379 silc_schedule(schedule);
384 silc_schedule_uninit(schedule);
390 SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
391 fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");