9 BEGIN { delete $ENV{PERL_INDIRECT_PM_DISABLE} }
11 my ($module, $thread_safe_var);
14 $thread_safe_var = 'indirect::I_THREADSAFE()';
19 if (defined &indirect::msg) {
21 eval 'BEGIN { indirect->unimport(":fatal") if defined &indirect::msg } return; my $x = new X;';
24 if (defined $res and $res =~ /^Indirect call of method/) {
26 } elsif (not defined $res or $res eq '') {
33 # Keep the rest of the file untouched
38 if (defined $thread_safe_var) {
39 my $stat = run_perl "require POSIX; require $module; exit($thread_safe_var ? POSIX::EXIT_SUCCESS() : POSIX::EXIT_FAILURE())";
43 if ($res == POSIX::EXIT_SUCCESS()) {
45 } elsif ($res == POSIX::EXIT_FAILURE()) {
49 if (not defined $is_threadsafe) {
50 skip_all "Could not detect if $module is thread safe or not";
54 VPIT::TestHelpers->import(
55 threads => [ $module => $is_threadsafe ],
59 my $could_not_create_thread = 'Could not create thread';
61 use Test::Leaner tests => 1 + (2 + 2 * 2) + 6 + (2 * 4 + 1) * 2 + 1;
64 my ($affirmative, $desc) = @_;
66 my $res = load_test();
71 $desc = "$desc: module loaded";
74 $desc = "$desc: module not loaded";
77 unless (is $res, $expected, $desc) {
78 $res = defined $res ? "'$res'" : 'undef';
79 $expected = "'$expected'";
80 diag("Test '$desc' failed: got $res, expected $expected");
88 my $code = eval "sub { require $module }";
93 is_loaded 0, 'main body, beginning';
95 # Test serial loadings
99 my $here = "first serial thread";
100 is_loaded 0, "$here, beginning";
103 is_loaded 1, "$here, after loading";
108 skip "$could_not_create_thread (serial 1)" => 2 unless defined $thr;
111 if (my $err = $thr->error) {
116 is_loaded 0, 'main body, in between serial loadings';
119 my $thr = spawn(sub {
120 my $here = "second serial thread";
121 is_loaded 0, "$here, beginning";
124 is_loaded 1, "$here, after loading";
129 skip "$could_not_create_thread (serial 2)" => 2 unless defined $thr;
132 if (my $err = $thr->error) {
137 is_loaded 0, 'main body, after serial loadings';
139 # Test nested loadings
142 my $thr = spawn(sub {
143 my $here = 'parent thread';
144 is_loaded 0, "$here, beginning";
147 my $kid = spawn(sub {
148 my $here = 'child thread';
149 is_loaded 0, "$here, beginning";
152 is_loaded 1, "$here, after loading";
157 skip "$could_not_create_thread (nested child)" => 2 unless defined $kid;
160 if (my $err = $kid->error) {
161 die "in child thread: $err\n";
165 is_loaded 0, "$here, after child terminated";
168 is_loaded 1, "$here, after loading";
173 skip "$could_not_create_thread (nested parent)" => (3 + 2) unless defined $thr;
176 if (my $err = $thr->error) {
181 is_loaded 0, 'main body, after nested loadings';
183 # Test parallel loadings
190 my @locks_down = (1) x $sync_points;
191 my @locks_up = (0) x $sync_points;
192 share($_) for @locks_down, @locks_up;
194 my $default_peers = 2;
197 my ($id, $peers) = @_;
199 $peers = $default_peers unless defined $peers;
202 lock $locks_down[$id];
203 $locks_down[$id] = 0;
204 cond_broadcast $locks_down[$id];
209 cond_wait $locks_up[$id] until $locks_up[$id] == $peers;
217 lock $locks_down[$id];
218 cond_wait $locks_down[$id] until $locks_down[$id] == 0;
224 cond_signal $locks_up[$id];
228 for my $first_thread_ends_first (0, 1) {
229 for my $id (0 .. $sync_points - 1) {
231 lock $locks_down[$id];
232 $locks_down[$id] = 1;
240 my $thr1_end = 'finishes first';
241 my $thr2_end = 'finishes last';
243 ($thr1_end, $thr2_end) = ($thr2_end, $thr1_end)
244 unless $first_thread_ends_first;
247 my $thr1 = spawn(sub {
248 my $here = "first simultaneous thread ($thr1_end)";
251 is_loaded 0, "$here, beginning";
255 is_loaded 1, "$here, after loading";
260 is_loaded 1, "$here, still loaded while also loaded in the other thread";
263 sync_slave 6 unless $first_thread_ends_first;
265 is_loaded 1, "$here, end";
270 skip "$could_not_create_thread (parallel 1)" => (4 * 2) unless defined $thr1;
272 my $thr2 = spawn(sub {
273 my $here = "second simultaneous thread ($thr2_end)";
276 is_loaded 0, "$here, beginning";
281 is_loaded 0, "$here, loaded in other thread but not here";
284 is_loaded 1, "$here, after loading";
288 sync_slave 6 if $first_thread_ends_first;
290 is_loaded 1, "$here, end";
295 sync_master($_) for 0 .. 5;
298 ($thr2, $thr1) = ($thr1, $thr2) unless $first_thread_ends_first;
301 if (my $err = $thr1->error) {
308 if (my $err = $thr1->error) {
312 sync_master(6, 1) unless $first_thread_ends_first;
315 if (my $err = $thr1->error) {
319 skip "$could_not_create_thread (parallel 2)" => (4 * 1);
323 is_loaded 0, 'main body, after simultaneous threads';
327 is_loaded 1, 'main body, loaded at end';