#! /usr/bin/perl
#
use strict;
use vars qw(@files %processes $swigradir $parser);
use constant CONCURRENCY_LEVEL => 4;

use BSD::Resource;

die unless @ARGV == 1;

$swigradir = "$ENV{HOME}/swigra/parser";
$parser = 'gfjp2-bin';

@files = glob(shift);
%processes = ();

print STDERR "There are ".scalar(@files)." files to process.\n";

spawn_child(shift @files)
    while (keys %processes < CONCURRENCY_LEVEL && @files > 0);

while (@files >0) {
    my $kid = waitpid(-1, 0);
    if (defined $processes{$kid}) {
	print STDERR "Process $kid for $processes{$kid} has finished, ${\(scalar(keys %processes)-1)} running.\n";
	delete $processes{$kid};
	spawn_child(shift @files);
    } else {
	print STDERR "STRANGE: we haven't been waiting for process $kid.\n";
    }
}

# wait for remaining children
while (keys %processes > 0) {
    my $kid = waitpid(-1, 0);
    if (defined $processes{$kid}) {
	print STDERR "Process $kid for $processes{$kid} has finished, ${\(scalar(keys %processes)-1)} remaining.\n";
	delete $processes{$kid};
    } else {
	print STDERR "STRANGE: we haven't been waiting for process $kid.\n";
    }
}

########################################################################

sub run_swigra { # to be executed in a child process!
    my $doa = shift;
    my $forest = $doa;
    $forest =~ s/.doa$/.forest/;
    if ( -s $forest ) { # file exists and has nonzero size
	print STDERR "--- $forest already present.\n";
	exit 0;
    }
    # ulimit -n 8*60:
    # “Processes have soft and hard resource limits.  On crossing the
    # soft limit they receive a signal (for example the "SIGXCPU" or
    # "SIGXFSZ", corresponding to the "RLIMIT_CPU" and "RLIMIT_FSIZE",
    # respectively).  The processes can trap and handle some of these
    # signals, please see "Signals" in perlipc.  After the hard limit
    # the processes will be ruthlessly killed by the "KILL" signal
    # which cannot be caught.

    # We set the soft limit (setting the hard limit results in “invalid argument” error!):
    setrlimit(RLIMIT_CPU,8*60,RLIM_INFINITY) || die "setrlimit failed for cputime: $!";
    setrlimit(RLIMIT_VMEM,1600*1000*1000,RLIM_INFINITY) || die "setrlimit failed for vmem: $!";
    # nice -n 19
    setpriority(PRIO_PROCESS,0, 19) || die "setpriority failed: $!";

    open STDOUT, '>', $forest or die "Can't redirect STDOUT: $!";
    exec 'swipl', '-x', "$swigradir/$parser",'-t','halt', '-g',"['$doa']";

    }

sub spawn_child {
    my $file = shift;
#    my $workload = int(rand(7));
    if (!defined(my $kidpid = fork())) {
	# fork returned undef, so failed
	die "cannot fork for $file:\n $!";
    } elsif ($kidpid == 0) {
	# fork returned 0, so this branch is the child
#	sleep $workload;
#	exec("date");
	run_swigra($file);
	# if the exec fails, fall through to the next statement
	die "can't exec Swigra: $!";
    } else { 
	# fork returned neither 0 nor undef, 
	# so this branch is the parent
#	print STDERR "Started process $kidpid with $workload for $file.\n";
	print STDERR "Started process $kidpid for $file.\n";
	$processes{$kidpid} = $file;
    }
}

# # from http://www.perlmonks.org/?node_id=254756:
## failed with EPERM!
# sub set_max_cpu_time
#   {
#     my $n_seconds = shift;
#     my $s = pack( 'LL', $n_seconds, $n_seconds+1 );
#     $! = 0;
#     if ( syscall( 128, 0, $s ) == -1 )  # SYS_setrlimit, RLIMIT_CPU
#     {
#       if ( $! == 1 )  # EPERM
#       {
#         die "$!; Sorry, you need to be superuser to do that.\n";
#       }
#       elsif ( $! == 14 )  # EFAULT
#       {
#         die "$!; Error: argument to setrlimit pointed to an illegal ad
# +dress.\n";
#       }
#       elsif ( $! == 22 )  # EINVAL
#       {
#         die "$!; Error: the new rlim_cur exceeds the new rlim_max,
#           or the limit specified cannot be lowered because current usa
# +ge
#           is already higher than the limit.\n";
#       }
#     }
#   }


# non-blocking test for running children:
# use POSIX ":sys_wait_h";
# #...
# do {
#     $kid = waitpid(-1, WNOHANG);
# } while $kid > 0;

# redyrekcje:
#open(STDERR,">&STDOUT")
