[t][TT #1122] Convert t/op/numbert.t to PIR, mgrimes++
[parrot.git] / t / pmc / threads.t
blobd710c54233136b066de5e709313a1a53a766d55c
1 #! perl
2 # Copyright (C) 2001-2009, Parrot Foundation.
3 # $Id$
5 use strict;
6 use warnings;
7 use lib qw( . lib ../lib ../../lib );
8 use Test::More;
9 use Parrot::Test;
10 use Parrot::Config;
12 =head1 NAME
14 t/pmc/threads.t - Threads
16 =head1 SYNOPSIS
18     % prove t/pmc/threads.t
20 =head1 DESCRIPTION
22 Tests running threads. All tests skipped unless running on known-good
23 platform.
25 =cut
27 if ( $^O eq "cygwin" ) {
28     my @uname = split / /, qx'uname -v';
30     if ( $uname[0] eq "2004-09-04" ) {
31         plan skip_all => "This cygwin version is known to fail the thread tests";
32         exit;
33     }
35 if ( $PConfig{HAS_THREADS} ) {
36     plan tests => 14;
38 else {
39     plan skip_all => "No threading enabled for '$^O'";
42 pasm_output_is( <<'CODE', <<'OUTPUT', "interp identity" );
43     getinterp P2
44     clone P3, P2
45     ne P3, P2, ok1
46     print "not"
47 ok1:
48     print "ok 1\n"
49     new P4, ['ParrotThread']
50     ne P4, P2, ok2
51     print "not"
52 ok2:
53     print "ok 2\n"
54     end
55 CODE
56 ok 1
57 ok 2
58 OUTPUT
60 # TT #1249:  rework tests since we don't really have thread types?
62 SKIP: {
63     skip 'busted on win32' => 2 if $^O eq 'MSWin32';
65     pir_output_is( <<'CODE', <<'OUTPUT', "thread type 1" );
66 .sub main :main
67     .local pmc threadfunc
68     .local pmc thread
69     $I5 = 10
70     threadfunc = get_global "foo"
71     thread = new ['ParrotThread']
72     thread.'run_clone'(threadfunc)
74     sleep 1
75     print "main "
76     print $I5
77     print "\n"
78     # get tid of thread
79     $I0 = thread
80     # wait for it
81     thread.'join'()
82 .end
84 .sub foo
85     # check if vars are fresh
86     inc $I5
87     print "thread"
88     # print I5 # not done because registers aren't guaranteed to be
89                # initialized to anything in particular
90     print "\n"
91     set $I3, 0   # no retval
92     returncc    # ret and be done with thread
93 .end
94 # output from threads could be reversed
95 CODE
96 thread
97 main 10
98 OUTPUT
100     pir_output_is( <<'CODE', <<'OUTPUT', "thread type 1 -- repeated" );
101 .sub real_main :main
102     $I0 = 0
103 loop:
104     main()
105     inc $I0
106     if $I0 < 2 goto loop
107 .end
109 .sub main
110     .local pmc threadfunc
111     .local pmc thread
112     $I5 = 10
113     threadfunc = get_global "foo"
114     thread = new ['ParrotThread']
115     thread.'run_clone'(threadfunc)
117     sleep 1
118     print "main "
119     print $I5
120     print "\n"
121     # get tid of thread
122     $I0 = thread
123     # wait for it
124     thread.'join'()
125 .end
127 .sub foo
128     # check if vars are fresh
129     inc $I5
130     print "thread"
131     # print I5 # not done because registers aren't guaranteed to be
132                # initialized to anything in particular
133     print "\n"
134     set $I3, 0   # no retval
135     returncc    # ret and be done with thread
136 .end
137 # output from threads could be reversed
138 CODE
139 thread
140 main 10
141 thread
142 main 10
143 OUTPUT
147 pir_output_is( <<'CODE', <<'OUTPUT', "thread type 2" );
148 .sub main :main
149     set $I5, 10
150     .local pmc thread
151     .local pmc threadsub
152     $S5 = " interp\n"
153     $P6 = new ['String']
154     $P6 = 'from '
156     print "ok 1\n"
157     threadsub = get_global "foo"
158     thread = new ['ParrotThread']
159     thread.'run_clone'(threadsub, $P6)
160     sleep 1 # to let the thread run
161     print $P6
162     print $I5
163     print $S5
164     thread.'join'()
165 .end
167 .sub foo
168     .param pmc passed
169     inc $I5
170     $S5 = " thread\n"
171     .local pmc salutation
172     salutation = box 'hello from'
173     print salutation
174     # print I5 # not done because register initialization is not guaranteed
175     print $S5
176     $P0 = getinterp
177     $S0 = typeof $P0
178     print $S0
179     print ' tid '
180     $I0 = $P0
181     print $I0
182     print "\n"
183 .end
184 CODE
185 ok 1
186 hello from thread
187 ParrotThread tid 1
188 from 10 interp
189 OUTPUT
192 pir_output_is( <<'CODE', <<'OUTPUT', 'thread - kill' );
193 .sub main :main
194     .local pmc threadsub
195     .local pmc thread
196     bounds 1    # assert slow core -S and -g are fine too
197     threadsub = get_global "foo"
198     thread = new ['ParrotThread']
199     $I0 = thread
200     print 'start '
201     print $I0
202     print "\n"
203     thread.'run_clone'(threadsub)
205     sleep 1 # to let the thread run
207     thread.'kill'()
209     print "done\n"
210 .end
212 .sub foo
213     print "in thread\n"
214     # run an endles loop
216     noop
217     branch lp
218 .end
219 CODE
220 start 1
221 in thread
222 done
223 OUTPUT
226 pir_output_is( <<'CODE', <<'OUTPUT', "join, get retval" );
227 .sub _main
228     .const int MAX = 1000
229     .local pmc kid
230     .local pmc Adder
231     Adder = get_global '_add'
232     kid = new ['ParrotThread']
233     .local pmc from
234     from = new ['Integer']
235     from = 0
236     .local pmc to
237     to = new ['Integer']
238     to = MAX
239     kid.'run_clone'(Adder, Adder, from, to)
241     .local pmc result
242     result = kid.'join'()
243     print result
244     print "\n"
245     # sum = n * (n + 1)/2
246     .local pmc Mul
247     Mul = new ['Integer']
248     assign Mul, to
249     inc Mul
250     Mul = to * Mul
251     Mul = Mul / 2
252     print Mul
253     print "\n"
254     end
255 .end
257 .sub _add
258    .param pmc sub
259    .param pmc from
260    .param pmc to
261    .local pmc sum
262    sum = new ['Integer']
263 loop:
264     add sum, from
265     inc from
266     le from, to, loop
268     .begin_return
269     .set_return sum
270     .end_return
271 .end
272 CODE
273 500500
274 500500
275 OUTPUT
277 pir_output_is( <<'CODE', <<'OUT', "sub name lookup in new thread" );
278 .sub check
279     $P0 = get_global ['Foo'], 'foo'
280     $I0 = isa $P0, 'Sub'
281     if $I0 goto okay
282     print "not "
283 okay:
284     print "ok\n"
285 .end
287 .sub main :main
288     check()
289     $P0 = new ['ParrotThread']
290     .local pmc thread_main
291     thread_main = get_global 'thread_main'
292     $P0.'run_clone'(thread_main)
293     $P0.'join'()
294 .end
296 .sub thread_main
297     check()
298 .end
300 .namespace [ 'Foo' ]
302 .sub foo
303     print "not reached\n"
304 .end
305 CODE
310 pir_output_is( <<'CODE', <<'OUTPUT', "CLONE_CODE only" );
312 .namespace [ 'Test2' ]
313 .sub test2
314     print "ok 2\n"
315 .end
317 .namespace [ 'Test3' ]
318 .sub test3
319     print "ok 3\n"
320 .end
322 .namespace [ 'main' ]
324 .include 'errors.pasm'
325 .sub thread_func
326     .param pmc test2
327     print "ok 1\n"
328     test2()
329     .local pmc test3
330     test3 = get_hll_global ['Test3'], 'test3'
331     test3()
332     .local pmc test4
333     errorsoff .PARROT_ERRORS_GLOBALS_FLAG
334     test4 = get_global 'test4'
335     if null test4 goto okay
336     print "not "
337 okay:
338     print "ok 4\n"
339 .end
341 .include 'cloneflags.pasm'
342 .sub main :main
343     .local pmc test4
344     .local pmc test2
346     test2 = get_hll_global ['Test2'], 'test2'
348     test4 = new ['Integer']
349     test4 = 42
350     set_global 'test4', test4
352     .local pmc thread
353     thread = new ['ParrotThread']
354     .local pmc thread_func
355     thread_func = get_global 'thread_func'
356     $I0 = .PARROT_CLONE_CODE
357     thread.'run'($I0, thread_func, test2)
358     thread.'join'()
359     print "ok 5\n"
360 .end
361 CODE
362 ok 1
363 ok 2
364 ok 3
365 ok 4
366 ok 5
367 OUTPUT
369 pir_output_is( <<'CODE', <<'OUTPUT', "CLONE_CODE | CLONE_GLOBALS" );
371 .namespace [ 'Foo' ]
372 .sub 'is'
373     .param pmc what
374     .param pmc expect
375     .param pmc label
376     .param pmc shortlabel
377     if what == expect goto okay
378     print "# "
379     print label
380     print "\n"
381     print "# got:      "
382     print what
383     print "\n"
384     print "# expected: "
385     print expect
386     print "\nnot "
387 okay:
388     print "ok "
389     print shortlabel
390     print "\n"
391 .end
393 .sub thread_test_func
394     $P0 = get_hll_global [ 'Bar' ], 'alpha'
395     'is'($P0, 1, 'Bar::alpha == 1', 'alpha')
396     $P0 = 43
397     sleep 0.2 # give enough time that the main thread might modify
398               # any shared Foo::beta can cause phantom errors
399     $P0 = get_global 'beta'
400     'is'($P0, 2, 'Foo::beta == 2 [accessed locally]', 'beta1')
401     $P0 = 5
402     $P0 = get_global 'beta'
403     'is'($P0, 5, 'Foo::beta == 5 [accessed locally after assignment]', 'beta2')
404     $P0 = get_hll_global [ 'Foo' ], 'beta'
405     'is'($P0, 5, 'Foo::beta == 5 [after assign; absolute]', 'beta3')
406 .end
408 .namespace [ 'main' ]
410 .sub test_setup
411     $P0 = new ['Integer']
412     $P0 = 1
413     set_hll_global [ 'Bar' ], 'alpha', $P0
414     $P0 = new ['Integer']
415     $P0 = 2
416     set_hll_global [ 'Foo' ], 'beta', $P0
417 .end
419 .include 'cloneflags.pasm'
420 .sub main :main
421     'test_setup'()
423     .local pmc thread
424     thread = new ['ParrotThread']
425     .local pmc _thread_func
426     _thread_func = get_hll_global [ 'Foo' ], 'thread_test_func'
427     $I0 = .PARROT_CLONE_CODE
428     bor $I0, $I0, .PARROT_CLONE_GLOBALS
429     print "in thread:\n"
430     thread.'run'($I0, _thread_func)
431     $P0 = get_hll_global [ 'Foo' ], 'beta'
432     $P0 = 42
433     thread.'join'()
434     print "in main:\n"
435     $P0 = 2
436     _thread_func()
437 .end
438 CODE
439 in thread:
440 ok alpha
441 ok beta1
442 ok beta2
443 ok beta3
444 in main:
445 ok alpha
446 ok beta1
447 ok beta2
448 ok beta3
449 OUTPUT
451 TODO: {
452     local $TODO = "vtable overrides aren't properly cloned TT # 1248";
454     pir_output_is( <<'CODE', <<'OUTPUT', "CLONE_CODE | CLONE_CLASSES; superclass not built-in" );
455 .namespace [ 'Foo' ]
457 .sub foometh :method
458     print "called Foo's foometh\n"
459 .end
461 .sub barmeth :method
462     print "called Foo's barmeth\n"
463 .end
465 .namespace [ 'Bar' ]
467 .sub barmeth :method
468     print "called Bar's barmeth\n"
469 .end
471 .sub get_string :vtable :method
472     .return ("A Bar")
473 .end
475 .namespace [ 'main' ]
477 .sub init
478     $P1 = newclass 'Foo'
479     addattribute $P1, 'foo1'
480     addattribute $P1, 'foo2'
481     $P2 = subclass $P1, 'Bar'
482     addattribute $P2, 'bar1'
483 .end
485 .sub thread_test_func
486     $P0 = new ['Bar']
487     print $P0
488     print "\n"
489     $P0.'barmeth'()
490     $P0.'foometh'()
491     $I0 = isa $P0, 'Integer'
492     print "Integer? "
493     print $I0
494     print "\n"
495     $I0 = isa $P0, 'Foo'
496     print "Foo? "
497     print $I0
498     print "\n"
499     $I0 = isa $P0, 'Bar'
500     print "Bar? "
501     print $I0
502     print "\n"
503 .end
505 .include 'cloneflags.pasm'
506 .sub main :main
507     init()
509     .local pmc thread
510     thread = new ['ParrotThread']
511     .local pmc _thread_func
512     _thread_func = get_hll_global ['main'], 'thread_test_func'
513     $I0 = .PARROT_CLONE_CODE
514     bor $I0, $I0, .PARROT_CLONE_CLASSES
515     print "in thread:\n"
516     thread.'run'($I0, _thread_func)
517     thread.'join'()
518     print "in main:\n"
519     _thread_func()
520 .end
521 CODE
522 in thread:
523 A Bar
524 called Bar's barmeth
525 called Foo's foometh
526 Integer? 0
527 Foo? 1
528 Bar? 1
529 in main:
530 A Bar
531 called Bar's barmeth
532 called Foo's foometh
533 Integer? 0
534 Foo? 1
535 Bar? 1
536 OUTPUT
539 pir_output_is( <<'CODE', <<'OUTPUT', "CLONE_CODE | CLONE_CLASSES; superclass built-in", todo => 'likely incorrect test TT 1248');
540 .namespace [ 'Foo' ]
542 .sub foometh :method
543     print "called Foo's foometh\n"
544 .end
546 .sub barmeth :method
547     print "called Foo's barmeth\n"
548 .end
550 .namespace [ 'Bar' ]
552 .sub barmeth :method
553     print "called Bar's barmeth\n"
554 .end
556 .sub get_string :vtable :method
557     .return ("A Bar")
558 .end
560 .namespace [ 'main' ]
562 .sub init
563     $P0 = get_class 'Integer'
564     $P1 = subclass $P0, 'Foo'
565     addattribute $P1, 'foo1'
566     addattribute $P1, 'foo2'
567     $P2 = subclass $P1, 'Bar'
568     addattribute $P2, 'bar1'
569 .end
571 .sub thread_test_func
572     $P0 = new ['Bar']
573     print $P0
574     print "\n"
575     $P0.'barmeth'()
576     $P0.'foometh'()
577     $I0 = isa $P0, 'Integer'
578     print "Integer? "
579     print $I0
580     print "\n"
581     $I0 = isa $P0, 'Foo'
582     print "Foo? "
583     print $I0
584     print "\n"
585     $I0 = isa $P0, 'Bar'
586     print "Bar? "
587     print $I0
588     print "\n"
589 .end
591 .include 'cloneflags.pasm'
592 .sub main :main
593     init()
595     .local pmc thread
596     thread = new ['ParrotThread']
597     .local pmc _thread_func
598     _thread_func = get_global 'thread_test_func'
599     $I0 = .PARROT_CLONE_CODE
600     bor $I0, $I0, .PARROT_CLONE_CLASSES
601     print "in thread:\n"
602     thread.'run'($I0, _thread_func)
603     thread.'join'()
604     print "in main:\n"
605     _thread_func()
606 .end
607 CODE
608 in thread:
609 A Bar
610 called Bar's barmeth
611 called Foo's foometh
612 Integer? 1
613 Foo? 1
614 Bar? 1
615 in main:
616 A Bar
617 called Bar's barmeth
618 called Foo's foometh
619 Integer? 1
620 Foo? 1
621 Bar? 1
622 OUTPUT
624 pir_output_is( <<'CODE', <<'OUTPUT', "CLONE_CODE | CLONE_GLOBALS| CLONE_HLL" );
625 .HLL 'Test'
626 .sub setup
627     $P0 = new ['Integer']
628     $P0 = 42
629     set_global 'x', $P0
630 .end
632 .include 'interpinfo.pasm'
633 .sub test
634     $P0 = get_global 'x'
635     if $P0 == 42 goto okay1
636     print "not "
637 okay1:
638     print "ok 1\n"
639     $P1 = get_root_namespace
640     $P1 = $P1['test']
641     $P1 = $P1['x']
642     $P1 = 43
643     if $P0 == 43 goto okay2
644     print "not "
645 okay2:
646     print "ok 2\n"
647 .end
649 .HLL ''
651 .include 'cloneflags.pasm'
653 .sub main :main
654     .local pmc setup
655     .local pmc test
656     setup = get_root_namespace
657     setup = setup['test']
658     test = setup['test']
659     setup = setup['setup']
660     setup()
662     .local pmc thread
663     .local int flags
664     thread = new ['ParrotThread']
665     flags = .PARROT_CLONE_CODE
666     bor flags, flags, .PARROT_CLONE_GLOBALS
667     bor flags, flags, .PARROT_CLONE_HLL
668     print "in thread:\n"
669     thread.'run'(flags, test)
670     thread.'join'()
671     print "in main:\n"
672     test()
673 .end
674 CODE
675 in thread:
676 ok 1
677 ok 2
678 in main:
679 ok 1
680 ok 2
681 OUTPUT
683 # Direct constant access to sub objects commented out, see TT #1120.
684 pir_output_unlike( <<'CODE', qr/not/, "globals + constant table subs issue");
685 .namespace [ 'Foo' ]
687 .include 'interpinfo.pasm'
688 .sub 'is'
689     .param pmc    what
690     .param pmc    expect
691     .param string desc      :optional
692     .param int    have_desc :opt_flag
694     unless have_desc goto diagnose
695     desc = ' - ' . desc
697   diagnose:
698     .local pmc number
699     number = get_global 'test_num'
700     if what == expect goto okay
701     print "# got:      "
702     say what
703     print "# expected: "
704     say expect
705     print "not ok "
706     print number
707     say desc
708     inc number
709     $P0 = interpinfo .INTERPINFO_CURRENT_CONT
710 loop:
711     $I0 = defined $P0
712     if $I0 == 0 goto done
713     print "    "
714     say $P0
715     $P0 = $P0.'continuation'()
716     branch loop
717 done:
718     .return ()
719 okay:
720     print "ok "
721     print number
722     inc number
723     say desc
724 .end
726 .sub setup
727     $P0 = new ['Integer']
728     $P0 = 1
729     set_global 'foo', $P0
730 .end
732 .sub _check_sanity
733     .param string desc
734     $P0 = get_global 'foo'
735     $P1 = get_hll_global [ 'Foo' ], 'foo'
736     is($P0, $P1, desc)
737 .end
739 .sub mutate
740     $P0 = new ['Integer']
741     $P0 = 2
742     set_global 'foo', $P0
743 .end
745 .sub check_sanity
746 #    _check_sanity( 'direct call' )
747     $P0 = get_global '_check_sanity'
748     $P0( 'call from get_global' )
749     $P0 = get_hll_global [ 'Foo' ], '_check_sanity'
750     $P0( 'call from get_hll_global' )
751 .end
753 .sub _check_value
754     .param int value
755     $P0 = get_global 'foo'
756     is($P0, value)
757 .end
759 .sub check_value
760     .param int value
761 #    _check_value(value)
762     $P0 = get_global '_check_value'
763     $P0(value)
764     $P0 = get_hll_global [ 'Foo' ], '_check_value'
765     $P0(value)
766 .end
768 .sub full_check
769 #    .const 'Sub' c_setup = 'setup'
770 #    .const 'Sub' c_sanity = 'check_sanity'
771 #    .const 'Sub' c_mutate = 'mutate'
772 #    .const 'Sub' c_value = 'check_value'
774     .local pmc c_setup
775     c_setup = get_global  'setup'
776     .local pmc c_sanity
777     c_sanity = get_global 'check_sanity'
778     .local pmc c_mutate
779     c_mutate = get_global 'mutate'
780     .local pmc c_value
781     c_value = get_global  'check_value'
783     .local pmc g_setup
784     g_setup = get_hll_global [ 'Foo' ], 'setup'
785     .local pmc g_sanity
786     g_sanity = get_hll_global [ 'Foo' ], 'check_sanity'
787     .local pmc g_mutate
788     g_mutate = get_hll_global [ 'Foo' ], 'mutate'
789     .local pmc g_value
790     g_value = get_hll_global [  'Foo' ], 'check_value'
792     c_setup()
793     c_sanity()
794     g_sanity()
795     c_value(1)
796     g_value(1)
797     c_mutate()
798     c_value(2)
799     g_value(2)
800     c_sanity()
801     g_sanity()
803     g_setup()
804     c_sanity()
805     g_sanity()
806     c_value(1)
807     g_value(1)
808     g_mutate()
809     c_value(2)
810     g_value(2)
811     c_sanity()
812     g_sanity()
813 .end
817 .sub main :main
818     $P0 = new ['Integer']
819     $P0 = 1
820     set_global 'test_num', $P0
822     .const 'Sub' _check = 'full_check'
823     _check()
825     $P0 = new ['ParrotThread']
826     $P0.'run_clone'(_check)
827     $P0.'join'()
828 .end
829 CODE
831 pir_output_is(
832     <<'CODE', <<'OUTPUT', 'CLONE_CODE|CLONE_GLOBALS|CLONE_HLL|CLONE_LIBRARIES - TT # 1250' );
833 .HLL 'Perl'
835 .include 'interpinfo.pasm'
837 .loadlib 'foo_group'
838 .loadlib 'myops_ops'
840 .sub test
841     .param pmc passed_value
842     .local pmc the_value
843     the_value = new ['Integer']
844     the_value = 42
845     set_hll_global ['Foo'], 'x', the_value
846     $S0 = typeof passed_value
847     $S1 = typeof the_value
848     $I0 = iseq $S0, $S1
849     say $I0
851     .local pmc ns
852     ns = get_namespace ['Foo']
853     $P0 = interpinfo .INTERPINFO_CURRENT_SUB
854     ns = $P0.'get_namespace'()
855     ns = ns['Foo']
856     $P0 = ns['x']
857     if $P0 == the_value goto okay
858     print "not "
859 okay:
860     say "ok (equal)"
862     $I0 = the_value
863     say $I0
864 .end
866 .include 'cloneflags.pasm'
868 .sub main :main
869     .local pmc thread
870     .local int flags
871     thread = new ['ParrotThread']
872     flags = .PARROT_CLONE_CODE
873     bor flags, flags, .PARROT_CLONE_GLOBALS
874     bor flags, flags, .PARROT_CLONE_HLL
875     bor flags, flags, .PARROT_CLONE_LIBRARIES
877     .local pmc passed
878     passed = new ['Foo']
879     passed = 15
881     .local pmc thread_func
882     thread_func = get_global 'test'
883     say "in thread:"
884     thread.'run'(flags, thread_func, passed)
885     thread.'join'()
886     say "in main:"
887     thread_func(passed)
888 .end
889 CODE
890 in thread:
892 ok (equal)
894 in main:
896 ok (equal)
898 OUTPUT
900 # Local Variables:
901 #   mode: cperl
902 #   cperl-indent-level: 4
903 #   fill-column: 100
904 # End:
905 # vim: expandtab shiftwidth=4: