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