From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

use strict;
BEGIN {
use Config;
if (! $Config{'useithreads'}) {
print("1..0 # SKIP Perl not compiled with 'useithreads'\n");
exit(0);
}
}
BEGIN {
$| = 1;
print("1..226\n"); ### Number of tests that will be run ###
}
use threads;
use Scalar::Util qw(dualvar);
my $TEST = 1;
sub ok {
my ($ok, $name) = @_;
# You have to do it this way or VMS will get confused.
if ($ok) {
print("ok $TEST - $name\n");
} else {
print("not ok $TEST - $name\n");
printf("# Failed test at line %d\n", (caller(1))[2]);
}
$TEST++;
}
sub ok_iv
{
my ($var, $iv) = @_;
ok($var == $iv, 'IV number preserved');
ok($var eq $iv, 'String preserved');
}
sub ok_nv
{
my ($var, $nv) = @_;
ok($var == $nv, 'NV number preserved');
ok($var eq $nv, 'String preserved');
}
sub ok_uv
{
my ($var, $uv) = @_;
ok($var == $uv, 'UV number preserved');
ok($var > 0, 'UV number preserved');
ok($var eq $uv, 'String preserved');
}
### Start of Testing ###
my $iv = dualvar(42, 'Fourty-Two');
my $nv = dualvar(3.14, 'PI');
my $bits = ($Config{'use64bitint'}) ? 63 : 31;
my $uv = dualvar(1<<$bits, 'Large unsigned int');
print("# Shared scalar assignment using shared_clone()\n");
my $siv :shared = shared_clone($iv);
my $snv :shared = shared_clone($nv);
my $suv :shared = shared_clone($uv);
ok_iv($siv, $iv);
ok_nv($snv, $nv);
ok_uv($suv, $uv);
{
print("# Shared array initialization\n");
my @ary :shared = ($iv, $nv, $uv);
ok_iv($ary[0], $iv);
ok_nv($ary[1], $nv);
ok_uv($ary[2], $uv);
}
{
print("# Shared array list assignment\n");
my @ary :shared;
@ary = ($iv, $nv, $uv);
ok_iv($ary[0], $iv);
ok_nv($ary[1], $nv);
ok_uv($ary[2], $uv);
}
{
print("# Shared array element assignment\n");
my @ary :shared;
$ary[0] = $iv;
$ary[1] = $nv;
$ary[2] = $uv;
ok_iv($ary[0], $iv);
ok_nv($ary[1], $nv);
ok_uv($ary[2], $uv);
}
{
print("# Shared array initialization - shared scalars\n");
my @ary :shared = ($siv, $snv, $suv);
ok_iv($ary[0], $iv);
ok_nv($ary[1], $nv);
ok_uv($ary[2], $uv);
}
{
print("# Shared array list assignment - shared scalars\n");
my @ary :shared;
@ary = ($siv, $snv, $suv);
ok_iv($ary[0], $iv);
ok_nv($ary[1], $nv);
ok_uv($ary[2], $uv);
}
{
print("# Shared array element assignment - shared scalars\n");
my @ary :shared;
$ary[0] = $siv;
$ary[1] = $snv;
$ary[2] = $suv;
ok_iv($ary[0], $iv);
ok_nv($ary[1], $nv);
ok_uv($ary[2], $uv);
}
{
print("# Shared hash initialization\n");
my %hsh :shared = (
'iv' => $iv,
'nv' => $nv,
'uv' => $uv,
);
ok_iv($hsh{'iv'}, $iv);
ok_nv($hsh{'nv'}, $nv);
ok_uv($hsh{'uv'}, $uv);
}
{
print("# Shared hash assignment\n");
my %hsh :shared;
%hsh = (
'iv' => $iv,
'nv' => $nv,
'uv' => $uv,
);
ok_iv($hsh{'iv'}, $iv);
ok_nv($hsh{'nv'}, $nv);
ok_uv($hsh{'uv'}, $uv);
}
{
print("# Shared hash element assignment\n");
my %hsh :shared;
$hsh{'iv'} = $iv;
$hsh{'nv'} = $nv;
$hsh{'uv'} = $uv;
ok_iv($hsh{'iv'}, $iv);
ok_nv($hsh{'nv'}, $nv);
ok_uv($hsh{'uv'}, $uv);
}
{
print("# Shared hash initialization - shared scalars\n");
my %hsh :shared = (
'iv' => $siv,
'nv' => $snv,
'uv' => $suv,
);
ok_iv($hsh{'iv'}, $iv);
ok_nv($hsh{'nv'}, $nv);
ok_uv($hsh{'uv'}, $uv);
}
{
print("# Shared hash assignment - shared scalars\n");
my %hsh :shared;
%hsh = (
'iv' => $siv,
'nv' => $snv,
'uv' => $suv,
);
ok_iv($hsh{'iv'}, $iv);
ok_nv($hsh{'nv'}, $nv);
ok_uv($hsh{'uv'}, $uv);
}
{
print("# Shared hash element assignment - shared scalars\n");
my %hsh :shared;
$hsh{'iv'} = $siv;
$hsh{'nv'} = $snv;
$hsh{'uv'} = $suv;
ok_iv($hsh{'iv'}, $iv);
ok_nv($hsh{'nv'}, $nv);
ok_uv($hsh{'uv'}, $uv);
}
{
print("# Shared array push\n");
my @ary :shared;
push(@ary, $iv, $nv, $uv);
ok_iv($ary[0], $iv);
ok_nv($ary[1], $nv);
ok_uv($ary[2], $uv);
print("# Shared array pop\n");
my $xuv = pop(@ary);
my $xnv = pop(@ary);
my $xiv = pop(@ary);
ok_iv($xiv, $iv);
ok_nv($xnv, $nv);
ok_uv($xuv, $uv);
print("# Shared array unshift\n");
unshift(@ary, $iv, $nv, $uv);
ok_iv($ary[0], $iv);
ok_nv($ary[1], $nv);
ok_uv($ary[2], $uv);
print("# Shared array shift\n");
$xiv = shift(@ary);
$xnv = shift(@ary);
$xuv = shift(@ary);
ok_iv($xiv, $iv);
ok_nv($xnv, $nv);
ok_uv($xuv, $uv);
}
{
print("# Shared array push - shared scalars\n");
my @ary :shared;
push(@ary, $siv, $snv, $suv);
ok_iv($ary[0], $iv);
ok_nv($ary[1], $nv);
ok_uv($ary[2], $uv);
print("# Shared array pop - shared scalars\n");
my $xuv = pop(@ary);
my $xnv = pop(@ary);
my $xiv = pop(@ary);
ok_iv($xiv, $iv);
ok_nv($xnv, $nv);
ok_uv($xuv, $uv);
print("# Shared array unshift - shared scalars\n");
unshift(@ary, $siv, $snv, $suv);
ok_iv($ary[0], $iv);
ok_nv($ary[1], $nv);
ok_uv($ary[2], $uv);
print("# Shared array shift - shared scalars\n");
$xiv = shift(@ary);
$xnv = shift(@ary);
$xuv = shift(@ary);
ok_iv($xiv, $iv);
ok_nv($xnv, $nv);
ok_uv($xuv, $uv);
}
{
print("# Shared hash delete\n");
my %hsh :shared = (
'iv' => $iv,
'nv' => $nv,
'uv' => $uv,
);
ok_iv(delete($hsh{'iv'}), $iv);
ok_nv(delete($hsh{'nv'}), $nv);
ok_uv(delete($hsh{'uv'}), $uv);
}
{
print("# Shared hash delete - shared scalars\n");
my %hsh :shared = (
'iv' => $siv,
'nv' => $snv,
'uv' => $suv,
);
ok_iv(delete($hsh{'iv'}), $iv);
ok_nv(delete($hsh{'nv'}), $nv);
ok_uv(delete($hsh{'uv'}), $uv);
}
{
print("# Shared array copy to non-shared array\n");
my @ary :shared = ($iv, $nv, $uv);
my @nsa = @ary;
ok_iv($nsa[0], $iv);
ok_nv($nsa[1], $nv);
ok_uv($nsa[2], $uv);
print("# Shared array copy using shared_clone()\n");
my $copy :shared = shared_clone(\@nsa);
ok_iv($$copy[0], $iv);
ok_nv($$copy[1], $nv);
ok_uv($$copy[2], $uv);
}
{
print("# Shared array copy to non-shared array - shared scalars\n");
my @ary :shared = ($siv, $snv, $suv);
my @nsa = @ary;
ok_iv($nsa[0], $iv);
ok_nv($nsa[1], $nv);
ok_uv($nsa[2], $uv);
print("# Shared array copy using shared_clone()\n");
my $copy :shared = shared_clone(\@nsa);
ok_iv($$copy[0], $iv);
ok_nv($$copy[1], $nv);
ok_uv($$copy[2], $uv);
}
{
print("# Shared hash copy to non-shared hash\n");
my %hsh :shared = (
'iv' => $iv,
'nv' => $nv,
'uv' => $uv,
);
my %nsh = %hsh;
ok_iv($nsh{'iv'}, $iv);
ok_nv($nsh{'nv'}, $nv);
ok_uv($nsh{'uv'}, $uv);
print("# Shared hash copy using shared_clone()\n");
my $copy :shared = shared_clone(\%nsh);
ok_iv($$copy{'iv'}, $iv);
ok_nv($$copy{'nv'}, $nv);
ok_uv($$copy{'uv'}, $uv);
}
{
print("# Shared hash copy to non-shared hash - shared scalars\n");
my %hsh :shared = (
'iv' => $siv,
'nv' => $snv,
'uv' => $suv,
);
my %nsh = %hsh;
ok_iv($nsh{'iv'}, $iv);
ok_nv($nsh{'nv'}, $nv);
ok_uv($nsh{'uv'}, $uv);
print("# Shared hash copy using shared_clone()\n");
my $copy :shared = shared_clone(\%nsh);
ok_iv($$copy{'iv'}, $iv);
ok_nv($$copy{'nv'}, $nv);
ok_uv($$copy{'uv'}, $uv);
}
print("# Mix it up with a thread\n");
my @ary :shared;
my %hsh :shared;
threads->create(sub {
@ary = ($siv);
push(@ary, $snv);
%hsh = ( 'nv' => $ary[1] );
$hsh{'iv'} = $ary[0];
$hsh{'uv'} = $suv;
$ary[2] = $hsh{'uv'};
})->join();
ok_iv($hsh{'iv'}, $ary[0]);
ok_nv($hsh{'nv'}, $ary[1]);
ok_uv($hsh{'uv'}, $ary[2]);
# $! behaves like a dualvar, but is really implemented as a tied SV.
# As a result sharing $! directly only propagates the string value.
# However, we can create a dualvar from it.
print("# Errno\n");
$! = 1;
my $ss :shared = dualvar($!,$!);
ok_iv($ss, $!);
exit(0);