#
# make sure v4 works in threads.
#
use strict;
use warnings;
use Config;

BEGIN {
    unless ($Config{useithreads}) {
        print "1..0 # SKIP no ithreads\n";
        exit 0;
    }
}

use threads;
use threads::shared;
use Thread::Semaphore;
use Test::More;

use vars qw(@OPTS);

BEGIN {
    @OPTS = qw(uuid4);
    ok 1, 'began';
}

use UUID @OPTS;
ok 1, 'loaded';

my $sync = 0;
my $seen = {};
my $mutex = Thread::Semaphore->new(0); # locked
note 'mutex init';
share($sync);
note 'shared sync';
share($seen);
note 'shared seen';
share($mutex);
note 'shared mutex';

my ($t10, $t11, $t12, $t13, $t14, $t15, $t16, $t17, $t18, $t19);
my ($t20, $t21, $t22, $t23, $t24, $t25, $t26, $t27, $t28, $t29);
my ($t30, $t31, $t32, $t33, $t34, $t35, $t36, $t37, $t38, $t39);

my $cnt = 0;
$t10 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t11 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t12 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t13 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t14 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t15 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t16 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t17 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t18 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t19 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t20 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t21 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t22 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t23 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t24 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t25 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t26 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t27 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t28 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t29 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t30 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t31 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t32 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t33 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t34 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t35 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t36 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t37 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t38 = threads->create(\&doit, ++$cnt);
note 'threads created';
$t39 = threads->create(\&doit, ++$cnt);
note 'threads created';

note 'waiting';
my $timeout = 20; # 5 secs
while (1) {
    my $s;
    { lock($sync); $s = $sync }
    note "so far: $s";
    last if $s >= 30;
    select undef, undef, undef, 0.25;
    next if --$timeout > 0;
    fail 'Waiting too long';
    plan skip_all => 'HUNG';
}

note 'do it';
$mutex->up(30);  # thundering herd!

$t10->join; $t11->join; $t12->join; $t13->join; $t14->join; $t15->join;
$t16->join; $t17->join; $t18->join; $t19->join; $t20->join; $t21->join;
$t22->join; $t23->join; $t24->join; $t25->join; $t26->join; $t27->join;
$t28->join; $t29->join; $t30->join; $t31->join; $t32->join; $t33->join;
$t34->join; $t35->join; $t36->join; $t37->join; $t38->join; $t39->join;

sub doit {
    note 'in doit()';
    my $i = shift;
    note "reporting $i";
    { lock $sync; ++$sync }
    note "requesting $i";
    $mutex->down;
    note "generating $i";
    my $uu = uuid4();
    note "releasing $i";
    $mutex->up;
    note $uu;
    lock $seen;
    note "recording $i";
    ++$seen->{$uu};
}

is scalar(keys %$seen), 30, 'no dupes';
if ((scalar keys %$seen) != 0) {
    note "$_  $seen->{$_}"
        for sort keys %$seen;
}

done_testing;
