6 my ($module, $thread_safe_var);
8 $module = 'Variable::Magic';
9 $thread_safe_var = 'Variable::Magic::VMG_THREADSAFE()';
14 if (defined &Variable::Magic::wizard) {
15 my $wiz = Variable::Magic::wizard(
16 free => sub { $res = 1; return },
19 &Variable::Magic::cast(\$var, $wiz);
25 # Keep the rest of the file untouched
28 use VPIT::TestHelpers threads => [ $module, $thread_safe_var ];
30 my $could_not_create_thread = 'Could not create thread';
33 tests => 1 + (2 + 2 * 2) + 6 + (2 * 4 + 1) * 2 + (4 + 1) + (6 + 1) + 1
37 my ($affirmative, $desc) = @_;
39 my $res = load_test();
44 $desc = "$desc: module loaded";
47 $desc = "$desc: module not loaded";
50 unless (is $res, $expected, $desc) {
51 $res = defined $res ? "'$res'" : 'undef';
52 $expected = "'$expected'";
53 diag("Test '$desc' failed: got $res, expected $expected");
61 my $code = eval "sub { require $module }";
66 is_loaded 0, 'main body, beginning';
68 # Test serial loadings
72 my $here = "first serial thread";
73 is_loaded 0, "$here, beginning";
76 is_loaded 1, "$here, after loading";
81 skip "$could_not_create_thread (serial 1)" => 2 unless defined $thr;
84 if (my $err = $thr->error) {
89 is_loaded 0, 'main body, in between serial loadings';
93 my $here = "second serial thread";
94 is_loaded 0, "$here, beginning";
97 is_loaded 1, "$here, after loading";
102 skip "$could_not_create_thread (serial 2)" => 2 unless defined $thr;
105 if (my $err = $thr->error) {
110 is_loaded 0, 'main body, after serial loadings';
112 # Test nested loadings
115 my $thr = spawn(sub {
116 my $here = 'parent thread';
117 is_loaded 0, "$here, beginning";
120 my $kid = spawn(sub {
121 my $here = 'child thread';
122 is_loaded 0, "$here, beginning";
125 is_loaded 1, "$here, after loading";
130 skip "$could_not_create_thread (nested child)" => 2 unless defined $kid;
133 if (my $err = $kid->error) {
134 die "in child thread: $err\n";
138 is_loaded 0, "$here, after child terminated";
141 is_loaded 1, "$here, after loading";
146 skip "$could_not_create_thread (nested parent)" => (3 + 2) unless defined $thr;
149 if (my $err = $thr->error) {
154 is_loaded 0, 'main body, after nested loadings';
156 # Test parallel loadings
163 my @locks_down = (1) x $sync_points;
164 my @locks_up = (0) x $sync_points;
165 share($_) for @locks_down, @locks_up;
167 my $default_peers = 2;
170 my ($id, $peers) = @_;
172 $peers = $default_peers unless defined $peers;
175 lock $locks_down[$id];
176 $locks_down[$id] = 0;
177 cond_broadcast $locks_down[$id];
182 cond_wait $locks_up[$id] until $locks_up[$id] == $peers;
190 lock $locks_down[$id];
191 cond_wait $locks_down[$id] until $locks_down[$id] == 0;
197 cond_signal $locks_up[$id];
201 for my $first_thread_ends_first (0, 1) {
202 for my $id (0 .. $sync_points - 1) {
204 lock $locks_down[$id];
205 $locks_down[$id] = 1;
213 my $thr1_end = 'finishes first';
214 my $thr2_end = 'finishes last';
216 ($thr1_end, $thr2_end) = ($thr2_end, $thr1_end)
217 unless $first_thread_ends_first;
220 my $thr1 = spawn(sub {
221 my $here = "first simultaneous thread ($thr1_end)";
224 is_loaded 0, "$here, beginning";
228 is_loaded 1, "$here, after loading";
233 is_loaded 1, "$here, still loaded while also loaded in the other thread";
236 sync_slave 6 unless $first_thread_ends_first;
238 is_loaded 1, "$here, end";
243 skip "$could_not_create_thread (parallel 1)" => (4 * 2) unless defined $thr1;
245 my $thr2 = spawn(sub {
246 my $here = "second simultaneous thread ($thr2_end)";
249 is_loaded 0, "$here, beginning";
254 is_loaded 0, "$here, loaded in other thread but not here";
257 is_loaded 1, "$here, after loading";
261 sync_slave 6 if $first_thread_ends_first;
263 is_loaded 1, "$here, end";
268 sync_master($_) for 0 .. 5;
271 ($thr2, $thr1) = ($thr1, $thr2) unless $first_thread_ends_first;
274 if (my $err = $thr1->error) {
281 if (my $err = $thr1->error) {
285 sync_master(6, 1) unless $first_thread_ends_first;
288 if (my $err = $thr1->error) {
292 skip "$could_not_create_thread (parallel 2)" => (4 * 1);
296 is_loaded 0, 'main body, after simultaneous threads';
302 my $parent = spawn(sub {
303 my $here = 'simple clone, parent thread';
304 is_loaded 0, "$here, beginning";
307 is_loaded 1, "$here, after loading";
310 my $kid = spawn(sub {
311 my $here = 'simple clone, child thread';
313 is_loaded 1, "$here, beginning";
318 skip "$could_not_create_thread (simple clone child)" => 1
322 if (my $err = $kid->error) {
323 die "in child thread: $err\n";
327 is_loaded 1, "$here, after child terminated";
332 skip "$could_not_create_thread (simple clone parent)" => (3 + 1)
333 unless defined $parent;
336 if (my $err = $parent->error) {
341 is_loaded 0, 'main body, after simple clone';
343 # Test clone outliving its parent
352 my $parent = spawn(sub {
353 my $here = 'outliving clone, parent thread';
354 is_loaded 0, "$here, beginning";
359 is_loaded 1, "$here, after loading";
362 my $kid = spawn(sub {
363 my $here = 'outliving clone, child thread';
365 is_loaded 1, "$here, beginning";
369 $kid_tid = threads->tid();
370 cond_signal $kid_tid;
373 is_loaded 1, "$here, kid tid was communicated";
377 cond_wait $kid_done until $kid_done;
380 is_loaded 1, "$here, end";
385 unless (defined $kid) {
387 skip "$could_not_create_thread (outliving clone child)" => 3;
391 is_loaded 1, "$here, end";
396 skip "$could_not_create_thread (outliving clone parent)" => (3 + 3)
397 unless defined $parent;
399 my $no_kid = $parent->join;
400 if (my $err = $parent->error) {
407 cond_wait $kid_tid until defined $kid_tid;
411 my $kid = threads->object($tid);
416 cond_signal $kid_done;
424 is_loaded 0, 'main body, after outliving clone';
427 is_loaded 1, 'main body, loaded at end';