/*
    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: L.McLoughlin@doc.ic.ac.uk
*/

/* 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" );
}
