The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
###############################################################################
## ----------------------------------------------------------------------------
## MCE::Mutex - Simple semaphore for Many-Core Engine.
##
###############################################################################

package MCE::Mutex;

use strict;
use warnings;

use Socket qw( :crlf PF_UNIX PF_UNSPEC SOCK_STREAM );

our $VERSION = '1.600';

sub DESTROY {

   my ($_mutex) = @_;

   return if (defined $MCE::MCE && $MCE::MCE->wid);

   if (defined $_mutex->{_r_sock}) {
      local ($!, $?);

      CORE::shutdown $_mutex->{_w_sock}, 2;
      CORE::shutdown $_mutex->{_r_sock}, 2;

      close $_mutex->{_w_sock}; undef $_mutex->{_w_sock};
      close $_mutex->{_r_sock}; undef $_mutex->{_r_sock};
   }

   return;
}

###############################################################################
## ----------------------------------------------------------------------------
## New instance instantiation.
##
###############################################################################

sub new {

   my ($_class, %_argv) = @_;

   @_ = (); local $!;

   return if (defined $MCE::MCE && $MCE::MCE->wid);

   my $_mutex = {}; bless($_mutex, ref($_class) || $_class);

   socketpair( $_mutex->{_r_sock}, $_mutex->{_w_sock},
      PF_UNIX, SOCK_STREAM, PF_UNSPEC ) or die "socketpair: $!\n";

   binmode $_mutex->{_r_sock};
   binmode $_mutex->{_w_sock};

   my $_old_hndl = select $_mutex->{_r_sock}; $| = 1;
                   select $_mutex->{_w_sock}; $| = 1;

   select $_old_hndl;

   syswrite $_mutex->{_w_sock}, '0';

   return $_mutex;
}

###############################################################################
## ----------------------------------------------------------------------------
## Lock method.
##
###############################################################################

sub lock {

   my ($_mutex) = @_;

   sysread $_mutex->{_r_sock}, my $_b, 1;

   return;
}

###############################################################################
## ----------------------------------------------------------------------------
## Unlock method.
##
###############################################################################

sub unlock {

   my ($_mutex) = @_;

   syswrite $_mutex->{_w_sock}, '0';

   return;
}

###############################################################################
## ----------------------------------------------------------------------------
## Synchronize method.
##
###############################################################################

sub synchronize {

   my ($_mutex, $_code) = (shift, shift);

   if (ref $_code eq 'CODE') {
      $_mutex->lock; $_code->(@_); $_mutex->unlock;
   }

   return;
}

1;

__END__

###############################################################################
## ----------------------------------------------------------------------------
## Module usage.
##
###############################################################################

=head1 NAME

MCE::Mutex - Simple semaphore for Many-Core Engine

=head1 VERSION

This document describes MCE::Mutex version 1.600

=head1 SYNOPSIS

   use MCE::Flow max_workers => 4;
   use MCE::Mutex;

   print "## running a\n";
   my $a = MCE::Mutex->new;

   mce_flow sub {
      $a->lock;

      ## access shared resource
      my $wid = MCE->wid; MCE->say($wid); sleep 1;

      $a->unlock;
   };

   print "## running b\n";
   my $b = MCE::Mutex->new;

   mce_flow sub {
      $b->synchronize( sub {

         ## access shared resource
         my ($wid) = @_; MCE->say($wid); sleep 1;

      }, MCE->wid );
   };

=head1 DESCRIPTION

This module implements locking methods that can be used to coordinate access
to shared data from multiple workers spawned as threads or processes.

=back

=head1 API DOCUMENTATION

=over 3

=item ->new ( void )

Creates a new mutex.

=item ->lock ( void )

Attempts to grab the lock and waits if not available.

=item ->unlock ( void )

Releases the lock.

=item ->synchronize ( sub { ... }, @_ )

Obtains a lock, runs the code block, and releases the lock after the block
completes.

=back

=head1 INDEX

L<MCE|MCE>

=head1 AUTHOR

Mario E. Roy, S<E<lt>marioeroy AT gmail DOT comE<gt>>

=head1 LICENSE

This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.

See L<http://dev.perl.org/licenses/> for more information.

=cut