2 # Copyright (C) 2006-2007, The Perl Foundation.
7 use lib qw( . lib ../lib ../../lib );
18 t/stm/runtime.t -- STM Runtime library tests
22 Tests STM.pir and, as a side effect, the underlying STM implementation.
23 This tests its general functionality using an array-based queue implemtation
24 modified to use it, and includes several tests designed to trigger all
25 cases for choice() (which in turn requires STMLog work correctly).
29 my $choice_test = <<'CODE';
34 .local pmc _choice_one
35 .local pmc _choice_two
36 .const .Sub choice_one = 'choice_one'
37 .const .Sub choice_two = 'choice_two'
38 _choice_one = newclosure choice_one
39 _choice_two = newclosure choice_two
41 _choice = get_hll_global ['STM'], 'choice'
42 $I0 = _choice(_choice_one, _choice_two)
46 .sub choice_one :outer(do_choice)
48 values = find_lex 'values'
51 what = what.'get_update'()
52 if what == 1 goto need_retry
57 retry = get_hll_global ['STM'], 'retry'
61 .sub choice_two :outer(do_choice)
63 values = find_lex 'values'
67 the_value = what.'get_read'()
68 if the_value == 1 goto need_retry
69 the_value = new 'Integer'
75 retry = get_hll_global ['STM'], 'retry'
82 pir_output_is( $choice_test . <<'CODE', <<'OUTPUT', "choice (one thread)" );
86 thread_one = new 'ParrotThread'
87 thread_two = new 'ParrotThread'
89 load_bytecode 'STM.pbc'
92 values = new 'FixedPMCArray'
96 $P0 = new 'STMVar', $P0
100 $P0 = new 'STMVar', $P0
102 .local pmc _thread_main
103 _thread_main = global 'do_choice'
105 $I0 = _thread_main(values)
106 $I1 = _thread_main(values)
108 if $I2 != 3 goto fail
109 if $I0 == 1 goto okay
110 if $I1 == 1 goto okay
128 skip( "Intermittently failing everywhere", 2 );
130 pir_output_is( $choice_test . <<'CODE', <<'OUTPUT', "choice (multiple threads)" );
141 .local pmc transaction
143 transaction = get_hll_global ['STM'], 'transaction'
144 real_sub = global '_wakeup_func'
145 transaction(real_sub, values)
150 .local pmc thread_one
151 .local pmc thread_two
152 .local pmc thread_three
153 .local pmc wakeup_thread
154 thread_one = new 'ParrotThread'
155 thread_two = new 'ParrotThread'
156 thread_three = new 'ParrotThread'
157 wakeup_thread = new 'ParrotThread'
159 load_bytecode 'STM.pbc'
162 values = new 'FixedPMCArray'
166 $P0 = new 'STMVar', $P0
170 $P0 = new 'STMVar', $P0
172 .local pmc _thread_main
173 _thread_main = global 'do_choice'
174 thread_one.'run_clone'(_thread_main, values)
175 thread_two.'run_clone'(_thread_main, values)
176 thread_three.'run_clone'(_thread_main, values)
177 .local pmc _wakeup_thread_main
178 _wakeup_thread_main = global 'wakeup_func'
179 wakeup_thread.'run_clone'(_wakeup_thread_main, values)
180 $I0 = thread_one.'join'()
181 $I1 = thread_two.'join'()
182 $I2 = thread_three.'join'()
183 wakeup_thread.'join'()
193 if $I0 != 1 goto zero_two
196 if $I1 != 1 goto one_two
199 if $I2 != 1 goto two_two
202 if num_ones != 2 goto fail
220 pir_output_is( <<'CODE', <<'OUTPUT', "choice doesn't clobber" );
225 .lex 'set_to', setting
226 .const .Sub _clobber = '_clobber'
227 $P0 = newclosure _clobber
231 .sub _clobber :outer(make_clobber)
234 value = find_lex 'value'
235 setting = find_lex 'set_to'
238 retry = get_hll_global ['STM'], 'retry'
245 .const .Sub _normal = '_normal'
246 $P0 = newclosure _normal
250 .sub _normal :outer(make_normal)
252 value = find_lex 'value'
253 $P0 = value.'get_read'()
254 if $P0 < 0 goto do_retry
258 retry = get_hll_global ['STM'], 'retry'
265 result = value.'get_read'()
271 $P0 = make_clobber(value, 10)
272 $P1 = make_clobber(value, 20)
273 $P2 = make_clobber(value, 30)
274 $P3 = make_normal(value)
275 $P4 = make_clobber(value, 40)
277 choice = get_hll_global ['STM'], 'choice'
278 choice($P0, $P1, $P2, $P3, $P4)
288 .local pmc transaction
290 transaction = get_hll_global ['STM'], 'transaction'
291 real_sub = global '_wakeup_func'
292 transaction(real_sub, what)
300 load_bytecode 'STM.pbc'
302 value = new 'Integer'
304 value = new 'STMVar', value
306 .const .Sub wakeup = 'wakeup_func'
307 .const .Sub choice = 'choice_thread'
308 $P0 = new 'ParrotThread'
309 $P1 = new 'ParrotThread'
310 $P0.'run_clone'(choice, value)
312 $P1.'run_clone'(wakeup, value)
316 tx = get_hll_global ['STM'], 'transaction'
317 .const .Sub _get = '_get'
318 $P0 = tx(_get, value)
319 if $P0 != 0 goto failed
332 my $queue_test = <<'CODE';
334 # head: index of next element to read
335 # tail: index of next element to add
336 # used: index of number of items used
337 # array: fixed-sized array of STMVars.
339 .namespace ['STMQueue']
343 $P0 = get_class 'STMQueue'
344 unless null $P0 goto done
346 class = newclass 'STMQueue'
347 addattribute class, 'head'
348 addattribute class, 'tail'
349 addattribute class, 'used'
350 addattribute class, 'array'
351 addattribute class, 'length'
356 .sub init_pmc :vtable :method
362 tmpint = new 'Integer'
364 stmv = new 'STMVar', tmpint
365 setattribute self, 'head', stmv
366 stmv = new 'STMVar', tmpint
367 setattribute self, 'used', stmv
368 stmv = new 'STMVar', tmpint
369 setattribute self, 'tail', stmv
371 # Length is set during initialization
373 $P0 = getattribute self, 'length'
386 if i < length goto loop
387 setattribute self, 'array', array
390 .sub fetchHead :method
394 $P0 = get_hll_global ['STM'], 'transaction'
395 $P1 = global '_fetchHead'
396 .return $P0($P1, self, removep, blockp)
399 .sub _fetchHead :method
407 used = getattribute self, 'used'
408 used = used.'get_read'()
409 if used != 0 goto have_items
411 unless blockp goto no_block
412 $P0 = get_hll_global ['STM'], 'retry'
416 tmp = getattribute self, 'head'
418 tmp = getattribute self, 'array'
420 ret = tmp.'get_read'()
422 unless removep goto skip_remove
423 tmp = getattribute self, 'head'
424 $P0 = getattribute self, 'array'
430 tmp = getattribute self, 'used'
439 $P0 = get_hll_global ['STM'], 'give_up'
449 $P0 = get_hll_global ['STM'], 'transaction'
450 $P1 = global '_addTail'
451 $P2 = $P0($P1, self, what, blockp)
455 .sub _addTail :method
467 i = getattribute self, 'tail'
469 used = getattribute self, 'used'
470 used = used.'get_update'()
471 $P0 = getattribute self, 'array'
474 if used == length goto is_full
478 tmp = getattribute self, 'array'
485 tmp = getattribute self, 'tail'
491 unless blockp goto no_block
492 $P0 = get_hll_global ['STM'], 'retry'
496 $P0 = get_hll_global ['STM'], 'give_up'
506 local $TODO = "sub bodies aren't properly cloned in threads, RT# 46519";
509 pir_output_is( $queue_test . <<'CODE', <<'OUTPUT', "queue adapted for the library" );
510 .const int MAX = 5000
511 .const int SIZE = 100
519 queue.'addTail'(i, 1)
533 got = queue.'fetchHead'(1, 1)
534 if got != i goto not_okay
545 .local pmc removeThread
551 load_bytecode 'STM.pbc'
553 $P0 = get_hll_global ['STMQueue'], '__onload'
556 _add = global "adder"
557 _remove = global "remover"
559 addThread = new 'ParrotThread'
560 removeThread = new 'ParrotThread'
561 $P0 = get_class 'STMQueue'
562 queue = $P0.'new'('length' => SIZE)
564 # addThreadId = addThread
565 # removeThreadId = removeThread
567 addThread.'run_clone'(_add, queue)
568 removeThread.'run_clone'(_remove, queue)
569 removeThread.'join'()
579 pir_output_is( $queue_test . <<'CODE', <<'OUTPUT', "queue (non-blocking; nested)" );
585 $P0 = queue.'fetchHead'(1, 0)
587 if $I0 == 1 goto fail
588 queue.'addTail'(42, 1)
589 $P0 = queue.'fetchHead'(0, 0)
590 if $P0 != 42 goto fail
591 $P0 = queue.'fetchHead'(1, 0)
592 if $P0 != 42 goto fail
593 $P0 = queue.'fetchHead'(1, 0)
595 if $I0 == 1 goto fail
604 load_bytecode 'STM.pbc'
606 $P0 = get_hll_global ['STMQueue'], '__onload'
609 $P0 = get_class 'STMQueue'
610 queue = $P0.'new'('length' => SIZE)
612 $P0 = get_hll_global ['STM'], 'transaction'
627 # cperl-indent-level: 4
630 # vim: expandtab shiftwidth=4: