6 typedef void (*Callback)(void *context);
8 #define NUM_THREADS 200
10 typedef struct FooStruct *Foo;
13 SilcFSMThreadStruct thread;
14 SilcFSMEventStruct sema;
23 SilcFSMThreadStruct thread;
25 SilcFSMEventStruct sema;
26 SilcFSMEventStruct wait2;
27 SilcSchedule schedule;
30 T threads[NUM_THREADS];
31 T threads2[NUM_THREADS];
37 SILC_FSM_STATE(test_st_start);
38 SILC_FSM_STATE(test_st_second);
39 SILC_FSM_STATE(test_st_second_timeout);
40 SILC_FSM_STATE(test_st_third);
41 SILC_FSM_STATE(test_st_fourth);
42 SILC_FSM_STATE(test_st_fifth);
43 SILC_FSM_STATE(test_st_sixth);
44 SILC_FSM_STATE(test_st_seventh);
45 SILC_FSM_STATE(test_st_eighth);
46 SILC_FSM_STATE(test_st_ninth);
47 SILC_FSM_STATE(test_st_tenth);
48 SILC_FSM_STATE(test_st_finish);
50 SILC_FSM_STATE(test_st_wait1);
51 SILC_FSM_STATE(test_st_wait2);
52 SILC_FSM_STATE(test_st_signal1);
53 SILC_FSM_STATE(test_st_signal1_check);
55 SILC_FSM_STATE(test_thread_st_start);
56 SILC_FSM_STATE(test_thread_st_finish);
57 SILC_FSM_STATE(test_thread2_st_start);
58 SILC_FSM_STATE(test_thread2_st_finish);
59 SILC_FSM_STATE(test_thread3_st_start);
60 SILC_FSM_STATE(test_thread4_st_start);
62 static void test_fsm_destr(SilcFSMThread thread, void *thread_context,
65 silc_fsm_free(thread);
68 SILC_TASK_CALLBACK(async_call_timeout)
71 SILC_LOG_DEBUG(("Async call cb, continuing FSM"));
75 static void async_call(Callback cb, void *context)
79 f->cb_context = context;
80 SILC_LOG_DEBUG(("Async call"));
81 silc_schedule_task_add(f->schedule, 0, async_call_timeout, f, 0, 200000,
85 SILC_FSM_STATE(test_st_start)
87 SILC_LOG_DEBUG(("test_st_start"));
89 /** Move to second state */
90 SILC_LOG_DEBUG(("Move to next state"));
91 silc_fsm_next(fsm, test_st_second);
92 return SILC_FSM_CONTINUE;
95 SILC_FSM_STATE(test_st_second)
97 SILC_LOG_DEBUG(("test_st_second"));
99 /** Move to second timeout state, timeout */
100 SILC_LOG_DEBUG(("Move to next state with 2 second timeout"));
101 silc_fsm_next_later(fsm, test_st_second_timeout, 2, 0);
102 return SILC_FSM_WAIT;
105 SILC_TASK_CALLBACK(test_second_timeout)
108 SILC_LOG_DEBUG(("test_second_timeout"));
110 SILC_LOG_DEBUG(("Interrupt 3 second wait and continue immediately"));
112 silc_fsm_next(f->fsm, test_st_third);
113 silc_fsm_continue(f->fsm);
116 SILC_FSM_STATE(test_st_second_timeout)
120 SILC_LOG_DEBUG(("test_st_second_timeout"));
122 /** Move to third state, timeout */
123 SILC_LOG_DEBUG(("Move to next state with 3 second timeout"));
124 SILC_LOG_DEBUG(("The timeout will be interrupted with silc_fsm_continue"));
125 silc_fsm_next_later(fsm, test_st_third, 3, 0);
126 silc_schedule_task_add_timeout(silc_fsm_get_schedule(fsm),
127 test_second_timeout, f, 2, 500000);
128 return SILC_FSM_WAIT;
131 static void async_call_cb(void *context)
134 SILC_LOG_DEBUG(("Callback, continue to next state"));
135 SILC_FSM_CALL_CONTINUE(f->fsm);
138 SILC_FSM_STATE(test_st_third)
142 SILC_LOG_DEBUG(("test_st_third"));
149 /** Wait async callback*/
150 SILC_LOG_DEBUG(("Call async call"));
151 silc_fsm_next(fsm, test_st_fourth);
152 SILC_FSM_CALL(async_call(async_call_cb, f));
155 SILC_FSM_STATE(test_st_fourth)
160 SILC_LOG_DEBUG(("test_st_fourth"));
164 SILC_LOG_DEBUG(("Creating FSM thread"));
165 silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, FALSE);
166 SILC_LOG_DEBUG(("Starting thread"));
168 silc_fsm_start(&f->thread, test_thread_st_start);
170 SILC_LOG_DEBUG(("Creating two waiting threads"));
171 silc_fsm_event_init(&f->wait2, fsm);
172 t = silc_fsm_thread_alloc(fsm, f, test_fsm_destr, NULL, FALSE);
173 silc_fsm_start(t, test_st_wait1);
174 t = silc_fsm_thread_alloc(fsm, f, test_fsm_destr, NULL, FALSE);
175 silc_fsm_start(t, test_st_wait2);
177 SILC_LOG_DEBUG(("Create signaller thread"));
178 t = silc_fsm_thread_alloc(fsm, f, test_fsm_destr, NULL, FALSE);
179 silc_fsm_start(t, test_st_signal1);
181 /** Waiting thread to terminate */
182 SILC_LOG_DEBUG(("Waiting for thread to terminate"));
183 silc_fsm_next(fsm, test_st_fifth);
184 SILC_FSM_THREAD_WAIT(&f->thread);
187 SILC_FSM_STATE(test_st_wait1)
191 SILC_LOG_DEBUG(("Waiter 1"));
192 SILC_FSM_EVENT_WAIT(&f->wait2);
193 SILC_LOG_DEBUG(("Waiter 1 signalled"));
195 return SILC_FSM_FINISH;
198 SILC_FSM_STATE(test_st_wait2)
202 SILC_LOG_DEBUG(("Waiter 2"));
203 SILC_FSM_EVENT_WAIT(&f->wait2);
204 SILC_LOG_DEBUG(("Waiter 2 signalled"));
206 return SILC_FSM_FINISH;
209 SILC_FSM_STATE(test_st_signal1)
213 SILC_LOG_DEBUG(("Signaller 1"));
214 SILC_FSM_EVENT_SIGNAL(&f->wait2);
215 silc_fsm_next_later(fsm, test_st_signal1_check, 0, 500000);
216 return SILC_FSM_WAIT;;
219 SILC_FSM_STATE(test_st_signal1_check)
223 SILC_LOG_DEBUG(("Signal check"));
224 assert(f->got_wait1 && f->got_wait2);
225 return SILC_FSM_FINISH;
228 SILC_FSM_STATE(test_thread_st_start)
232 SILC_LOG_DEBUG(("test_thread_st_start"));
234 /** Move to final state, timeout */
235 SILC_LOG_DEBUG(("Move to final state with %d second timeout", f->timeout));
236 silc_fsm_next_later(fsm, test_thread_st_finish, f->timeout, 0);
237 return SILC_FSM_WAIT;
240 SILC_FSM_STATE(test_thread_st_finish)
242 SILC_LOG_DEBUG(("test_thread_st_finish"));
244 SILC_LOG_DEBUG(("Finishing the thread"));
245 return SILC_FSM_FINISH;
248 SILC_FSM_STATE(test_st_fifth)
251 SILC_LOG_DEBUG(("test_st_fifth"));
253 SILC_LOG_DEBUG(("Thread terminated, start new real thread"));
257 SILC_LOG_DEBUG(("Creating FSM event"));
258 silc_fsm_event_init(&f->sema, fsm);
260 SILC_LOG_DEBUG(("Creating FSM thread"));
261 silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, TRUE);
262 SILC_LOG_DEBUG(("Starting thread"));
263 silc_fsm_start(&f->thread, test_thread2_st_start);
265 /** Waiting thread to terminate, timeout */
266 SILC_LOG_DEBUG(("Waiting for thread to terminate for 5 seconds"));
267 silc_fsm_next(fsm, test_st_sixth);
268 SILC_FSM_EVENT_TIMEDWAIT(&f->sema, 5, 0, NULL);
269 return SILC_FSM_CONTINUE;
272 SILC_FSM_STATE(test_thread2_st_start)
276 SILC_LOG_DEBUG(("test_thread2_st_start"));
278 /** Move to final state, timeout */
279 SILC_LOG_DEBUG(("Move to final state with %d second timeout", f->timeout));
280 silc_fsm_next_later(fsm, test_thread2_st_finish, f->timeout, 0);
281 return SILC_FSM_WAIT;
284 SILC_FSM_STATE(test_thread2_st_finish)
287 SILC_LOG_DEBUG(("test_thread2_st_finish"));
289 SILC_LOG_DEBUG(("Post semaphore"));
290 SILC_FSM_EVENT_SIGNAL(&f->sema);
292 SILC_LOG_DEBUG(("Finishing the thread"));
293 return SILC_FSM_FINISH;
296 SILC_FSM_STATE(test_st_sixth)
298 SILC_LOG_DEBUG(("test_st_sixth"));
300 SILC_LOG_DEBUG(("Thread wait timedout, OK"));
302 /** Move to next state, timeout */
303 SILC_LOG_DEBUG(("Continue to next state with 4 second timeout"));
304 silc_fsm_next_later(fsm, test_st_seventh, 4, 0);
305 return SILC_FSM_WAIT;
308 SILC_FSM_STATE(test_thread3_st_start)
312 if (t->rounds == 0) {
313 SILC_FSM_EVENT_SIGNAL(&t->sema);
314 return SILC_FSM_FINISH;
319 /** Call in recursive */
320 silc_fsm_next(fsm, test_thread3_st_start);
321 return SILC_FSM_CONTINUE;
324 SILC_FSM_STATE(test_st_seventh)
329 SILC_LOG_DEBUG(("test_st_seventh"));
332 SILC_LOG_DEBUG(("Creating %d FSM threads", NUM_THREADS));
333 for (i = 0; i < NUM_THREADS; i++) {
334 f->threads[i].rounds = 10;
336 silc_fsm_event_init(&f->threads[i].sema, fsm);
337 silc_fsm_thread_init(&f->threads[i].thread, fsm,
338 &f->threads[i], NULL, NULL, FALSE);
339 silc_fsm_start(&f->threads[i].thread, test_thread3_st_start);
342 /** Move to wait threads */
343 silc_fsm_next(fsm, test_st_eighth);
344 return SILC_FSM_CONTINUE;
347 SILC_FSM_STATE(test_st_eighth)
352 for (i = 0; i < NUM_THREADS; i++) {
353 if (f->threads[i].finished == FALSE) {
354 SILC_FSM_EVENT_WAIT(&f->threads[i].sema);
355 f->threads[i].finished = TRUE;
359 SILC_LOG_DEBUG(("All %d threads terminated", NUM_THREADS));
361 /** Move to next thread */
362 silc_fsm_next(fsm, test_st_ninth);
363 return SILC_FSM_CONTINUE;
366 SILC_FSM_STATE(test_thread4_st_start)
370 if (t->rounds == 0) {
371 SILC_FSM_EVENT_SIGNAL(&t->sema);
372 return SILC_FSM_FINISH;
377 /** Call in recursive */
378 silc_fsm_next(fsm, test_thread4_st_start);
379 return SILC_FSM_CONTINUE;
382 SILC_FSM_STATE(test_st_ninth)
387 SILC_LOG_DEBUG(("test_st_ninth"));
389 SILC_LOG_DEBUG(("Creating FSM event"));
390 silc_fsm_event_init(&f->sema, fsm);
392 SILC_LOG_DEBUG(("Creating %d real FSM threads", NUM_THREADS));
393 for (i = 0; i < NUM_THREADS; i++) {
394 f->threads2[i].rounds = 10;
395 f->threads2[i].f = f;
396 silc_fsm_event_init(&f->threads2[i].sema, fsm);
397 silc_fsm_thread_init(&f->threads2[i].thread, fsm,
398 &f->threads2[i], NULL, NULL, TRUE);
399 silc_fsm_start(&f->threads2[i].thread, test_thread4_st_start);
402 /** Move to wait threads */
403 silc_fsm_next(fsm, test_st_tenth);
404 return SILC_FSM_CONTINUE;
407 SILC_FSM_STATE(test_st_tenth)
412 for (i = 0; i < NUM_THREADS; i++)
413 if (f->threads2[i].finished == FALSE) {
414 SILC_FSM_EVENT_WAIT(&f->threads2[i].sema);
415 f->threads2[i].finished = TRUE;
418 SILC_LOG_DEBUG(("All %d real threads terminated", NUM_THREADS));
420 /** Finished successfully */
421 silc_fsm_next_later(fsm, test_st_finish, 2, 0);
422 return SILC_FSM_WAIT;
425 SILC_FSM_STATE(test_st_finish)
427 SILC_LOG_DEBUG(("test_st_finish"));
429 SILC_LOG_DEBUG(("Finish machine"));
430 return SILC_FSM_FINISH;
433 static void destructor(SilcFSM fsm, void *fsm_context,
434 void *destructor_context)
436 Foo f = destructor_context;
437 SILC_LOG_DEBUG(("FSM destructor, stopping scheduler"));
439 silc_schedule_stop(f->schedule);
442 int main(int argc, char **argv)
444 SilcBool success = FALSE;
445 SilcSchedule schedule;
449 if (argc > 1 && !strcmp(argv[1], "-d")) {
450 silc_log_debug(TRUE);
451 silc_log_debug_hexdump(TRUE);
452 silc_log_quick(TRUE);
453 silc_log_set_debug_string("*fsm*,*async*");
456 SILC_LOG_DEBUG(("Allocating scheduler"));
457 schedule = silc_schedule_init(0, NULL);
459 f = silc_calloc(1, sizeof(*f));
462 f->schedule = schedule;
464 SILC_LOG_DEBUG(("Allocating FSM context"));
465 f->fsm = fsm = silc_fsm_alloc(f, destructor, f, schedule);
468 silc_fsm_start(fsm, test_st_start);
470 SILC_LOG_DEBUG(("Running scheduler"));
471 silc_schedule(schedule);
476 silc_schedule_uninit(schedule);
482 SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
483 fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");