use strict;
use warnings;

use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More tests => 1;

use threads;
use threads::shared;

sub pid_check {
    my @args = @_;
    my ($thread_num, $port) = @args;
	my $i = 1;
    $SIG{'KILL'} = sub { print("Thread killed on iteration $i.\n"); threads->exit(); };
    my $prepid = 0;
	my ($stdout, $stderr);
	print("Thread $thread_num started\n");
    while (1) { 
        my $cmd = [ 'psql', '-h', 'localhost', '-p', $port, '-d', 'postgres', '-Aqt', '-c', 'SELECT pg_backend_pid()' ];
		my $stdoutfile = "temp-$thread_num.out";
		my $stderrfile = "temp-$thread_num.err";
		my $result = system("psql -p $port -d postgres -U postgres -Aqt -c \"SELECT pg_backend_pid()\" >$stdoutfile 2>$stderrfile");
		my $out = slurp_file($stdoutfile);
		my $err = slurp_file($stderrfile);
		if ($result != 0) {
			return "Error:\n$result\n$out\n$err";
		}
		my $pid = int($out);
		if ($pid == 0) {
			return "Invalid output:\n$out";
		}
        if ($pid == $prepid) {
            return "Got two equal pids in a row: $pid on iteration $i\n"
		} elsif (abs($pid - $prepid) < 5) {
			print "$pid near $prepid\n";
		}
		$prepid = $pid;
		$i++;
    }
	return "Unexpected state";
}

sub shutdown_threads {
    my @args = @_;
    my (@threads) = @args;
    for my $thread (@threads) {
        if ($thread->is_running()) {
            $thread->kill('KILL')->detach;
        }
    }
	return;
}

my $node = PostgreSQL::Test::Cluster->new('main');
$node->init();

$node->append_conf(
    'postgresql.conf', qq{
# log_min_messages = DEBUG1
log_min_error_statement = log
log_connections = on
log_disconnections = on
log_line_prefix = '%m|%u|%d|%p|%c|'
log_statement = 'all'
});
		
unlink($node->data_dir . '/pg_hba.conf');
$node->append_conf('pg_hba.conf', "host all all 127.0.0.1/32 trust");

$node->start;
$node->safe_psql('postgres', 'CREATE USER postgres SUPERUSER');

my $numthreads = 20;
my @threads;
foreach my $ti (1 .. $numthreads) {
    push @threads, threads->create('pid_check', $ti, $node->port);
}
my $max_duration = 600;

my $failed_threads = 0;
my $duration = 0;
while (1) {
    foreach my $ti (1 .. $numthreads) {
        my $thread = $threads[$ti - 1];
        if ($thread->is_joinable()) {
            my $result = $thread->join();
            $failed_threads += 1;
            diag("Thread $ti failed:\n$result");
        } elsif (!$thread->is_running()) {
            $failed_threads += 1;
			diag("Thread $ti is not running:\n");
        }
    }
    if ($failed_threads > 0) {
        last;
    }
    sleep(1);
	diag("$duration\n");
    $duration += 1;
    if ($duration >= $max_duration) {
        last;
    }
}
diag($failed_threads);
shutdown_threads(@threads);
ok($failed_threads == 0);
