/*
   Buffer.  Very fast reblocking filter speedy writing of tapes.
   Copyright (C) 1990,1991  Lee McLoughlin

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 1, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

   Lee McLoughlin.
   Dept of Computing, Imperial College,
   180 Queens Gate, London, SW7 2BZ, UK.

   Email: [email protected]
*/

/* This is a simple module to provide an easier to understand interface to
* semaphores */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#if defined(SYS5) || defined(ultrix) || defined(_AIX)
union semun {
       int val;
       struct semid_ds *buf;
       ushort *array;
};
#endif

/* Set a semaphore to a particular value - meant to be used before
* first lock/unlock */
void
sem_set( sem_id, val )
       int sem_id;
       int val;
{
       union semun arg;
       extern int errno;

       arg.val = val;

       errno = 0;
       semctl( sem_id, 0, SETVAL, arg );
       if( errno != 0 ){
               perror( "buffer: internal error, sem_set" );
               exit( -1 );
       }
}

int
new_sem()
{
       int sem;

       sem = semget( IPC_PRIVATE, 1, IPC_CREAT|S_IREAD|S_IWRITE );
       if( sem < 0 ){
               perror( "buffer: internal error, couldn't create semaphore" );
               exit( -1 );
       }
       sem_set( sem, 1 );

       return sem;
}

void
lock( sem_id )
       int sem_id;
{
       struct sembuf sembuf;

       sembuf.sem_num = 0;
       sembuf.sem_op = -1;
       sembuf.sem_flg = 0;

       if( semop( sem_id, &sembuf, 1 ) == -1 ){
               fprintf( stderr, "internal error, lock id %d\n", sem_id );
               perror( "buffer: lock error" );
               exit( -1 );
       }
}

void
unlock( sem_id )
       int sem_id;
{
       struct sembuf sembuf;

       sembuf.sem_num = 0;
       sembuf.sem_op = 1;
       sembuf.sem_flg = 0;

       if( semop( sem_id, &sembuf, 1 ) == -1 ){
               fprintf( stderr, "internal error, lock id %d\n", sem_id );
               perror( "buffer: unlock error" );
               exit( -1 );
       }
}

void
remove_sem( sem_id )
       int sem_id;
{
       if( sem_id == -1 )
               return;

       if( semctl( sem_id, 0, IPC_RMID, NULL ) == -1 )
               perror( "buffer: internal error, failed to remove semaphore" );
}