#!/usr/bin/perl -w
######################################################################
# (c) Michael Schilli 1999
######################################################################

package Mutex;

use strict;

# Flags für Semaphore

my $IPC_CREAT  = 0001000;   # Semaphor erzeugen
my $IPC_EXCL   = 0002000;   # Exklusiver Create
my $IPC_NOWAIT = 0004000;   # Fehler, falls blockiert

my $SEM_UNDO   = 0100000;   # Semaphor freigeben, falls Prozeß
			    # endet
# Semaphor-Kommandos

my $IPC_RMID   = 0000000;   # Entfernen
my $IPC_SET    = 0000001;   # Setzen
my $IPC_STAT   = 0000002;   # Abfragen

###########################################################
sub new {
###########################################################
    my $class = shift;
    my $key   = shift;

    my $self = {};

    $self->{'semid'}  = semget($key, 1, 0644|$IPC_CREAT);

    die "Create failed" unless defined($self->{'semid'});

    bless($self, $class);
}

###########################################################
# Semaphor-Lock setzen: $sem->lock();
###########################################################
sub lock {
    my $self = shift;

    my $semnum  = 0;   # Erster Semaphor der Liste
    my $semflag = 0;

    # Warten, bis Semaphore Null ist
    my $semop     = 0;
    my $opstring1 = pack("sss", $semnum, $semop, $semflag);

    # Semaphor-Zähler um 1 erhöhen
    $semop     = $IPC_SET;
    $semflag   = $SEM_UNDO;  # Semaphore freigeben, wenn
			     # Prozeß endet
    my $opstring2 = pack("sss", $semnum, $semop,  $semflag);

    semop($self->{'semid'}, $opstring1 . $opstring2) || 
				       die "Lock failed";
}

###########################################################
# Semaphor-Lock freigeben: $sem->release();
###########################################################
sub release {
    my $self = shift;

    my $semnum  = 0;   # Erster Semaphor der Liste
    my $semflag = 0;

    # Herunterzählen
    my $semop = -1;
    my $opstring = pack("sss", $semnum, $semop, $semflag);

    semop($self->{'semid'},$opstring) || 
				die "Release failed";
}

###########################################################
# Semaphor löschen: $sem->delete();
###########################################################
sub delete {
    my $self = shift;

    semctl($self->{'semid'}, 0, $IPC_RMID, 0) || 
				die "Delete failed";
}

1;
