1use strict;
2use warnings;
3
4BEGIN {
5    use Config;
6    if (! $Config{'useithreads'}) {
7        print("1..0 # SKIP Perl not compiled with 'useithreads'\n");
8        exit(0);
9    }
10    if ($] < 5.010) {
11        print("1..0 # SKIP Needs Perl 5.10.0 or later\n");
12        exit(0);
13    }
14}
15
16use ExtUtils::testlib;
17
18BEGIN {
19    $| = 1;
20    print("1..133\n");   ### Number of tests that will be run ###
21};
22
23use threads;
24use threads::shared;
25
26my $TEST;
27BEGIN {
28    share($TEST);
29    $TEST = 1;
30}
31
32sub ok {
33    my ($ok, $name) = @_;
34
35    lock($TEST);
36    my $id = $TEST++;
37
38    # You have to do it this way or VMS will get confused.
39    if ($ok) {
40        print("ok $id - $name\n");
41    } else {
42        print("not ok $id - $name\n");
43        printf("# Failed test at line %d\n", (caller)[2]);
44    }
45
46    return ($ok);
47}
48
49ok(1, 'Loaded');
50
51### Start of Testing ###
52
53my $ID :shared = -1;
54my (@created, @destroyed);
55
56{ package HashObj;
57   sub new {
58       my $class = shift;
59       my $self = &threads::shared::share({});
60       $$self{'ID'} = ++$ID;
61       $created[$ID] = 1;
62       return bless($self, $class);
63   }
64
65   sub DESTROY {
66       my $self = shift;
67       $destroyed[$$self{'ID'}] = 1;
68   }
69}
70
71{ package AryObj;
72   sub new {
73       my $class = shift;
74       my $self = &threads::shared::share([]);
75       $$self[0] = ++$ID;
76       $created[$ID] = 1;
77       return bless($self, $class);
78   }
79
80   sub DESTROY {
81       my $self = shift;
82       $destroyed[$$self[0]] = 1;
83   }
84}
85
86{ package SclrObj;
87   sub new {
88       my $class = shift;
89       my $self = \do{ my $scalar = ++$ID; };
90       $created[$ID] = 1;
91       threads::shared::share($self);
92       return bless($self, $class);
93   }
94
95   sub DESTROY {
96       my $self = shift;
97       $destroyed[$$self] = 1;
98   }
99}
100
101# Testing with normal array
102my @normal_ary;
103
104# Testing with hash object
105$normal_ary[0] = HashObj->new();
106ok($created[$ID], 'Created hash object in normal array');
107delete($normal_ary[0]);
108ok($destroyed[$ID], 'Deleted hash object in normal array');
109
110$normal_ary[0] = HashObj->new();
111ok($created[$ID], 'Created hash object in normal array');
112$normal_ary[0] = undef;
113ok($destroyed[$ID], 'Undef hash object in normal array');
114
115$normal_ary[0] = HashObj->new();
116ok($created[$ID], 'Created hash object in normal array');
117$normal_ary[0] = HashObj->new();
118ok($created[$ID], 'Created hash object in normal array');
119ok($destroyed[$ID-1], 'Replaced hash object in normal array');
120@normal_ary = ();
121ok($destroyed[$ID], 'Hash object removed from cleared normal array');
122
123$normal_ary[0] = HashObj->new();
124ok($created[$ID], 'Created hash object in normal array');
125undef(@normal_ary);
126ok($destroyed[$ID], 'Hash object removed from undef normal array');
127
128# Testing with array object
129$normal_ary[0] = AryObj->new();
130ok($created[$ID], 'Created array object in normal array');
131delete($normal_ary[0]);
132ok($destroyed[$ID], 'Deleted array object in normal array');
133
134$normal_ary[0] = AryObj->new();
135ok($created[$ID], 'Created array object in normal array');
136$normal_ary[0] = undef;
137ok($destroyed[$ID], 'Undef array object in normal array');
138
139$normal_ary[0] = AryObj->new();
140ok($created[$ID], 'Created array object in normal array');
141$normal_ary[0] = AryObj->new();
142ok($created[$ID], 'Created array object in normal array');
143ok($destroyed[$ID-1], 'Replaced array object in normal array');
144@normal_ary = ();
145ok($destroyed[$ID], 'Array object removed from cleared normal array');
146
147$normal_ary[0] = AryObj->new();
148ok($created[$ID], 'Created array object in normal array');
149undef(@normal_ary);
150ok($destroyed[$ID], 'Array object removed from undef normal array');
151
152# Testing with scalar object
153$normal_ary[0] = SclrObj->new();
154ok($created[$ID], 'Created scalar object in normal array');
155delete($normal_ary[0]);
156ok($destroyed[$ID], 'Deleted scalar object in normal array');
157
158$normal_ary[0] = SclrObj->new();
159ok($created[$ID], 'Created scalar object in normal array');
160$normal_ary[0] = undef;
161ok($destroyed[$ID], 'Undef scalar object in normal array');
162
163$normal_ary[0] = SclrObj->new();
164ok($created[$ID], 'Created scalar object in normal array');
165$normal_ary[0] = SclrObj->new();
166ok($created[$ID], 'Created scalar object in normal array');
167ok($destroyed[$ID-1], 'Replaced scalar object in normal array');
168@normal_ary = ();
169ok($destroyed[$ID], 'Scalar object removed from cleared normal array');
170
171$normal_ary[0] = SclrObj->new();
172ok($created[$ID], 'Created scalar object in normal array');
173undef(@normal_ary);
174ok($destroyed[$ID], 'Scalar object removed from undef normal array');
175
176# Testing with normal hash
177my %normal_hash;
178
179# Testing with hash object
180$normal_hash{'obj'} = HashObj->new();
181ok($created[$ID], 'Created hash object in normal hash');
182delete($normal_hash{'obj'});
183ok($destroyed[$ID], 'Deleted hash object in normal hash');
184
185$normal_hash{'obj'} = HashObj->new();
186ok($created[$ID], 'Created hash object in normal hash');
187$normal_hash{'obj'} = undef;
188ok($destroyed[$ID], 'Undef hash object in normal hash');
189
190$normal_hash{'obj'} = HashObj->new();
191ok($created[$ID], 'Created hash object in normal hash');
192$normal_hash{'obj'} = HashObj->new();
193ok($created[$ID], 'Created hash object in normal hash');
194ok($destroyed[$ID-1], 'Replaced hash object in normal hash');
195%normal_hash = ();
196ok($destroyed[$ID], 'Hash object removed from cleared normal hash');
197
198$normal_hash{'obj'} = HashObj->new();
199ok($created[$ID], 'Created hash object in normal hash');
200undef(%normal_hash);
201ok($destroyed[$ID], 'Hash object removed from undef normal hash');
202
203# Testing with array object
204$normal_hash{'obj'} = AryObj->new();
205ok($created[$ID], 'Created array object in normal hash');
206delete($normal_hash{'obj'});
207ok($destroyed[$ID], 'Deleted array object in normal hash');
208
209$normal_hash{'obj'} = AryObj->new();
210ok($created[$ID], 'Created array object in normal hash');
211$normal_hash{'obj'} = undef;
212ok($destroyed[$ID], 'Undef array object in normal hash');
213
214$normal_hash{'obj'} = AryObj->new();
215ok($created[$ID], 'Created array object in normal hash');
216$normal_hash{'obj'} = AryObj->new();
217ok($created[$ID], 'Created array object in normal hash');
218ok($destroyed[$ID-1], 'Replaced array object in normal hash');
219%normal_hash = ();
220ok($destroyed[$ID], 'Array object removed from cleared normal hash');
221
222$normal_hash{'obj'} = AryObj->new();
223ok($created[$ID], 'Created array object in normal hash');
224undef(%normal_hash);
225ok($destroyed[$ID], 'Array object removed from undef normal hash');
226
227# Testing with scalar object
228$normal_hash{'obj'} = SclrObj->new();
229ok($created[$ID], 'Created scalar object in normal hash');
230delete($normal_hash{'obj'});
231ok($destroyed[$ID], 'Deleted scalar object in normal hash');
232
233$normal_hash{'obj'} = SclrObj->new();
234ok($created[$ID], 'Created scalar object in normal hash');
235$normal_hash{'obj'} = undef;
236ok($destroyed[$ID], 'Undef scalar object in normal hash');
237
238$normal_hash{'obj'} = SclrObj->new();
239ok($created[$ID], 'Created scalar object in normal hash');
240$normal_hash{'obj'} = SclrObj->new();
241ok($created[$ID], 'Created scalar object in normal hash');
242ok($destroyed[$ID-1], 'Replaced scalar object in normal hash');
243%normal_hash = ();
244ok($destroyed[$ID], 'Scalar object removed from cleared normal hash');
245
246$normal_hash{'obj'} = SclrObj->new();
247ok($created[$ID], 'Created scalar object in normal hash');
248undef(%normal_hash);
249ok($destroyed[$ID], 'Scalar object removed from undef normal hash');
250
251# Testing with shared array
252my @shared_ary :shared;
253
254# Testing with hash object
255$shared_ary[0] = HashObj->new();
256ok($created[$ID], 'Created hash object in shared array');
257delete($shared_ary[0]);
258ok($destroyed[$ID], 'Deleted hash object in shared array');
259
260$shared_ary[0] = HashObj->new();
261ok($created[$ID], 'Created hash object in shared array');
262$shared_ary[0] = undef;
263ok($destroyed[$ID], 'Undef hash object in shared array');
264
265$shared_ary[0] = HashObj->new();
266ok($created[$ID], 'Created hash object in shared array');
267$shared_ary[0] = HashObj->new();
268ok($created[$ID], 'Created hash object in shared array');
269ok($destroyed[$ID-1], 'Replaced hash object in shared array');
270@shared_ary = ();
271ok($destroyed[$ID], 'Hash object removed from cleared shared array');
272
273$shared_ary[0] = HashObj->new();
274ok($created[$ID], 'Created hash object in shared array');
275undef(@shared_ary);
276ok($destroyed[$ID], 'Hash object removed from undef shared array');
277
278# Testing with array object
279$shared_ary[0] = AryObj->new();
280ok($created[$ID], 'Created array object in shared array');
281delete($shared_ary[0]);
282ok($destroyed[$ID], 'Deleted array object in shared array');
283
284$shared_ary[0] = AryObj->new();
285ok($created[$ID], 'Created array object in shared array');
286$shared_ary[0] = undef;
287ok($destroyed[$ID], 'Undef array object in shared array');
288
289$shared_ary[0] = AryObj->new();
290ok($created[$ID], 'Created array object in shared array');
291$shared_ary[0] = AryObj->new();
292ok($created[$ID], 'Created array object in shared array');
293ok($destroyed[$ID-1], 'Replaced array object in shared array');
294@shared_ary = ();
295ok($destroyed[$ID], 'Array object removed from cleared shared array');
296
297$shared_ary[0] = AryObj->new();
298ok($created[$ID], 'Created array object in shared array');
299undef(@shared_ary);
300ok($destroyed[$ID], 'Array object removed from undef shared array');
301
302# Testing with scalar object
303$shared_ary[0] = SclrObj->new();
304ok($created[$ID], 'Created scalar object in shared array');
305delete($shared_ary[0]);
306ok($destroyed[$ID], 'Deleted scalar object in shared array');
307
308$shared_ary[0] = SclrObj->new();
309ok($created[$ID], 'Created scalar object in shared array');
310$shared_ary[0] = undef;
311ok($destroyed[$ID], 'Undef scalar object in shared array');
312
313$shared_ary[0] = SclrObj->new();
314ok($created[$ID], 'Created scalar object in shared array');
315$shared_ary[0] = SclrObj->new();
316ok($created[$ID], 'Created scalar object in shared array');
317ok($destroyed[$ID-1], 'Replaced scalar object in shared array');
318@shared_ary = ();
319ok($destroyed[$ID], 'Scalar object removed from cleared shared array');
320
321$shared_ary[0] = SclrObj->new();
322ok($created[$ID], 'Created scalar object in shared array');
323undef(@shared_ary);
324ok($destroyed[$ID], 'Scalar object removed from undef shared array');
325
326# Testing with shared hash
327my %shared_hash :shared;
328
329# Testing with hash object
330$shared_hash{'obj'} = HashObj->new();
331ok($created[$ID], 'Created hash object in shared hash');
332delete($shared_hash{'obj'});
333ok($destroyed[$ID], 'Deleted hash object in shared hash');
334
335$shared_hash{'obj'} = HashObj->new();
336ok($created[$ID], 'Created hash object in shared hash');
337$shared_hash{'obj'} = undef;
338ok($destroyed[$ID], 'Undef hash object in shared hash');
339
340$shared_hash{'obj'} = HashObj->new();
341ok($created[$ID], 'Created hash object in shared hash');
342$shared_hash{'obj'} = HashObj->new();
343ok($created[$ID], 'Created hash object in shared hash');
344ok($destroyed[$ID-1], 'Replaced hash object in shared hash');
345%shared_hash = ();
346ok($destroyed[$ID], 'Hash object removed from cleared shared hash');
347
348$shared_hash{'obj'} = HashObj->new();
349ok($created[$ID], 'Created hash object in shared hash');
350undef(%shared_hash);
351ok($destroyed[$ID], 'Hash object removed from undef shared hash');
352
353# Testing with array object
354$shared_hash{'obj'} = AryObj->new();
355ok($created[$ID], 'Created array object in shared hash');
356delete($shared_hash{'obj'});
357ok($destroyed[$ID], 'Deleted array object in shared hash');
358
359$shared_hash{'obj'} = AryObj->new();
360ok($created[$ID], 'Created array object in shared hash');
361$shared_hash{'obj'} = undef;
362ok($destroyed[$ID], 'Undef array object in shared hash');
363
364$shared_hash{'obj'} = AryObj->new();
365ok($created[$ID], 'Created array object in shared hash');
366$shared_hash{'obj'} = AryObj->new();
367ok($created[$ID], 'Created array object in shared hash');
368ok($destroyed[$ID-1], 'Replaced array object in shared hash');
369%shared_hash = ();
370ok($destroyed[$ID], 'Array object removed from cleared shared hash');
371
372$shared_hash{'obj'} = AryObj->new();
373ok($created[$ID], 'Created array object in shared hash');
374undef(%shared_hash);
375ok($destroyed[$ID], 'Array object removed from undef shared hash');
376
377# Testing with scalar object
378$shared_hash{'obj'} = SclrObj->new();
379ok($created[$ID], 'Created scalar object in shared hash');
380delete($shared_hash{'obj'});
381ok($destroyed[$ID], 'Deleted scalar object in shared hash');
382
383$shared_hash{'obj'} = SclrObj->new();
384ok($created[$ID], 'Created scalar object in shared hash');
385$shared_hash{'obj'} = undef;
386ok($destroyed[$ID], 'Undef scalar object in shared hash');
387
388$shared_hash{'obj'} = SclrObj->new();
389ok($created[$ID], 'Created scalar object in shared hash');
390$shared_hash{'obj'} = SclrObj->new();
391ok($created[$ID], 'Created scalar object in shared hash');
392ok($destroyed[$ID-1], 'Replaced scalar object in shared hash');
393%shared_hash = ();
394ok($destroyed[$ID], 'Scalar object removed from cleared shared hash');
395
396$shared_hash{'obj'} = SclrObj->new();
397ok($created[$ID], 'Created scalar object in shared hash');
398undef(%shared_hash);
399ok($destroyed[$ID], 'Scalar object removed from undef shared hash');
400
401# Testing with shared scalar
402{
403    my $shared_scalar : shared;
404    # Use a separate thread to make sure we have no private SV
405    async { $shared_scalar = SclrObj->new(); }->join();
406}
407ok($destroyed[$ID], 'Scalar object removed from shared scalar');
408
409#
410# RT #122950 abandoning array elements (e.g. by setting $#ary)
411# should trigger destructors
412
413{
414    package rt122950;
415
416    my $count = 0;
417    sub DESTROY { $count++ }
418
419    my $n = 4;
420
421    for my $type (0..1) {
422        my @a : shared;
423        $count = 0;
424        push @a, bless &threads::shared::share({}) for 1..$n;
425        for (1..$n) {
426            { # new scope to ensure tmps are freed, destructors called
427                if ($type) {
428                    pop @a;
429                }
430                else {
431                    $#a = $n - $_ - 1;
432                }
433            }
434            ::ok($count == $_,
435                "remove array object $_ by " . ($type ? "pop" : '$#a=N'));
436        }
437    }
438
439    my @a : shared;
440    $count = 0;
441    push @a, bless &threads::shared::share({}) for 1..$n;
442    {
443        undef @a; # this is implemented internally as $#a = -01
444    }
445    ::ok($count == $n, "remove array object by undef");
446}
447
448# RT #131124
449# Emptying a shared array creates new temp SVs. If there are no spare
450# SVs, a new arena is allocated. shared.xs was mallocing a new arena
451# with the wrong perl context set, meaning that when the arena was later
452# freed, it would "panic: realloc from wrong pool"
453#
454
455{
456    threads->new(sub {
457        my @a :shared;
458        push @a, bless &threads::shared::share({}) for 1..1000;
459        undef @a; # this creates lots of temp SVs
460    })->join;
461    ok(1, "#131124 undef array doesnt panic");
462
463    threads->new(sub {
464        my @a :shared;
465        push @a, bless &threads::shared::share({}) for 1..1000;
466        @a = (); # this creates lots of temp SVs
467    })->join;
468    ok(1, "#131124 clear array doesnt panic");
469}
470
471
472# EOF
473