15759b3d2Safresh1package Test2::Util; 25759b3d2Safresh1use strict; 35759b3d2Safresh1use warnings; 45759b3d2Safresh1 5*5486feefSafresh1our $VERSION = '1.302199'; 65759b3d2Safresh1 75759b3d2Safresh1use POSIX(); 85759b3d2Safresh1use Config qw/%Config/; 95759b3d2Safresh1use Carp qw/croak/; 105759b3d2Safresh1 115759b3d2Safresh1BEGIN { 125759b3d2Safresh1 local ($@, $!, $SIG{__DIE__}); 135759b3d2Safresh1 *HAVE_PERLIO = eval { require PerlIO; PerlIO->VERSION(1.02); } ? sub() { 1 } : sub() { 0 }; 145759b3d2Safresh1} 155759b3d2Safresh1 165759b3d2Safresh1our @EXPORT_OK = qw{ 175759b3d2Safresh1 try 185759b3d2Safresh1 195759b3d2Safresh1 pkg_to_file 205759b3d2Safresh1 215759b3d2Safresh1 get_tid USE_THREADS 225759b3d2Safresh1 CAN_THREAD 235759b3d2Safresh1 CAN_REALLY_FORK 245759b3d2Safresh1 CAN_FORK 255759b3d2Safresh1 265759b3d2Safresh1 CAN_SIGSYS 275759b3d2Safresh1 285759b3d2Safresh1 IS_WIN32 295759b3d2Safresh1 305759b3d2Safresh1 ipc_separator 315759b3d2Safresh1 32f3efcd01Safresh1 gen_uid 33f3efcd01Safresh1 345759b3d2Safresh1 do_rename do_unlink 355759b3d2Safresh1 365759b3d2Safresh1 try_sig_mask 375759b3d2Safresh1 385759b3d2Safresh1 clone_io 395759b3d2Safresh1}; 405759b3d2Safresh1BEGIN { require Exporter; our @ISA = qw(Exporter) } 415759b3d2Safresh1 425759b3d2Safresh1BEGIN { 435759b3d2Safresh1 *IS_WIN32 = ($^O eq 'MSWin32') ? sub() { 1 } : sub() { 0 }; 445759b3d2Safresh1} 455759b3d2Safresh1 465759b3d2Safresh1sub _can_thread { 475759b3d2Safresh1 return 0 unless $] >= 5.008001; 485759b3d2Safresh1 return 0 unless $Config{'useithreads'}; 495759b3d2Safresh1 505759b3d2Safresh1 # Threads are broken on perl 5.10.0 built with gcc 4.8+ 515759b3d2Safresh1 if ($] == 5.010000 && $Config{'ccname'} eq 'gcc' && $Config{'gccversion'}) { 52256a93a4Safresh1 return 0 unless $Config{'gccversion'} =~ m/^(\d+)\.(\d+)/; 53256a93a4Safresh1 my @parts = split /[\.\s]+/, $Config{'gccversion'}; 545759b3d2Safresh1 return 0 if $parts[0] > 4 || ($parts[0] == 4 && $parts[1] >= 8); 555759b3d2Safresh1 } 565759b3d2Safresh1 575759b3d2Safresh1 # Change to a version check if this ever changes 585759b3d2Safresh1 return 0 if $INC{'Devel/Cover.pm'}; 595759b3d2Safresh1 return 1; 605759b3d2Safresh1} 615759b3d2Safresh1 625759b3d2Safresh1sub _can_fork { 635759b3d2Safresh1 return 1 if $Config{d_fork}; 645759b3d2Safresh1 return 0 unless IS_WIN32 || $^O eq 'NetWare'; 655759b3d2Safresh1 return 0 unless $Config{useithreads}; 665759b3d2Safresh1 return 0 unless $Config{ccflags} =~ /-DPERL_IMPLICIT_SYS/; 675759b3d2Safresh1 685759b3d2Safresh1 return _can_thread(); 695759b3d2Safresh1} 705759b3d2Safresh1 715759b3d2Safresh1BEGIN { 725759b3d2Safresh1 no warnings 'once'; 735759b3d2Safresh1 *CAN_THREAD = _can_thread() ? sub() { 1 } : sub() { 0 }; 745759b3d2Safresh1} 755759b3d2Safresh1my $can_fork; 765759b3d2Safresh1sub CAN_FORK () { 775759b3d2Safresh1 return $can_fork 785759b3d2Safresh1 if defined $can_fork; 795759b3d2Safresh1 $can_fork = !!_can_fork(); 805759b3d2Safresh1 no warnings 'redefine'; 815759b3d2Safresh1 *CAN_FORK = $can_fork ? sub() { 1 } : sub() { 0 }; 825759b3d2Safresh1 $can_fork; 835759b3d2Safresh1} 845759b3d2Safresh1my $can_really_fork; 855759b3d2Safresh1sub CAN_REALLY_FORK () { 865759b3d2Safresh1 return $can_really_fork 875759b3d2Safresh1 if defined $can_really_fork; 885759b3d2Safresh1 $can_really_fork = !!$Config{d_fork}; 895759b3d2Safresh1 no warnings 'redefine'; 905759b3d2Safresh1 *CAN_REALLY_FORK = $can_really_fork ? sub() { 1 } : sub() { 0 }; 915759b3d2Safresh1 $can_really_fork; 925759b3d2Safresh1} 935759b3d2Safresh1 945759b3d2Safresh1sub _manual_try(&;@) { 955759b3d2Safresh1 my $code = shift; 965759b3d2Safresh1 my $args = \@_; 975759b3d2Safresh1 my $err; 985759b3d2Safresh1 995759b3d2Safresh1 my $die = delete $SIG{__DIE__}; 1005759b3d2Safresh1 1015759b3d2Safresh1 eval { $code->(@$args); 1 } or $err = $@ || "Error was squashed!\n"; 1025759b3d2Safresh1 1035759b3d2Safresh1 $die ? $SIG{__DIE__} = $die : delete $SIG{__DIE__}; 1045759b3d2Safresh1 1055759b3d2Safresh1 return (!defined($err), $err); 1065759b3d2Safresh1} 1075759b3d2Safresh1 1085759b3d2Safresh1sub _local_try(&;@) { 1095759b3d2Safresh1 my $code = shift; 1105759b3d2Safresh1 my $args = \@_; 1115759b3d2Safresh1 my $err; 1125759b3d2Safresh1 1135759b3d2Safresh1 no warnings; 1145759b3d2Safresh1 local $SIG{__DIE__}; 1155759b3d2Safresh1 eval { $code->(@$args); 1 } or $err = $@ || "Error was squashed!\n"; 1165759b3d2Safresh1 1175759b3d2Safresh1 return (!defined($err), $err); 1185759b3d2Safresh1} 1195759b3d2Safresh1 1205759b3d2Safresh1# Older versions of perl have a nasty bug on win32 when localizing a variable 1215759b3d2Safresh1# before forking or starting a new thread. So for those systems we use the 1225759b3d2Safresh1# non-local form. When possible though we use the faster 'local' form. 1235759b3d2Safresh1BEGIN { 1245759b3d2Safresh1 if (IS_WIN32 && $] < 5.020002) { 1255759b3d2Safresh1 *try = \&_manual_try; 1265759b3d2Safresh1 } 1275759b3d2Safresh1 else { 1285759b3d2Safresh1 *try = \&_local_try; 1295759b3d2Safresh1 } 1305759b3d2Safresh1} 1315759b3d2Safresh1 1325759b3d2Safresh1BEGIN { 1335759b3d2Safresh1 if (CAN_THREAD) { 1345759b3d2Safresh1 if ($INC{'threads.pm'}) { 1355759b3d2Safresh1 # Threads are already loaded, so we do not need to check if they 1365759b3d2Safresh1 # are loaded each time 1375759b3d2Safresh1 *USE_THREADS = sub() { 1 }; 1385759b3d2Safresh1 *get_tid = sub() { threads->tid() }; 1395759b3d2Safresh1 } 1405759b3d2Safresh1 else { 1415759b3d2Safresh1 # :-( Need to check each time to see if they have been loaded. 1425759b3d2Safresh1 *USE_THREADS = sub() { $INC{'threads.pm'} ? 1 : 0 }; 1435759b3d2Safresh1 *get_tid = sub() { $INC{'threads.pm'} ? threads->tid() : 0 }; 1445759b3d2Safresh1 } 1455759b3d2Safresh1 } 1465759b3d2Safresh1 else { 1475759b3d2Safresh1 # No threads, not now, not ever! 1485759b3d2Safresh1 *USE_THREADS = sub() { 0 }; 1495759b3d2Safresh1 *get_tid = sub() { 0 }; 1505759b3d2Safresh1 } 1515759b3d2Safresh1} 1525759b3d2Safresh1 1535759b3d2Safresh1sub pkg_to_file { 1545759b3d2Safresh1 my $pkg = shift; 1555759b3d2Safresh1 my $file = $pkg; 1565759b3d2Safresh1 $file =~ s{(::|')}{/}g; 1575759b3d2Safresh1 $file .= '.pm'; 1585759b3d2Safresh1 return $file; 1595759b3d2Safresh1} 1605759b3d2Safresh1 1615759b3d2Safresh1sub ipc_separator() { "~" } 1625759b3d2Safresh1 163f3efcd01Safresh1my $UID = 1; 164f3efcd01Safresh1sub gen_uid() { join ipc_separator() => ($$, get_tid(), time, $UID++) } 165f3efcd01Safresh1 1665759b3d2Safresh1sub _check_for_sig_sys { 1675759b3d2Safresh1 my $sig_list = shift; 1685759b3d2Safresh1 return $sig_list =~ m/\bSYS\b/; 1695759b3d2Safresh1} 1705759b3d2Safresh1 1715759b3d2Safresh1BEGIN { 1725759b3d2Safresh1 if (_check_for_sig_sys($Config{sig_name})) { 1735759b3d2Safresh1 *CAN_SIGSYS = sub() { 1 }; 1745759b3d2Safresh1 } 1755759b3d2Safresh1 else { 1765759b3d2Safresh1 *CAN_SIGSYS = sub() { 0 }; 1775759b3d2Safresh1 } 1785759b3d2Safresh1} 1795759b3d2Safresh1 1805759b3d2Safresh1my %PERLIO_SKIP = ( 1815759b3d2Safresh1 unix => 1, 1825759b3d2Safresh1 via => 1, 1835759b3d2Safresh1); 1845759b3d2Safresh1 1855759b3d2Safresh1sub clone_io { 1865759b3d2Safresh1 my ($fh) = @_; 187f3efcd01Safresh1 my $fileno = eval { fileno($fh) }; 1885759b3d2Safresh1 1895759b3d2Safresh1 return $fh if !defined($fileno) || !length($fileno) || $fileno < 0; 1905759b3d2Safresh1 1915759b3d2Safresh1 open(my $out, '>&' . $fileno) or die "Can't dup fileno $fileno: $!"; 1925759b3d2Safresh1 1935759b3d2Safresh1 my %seen; 1945759b3d2Safresh1 my @layers = HAVE_PERLIO ? grep { !$PERLIO_SKIP{$_} and !$seen{$_}++ } PerlIO::get_layers($fh) : (); 1955759b3d2Safresh1 binmode($out, join(":", "", "raw", @layers)); 1965759b3d2Safresh1 1975759b3d2Safresh1 my $old = select $fh; 1985759b3d2Safresh1 my $af = $|; 1995759b3d2Safresh1 select $out; 2005759b3d2Safresh1 $| = $af; 2015759b3d2Safresh1 select $old; 2025759b3d2Safresh1 2035759b3d2Safresh1 return $out; 2045759b3d2Safresh1} 2055759b3d2Safresh1 2065759b3d2Safresh1BEGIN { 2075759b3d2Safresh1 if (IS_WIN32) { 2085759b3d2Safresh1 my $max_tries = 5; 2095759b3d2Safresh1 2105759b3d2Safresh1 *do_rename = sub { 2115759b3d2Safresh1 my ($from, $to) = @_; 2125759b3d2Safresh1 2135759b3d2Safresh1 my $err; 2145759b3d2Safresh1 for (1 .. $max_tries) { 2155759b3d2Safresh1 return (1) if rename($from, $to); 2165759b3d2Safresh1 $err = "$!"; 2175759b3d2Safresh1 last if $_ == $max_tries; 2185759b3d2Safresh1 sleep 1; 2195759b3d2Safresh1 } 2205759b3d2Safresh1 2215759b3d2Safresh1 return (0, $err); 2225759b3d2Safresh1 }; 2235759b3d2Safresh1 *do_unlink = sub { 2245759b3d2Safresh1 my ($file) = @_; 2255759b3d2Safresh1 2265759b3d2Safresh1 my $err; 2275759b3d2Safresh1 for (1 .. $max_tries) { 2285759b3d2Safresh1 return (1) if unlink($file); 2295759b3d2Safresh1 $err = "$!"; 2305759b3d2Safresh1 last if $_ == $max_tries; 2315759b3d2Safresh1 sleep 1; 2325759b3d2Safresh1 } 2335759b3d2Safresh1 2345759b3d2Safresh1 return (0, "$!"); 2355759b3d2Safresh1 }; 2365759b3d2Safresh1 } 2375759b3d2Safresh1 else { 2385759b3d2Safresh1 *do_rename = sub { 2395759b3d2Safresh1 my ($from, $to) = @_; 2405759b3d2Safresh1 return (1) if rename($from, $to); 2415759b3d2Safresh1 return (0, "$!"); 2425759b3d2Safresh1 }; 2435759b3d2Safresh1 *do_unlink = sub { 2445759b3d2Safresh1 my ($file) = @_; 2455759b3d2Safresh1 return (1) if unlink($file); 2465759b3d2Safresh1 return (0, "$!"); 2475759b3d2Safresh1 }; 2485759b3d2Safresh1 } 2495759b3d2Safresh1} 2505759b3d2Safresh1 2515759b3d2Safresh1sub try_sig_mask(&) { 2525759b3d2Safresh1 my $code = shift; 2535759b3d2Safresh1 2545759b3d2Safresh1 my ($old, $blocked); 2555759b3d2Safresh1 unless(IS_WIN32) { 2565759b3d2Safresh1 my $to_block = POSIX::SigSet->new( 2575759b3d2Safresh1 POSIX::SIGINT(), 2585759b3d2Safresh1 POSIX::SIGALRM(), 2595759b3d2Safresh1 POSIX::SIGHUP(), 2605759b3d2Safresh1 POSIX::SIGTERM(), 2615759b3d2Safresh1 POSIX::SIGUSR1(), 2625759b3d2Safresh1 POSIX::SIGUSR2(), 2635759b3d2Safresh1 ); 2645759b3d2Safresh1 $old = POSIX::SigSet->new; 2655759b3d2Safresh1 $blocked = POSIX::sigprocmask(POSIX::SIG_BLOCK(), $to_block, $old); 2665759b3d2Safresh1 # Silently go on if we failed to log signals, not much we can do. 2675759b3d2Safresh1 } 2685759b3d2Safresh1 2695759b3d2Safresh1 my ($ok, $err) = &try($code); 2705759b3d2Safresh1 2715759b3d2Safresh1 # If our block was successful we want to restore the old mask. 2725759b3d2Safresh1 POSIX::sigprocmask(POSIX::SIG_SETMASK(), $old, POSIX::SigSet->new()) if defined $blocked; 2735759b3d2Safresh1 2745759b3d2Safresh1 return ($ok, $err); 2755759b3d2Safresh1} 2765759b3d2Safresh1 2775759b3d2Safresh11; 2785759b3d2Safresh1 2795759b3d2Safresh1__END__ 2805759b3d2Safresh1 2815759b3d2Safresh1=pod 2825759b3d2Safresh1 2835759b3d2Safresh1=encoding UTF-8 2845759b3d2Safresh1 2855759b3d2Safresh1=head1 NAME 2865759b3d2Safresh1 2875759b3d2Safresh1Test2::Util - Tools used by Test2 and friends. 2885759b3d2Safresh1 2895759b3d2Safresh1=head1 DESCRIPTION 2905759b3d2Safresh1 2915759b3d2Safresh1Collection of tools used by L<Test2> and friends. 2925759b3d2Safresh1 2935759b3d2Safresh1=head1 EXPORTS 2945759b3d2Safresh1 2955759b3d2Safresh1All exports are optional. You must specify subs to import. 2965759b3d2Safresh1 2975759b3d2Safresh1=over 4 2985759b3d2Safresh1 2995759b3d2Safresh1=item ($success, $error) = try { ... } 3005759b3d2Safresh1 3015759b3d2Safresh1Eval the codeblock, return success or failure, and the error message. This code 3025759b3d2Safresh1protects $@ and $!, they will be restored by the end of the run. This code also 3035759b3d2Safresh1temporarily blocks $SIG{DIE} handlers. 3045759b3d2Safresh1 3055759b3d2Safresh1=item protect { ... } 3065759b3d2Safresh1 3075759b3d2Safresh1Similar to try, except that it does not catch exceptions. The idea here is to 3085759b3d2Safresh1protect $@ and $! from changes. $@ and $! will be restored to whatever they 3095759b3d2Safresh1were before the run so long as it is successful. If the run fails $! will still 3105759b3d2Safresh1be restored, but $@ will contain the exception being thrown. 3115759b3d2Safresh1 3125759b3d2Safresh1=item CAN_FORK 3135759b3d2Safresh1 3145759b3d2Safresh1True if this system is capable of true or pseudo-fork. 3155759b3d2Safresh1 3165759b3d2Safresh1=item CAN_REALLY_FORK 3175759b3d2Safresh1 3185759b3d2Safresh1True if the system can really fork. This will be false for systems where fork 3195759b3d2Safresh1is emulated. 3205759b3d2Safresh1 3215759b3d2Safresh1=item CAN_THREAD 3225759b3d2Safresh1 3235759b3d2Safresh1True if this system is capable of using threads. 3245759b3d2Safresh1 3255759b3d2Safresh1=item USE_THREADS 3265759b3d2Safresh1 3275759b3d2Safresh1Returns true if threads are enabled, false if they are not. 3285759b3d2Safresh1 3295759b3d2Safresh1=item get_tid 3305759b3d2Safresh1 3315759b3d2Safresh1This will return the id of the current thread when threads are enabled, 3325759b3d2Safresh1otherwise it returns 0. 3335759b3d2Safresh1 3345759b3d2Safresh1=item my $file = pkg_to_file($package) 3355759b3d2Safresh1 3365759b3d2Safresh1Convert a package name to a filename. 3375759b3d2Safresh1 338f3efcd01Safresh1=item $string = ipc_separator() 339f3efcd01Safresh1 340f3efcd01Safresh1Get the IPC separator. Currently this is always the string C<'~'>. 341f3efcd01Safresh1 342f3efcd01Safresh1=item $string = gen_uid() 343f3efcd01Safresh1 344f3efcd01Safresh1Generate a unique id (NOT A UUID). This will typically be the process id, the 345f3efcd01Safresh1thread id, the time, and an incrementing integer all joined with the 346f3efcd01Safresh1C<ipc_separator()>. 347f3efcd01Safresh1 348f3efcd01Safresh1These ID's are unique enough for most purposes. For identical ids to be 349f3efcd01Safresh1generated you must have 2 processes with the same PID generate IDs at the same 350f3efcd01Safresh1time with the same current state of the incrementing integer. This is a 351f3efcd01Safresh1perfectly reasonable thing to expect to happen across multiple machines, but is 352f3efcd01Safresh1quite unlikely to happen on one machine. 353f3efcd01Safresh1 354f3efcd01Safresh1This can fail to be unique if a process generates an id, calls exec, and does 355f3efcd01Safresh1it again after the exec and it all happens in less than a second. It can also 356f3efcd01Safresh1happen if the systems process id's cycle in less than a second allowing 2 357f3efcd01Safresh1different programs that use this generator to run with the same PID in less 358f3efcd01Safresh1than a second. Both these cases are sufficiently unlikely. If you need 359f3efcd01Safresh1universally unique ids, or ids that are unique in these conditions, look at 360f3efcd01Safresh1L<Data::UUID>. 361f3efcd01Safresh1 3625759b3d2Safresh1=item ($ok, $err) = do_rename($old_name, $new_name) 3635759b3d2Safresh1 3645759b3d2Safresh1Rename a file, this wraps C<rename()> in a way that makes it more reliable 3655759b3d2Safresh1cross-platform when trying to rename files you recently altered. 3665759b3d2Safresh1 3675759b3d2Safresh1=item ($ok, $err) = do_unlink($filename) 3685759b3d2Safresh1 3695759b3d2Safresh1Unlink a file, this wraps C<unlink()> in a way that makes it more reliable 3705759b3d2Safresh1cross-platform when trying to unlink files you recently altered. 3715759b3d2Safresh1 3725759b3d2Safresh1=item ($ok, $err) = try_sig_mask { ... } 3735759b3d2Safresh1 3745759b3d2Safresh1Complete an action with several signals masked, they will be unmasked at the 3755759b3d2Safresh1end allowing any signals that were intercepted to get handled. 3765759b3d2Safresh1 3775759b3d2Safresh1This is primarily used when you need to make several actions atomic (against 3785759b3d2Safresh1some signals anyway). 3795759b3d2Safresh1 3805759b3d2Safresh1Signals that are intercepted: 3815759b3d2Safresh1 3825759b3d2Safresh1=over 4 3835759b3d2Safresh1 3845759b3d2Safresh1=item SIGINT 3855759b3d2Safresh1 3865759b3d2Safresh1=item SIGALRM 3875759b3d2Safresh1 3885759b3d2Safresh1=item SIGHUP 3895759b3d2Safresh1 3905759b3d2Safresh1=item SIGTERM 3915759b3d2Safresh1 3925759b3d2Safresh1=item SIGUSR1 3935759b3d2Safresh1 3945759b3d2Safresh1=item SIGUSR2 3955759b3d2Safresh1 3965759b3d2Safresh1=back 3975759b3d2Safresh1 3985759b3d2Safresh1=back 3995759b3d2Safresh1 4005759b3d2Safresh1=head1 NOTES && CAVEATS 4015759b3d2Safresh1 4025759b3d2Safresh1=over 4 4035759b3d2Safresh1 4045759b3d2Safresh1=item 5.10.0 4055759b3d2Safresh1 4065759b3d2Safresh1Perl 5.10.0 has a bug when compiled with newer gcc versions. This bug causes a 4075759b3d2Safresh1segfault whenever a new thread is launched. Test2 will attempt to detect 4085759b3d2Safresh1this, and note that the system is not capable of forking when it is detected. 4095759b3d2Safresh1 4105759b3d2Safresh1=item Devel::Cover 4115759b3d2Safresh1 4125759b3d2Safresh1Devel::Cover does not support threads. CAN_THREAD will return false if 4135759b3d2Safresh1Devel::Cover is loaded before the check is first run. 4145759b3d2Safresh1 4155759b3d2Safresh1=back 4165759b3d2Safresh1 4175759b3d2Safresh1=head1 SOURCE 4185759b3d2Safresh1 4195759b3d2Safresh1The source code repository for Test2 can be found at 420*5486feefSafresh1L<https://github.com/Test-More/test-more/>. 4215759b3d2Safresh1 4225759b3d2Safresh1=head1 MAINTAINERS 4235759b3d2Safresh1 4245759b3d2Safresh1=over 4 4255759b3d2Safresh1 4265759b3d2Safresh1=item Chad Granum E<lt>exodist@cpan.orgE<gt> 4275759b3d2Safresh1 4285759b3d2Safresh1=back 4295759b3d2Safresh1 4305759b3d2Safresh1=head1 AUTHORS 4315759b3d2Safresh1 4325759b3d2Safresh1=over 4 4335759b3d2Safresh1 4345759b3d2Safresh1=item Chad Granum E<lt>exodist@cpan.orgE<gt> 4355759b3d2Safresh1 4365759b3d2Safresh1=item Kent Fredric E<lt>kentnl@cpan.orgE<gt> 4375759b3d2Safresh1 4385759b3d2Safresh1=back 4395759b3d2Safresh1 4405759b3d2Safresh1=head1 COPYRIGHT 4415759b3d2Safresh1 442256a93a4Safresh1Copyright 2020 Chad Granum E<lt>exodist@cpan.orgE<gt>. 4435759b3d2Safresh1 4445759b3d2Safresh1This program is free software; you can redistribute it and/or 4455759b3d2Safresh1modify it under the same terms as Perl itself. 4465759b3d2Safresh1 447*5486feefSafresh1See L<https://dev.perl.org/licenses/> 4485759b3d2Safresh1 4495759b3d2Safresh1=cut 450