#!/usr/bin/perl use warnings; use strict; # PHFOS - Perl Hold File Open Script use Getopt::Long; use threads; use threads::shared; use POSIX; use File::Random qw/:all/; sub print_usage { print "Flags:\n"; print " -d \t\tDirectory to read files from (REQUIRED)\n"; print " -n \t\tMaximum number of threads to spawn (default 10)\n"; print " -r\t\t\tRead the contents of the files in addition to opening\n"; print " --min=\tMinimum number of seconds to keep a file open (default 5)\n"; print " --max=\tMaximum number of seconds to keep a file open (default 10)\n"; print " --readstop\t\tIf set, immediately exit thread after reading contents of the file\n"; print " --recurse\t\tIf set, recurse through the directories\n"; print " --tstack=\tSize in bytes to use for the threadstack, must be a multiple of 4096 (default 16*4096)\n"; print " -v\t\t\tVerbose mode, tell me what files are open and for how long\n"; print " -h\t\t\tDisplay this usage\n"; exit(0); } my %options = (); my $verbose = 0; GetOptions("verbose!" => \$verbose, # verbose option "d:s" => \$options{dir}, # directory to read files from "n:i" => \$options{numOpen}, # number of threads to open at the same time "min:i" => \$options{minTime}, # minimum time to keep a file open "max:i" => \$options{maxTime}, # maximum time to keep a file open "readstop" => \$options{readStop}, "recurse" => \$options{recurse}, "tstack:i" => \$options{tstack}, "r" => \$options{readFile}, # read file contents "h" => \$options{help} # display usage ); if ($options{help}) { print_usage(); } # if help is set, display usage and exit if (!defined($options{dir})) { print_usage(); } if (!defined($options{numOpen})) { $options{numOpen} = 10; } my $dir = $options{dir}; my @threadList; my $maxThreads = $options{numOpen} || 10; my $minTime = $options{minTime} || 5; my $maxTime = $options{maxTime} || 10; my $recurse = $options{recurse} || 0; my $tstack = $options{tstack} || 65536; our $readfile : shared = $options{readFile}; our $readstop : shared = $options{readStop}; my @filelist; my $file; print "Using a stacksize of $tstack...\n"; threads->set_stack_size($tstack); if (($maxTime <= $minTime) || ($minTime < 1) || ($maxTime < 1)) { print "Invalid min/max time\n"; exit(0); } if ($maxThreads < 1) { print "Invalid number of threads\n"; exit(0); } my $index = 0; while (0 == 0) { $file = random_file(-dir => $dir, -rec => $recurse); my $time = int( rand($maxTime-$minTime + 1)) + $minTime; if (!$readstop) { print "Randomly selected file: $file will be opened for $time seconds\n" if $verbose; } my $filename = $dir . "/" . $file; if(-f $filename) { my $newthread = threads->new(\&hold_file_open, $filename, $time); $newthread->detach; $index++; } if ($index >= $maxThreads) { # give the OS a chance to recover sleep(int(($minTime+$maxTime)/2)+1); $index = int($index / 2); } } sub hold_file_open { my $filename = shift; # which file to hold open my $openlength = shift; # the length in seconds to keep it open my $data; my $size = 0; my $bytesread = 0; my $FIN = POSIX::open($filename); if (!defined($FIN)) { die "Unable to open $filename: $!\n"; } if ($readfile) { my $starttime = time(); while (($bytesread = POSIX::read($FIN,$data,65536)) > 0) { $size = $size + $bytesread; #print "[" . $data . "]"; } my $endtime = time(); my $readtime = $endtime - $starttime; print "thread[" . threads->self->tid . "]" if $verbose; print "[" . threads->self->get_stack_size() . "] " if $verbose; print "read $size bytes from $filename in $readtime seconds\n" if $verbose; if ($readstop) { sleep(1); # give the OS a bit of time to play catchup POSIX::close($FIN); return 0; } my $newsleeptime = $openlength - $readtime; if ($newsleeptime < 1) { return 0; } $openlength = $newsleeptime; } sleep($openlength); POSIX::close($FIN); return 0; }