I am not sure that you need to go to that trouble for the described purpose. Why not dump information into a plain file, which the ever-running process can check for and read? Or, use a socket which is far more flexible? But what you ask can be done of course.
The writer gets blocked at opening the FIFO until the reader opens it, what is OK from what I read in the question. The reader can check in a non-blocking way by using a select. But then it's simpler that the writer creates the pipe in the first place and deletes it once it's done, so the reader knows that there is no new data when there's no file to open,.
Writer
use warnings;
use strict;
use feature 'say';
my $fifo = 'test.fifo';
if (-e $fifo) { unlink $fifo or die "Can't unlink $fifo: $!" }
system('mkfifo', $fifo) and system('mknod', $fifo, 'p')
and die "Can't make $fifo: $!";
open my $fh, '>', $fifo or die "Can't open fifo $fifo: $!"; # Blocks here until
say $fh "Message to fifo from $$"; # there's a reader
close $fh;
unlink $fifo or die "Error unlinking $fifo: $!";
Reader, the ever-running program
use warnings;
use strict;
use feature 'say';
use Errno qw(ENOENT);
my $fifo = 'test.fifo';
while (1) {
say "\nDo work (sleep a little really), try for message ...";
sleep 3;
if (my $msg = read_fifo($fifo)) {
say $msg;
#last; # done with this exercise
}
# Run the writer program in another terminal at some point
# Or, to simulate that:
#my $pid = fork // die "Can't fork: $!";
#if ($pid == 0) { exec $writer_path }
}
sub read_fifo {
my ($fifo) = @_;
open my $fh, '<', $fifo or do {
if ($! == ENOENT) {
say "No file $fifo -- no new data, carry on and use default";
return;
}
else { die "Can't open fifo $fifo: $!" } # some other error
};
return join '', <$fh>;
}
This leaves out more testing that would be appropriate, and yet other details.
In my take all this shows firstly that communicating over a plain file is far simpler in this case.
The problem got rounded with a lot of context, provided in comments and a chat. One detail substantially changes the problem: the writer actually can't wait. Here is a way to handle that.
The writer needs to do other things after making data available, picked up by the reader at an unspecified time, so it cannot wait at the pipe. Then fork a process in the writer and deal with the FIFO in that child process, while the parent is free to do what it needs.
Writer from above, now handling FIFO in a child process
use warnings;
use strict;
use feature 'say';
my $fifo = 'test.fifo';
my $pid = fork // die "Can't fork: $!";
if ($pid == 0) {
if (-e $fifo) { unlink $fifo or die "Can't unlink $fifo: $!" }
system('mkfifo', $fifo) and system('mknod', $fifo, 'p')
and die "Can't make $fifo: $!";
open my $fh, '>', $fifo or die "Can't open fifo $fifo: $!"; # awaits reader
say $fh "Message to fifo from $$";
close $fh;
unlink $fifo or die "Error unlinking $fifo: $!";
exit;
}
# parent can now do its work
# Always reap -- but now also must not leave until FIFO's been read
my $gone = waitpid $pid, 0;
if ($gone > 0) { say "FIFO-handling child exited with $?" }
This can be tested the same way as the initial writer, with the same reader.
The writer's child is waiting on the pipe in a blocked open, until the reader gets to go to read it. As the reader opens the pipe for reading the writer's open completes and the data gets written, and is received by the reader. Or there is no FIFO at all and the reader's open fails (with ENOENT) so the reader knows that there is no new data and can use its default.