Removed silc_fsm_uninit -> not needed.
[silc.git] / lib / silcutil / tests / test_silcfsm.c
1 /* SILC FSM tests */
2
3 #include "silc.h"
4 #include "silcfsm.h"
5
6 typedef void (*Callback)(void *context);
7
8 #define NUM_THREADS 200
9
10 typedef struct FooStruct *Foo;
11
12 typedef struct {
13   SilcFSMThreadStruct thread;
14   SilcFSMSemaStruct sema;
15   SilcBool finished;
16   int rounds;
17   Foo f;
18 } T;
19
20 struct FooStruct {
21   SilcBool error;
22   SilcFSM fsm;
23   SilcFSMThreadStruct thread;
24   int timeout;
25   SilcFSMSemaStruct sema;
26   SilcSchedule schedule;
27   Callback cb;
28   void *cb_context;
29   T threads[NUM_THREADS];
30   T threads2[NUM_THREADS];
31 };
32
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);
44
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);
51
52 SILC_TASK_CALLBACK(async_call_timeout)
53 {
54   Foo f = context;
55   SILC_LOG_DEBUG(("Async call cb, continuing FSM"));
56   f->cb(f->cb_context);
57 }
58
59 static void async_call(Callback cb, void *context)
60 {
61   Foo f = context;
62   f->cb = cb;
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,
66                          SILC_TASK_TIMEOUT);
67 }
68
69 SILC_FSM_STATE(test_st_start)
70 {
71   SILC_LOG_DEBUG(("test_st_start"));
72
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;
77 }
78
79 SILC_FSM_STATE(test_st_second)
80 {
81   SILC_LOG_DEBUG(("test_st_second"));
82
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);
86   return SILC_FSM_WAIT;
87 }
88
89 static void async_call_cb(void *context)
90 {
91   Foo f = context;
92   SILC_LOG_DEBUG(("Callback, continue to next state"));
93   SILC_FSM_CALL_CONTINUE(f->fsm);
94 }
95
96 SILC_FSM_STATE(test_st_third)
97 {
98   Foo f = fsm_context;
99
100   SILC_LOG_DEBUG(("test_st_third"));
101
102   f->fsm = fsm;
103
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));
108 }
109
110 SILC_FSM_STATE(test_st_fourth)
111 {
112   Foo f = fsm_context;
113
114   SILC_LOG_DEBUG(("test_st_fourth"));
115
116   f->timeout = 1;
117
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"));
121   /*** Start thread */
122   silc_fsm_start(&f->thread, test_thread_st_start);
123
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);
128 }
129
130 SILC_FSM_STATE(test_thread_st_start)
131 {
132   Foo f = fsm_context;
133
134   SILC_LOG_DEBUG(("test_thread_st_start"));
135
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;
140 }
141
142 SILC_FSM_STATE(test_thread_st_finish)
143 {
144   SILC_LOG_DEBUG(("test_thread_st_finish"));
145
146   SILC_LOG_DEBUG(("Finishing the thread"));
147   return SILC_FSM_FINISH;
148 }
149
150 SILC_FSM_STATE(test_st_fifth)
151 {
152   Foo f = fsm_context;
153   SILC_LOG_DEBUG(("test_st_fifth"));
154
155   SILC_LOG_DEBUG(("Thread terminated, start new real thread"));
156
157   f->timeout = 7;
158
159   SILC_LOG_DEBUG(("Creating FSM semaphore"));
160   silc_fsm_sema_init(&f->sema, fsm, 0);
161
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);
166
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;
172 }
173
174 SILC_FSM_STATE(test_thread2_st_start)
175 {
176   Foo f = fsm_context;
177
178   SILC_LOG_DEBUG(("test_thread2_st_start"));
179
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;
184 }
185
186 SILC_FSM_STATE(test_thread2_st_finish)
187 {
188   Foo f = fsm_context;
189   SILC_LOG_DEBUG(("test_thread2_st_finish"));
190
191   SILC_LOG_DEBUG(("Post semaphore"));
192   SILC_FSM_SEMA_POST(&f->sema);
193
194   SILC_LOG_DEBUG(("Finishing the thread"));
195   return SILC_FSM_FINISH;
196 }
197
198 SILC_FSM_STATE(test_st_sixth)
199 {
200   SILC_LOG_DEBUG(("test_st_sixth"));
201
202   SILC_LOG_DEBUG(("Thread wait timedout, OK"));
203
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;
208 }
209
210 SILC_FSM_STATE(test_thread3_st_start)
211 {
212   T *t = fsm_context;
213
214   if (t->rounds == 0) {
215     SILC_FSM_SEMA_POST(&t->sema);
216     return SILC_FSM_FINISH;
217   }
218
219   t->rounds--;
220
221   /** Call in recursive */
222   silc_fsm_next(fsm, test_thread3_st_start);
223   return SILC_FSM_CONTINUE;
224 }
225
226 SILC_FSM_STATE(test_st_seventh)
227 {
228   Foo f = fsm_context;
229   int i;
230
231   SILC_LOG_DEBUG(("test_st_seventh"));
232
233
234   SILC_LOG_DEBUG(("Creating %d FSM threads", NUM_THREADS));
235   for (i = 0; i < NUM_THREADS; i++) {
236     f->threads[i].rounds = 10;
237     f->threads[i].f = f;
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);
242   }
243
244   /** Move to wait threads */
245   silc_fsm_next(fsm, test_st_eighth);
246   return SILC_FSM_CONTINUE;
247 }
248
249 SILC_FSM_STATE(test_st_eighth)
250 {
251   Foo f = fsm_context;
252   int i;
253
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;
258     }
259   }
260
261   SILC_LOG_DEBUG(("All %d threads terminated", NUM_THREADS));
262
263   /** Move to next thread */
264   silc_fsm_next(fsm, test_st_ninth);
265   return SILC_FSM_CONTINUE;
266 }
267
268 SILC_FSM_STATE(test_thread4_st_start)
269 {
270   T *t = fsm_context;
271
272   if (t->rounds == 0) {
273     SILC_FSM_SEMA_POST(&t->sema);
274     return SILC_FSM_FINISH;
275   }
276
277   t->rounds--;
278
279   /** Call in recursive */
280   silc_fsm_next(fsm, test_thread4_st_start);
281   return SILC_FSM_CONTINUE;
282 }
283
284 SILC_FSM_STATE(test_st_ninth)
285 {
286   Foo f = fsm_context;
287   int i;
288
289   SILC_LOG_DEBUG(("test_st_ninth"));
290
291   SILC_LOG_DEBUG(("Creating FSM semaphore"));
292   silc_fsm_sema_init(&f->sema, fsm, NUM_THREADS + 1);
293
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);
302   }
303
304   /** Move to wait threads */
305   silc_fsm_next(fsm, test_st_tenth);
306   return SILC_FSM_CONTINUE;
307 }
308
309 SILC_FSM_STATE(test_st_tenth)
310 {
311   Foo f = fsm_context;
312   int i;
313
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;
318     }
319
320   SILC_LOG_DEBUG(("All %d real threads terminated", NUM_THREADS));
321
322   /** Finished successfully */
323   silc_fsm_next_later(fsm, test_st_finish, 2, 0);
324   return SILC_FSM_WAIT;
325 }
326
327 SILC_FSM_STATE(test_st_finish)
328 {
329   SILC_LOG_DEBUG(("test_st_finish"));
330
331   SILC_LOG_DEBUG(("Finish machine"));
332   return SILC_FSM_FINISH;
333 }
334
335 static void destructor(SilcFSM fsm, void *fsm_context,
336                        void *destructor_context)
337 {
338   Foo f = destructor_context;
339   SILC_LOG_DEBUG(("FSM destructor, stopping scheduler"));
340   silc_fsm_free(fsm);
341   silc_schedule_stop(f->schedule);
342 }
343
344 int main(int argc, char **argv)
345 {
346   SilcBool success = FALSE;
347   SilcSchedule schedule;
348   SilcFSM fsm;
349   Foo f;
350
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*");
356   }
357
358   SILC_LOG_DEBUG(("Allocating scheduler"));
359   schedule = silc_schedule_init(0, NULL);
360
361   f = silc_calloc(1, sizeof(*f));
362   if (!f)
363     goto err;
364   f->schedule = schedule;
365
366   SILC_LOG_DEBUG(("Allocating FSM context"));
367   fsm = silc_fsm_alloc(f, destructor, f, schedule);
368   if (!fsm)
369     goto err;
370   silc_fsm_start(fsm, test_st_start);
371
372   SILC_LOG_DEBUG(("Running scheduler"));
373   silc_schedule(schedule);
374
375   if (f->error)
376     goto err;
377
378   silc_schedule_uninit(schedule);
379   silc_free(f);
380
381   success = TRUE;
382
383  err:
384   SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
385   fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
386
387   return success;
388 }