132
|
1 import tango.core.Thread;
|
|
2
|
|
3 extern (C) int printf(char * str, ...);
|
|
4
|
|
5 void main()
|
|
6 {
|
|
7 printf("Compile with -unittest");
|
|
8 }
|
|
9
|
|
10
|
|
11 unittest
|
|
12 {
|
|
13 printf("Testing context creation/deletion\n");
|
|
14 int s0 = 0;
|
|
15 static int s1 = 0;
|
|
16
|
|
17 Fiber a = new Fiber(
|
|
18 delegate void()
|
|
19 {
|
|
20 s0++;
|
|
21 });
|
|
22
|
|
23 static void fb() { s1++; }
|
|
24
|
|
25 Fiber b = new Fiber(&fb);
|
|
26
|
|
27 Fiber c = new Fiber(
|
|
28 delegate void() { assert(false); });
|
|
29
|
|
30 assert(a);
|
|
31 assert(b);
|
|
32 assert(c);
|
|
33
|
|
34 assert(s0 == 0);
|
|
35 assert(s1 == 0);
|
|
36 assert(a.state == Fiber.State.HOLD);
|
|
37 assert(b.state == Fiber.State.HOLD);
|
|
38 assert(c.state == Fiber.State.HOLD);
|
|
39
|
|
40 delete c;
|
|
41
|
|
42 assert(s0 == 0);
|
|
43 assert(s1 == 0);
|
|
44 assert(a.state == Fiber.State.HOLD);
|
|
45 assert(b.state == Fiber.State.HOLD);
|
|
46
|
|
47 printf("running a\n");
|
|
48 a.call();
|
|
49 printf("done a\n");
|
|
50
|
|
51 assert(a);
|
|
52
|
|
53 assert(s0 == 1);
|
|
54 assert(s1 == 0);
|
|
55 assert(a.state == Fiber.State.TERM);
|
|
56 assert(b.state == Fiber.State.HOLD);
|
|
57
|
|
58 assert(b.state == Fiber.State.HOLD);
|
|
59
|
|
60 printf("Running b\n");
|
|
61 b.call();
|
|
62 printf("Done b\n");
|
|
63
|
|
64 assert(s0 == 1);
|
|
65 assert(s1 == 1);
|
|
66 assert(b.state == Fiber.State.TERM);
|
|
67
|
|
68 delete a;
|
|
69 delete b;
|
|
70
|
|
71 printf("Context creation passed\n");
|
|
72 }
|
|
73
|
|
74 unittest
|
|
75 {
|
|
76 printf("Testing context switching\n");
|
|
77 int s0 = 0;
|
|
78 int s1 = 0;
|
|
79 int s2 = 0;
|
|
80
|
|
81 Fiber a = new Fiber(
|
|
82 delegate void()
|
|
83 {
|
|
84 while(true)
|
|
85 {
|
|
86 debug printf(" ---A---\n");
|
|
87 s0++;
|
|
88 Fiber.yield();
|
|
89 }
|
|
90 });
|
|
91
|
|
92
|
|
93 Fiber b = new Fiber(
|
|
94 delegate void()
|
|
95 {
|
|
96 while(true)
|
|
97 {
|
|
98 debug printf(" ---B---\n");
|
|
99 s1++;
|
|
100 Fiber.yield();
|
|
101 }
|
|
102 });
|
|
103
|
|
104
|
|
105 Fiber c = new Fiber(
|
|
106 delegate void()
|
|
107 {
|
|
108 while(true)
|
|
109 {
|
|
110 debug printf(" ---C---\n");
|
|
111 s2++;
|
|
112 Fiber.yield();
|
|
113 }
|
|
114 });
|
|
115
|
|
116 assert(a);
|
|
117 assert(b);
|
|
118 assert(c);
|
|
119 assert(s0 == 0);
|
|
120 assert(s1 == 0);
|
|
121 assert(s2 == 0);
|
|
122
|
|
123 a.call();
|
|
124 b.call();
|
|
125
|
|
126 assert(a);
|
|
127 assert(b);
|
|
128 assert(c);
|
|
129 assert(s0 == 1);
|
|
130 assert(s1 == 1);
|
|
131 assert(s2 == 0);
|
|
132
|
|
133 for(int i=0; i<20; i++)
|
|
134 {
|
|
135 c.call();
|
|
136 a.call();
|
|
137 }
|
|
138
|
|
139 assert(a);
|
|
140 assert(b);
|
|
141 assert(c);
|
|
142 assert(s0 == 21);
|
|
143 assert(s1 == 1);
|
|
144 assert(s2 == 20);
|
|
145
|
|
146 delete a;
|
|
147 delete b;
|
|
148 delete c;
|
|
149
|
|
150 printf("Context switching passed\n");
|
|
151 }
|
|
152
|
|
153 unittest
|
|
154 {
|
|
155 printf("Testing nested contexts\n");
|
|
156 Fiber a, b, c;
|
|
157
|
|
158 int t0 = 0;
|
|
159 int t1 = 0;
|
|
160 int t2 = 0;
|
|
161
|
|
162 a = new Fiber(
|
|
163 delegate void()
|
|
164 {
|
|
165
|
|
166 t0++;
|
|
167 b.call();
|
|
168
|
|
169 });
|
|
170
|
|
171 b = new Fiber(
|
|
172 delegate void()
|
|
173 {
|
|
174 assert(t0 == 1);
|
|
175 assert(t1 == 0);
|
|
176 assert(t2 == 0);
|
|
177
|
|
178 t1++;
|
|
179 c.call();
|
|
180
|
|
181 });
|
|
182
|
|
183 c = new Fiber(
|
|
184 delegate void()
|
|
185 {
|
|
186 assert(t0 == 1);
|
|
187 assert(t1 == 1);
|
|
188 assert(t2 == 0);
|
|
189
|
|
190 t2++;
|
|
191 });
|
|
192
|
|
193 assert(a);
|
|
194 assert(b);
|
|
195 assert(c);
|
|
196 assert(t0 == 0);
|
|
197 assert(t1 == 0);
|
|
198 assert(t2 == 0);
|
|
199
|
|
200 a.call();
|
|
201
|
|
202 assert(t0 == 1);
|
|
203 assert(t1 == 1);
|
|
204 assert(t2 == 1);
|
|
205
|
|
206 assert(a);
|
|
207 assert(b);
|
|
208 assert(c);
|
|
209
|
|
210 delete a;
|
|
211 delete b;
|
|
212 delete c;
|
|
213
|
|
214 printf("Nesting contexts passed\n");
|
|
215 }
|
|
216
|
|
217 unittest
|
|
218 {
|
|
219 printf("Testing basic exceptions\n");
|
|
220
|
|
221
|
|
222 int t0 = 0;
|
|
223 int t1 = 0;
|
|
224 int t2 = 0;
|
|
225
|
|
226 assert(t0 == 0);
|
|
227 assert(t1 == 0);
|
|
228 assert(t2 == 0);
|
|
229
|
|
230 try
|
|
231 {
|
|
232
|
|
233 try
|
|
234 {
|
|
235 throw new Exception("Testing\n");
|
|
236 t2++;
|
|
237 }
|
|
238 catch(Exception fx)
|
|
239 {
|
|
240 t1++;
|
|
241 throw fx;
|
|
242 }
|
|
243
|
|
244 t2++;
|
|
245 }
|
|
246 catch(Exception ex)
|
|
247 {
|
|
248 t0++;
|
|
249 printf("%.*s\n", ex.toString);
|
|
250 }
|
|
251
|
|
252 assert(t0 == 1);
|
|
253 assert(t1 == 1);
|
|
254 assert(t2 == 0);
|
|
255
|
|
256 printf("Basic exceptions are supported\n");
|
|
257 }
|
|
258
|
|
259
|
|
260 unittest
|
|
261 {
|
|
262 printf("Testing exceptions\n");
|
|
263 Fiber a, b, c;
|
|
264
|
|
265 int t0 = 0;
|
|
266 int t1 = 0;
|
|
267 int t2 = 0;
|
|
268
|
|
269 printf("t0 = %d\nt1 = %d\nt2 = %d\n", t0, t1, t2);
|
|
270
|
|
271 a = new Fiber(
|
|
272 delegate void()
|
|
273 {
|
|
274 t0++;
|
|
275 throw new Exception("A exception\n");
|
|
276 t0++;
|
|
277 });
|
|
278
|
|
279 b = new Fiber(
|
|
280 delegate void()
|
|
281 {
|
|
282 t1++;
|
|
283 c.call();
|
|
284 t1++;
|
|
285 });
|
|
286
|
|
287 c = new Fiber(
|
|
288 delegate void()
|
|
289 {
|
|
290 t2++;
|
|
291 throw new Exception("C exception\n");
|
|
292 t2++;
|
|
293 });
|
|
294
|
|
295 assert(a);
|
|
296 assert(b);
|
|
297 assert(c);
|
|
298 assert(t0 == 0);
|
|
299 assert(t1 == 0);
|
|
300 assert(t2 == 0);
|
|
301
|
|
302 try
|
|
303 {
|
|
304 a.call();
|
|
305 assert(false);
|
|
306 }
|
|
307 catch(Exception e)
|
|
308 {
|
|
309 printf("%.*s\n", e.toString);
|
|
310 }
|
|
311
|
|
312 assert(a);
|
|
313 assert(a.state == Fiber.State.TERM);
|
|
314 assert(b);
|
|
315 assert(c);
|
|
316 assert(t0 == 1);
|
|
317 assert(t1 == 0);
|
|
318 assert(t2 == 0);
|
|
319
|
|
320 try
|
|
321 {
|
|
322 b.call();
|
|
323 assert(false);
|
|
324 }
|
|
325 catch(Exception e)
|
|
326 {
|
|
327 printf("%.*s\n", e.toString);
|
|
328 }
|
|
329
|
|
330 printf("blah2\n");
|
|
331
|
|
332 assert(a);
|
|
333 assert(b);
|
|
334 assert(b.state == Fiber.State.TERM);
|
|
335 assert(c);
|
|
336 assert(c.state == Fiber.State.TERM);
|
|
337 assert(t0 == 1);
|
|
338 assert(t1 == 1);
|
|
339 assert(t2 == 1);
|
|
340
|
|
341 delete a;
|
|
342 delete b;
|
|
343 delete c;
|
|
344
|
|
345
|
|
346 Fiber t;
|
|
347 int q0 = 0;
|
|
348 int q1 = 0;
|
|
349
|
|
350 t = new Fiber(
|
|
351 delegate void()
|
|
352 {
|
|
353 try
|
|
354 {
|
|
355 q0++;
|
|
356 throw new Exception("T exception\n");
|
|
357 q0++;
|
|
358 }
|
|
359 catch(Exception ex)
|
|
360 {
|
|
361 q1++;
|
|
362 printf("!!!!!!!!GOT EXCEPTION!!!!!!!!\n");
|
|
363 printf("%.*s\n", ex.toString);
|
|
364 }
|
|
365 });
|
|
366
|
|
367
|
|
368 assert(t);
|
|
369 assert(q0 == 0);
|
|
370 assert(q1 == 0);
|
|
371 t.call();
|
|
372 assert(t);
|
|
373 assert(t.state == Fiber.State.TERM);
|
|
374 assert(q0 == 1);
|
|
375 assert(q1 == 1);
|
|
376
|
|
377 delete t;
|
|
378
|
|
379 Fiber d, e;
|
|
380 int s0 = 0;
|
|
381 int s1 = 0;
|
|
382
|
|
383 d = new Fiber(
|
|
384 delegate void()
|
|
385 {
|
|
386 try
|
|
387 {
|
|
388 s0++;
|
|
389 e.call();
|
|
390 Fiber.yield();
|
|
391 s0++;
|
|
392 e.call();
|
|
393 s0++;
|
|
394 }
|
|
395 catch(Exception ex)
|
|
396 {
|
|
397 printf("%.*s\n", ex.toString);
|
|
398 }
|
|
399 });
|
|
400
|
|
401 e = new Fiber(
|
|
402 delegate void()
|
|
403 {
|
|
404 s1++;
|
|
405 Fiber.yield();
|
|
406 throw new Exception("E exception\n");
|
|
407 s1++;
|
|
408 });
|
|
409
|
|
410 assert(d);
|
|
411 assert(e);
|
|
412 assert(s0 == 0);
|
|
413 assert(s1 == 0);
|
|
414
|
|
415 d.call();
|
|
416
|
|
417 assert(d);
|
|
418 assert(e);
|
|
419 assert(s0 == 1);
|
|
420 assert(s1 == 1);
|
|
421
|
|
422 d.call();
|
|
423
|
|
424 assert(d);
|
|
425 assert(e);
|
|
426 assert(s0 == 2);
|
|
427 assert(s1 == 1);
|
|
428
|
|
429 assert(d.state == Fiber.State.TERM);
|
|
430 assert(e.state == Fiber.State.TERM);
|
|
431
|
|
432 delete d;
|
|
433 delete e;
|
|
434
|
|
435 printf("Exceptions passed\n");
|
|
436 }
|
|
437
|
|
438 unittest
|
|
439 {
|
|
440 printf("Testing standard exceptions\n");
|
|
441 int t = 0;
|
|
442
|
|
443 Fiber a = new Fiber(
|
|
444 delegate void()
|
|
445 {
|
|
446 throw new Exception("BLAHAHA");
|
|
447 });
|
|
448
|
|
449 assert(a);
|
|
450 assert(t == 0);
|
|
451
|
|
452 try
|
|
453 {
|
|
454 a.call();
|
|
455 assert(false);
|
|
456 }
|
|
457 catch(Exception e)
|
|
458 {
|
|
459 printf("%.*s\n", e.toString);
|
|
460 }
|
|
461
|
|
462 assert(a);
|
|
463 assert(a.state == Fiber.State.TERM);
|
|
464 assert(t == 0);
|
|
465
|
|
466 delete a;
|
|
467
|
|
468
|
|
469 printf("Standard exceptions passed\n");
|
|
470 }
|
|
471
|
|
472 unittest
|
|
473 {
|
|
474 printf("Memory stress test\n");
|
|
475
|
|
476 const uint STRESS_SIZE = 5000;
|
|
477
|
|
478 Fiber ctx[];
|
|
479 ctx.length = STRESS_SIZE;
|
|
480
|
|
481 int cnt0 = 0;
|
|
482 int cnt1 = 0;
|
|
483
|
|
484 void threadFunc()
|
|
485 {
|
|
486 cnt0++;
|
|
487 Fiber.yield;
|
|
488 cnt1++;
|
|
489 }
|
|
490
|
|
491 foreach(inout Fiber c; ctx)
|
|
492 {
|
|
493 c = new Fiber(&threadFunc, 1024);
|
|
494 }
|
|
495
|
|
496 assert(cnt0 == 0);
|
|
497 assert(cnt1 == 0);
|
|
498
|
|
499 foreach(inout Fiber c; ctx)
|
|
500 {
|
|
501 c.call;
|
|
502 }
|
|
503
|
|
504 assert(cnt0 == STRESS_SIZE);
|
|
505 assert(cnt1 == 0);
|
|
506
|
|
507 foreach(inout Fiber c; ctx)
|
|
508 {
|
|
509 c.call;
|
|
510 }
|
|
511
|
|
512 assert(cnt0 == STRESS_SIZE);
|
|
513 assert(cnt1 == STRESS_SIZE);
|
|
514
|
|
515 foreach(inout Fiber c; ctx)
|
|
516 {
|
|
517 delete c;
|
|
518 }
|
|
519
|
|
520 assert(cnt0 == STRESS_SIZE);
|
|
521 assert(cnt1 == STRESS_SIZE);
|
|
522
|
|
523 printf("Memory stress test passed\n");
|
|
524 }
|
|
525
|
|
526 unittest
|
|
527 {
|
|
528 printf("Testing floating point\n");
|
|
529
|
|
530 float f0 = 1.0;
|
|
531 float f1 = 0.0;
|
|
532
|
|
533 double d0 = 2.0;
|
|
534 double d1 = 0.0;
|
|
535
|
|
536 real r0 = 3.0;
|
|
537 real r1 = 0.0;
|
|
538
|
|
539 assert(f0 == 1.0);
|
|
540 assert(f1 == 0.0);
|
|
541 assert(d0 == 2.0);
|
|
542 assert(d1 == 0.0);
|
|
543 assert(r0 == 3.0);
|
|
544 assert(r1 == 0.0);
|
|
545
|
|
546 Fiber a, b, c;
|
|
547
|
|
548 a = new Fiber(
|
|
549 delegate void()
|
|
550 {
|
|
551 while(true)
|
|
552 {
|
|
553 f0 ++;
|
|
554 d0 ++;
|
|
555 r0 ++;
|
|
556
|
|
557 Fiber.yield();
|
|
558 }
|
|
559 });
|
|
560
|
|
561 b = new Fiber(
|
|
562 delegate void()
|
|
563 {
|
|
564 while(true)
|
|
565 {
|
|
566 f1 = d0 + r0;
|
|
567 d1 = f0 + r0;
|
|
568 r1 = f0 + d0;
|
|
569
|
|
570 Fiber.yield();
|
|
571 }
|
|
572 });
|
|
573
|
|
574 c = new Fiber(
|
|
575 delegate void()
|
|
576 {
|
|
577 while(true)
|
|
578 {
|
|
579 f0 *= d1;
|
|
580 d0 *= r1;
|
|
581 r0 *= f1;
|
|
582
|
|
583 Fiber.yield();
|
|
584 }
|
|
585 });
|
|
586
|
|
587 a.call();
|
|
588 assert(f0 == 2.0);
|
|
589 assert(f1 == 0.0);
|
|
590 assert(d0 == 3.0);
|
|
591 assert(d1 == 0.0);
|
|
592 assert(r0 == 4.0);
|
|
593 assert(r1 == 0.0);
|
|
594
|
|
595 b.call();
|
|
596 assert(f0 == 2.0);
|
|
597 assert(f1 == 7.0);
|
|
598 assert(d0 == 3.0);
|
|
599 assert(d1 == 6.0);
|
|
600 assert(r0 == 4.0);
|
|
601 assert(r1 == 5.0);
|
|
602
|
|
603 c.call();
|
|
604 assert(f0 == 12.0);
|
|
605 assert(f1 == 7.0);
|
|
606 assert(d0 == 15.0);
|
|
607 assert(d1 == 6.0);
|
|
608 assert(r0 == 28.0);
|
|
609 assert(r1 == 5.0);
|
|
610
|
|
611 a.call();
|
|
612 assert(f0 == 13.0);
|
|
613 assert(f1 == 7.0);
|
|
614 assert(d0 == 16.0);
|
|
615 assert(d1 == 6.0);
|
|
616 assert(r0 == 29.0);
|
|
617 assert(r1 == 5.0);
|
|
618
|
|
619 printf("Floating point passed\n");
|
|
620 }
|
|
621
|
|
622
|
|
623 version(x86) unittest
|
|
624 {
|
|
625 printf("Testing registers\n");
|
|
626
|
|
627 struct registers
|
|
628 {
|
|
629 int eax, ebx, ecx, edx;
|
|
630 int esi, edi;
|
|
631 int ebp, esp;
|
|
632
|
|
633 //TODO: Add fpu stuff
|
|
634 }
|
|
635
|
|
636 static registers old;
|
|
637 static registers next;
|
|
638 static registers g_old;
|
|
639 static registers g_next;
|
|
640
|
|
641 //I believe that D calling convention requires that
|
|
642 //EBX, ESI and EDI be saved. In order to validate
|
|
643 //this, we write to those registers and call the
|
|
644 //stack thread.
|
|
645 static StackThread reg_test = new StackThread(
|
|
646 delegate void()
|
|
647 {
|
|
648 asm
|
|
649 {
|
|
650 naked;
|
|
651
|
|
652 pushad;
|
|
653
|
|
654 mov EBX, 1;
|
|
655 mov ESI, 2;
|
|
656 mov EDI, 3;
|
|
657
|
|
658 mov [old.ebx], EBX;
|
|
659 mov [old.esi], ESI;
|
|
660 mov [old.edi], EDI;
|
|
661 mov [old.ebp], EBP;
|
|
662 mov [old.esp], ESP;
|
|
663
|
|
664 call StackThread.yield;
|
|
665
|
|
666 mov [next.ebx], EBX;
|
|
667 mov [next.esi], ESI;
|
|
668 mov [next.edi], EDI;
|
|
669 mov [next.ebp], EBP;
|
|
670 mov [next.esp], ESP;
|
|
671
|
|
672 popad;
|
|
673 }
|
|
674 });
|
|
675
|
|
676 //Run the stack context
|
|
677 asm
|
|
678 {
|
|
679 naked;
|
|
680
|
|
681 pushad;
|
|
682
|
|
683 mov EBX, 10;
|
|
684 mov ESI, 11;
|
|
685 mov EDI, 12;
|
|
686
|
|
687 mov [g_old.ebx], EBX;
|
|
688 mov [g_old.esi], ESI;
|
|
689 mov [g_old.edi], EDI;
|
|
690 mov [g_old.ebp], EBP;
|
|
691 mov [g_old.esp], ESP;
|
|
692
|
|
693 mov EAX, [reg_test];
|
|
694 call StackThread.call;
|
|
695
|
|
696 mov [g_next.ebx], EBX;
|
|
697 mov [g_next.esi], ESI;
|
|
698 mov [g_next.edi], EDI;
|
|
699 mov [g_next.ebp], EBP;
|
|
700 mov [g_next.esp], ESP;
|
|
701
|
|
702 popad;
|
|
703 }
|
|
704
|
|
705
|
|
706 //Make sure the registers are byte for byte equal.
|
|
707 assert(old.ebx = 1);
|
|
708 assert(old.esi = 2);
|
|
709 assert(old.edi = 3);
|
|
710 assert(old == next);
|
|
711
|
|
712 assert(g_old.ebx = 10);
|
|
713 assert(g_old.esi = 11);
|
|
714 assert(g_old.edi = 12);
|
|
715 assert(g_old == g_next);
|
|
716
|
|
717 printf("Registers passed!\n");
|
|
718 }
|
|
719
|
|
720
|
|
721 unittest
|
|
722 {
|
|
723 printf("Testing throwYield\n");
|
|
724
|
|
725 int q0 = 0;
|
|
726
|
|
727 Fiber st0 = new Fiber(
|
|
728 delegate void()
|
|
729 {
|
|
730 q0++;
|
|
731 Fiber.yieldAndThrow(new Exception("testing throw yield\n"));
|
|
732 q0++;
|
|
733 });
|
|
734
|
|
735 try
|
|
736 {
|
|
737 st0.call();
|
|
738 assert(false);
|
|
739 }
|
|
740 catch(Exception e)
|
|
741 {
|
|
742 printf("%.*s\n", e.toString);
|
|
743 }
|
|
744
|
|
745 assert(q0 == 1);
|
|
746 assert(st0.state == Fiber.State.HOLD);
|
|
747
|
|
748 st0.call();
|
|
749 assert(q0 == 2);
|
|
750 assert(st0.state == Fiber.State.TERM);
|
|
751
|
|
752 printf("throwYield passed!\n");
|
|
753 }
|
|
754
|
|
755 unittest
|
|
756 {
|
|
757 printf("Testing thread safety\n");
|
|
758
|
|
759 int x = 0, y = 0;
|
|
760
|
|
761 Fiber sc0 = new Fiber(
|
|
762 {
|
|
763 while(true)
|
|
764 {
|
|
765 x++;
|
|
766 Fiber.yield;
|
|
767 }
|
|
768 });
|
|
769
|
|
770 Fiber sc1 = new Fiber(
|
|
771 {
|
|
772 while(true)
|
|
773 {
|
|
774 y++;
|
|
775 Fiber.yield;
|
|
776 }
|
|
777 });
|
|
778
|
|
779 Thread t0 = new Thread(
|
|
780 {
|
|
781 for(int i=0; i<10000; i++)
|
|
782 sc0.call();
|
|
783 });
|
|
784
|
|
785 Thread t1 = new Thread(
|
|
786 {
|
|
787 for(int i=0; i<10000; i++)
|
|
788 sc1.call();
|
|
789 });
|
|
790
|
|
791 assert(sc0);
|
|
792 assert(sc1);
|
|
793 assert(t0);
|
|
794 assert(t1);
|
|
795
|
|
796 t0.start;
|
|
797 t1.start;
|
|
798 t0.join;
|
|
799 t1.join;
|
|
800
|
|
801 assert(x == 10000);
|
|
802 assert(y == 10000);
|
|
803
|
|
804 printf("Thread safety passed!\n");
|
|
805 }
|
|
806
|