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 SILC_LOG_DEBUG(("All %d threads terminated", NUM_THREADS));
263 /** Move to next thread */
264 silc_fsm_next(fsm, test_st_ninth);
265 return SILC_FSM_CONTINUE;
268 SILC_FSM_STATE(test_thread4_st_start)
272 if (t->rounds == 0) {
273 SILC_FSM_SEMA_POST(&t->sema);
274 return SILC_FSM_FINISH;
279 /** Call in recursive */
280 silc_fsm_next(fsm, test_thread4_st_start);
281 return SILC_FSM_CONTINUE;
284 SILC_FSM_STATE(test_st_ninth)
289 SILC_LOG_DEBUG(("test_st_ninth"));
291 SILC_LOG_DEBUG(("Creating FSM semaphore"));
292 silc_fsm_sema_init(&f->sema, fsm, NUM_THREADS + 1);
294 SILC_LOG_DEBUG(("Creating %d real FSM threads", NUM_THREADS));
295 for (i = 0; i < NUM_THREADS; i++) {
296 f->threads2[i].rounds = 10;
297 f->threads2[i].f = f;
298 silc_fsm_sema_init(&f->threads2[i].sema, fsm, 0);
299 silc_fsm_thread_init(&f->threads2[i].thread, fsm,
300 &f->threads2[i], NULL, NULL, TRUE);
301 silc_fsm_start(&f->threads2[i].thread, test_thread4_st_start);
304 /** Move to wait threads */
305 silc_fsm_next(fsm, test_st_tenth);
306 return SILC_FSM_CONTINUE;
309 SILC_FSM_STATE(test_st_tenth)
314 for (i = 0; i < NUM_THREADS; i++)
315 if (f->threads2[i].finished == FALSE) {
316 SILC_FSM_SEMA_WAIT(&f->threads2[i].sema);
317 f->threads2[i].finished = TRUE;
320 SILC_LOG_DEBUG(("All %d real threads terminated", NUM_THREADS));
322 /** Finished successfully */
323 silc_fsm_next_later(fsm, test_st_finish, 2, 0);
324 return SILC_FSM_WAIT;
327 SILC_FSM_STATE(test_st_finish)
329 SILC_LOG_DEBUG(("test_st_finish"));
331 SILC_LOG_DEBUG(("Finish machine"));
332 return SILC_FSM_FINISH;
335 static void destructor(SilcFSM fsm, void *fsm_context,
336 void *destructor_context)
338 Foo f = destructor_context;
339 SILC_LOG_DEBUG(("FSM destructor, stopping scheduler"));
341 silc_schedule_stop(f->schedule);
344 int main(int argc, char **argv)
346 SilcBool success = FALSE;
347 SilcSchedule schedule;
351 if (argc > 1 && !strcmp(argv[1], "-d")) {
352 silc_log_debug(TRUE);
353 silc_log_debug_hexdump(TRUE);
354 silc_log_quick(TRUE);
355 silc_log_set_debug_string("*fsm*,*async*");
358 SILC_LOG_DEBUG(("Allocating scheduler"));
359 schedule = silc_schedule_init(0, NULL);
361 f = silc_calloc(1, sizeof(*f));
364 f->schedule = schedule;
366 SILC_LOG_DEBUG(("Allocating FSM context"));
367 fsm = silc_fsm_alloc(f, destructor, f, schedule);
370 silc_fsm_start(fsm, test_st_start);
372 SILC_LOG_DEBUG(("Running scheduler"));
373 silc_schedule(schedule);
378 silc_schedule_uninit(schedule);
384 SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
385 fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");