xref: /openbsd/gnu/usr.bin/perl/t/op/threads.t (revision 73471bf0)
1#!perl
2
3BEGIN {
4     chdir 't' if -d 't';
5     require './test.pl';
6     set_up_inc( '../lib' );
7     $| = 1;
8
9     skip_all_without_config('useithreads');
10     skip_all_if_miniperl("no dynamic loading on miniperl, no threads");
11
12     plan(30);
13}
14
15use strict;
16use warnings;
17use threads;
18
19# test that we don't get:
20# Attempt to free unreferenced scalar: SV 0x40173f3c
21fresh_perl_is(<<'EOI', 'ok', { }, 'delete() under threads');
22use threads;
23threads->create(sub { my %h=(1,2); delete $h{1}})->join for 1..2;
24print "ok";
25EOI
26
27#PR24660
28# test that we don't get:
29# Attempt to free unreferenced scalar: SV 0x814e0dc.
30fresh_perl_is(<<'EOI', 'ok', { }, 'weaken ref under threads');
31use threads;
32use Scalar::Util;
33my $data = "a";
34my $obj = \$data;
35my $copy = $obj;
36Scalar::Util::weaken($copy);
37threads->create(sub { 1 })->join for (1..1);
38print "ok";
39EOI
40
41#PR24663
42# test that we don't get:
43# panic: magic_killbackrefs.
44# Scalars leaked: 3
45fresh_perl_is(<<'EOI', 'ok', { }, 'weaken ref #2 under threads');
46package Foo;
47sub new { bless {},shift }
48package main;
49use threads;
50use Scalar::Util qw(weaken);
51my $object = Foo->new;
52my $ref = $object;
53weaken $ref;
54threads->create(sub { $ref = $object } )->join; # $ref = $object causes problems
55print "ok";
56EOI
57
58#PR30333 - sort() crash with threads
59sub mycmp { length($b) <=> length($a) }
60
61sub do_sort_one_thread {
62   my $kid = shift;
63   print "# kid $kid before sort\n";
64   my @list = ( 'x', 'yy', 'zzz', 'a', 'bb', 'ccc', 'aaaaa', 'z',
65                'hello', 's', 'thisisalongname', '1', '2', '3',
66                'abc', 'xyz', '1234567890', 'm', 'n', 'p' );
67
68   for my $j (1..99999) {
69      for my $k (sort mycmp @list) {}
70   }
71   print "# kid $kid after sort, sleeping 1\n";
72   sleep(1);
73   print "# kid $kid exit\n";
74}
75
76sub do_sort_threads {
77   my $nthreads = shift;
78   my @kids = ();
79   for my $i (1..$nthreads) {
80      my $t = threads->create(\&do_sort_one_thread, $i);
81      print "# parent $$: continue\n";
82      push(@kids, $t);
83   }
84   for my $t (@kids) {
85      print "# parent $$: waiting for join\n";
86      $t->join();
87      print "# parent $$: thread exited\n";
88   }
89}
90
91do_sort_threads(2);        # crashes
92ok(1);
93
94# Change 24643 made the mistake of assuming that CvCONST can only be true on
95# XSUBs. Somehow it can also end up on perl subs.
96fresh_perl_is(<<'EOI', 'ok', { }, 'cloning constant subs');
97use constant x=>1;
98use threads;
99$SIG{__WARN__} = sub{};
100async sub {};
101print "ok";
102EOI
103
104# From a test case by Tim Bunce in
105# http://www.nntp.perl.org/group/perl.perl5.porters/63123
106fresh_perl_is(<<'EOI', 'ok', { }, 'Ensure PL_linestr can be cloned');
107use threads;
108print do 'op/threads_create.pl' || die $@;
109EOI
110
111
112# Scalars leaked: 1
113foreach my $BLOCK (qw(CHECK INIT)) {
114    fresh_perl_is(<<EOI, 'ok', { }, "threads in $BLOCK block");
115        use threads;
116        $BLOCK { threads->create(sub {})->join; }
117        print 'ok';
118EOI
119}
120
121# Scalars leaked: 1
122fresh_perl_is(<<'EOI', 'ok', { }, 'Bug #41138');
123    use threads;
124    leak($x);
125    sub leak
126    {
127        local $x;
128        threads->create(sub {})->join();
129    }
130    print 'ok';
131EOI
132
133
134# [perl #45053] Memory corruption with heavy module loading in threads
135#
136# run-time usage of newCONSTSUB (as done by the IO boot code) wasn't
137# thread-safe - got occasional coredumps or malloc corruption
138watchdog(180, "process");
139{
140    local $SIG{__WARN__} = sub {};   # Ignore any thread creation failure warnings
141    my @t;
142    for (1..10) {
143        my $thr = threads->create( sub { require IO });
144        last if !defined($thr);      # Probably ran out of memory
145        push(@t, $thr);
146    }
147    $_->join for @t;
148    ok(1, '[perl #45053]');
149}
150
151sub matchit {
152    is (ref $_[1], "Regexp");
153    like ($_[0], $_[1]);
154}
155
156threads->new(\&matchit, "Pie", qr/pie/i)->join();
157
158# tests in threads don't get counted, so
159curr_test(curr_test() + 2);
160
161
162# the seen_evals field of a regexp was getting zeroed on clone, so
163# within a thread it didn't  know that a regex object contained a 'safe'
164# code expression, so it later died with 'Eval-group not allowed' when
165# you tried to interpolate the object
166
167sub safe_re {
168    my $re = qr/(?{1})/;	# this is literal, so safe
169    eval { "a" =~ /$re$re/ };	# interpolating safe values, so safe
170    ok($@ eq "", 'clone seen-evals');
171}
172threads->new(\&safe_re)->join();
173
174# tests in threads don't get counted, so
175curr_test(curr_test() + 1);
176
177# This used to crash in 5.10.0 [perl #64954]
178
179undef *a;
180threads->new(sub {})->join;
181pass("undefing a typeglob doesn't cause a crash during cloning");
182
183
184# Test we don't get:
185# panic: del_backref during global destruction.
186# when returning a non-closure sub from a thread and subsequently starting
187# a new thread.
188fresh_perl_is(<<'EOI', 'ok', { }, 'No del_backref panic [perl #70748]');
189use threads;
190sub foo { return (sub { }); }
191my $bar = threads->create(\&foo)->join();
192threads->create(sub { })->join();
193print "ok";
194EOI
195
196# Another, more reliable test for the same del_backref bug:
197fresh_perl_is(
198 <<'   EOJ', 'ok', {}, 'No del_backref panic [perl #70748] (2)'
199   use threads;
200   push @bar, threads->create(sub{sub{}})->join() for 1...10;
201   print "ok";
202   EOJ
203);
204
205# Simple closure-returning test: At least this case works (though it
206# leaks), and we don't want to break it.
207fresh_perl_is(<<'EOJ', 'foo', {}, 'returning a closure');
208use threads;
209print create threads sub {
210 my $x = 'foo';
211 sub{sub{$x}}
212}=>->join->()()
213 //"undef"
214EOJ
215
216# At the point of thread creation, $h{1} is on the temps stack.
217# The weak reference $a, however, is visible from the symbol table.
218fresh_perl_is(<<'EOI', 'ok', { }, 'Test for 34394ecd06e704e9');
219    use threads;
220    %h = (1, 2);
221    use Scalar::Util 'weaken';
222    $a = \$h{1};
223    weaken($a);
224    delete $h{1} && threads->create(sub {}, shift)->join();
225    print 'ok';
226EOI
227
228# This will fail in "interesting" ways if stashes in clone_params is not
229# initialised correctly.
230fresh_perl_like(<<'EOI', qr/\AThread 1 terminated abnormally: Not a CODE reference/, { }, 'RT #73046');
231    use strict;
232    use threads;
233
234    sub foo::bar;
235
236    my %h = (1, *{$::{'foo::'}}{HASH});
237    *{$::{'foo::'}} = {};
238
239    threads->create({}, delete $h{1})->join();
240
241    print "end";
242EOI
243
244fresh_perl_is(<<'EOI', 'ok', { }, '0 refcnt neither on tmps stack nor in @_');
245    use threads;
246    my %h = (1, []);
247    use Scalar::Util 'weaken';
248    my $a = $h{1};
249    weaken($a);
250    delete $h{1} && threads->create(sub {}, shift)->join();
251    print 'ok';
252EOI
253
254{
255    my $got;
256    sub stuff {
257	my $a;
258	if (@_) {
259	    $a = "Leakage";
260	    threads->create(\&stuff)->join();
261	} else {
262	    is ($a, undef, 'RT #73086 - clone used to clone active pads');
263	}
264    }
265
266    stuff(1);
267
268    curr_test(curr_test() + 1);
269}
270
271{
272    my $got;
273    sub more_stuff {
274	my $a;
275	$::b = \$a;
276	if (@_) {
277	    $a = "More leakage";
278	    threads->create(\&more_stuff)->join();
279	} else {
280	    is ($a, undef, 'Just special casing lexicals in ?{ ... }');
281	}
282    }
283
284    more_stuff(1);
285
286    curr_test(curr_test() + 1);
287}
288
289# Test from Jerry Hedden, reduced by him from Object::InsideOut's tests.
290fresh_perl_is(<<'EOI', 'ok', { }, '0 refcnt during CLONE');
291use strict;
292use warnings;
293
294use threads;
295
296{
297    package My::Obj;
298    use Scalar::Util 'weaken';
299
300    my %reg;
301
302    sub new
303    {
304        # Create object with ID = 1
305        my $class = shift;
306        my $id = 1;
307        my $obj = bless(\do{ my $scalar = $id; }, $class);
308
309        # Save weak copy of object for reference during cloning
310        weaken($reg{$id} = $obj);
311
312        # Return object
313        return $obj;
314    }
315
316    # Return the internal ID of the object
317    sub id
318    {
319        my $obj = shift;
320        return $$obj;
321    }
322
323    # During cloning 'look' at the object
324    sub CLONE {
325        foreach my $id (keys(%reg)) {
326            # This triggers SvREFCNT_inc() then SvREFCNT_dec() on the referent.
327            my $obj = $reg{$id};
328        }
329    }
330}
331
332# Create object in 'main' thread
333my $obj = My::Obj->new();
334my $id = $obj->id();
335die "\$id is '$id'" unless $id == 1;
336
337# Access object in thread
338threads->create(
339    sub {
340        print $obj->id() == 1 ? "ok\n" : "not ok '" . $obj->id() . "'\n";
341    }
342)->join();
343
344EOI
345
346# make sure peephole optimiser doesn't recurse heavily.
347# (We run this inside a thread to get a small stack)
348
349{
350    # lots of constructs that have o->op_other etc
351    my $code = <<'EOF';
352	$r = $x || $y;
353	$x ||= $y;
354	$r = $x // $y;
355	$x //= $y;
356	$r = $x && $y;
357	$x &&= $y;
358	$r = $x ? $y : $z;
359	@a = map $x+1, @a;
360	@a = grep $x+1, @a;
361	$r = /$x/../$y/;
362
363	# this one will fail since we removed tail recursion optimisation
364	# with f11ca51e41e8
365	#while (1) { $x = 0 };
366
367	while (0) { $x = 0 };
368	for ($x=0; $y; $z=0) { $r = 0 };
369	for (1) { $x = 0 };
370	{ $x = 0 };
371	$x =~ s/a/$x + 1/e;
372EOF
373    $code = 'my ($r, $x,$y,$z,@a); return 5; ' . ($code x 1000);
374    my $res = threads->create(sub { eval $code})->join;
375    is($res, 5, "avoid peephole recursion");
376}
377
378
379# [perl #78494] Pipes shared between threads block when closed
380{
381  my $perl = which_perl;
382  $perl = qq'"$perl"' if $perl =~ /\s/;
383  open(my $OUT, "|$perl") || die("ERROR: $!");
384  threads->create(sub { })->join;
385  ok(1, "Pipes shared between threads do not block when closed");
386}
387
388# [perl #105208] Typeglob clones should not be cloned again during a join
389{
390  threads->create(sub { sub { $::hypogamma = 3 } })->join->();
391  is $::hypogamma, 3, 'globs cloned and joined are not recloned';
392}
393
394fresh_perl_is(
395  'use threads;' .
396  'async { delete $::{INC}; eval q"my $foo : bar" } ->join; print "ok\n";',
397  "ok",
398   {},
399  'no crash when deleting $::{INC} in thread'
400);
401
402fresh_perl_is(<<'CODE', 'ok', {}, 'no crash modifying extended array element');
403use threads;
404my @a = 1;
405threads->create(sub { $#a = 1; $a[1] = 2; print qq/ok\n/ })->join;
406CODE
407
408fresh_perl_is(<<'CODE', '3.5,3.5', {}, 'RT #36664: Strange behavior of shared array');
409use threads;
410use threads::shared;
411
412our @List : shared = (1..5);
413my $v = 3.5;
414$v > 0;
415$List[3] = $v;
416printf "%s,%s", @List[(3)], $List[3];
417CODE
418
419fresh_perl_like(<<'CODE', qr/ok/, {}, 'RT #41121 binmode(STDOUT,":encoding(utf8) does not crash');
420use threads;
421binmode(STDOUT,":encoding(utf8)");
422threads->create(sub{});
423print "ok\n";
424CODE
425
426# EOF
427