I use Mojo::IOLoop to talk to a port to send commands to a digital receiver.
Because the receiver can only open the port once, but the code talking to it sits behind a web interface and a web server, there is a risk that commands get sent concurrently - so the digital receiver loses them, and things go wrong.
So - how can I ensure that some piece of code never gets run concurrently?
I was trying to use file locks like this:
sub enqueue {
my $self = shift;
my ($cmd, $promise) = @_;
while (!(flock DATA, LOCK_EX|LOCK_NB)) { sleep(0.25) }
my (@r);
my $id = Mojo::IOLoop->client({ address => '192.168.1.204',
port => 23, timeout => 13 }
=> sub ($loop, $err, $stream) {
return $promise->reject('could not open stream') unless $stream;
$stream->on(error => sub ($stream, $err) {
flock(DATA, LOCK_UN);
$stream->close;
$promise->reject($err);
});
$stream->on(read => sub ($stream, $bytes) {
$bytes =~ s/\r\n$//;
push @r, split /\r\n/, $bytes;
# stream done is a function that checks that
# the appropriate number of lines got sent back
if (stream_done(@r)) {
flock(DATA, LOCK_UN);
$promise->resolve(\@r);
$stream->close;
};
});
$stream->on(timeout => sub ($stream) {
flock(DATA, LOCK_UN);
$stream->close;
$promise->reject('timeout') if ($err);
});
$stream->write($cmd);
});
}