9 my ($module, $thread_safe_var);
11 $module = 'Scope::Upper';
12 $thread_safe_var = 'Scope::Upper::SU_THREADSAFE()';
19 if (defined &Scope::Upper::reap) {
20 &Scope::Upper::reap(sub { $var *= 2 });
34 # Keep the rest of the file untouched
39 if (defined $thread_safe_var) {
40 my $stat = run_perl "require POSIX; require $module; exit($thread_safe_var ? POSIX::EXIT_SUCCESS() : POSIX::EXIT_FAILURE())";
44 if ($res == POSIX::EXIT_SUCCESS()) {
46 } elsif ($res == POSIX::EXIT_FAILURE()) {
50 if (not defined $is_threadsafe) {
51 skip_all "Could not detect if $module is thread safe or not";
55 VPIT::TestHelpers->import(
56 threads => [ $module => $is_threadsafe ],
60 my $could_not_create_thread = 'Could not create thread';
62 use Test::Leaner tests => 1 + (2 + 2 * 2) + 6 + (2 * 4 + 1) * 2 + 1;
65 my ($affirmative, $desc) = @_;
67 my $res = load_test();
72 $desc = "$desc: module loaded";
75 $desc = "$desc: module not loaded";
78 unless (is $res, $expected, $desc) {
79 $res = defined $res ? "'$res'" : 'undef';
80 $expected = "'$expected'";
81 diag("Test '$desc' failed: got $res, expected $expected");
89 my $code = eval "sub { require $module }";
94 is_loaded 0, 'main body, beginning';
96 # Test serial loadings
100 my $here = "first serial thread";
101 is_loaded 0, "$here, beginning";
104 is_loaded 1, "$here, after loading";
109 skip "$could_not_create_thread (serial 1)" => 2 unless defined $thr;
112 if (my $err = $thr->error) {
117 is_loaded 0, 'main body, in between serial loadings';
120 my $thr = spawn(sub {
121 my $here = "second serial thread";
122 is_loaded 0, "$here, beginning";
125 is_loaded 1, "$here, after loading";
130 skip "$could_not_create_thread (serial 2)" => 2 unless defined $thr;
133 if (my $err = $thr->error) {
138 is_loaded 0, 'main body, after serial loadings';
140 # Test nested loadings
143 my $thr = spawn(sub {
144 my $here = 'parent thread';
145 is_loaded 0, "$here, beginning";
148 my $kid = spawn(sub {
149 my $here = 'child thread';
150 is_loaded 0, "$here, beginning";
153 is_loaded 1, "$here, after loading";
158 skip "$could_not_create_thread (nested child)" => 2 unless defined $kid;
161 if (my $err = $kid->error) {
162 die "in child thread: $err\n";
166 is_loaded 0, "$here, after child terminated";
169 is_loaded 1, "$here, after loading";
174 skip "$could_not_create_thread (nested parent)" => (3 + 2) unless defined $thr;
177 if (my $err = $thr->error) {
182 is_loaded 0, 'main body, after nested loadings';
184 # Test parallel loadings
191 my @locks_down = (1) x $sync_points;
192 my @locks_up = (0) x $sync_points;
193 share($_) for @locks_down, @locks_up;
195 my $default_peers = 2;
198 my ($id, $peers) = @_;
200 $peers = $default_peers unless defined $peers;
203 lock $locks_down[$id];
204 $locks_down[$id] = 0;
205 cond_broadcast $locks_down[$id];
210 cond_wait $locks_up[$id] until $locks_up[$id] == $peers;
218 lock $locks_down[$id];
219 cond_wait $locks_down[$id] until $locks_down[$id] == 0;
225 cond_signal $locks_up[$id];
229 for my $first_thread_ends_first (0, 1) {
230 for my $id (0 .. $sync_points - 1) {
232 lock $locks_down[$id];
233 $locks_down[$id] = 1;
241 my $thr1_end = 'finishes first';
242 my $thr2_end = 'finishes last';
244 ($thr1_end, $thr2_end) = ($thr2_end, $thr1_end)
245 unless $first_thread_ends_first;
248 my $thr1 = spawn(sub {
249 my $here = "first simultaneous thread ($thr1_end)";
252 is_loaded 0, "$here, beginning";
256 is_loaded 1, "$here, after loading";
261 is_loaded 1, "$here, still loaded while also loaded in the other thread";
264 sync_slave 6 unless $first_thread_ends_first;
266 is_loaded 1, "$here, end";
271 skip "$could_not_create_thread (parallel 1)" => (4 * 2) unless defined $thr1;
273 my $thr2 = spawn(sub {
274 my $here = "second simultaneous thread ($thr2_end)";
277 is_loaded 0, "$here, beginning";
282 is_loaded 0, "$here, loaded in other thread but not here";
285 is_loaded 1, "$here, after loading";
289 sync_slave 6 if $first_thread_ends_first;
291 is_loaded 1, "$here, end";
296 sync_master($_) for 0 .. 5;
299 ($thr2, $thr1) = ($thr1, $thr2) unless $first_thread_ends_first;
302 if (my $err = $thr1->error) {
309 if (my $err = $thr1->error) {
313 sync_master(6, 1) unless $first_thread_ends_first;
316 if (my $err = $thr1->error) {
320 skip "$could_not_create_thread (parallel 2)" => (4 * 1);
324 is_loaded 0, 'main body, after simultaneous threads';
328 is_loaded 1, 'main body, loaded at end';