/* sync.c */
/*
* Vis5D system for visualizing five dimensional gridded data sets.
* Copyright (C) 1990 - 2000 Bill Hibbard, Johan Kellum, Brian Paul,
* Dave Santek, and Andre Battaiola.
*
* 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 2 of the License, or
* (at your option) any later version.
*
* As a special exception to the terms of the GNU General Public
* License, you are permitted to link Vis5D with (and distribute the
* resulting source and executables) the LUI library (copyright by
* Stellar Computer Inc. and licensed for distribution with Vis5D),
* the McIDAS library, and/or the NetCDF library, where those
* libraries are governed by the terms of their own licenses.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../config.h"
/* A library of concurrency functions and macros usable in C on Stellar,
SGI, and CRAY systems.
Note that when declaring LOCKs or SEMAPHOREs, only one can be declared
per line. For example:
LOCK a; this is correct
LOCK b;
LOCK a, b; this is incorrect
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "sync.h"
#ifdef HAVE_SGI_SPROC
# include <unistd.h>
# include <ulocks.h>
usptr_t *Arena;
static char *ArenaName;
#endif
/*
* The lock used to implement read/write locks below:
*/
static LOCK RWlock;
/*
* This function should be called before using any of sychronization
* primitives below.
* Return: 1 = success, 0 = error;
*/
int init_sync( void )
{
#ifdef HAVE_SGI_SPROC
ArenaName = tempnam( "", "LOCK" );
if (!ArenaName) {
fprintf(stderr,"Unable to allocate arena.\n");
return 0;
}
/*
* Increase CONF_INITUSERS to 20 to avoid the error:
* New process pid 20029 could not join I/O arena:No space left on device
* Need to raise CONF_INITUSERS? (usconfig(3P))
*/
usconfig( CONF_INITUSERS, 20 );
/*
* This options causes the temporary lock file to be unlinked automatically.
*/
usconfig( CONF_ARENATYPE, US_SHAREDONLY );
/*
* Initialize the shared arena
*/
Arena = usinit(ArenaName);
if (!Arena) {
fprintf(stderr,"Unable to allocate arena.\n");
return 0;
}
#endif
ALLOC_LOCK( RWlock );
return 1;
}
/*** term_sync ********************************************************
This function should be called prior to program termination to
release resources associated with the synchronization primitives.
**********************************************************************/
void term_sync( void )
{
#ifdef HAVE_SGI_SPROC
if (Arena) {
unlink( ArenaName );
Arena = NULL;
}
#endif
}
/********************************/
/*** CRAY SEMAPHORE FUNCTIONS ***/
/********************************/
#ifdef cray
/* Semaphore value (n):
if n<=0 then
the semaphore is held; calls to wait will be blocked
if n<0 then
abs(n) is the number of waiters
if n>0 then
the semaphore is available; n calls to wait will not block.
*/
void alloc_sem( s, initval )
struct sem *s;
int initval;
{
if (s) {
LOCKASGN( &(s->mutex) );
EVASGN( &(s->ev) );
s->val = initval;
s->evflag = 0;
s->awaken = 0;
}
}
void free_sem( s )
struct sem *s;
{
if (s) {
LOCKREL( &(s->mutex) );
EVREL( &(s->ev) );
}
}
/* changed to use awaken value: */
void wait_sem( s )
struct sem *s;
{
LOCKON( &(s->mutex) );
s->val--;
while (s->val<0) {
/* wait for a signal */
LOCKOFF( &(s->mutex) );
EVWAIT( &(s->ev) ); /* block until awaken>0 */
LOCKON( &(s->mutex) );
/* do EVCLEAR exactly once. */
if (s->evflag) {
EVCLEAR( &(s->ev) );
s->evflag = 0;
}
if (s->awaken>0) {
s->awaken--;
LOCKOFF( &(s->mutex) );
return;
}
}
LOCKOFF( &(s->mutex) );
}
void signal_sem( s )
struct sem *s;
{
LOCKON( &(s->mutex) );
s->val++;
if (s->val <= 0) {
s->awaken++;
if (s->evflag==0) {
EVPOST( &(s->ev) );
s->evflag = 1;
}
}
LOCKOFF( &(s->mutex) );
}
#endif /*cray*/
/**********************************************/
/*** STELLAR / STARDENT SEMAPHORE FUNCTIONS ***/
/**********************************************/
#ifdef stellar
void alloc_sem( s, n )
struct sem *s;
int n;
{
s->val = 0;
s->mutex = 0;
s->awaken = 0;
}
void wait_sem( s )
struct sem *s;
{
LOCK_ON( s->mutex );
s->val--;
while (s->val<0) {
/* wait for a signal */
LOCK_OFF( s->mutex );
wait_until_gt( &(s->awaken), 0 ); /* block until awaken>0 */
LOCK_ON( s->mutex );
if (s->awaken>0) {
s->awaken--;
LOCK_OFF( s->mutex );
return;
}
}
LOCK_OFF( s->mutex );
}
void signal_sem( s )
struct sem *s;
{
LOCK_ON( s->mutex );
s->val++;
if (s->val <= 0)
s->awaken++; /* wake-up another blocked process */
LOCK_OFF( s->mutex );
}
#endif /*stellar*/
/***********************************/
/*** SEQUENT SEMAPHORE FUNCTIONS ***/
/***********************************/
#ifdef sequent
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int alloc_sem( initval )
int initval;
{
key_t key;
int s, val;
key = 0;
s = semget( key, 1, 0666 | IPC_CREAT );
if (s<0) {
perror("getting semaphore");
return -1;
}
else {
if (semctl( s, 0, SETVAL, initval ) < 0) {
perror("initializing semaphore");
}
if (semctl( s, 0, GETVAL, 0 ) < 0) {
perror("initializing semaphore");
}
}
return s;
}
void free_sem( s )
int s;
{
if (semctl( s, 0, IPC_RMID, 0 ) < 0) {
perror("destroying semaphore");
}
}
void wait_sem( s )
int s;
{
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = -1;
sb.sem_flg = SEM_UNDO;
semop( s, &sb, 1 );
}
void signal_sem( s )
int s;
{
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = 1;
sb.sem_flg = SEM_UNDO;
semop( s, &sb, 1 );
}
#endif /*sequent*/
/*
* Read/write locking on an integer:
* if n==0 then lock is free
* if n>0 then there are (n) readers
* if n==-1 then there is a writer
*/
int cond_read_lock( int *lk )
{
int result;
LOCK_ON( RWlock );
if (*lk>=0) {
*lk = *lk + 1;
result = 1;
}
else {
result = 0;
}
LOCK_OFF( RWlock );
return result;
}
void wait_read_lock( int *lk )
{
int acquired = 0;
do {
LOCK_ON( RWlock );
if (*lk>=0) {
*lk = *lk + 1;
acquired = 1;
}
LOCK_OFF( RWlock );
} while (!acquired);
}
void wait_write_lock( int *lk )
{
int acquired = 0;
do {
LOCK_ON( RWlock );
if (*lk==0) {
*lk = -1;
acquired = 1;
}
LOCK_OFF( RWlock );
} while (!acquired);
}
void done_read_lock( int *lk )
{
LOCK_ON( RWlock );
assert( *lk > 0 );
*lk = *lk - 1;
LOCK_OFF( RWlock );
}
void done_write_lock( int *lk )
{
LOCK_ON( RWlock );
assert( *lk==-1 );
*lk = 0;
LOCK_OFF( RWlock );
}
syntax highlighted by Code2HTML, v. 0.9.1