1use strict;
2use warnings;
3
4BEGIN {
5    # Import test.pl into its own package
6    {
7        package Test;
8        require($ENV{PERL_CORE} ? '../../t/test.pl' : './t/test.pl');
9    }
10
11    use Config;
12    if (! $Config{'useithreads'}) {
13        Test::skip_all(q/Perl not compiled with 'useithreads'/);
14    }
15}
16
17use ExtUtils::testlib;
18
19sub ok {
20    my ($id, $ok, $name) = @_;
21
22    # You have to do it this way or VMS will get confused.
23    if ($ok) {
24        print("ok $id - $name\n");
25    } else {
26        print("not ok $id - $name\n");
27        printf("# Failed test at line %d\n", (caller)[2]);
28    }
29
30    return ($ok);
31}
32
33BEGIN {
34    $| = 1;
35    print("1..91\n");   ### Number of tests that will be run ###
36};
37
38use threads;
39use threads::shared;
40
41Test::watchdog(300);   # In case we get stuck
42
43my $TEST = 1;
44ok($TEST++, 1, 'Loaded');
45
46### Start of Testing ###
47
48# cond_wait and cond_timedwait extended tests adapted from cond.t
49
50# The two skips later on in these tests refer to this quote from the
51# pod/perl583delta.pod:
52#
53# =head1 Platform Specific Problems
54#
55# The regression test ext/threads/shared/t/wait.t fails on early RedHat 9
56# and HP-UX 10.20 due to bugs in their threading implementations.
57# RedHat users should see https://rhn.redhat.com/errata/RHBA-2003-136.html
58# and consider upgrading their glibc.
59
60
61# - TEST basics
62
63ok($TEST++, defined &cond_wait, "cond_wait() present");
64ok($TEST++, (prototype(\&cond_wait) eq '\[$@%];\[$@%]'),
65                q/cond_wait() prototype '\[$@%];\[$@%]'/);
66ok($TEST++, defined &cond_timedwait, "cond_timedwait() present");
67ok($TEST++, (prototype(\&cond_timedwait) eq '\[$@%]$;\[$@%]'),
68                q/cond_timedwait() prototype '\[$@%]$;\[$@%]'/);
69
70
71my @wait_how = (
72    "simple",  # cond var == lock var; implicit lock; e.g.: cond_wait($c)
73    "repeat",  # cond var == lock var; explicit lock; e.g.: cond_wait($c, $c)
74    "twain"    # cond var != lock var; explicit lock; e.g.: cond_wait($c, $l)
75);
76
77
78SYNC_SHARED: {
79    my $test_type :shared;   # simple|repeat|twain
80
81    my $cond :shared;
82    my $lock :shared;
83
84    ok($TEST++, 1, "Shared synchronization tests preparation");
85
86    sub signaller
87    {
88        my $testno = $_[0];
89
90        ok($testno++, 1, "$test_type: child before lock");
91        $test_type =~ /twain/ ? lock($lock) : lock($cond);
92        ok($testno++, 1, "$test_type: child obtained lock");
93
94        if ($test_type =~ 'twain') {
95            no warnings 'threads';   # lock var != cond var, so disable warnings
96            cond_signal($cond);
97        } else {
98            cond_signal($cond);
99        }
100        ok($testno++, 1, "$test_type: child signalled condition");
101
102        return($testno);
103    }
104
105    # - TEST cond_wait
106
107    sub cw
108    {
109        my ($testnum, $to) = @_;
110
111        # Which lock to obtain?
112        $test_type =~ /twain/ ? lock($lock) : lock($cond);
113        ok($testnum++, 1, "$test_type: obtained initial lock");
114
115        my $thr = threads->create(\&signaller, $testnum);
116        for ($test_type) {
117            cond_wait($cond), last        if /simple/;
118            cond_wait($cond, $cond), last if /repeat/;
119            cond_wait($cond, $lock), last if /twain/;
120            die "$test_type: unknown test\n";
121        }
122        $testnum = $thr->join();
123        ok($testnum++, 1, "$test_type: condition obtained");
124
125        return ($testnum);
126    }
127
128    foreach (@wait_how) {
129        $test_type = "cond_wait [$_]";
130        my $thr = threads->create(\&cw, $TEST);
131        $TEST = $thr->join();
132    }
133
134    # - TEST cond_timedwait success
135
136    sub ctw_ok
137    {
138        my ($testnum, $to) = @_;
139
140        # Which lock to obtain?
141        $test_type =~ /twain/ ? lock($lock) : lock($cond);
142        ok($testnum++, 1, "$test_type: obtained initial lock");
143
144        my $thr = threads->create(\&signaller, $testnum);
145        my $ok = 0;
146        for ($test_type) {
147            $ok = cond_timedwait($cond, time() + $to), last        if /simple/;
148            $ok = cond_timedwait($cond, time() + $to, $cond), last if /repeat/;
149            $ok = cond_timedwait($cond, time() + $to, $lock), last if /twain/;
150            die "$test_type: unknown test\n";
151        }
152        $testnum = $thr->join();
153        ok($testnum++, $ok, "$test_type: condition obtained");
154
155        return ($testnum);
156    }
157
158    foreach (@wait_how) {
159        $test_type = "cond_timedwait [$_]";
160        my $thr = threads->create(\&ctw_ok, $TEST, 5);
161        $TEST = $thr->join();
162    }
163
164    # - TEST cond_timedwait timeout
165
166    sub ctw_fail
167    {
168        my ($testnum, $to) = @_;
169
170        if ($^O eq "hpux" && $Config{osvers} <= 10.20) {
171            # The lock obtaining would pass, but the wait will not.
172            ok($testnum++, 1, "$test_type: obtained initial lock");
173            ok($testnum++, 0, "# SKIP see perl583delta");
174
175        } else {
176            $test_type =~ /twain/ ? lock($lock) : lock($cond);
177            ok($testnum++, 1, "$test_type: obtained initial lock");
178            my $ok;
179            for ($test_type) {
180                $ok = cond_timedwait($cond, time() + $to), last        if /simple/;
181                $ok = cond_timedwait($cond, time() + $to, $cond), last if /repeat/;
182                $ok = cond_timedwait($cond, time() + $to, $lock), last if /twain/;
183                die "$test_type: unknown test\n";
184            }
185            ok($testnum++, ! defined($ok), "$test_type: timeout");
186        }
187
188        return ($testnum);
189    }
190
191    foreach (@wait_how) {
192        $test_type = "cond_timedwait pause, timeout [$_]";
193        my $thr = threads->create(\&ctw_fail, $TEST, 3);
194        $TEST = $thr->join();
195    }
196
197    foreach (@wait_how) {
198        $test_type = "cond_timedwait instant timeout [$_]";
199        my $thr = threads->create(\&ctw_fail, $TEST, -60);
200        $TEST = $thr->join();
201    }
202
203} # -- SYNCH_SHARED block
204
205
206# same as above, but with references to lock and cond vars
207
208SYNCH_REFS: {
209    my $test_type :shared;   # simple|repeat|twain
210
211    my $true_cond :shared;
212    my $true_lock :shared;
213
214    my $cond = \$true_cond;
215    my $lock = \$true_lock;
216
217    ok($TEST++, 1, "Synchronization reference tests preparation");
218
219    sub signaller2
220    {
221        my $testno = $_[0];
222
223        ok($testno++, 1, "$test_type: child before lock");
224        $test_type =~ /twain/ ? lock($lock) : lock($cond);
225        ok($testno++, 1, "$test_type: child obtained lock");
226
227        if ($test_type =~ 'twain') {
228            no warnings 'threads';   # lock var != cond var, so disable warnings
229            cond_signal($cond);
230        } else {
231            cond_signal($cond);
232        }
233        ok($testno++, 1, "$test_type: child signalled condition");
234
235        return($testno);
236    }
237
238    # - TEST cond_wait
239
240    sub cw2
241    {
242        my ($testnum, $to) = @_;
243
244        # Which lock to obtain?
245        $test_type =~ /twain/ ? lock($lock) : lock($cond);
246        ok($testnum++, 1, "$test_type: obtained initial lock");
247
248        my $thr = threads->create(\&signaller2, $testnum);
249        for ($test_type) {
250            cond_wait($cond), last        if /simple/;
251            cond_wait($cond, $cond), last if /repeat/;
252            cond_wait($cond, $lock), last if /twain/;
253            die "$test_type: unknown test\n";
254        }
255        $testnum = $thr->join();
256        ok($testnum++, 1, "$test_type: condition obtained");
257
258        return ($testnum);
259    }
260
261    foreach (@wait_how) {
262        $test_type = "cond_wait [$_]";
263        my $thr = threads->create(\&cw2, $TEST);
264        $TEST = $thr->join();
265    }
266
267    # - TEST cond_timedwait success
268
269    sub ctw_ok2
270    {
271        my ($testnum, $to) = @_;
272
273        # Which lock to obtain?
274        $test_type =~ /twain/ ? lock($lock) : lock($cond);
275        ok($testnum++, 1, "$test_type: obtained initial lock");
276
277        my $thr = threads->create(\&signaller2, $testnum);
278        my $ok = 0;
279        for ($test_type) {
280            $ok = cond_timedwait($cond, time() + $to), last        if /simple/;
281            $ok = cond_timedwait($cond, time() + $to, $cond), last if /repeat/;
282            $ok = cond_timedwait($cond, time() + $to, $lock), last if /twain/;
283            die "$test_type: unknown test\n";
284        }
285        $testnum = $thr->join();
286        ok($testnum++, $ok, "$test_type: condition obtained");
287
288        return ($testnum);
289    }
290
291    foreach (@wait_how) {
292        $test_type = "cond_timedwait [$_]";
293        my $thr = threads->create(\&ctw_ok2, $TEST, 5);
294        $TEST = $thr->join();
295    }
296
297    # - TEST cond_timedwait timeout
298
299    sub ctw_fail2
300    {
301        my ($testnum, $to) = @_;
302
303        if ($^O eq "hpux" && $Config{osvers} <= 10.20) {
304            # The lock obtaining would pass, but the wait will not.
305            ok($testnum++, 1, "$test_type: obtained initial lock");
306            ok($testnum++, 0, "# SKIP see perl583delta");
307
308        } else {
309            $test_type =~ /twain/ ? lock($lock) : lock($cond);
310            ok($testnum++, 1, "$test_type: obtained initial lock");
311            my $ok;
312            for ($test_type) {
313                $ok = cond_timedwait($cond, time() + $to), last        if /simple/;
314                $ok = cond_timedwait($cond, time() + $to, $cond), last if /repeat/;
315                $ok = cond_timedwait($cond, time() + $to, $lock), last if /twain/;
316                die "$test_type: unknown test\n";
317            }
318            ok($testnum++, ! defined($ok), "$test_type: timeout");
319        }
320
321        return ($testnum);
322    }
323
324    foreach (@wait_how) {
325        $test_type = "cond_timedwait pause, timeout [$_]";
326        my $thr = threads->create(\&ctw_fail2, $TEST, 3);
327        $TEST = $thr->join();
328    }
329
330    foreach (@wait_how) {
331        $test_type = "cond_timedwait instant timeout [$_]";
332        my $thr = threads->create(\&ctw_fail2, $TEST, -60);
333        $TEST = $thr->join();
334    }
335
336} # -- SYNCH_REFS block
337
338# Done
339exit(0);
340
341# EOF
342