/****************************************************************
 *                                                              *
 *  LIBDIST V1.0						*
 *                                                              *
 *  sem.c -- semaphores                                         *
 *                                                              *
 *  Last changed: 17.02.96                                      *
 *  Author: Frank Kargl (frank.kargl@informatik.uni-ulm.de)     *
 *                                                              *
 *  Restrictions: works only for Solaris 2.6 or above           *
 *                                                              *
 ****************************************************************/

#include "libdist.h"
#include "config.h"

#include <synch.h>

static sema_t dl_sem_lock =  DL_SEM_UISEM;
				/* lock for semaphore lookup table */
				/* initialized this way so we can determine */
				/* if we have done sema_init yet */

static struct dl_sem_luts {
    char	name[DL_SEM_NSIZE];	/* Name of the semaphore */
    sema_t	*semaph;		/* associated semaphore */
} dl_sem_lut[DL_SEM_ESIZE] =		/* lookup table for semaphores */
    { { "", NULL} };

/***
 *** sema_t *dl_sem_create(char *name,int value)
 ***
 *** Function: create (or search for) a semaphore 'name'
 ***           if name==NULL then a new semaphore with a random
 ***           name is created and name is set to the name
 ***           if semaphore 'name' is created then it is
 ***           initialy set to 'val'
 ***           if semaphore 'name' allready exists then
 ***           ID is just returned and no further action
 ***           is taken
 ***           value should be zero in this case
 *** Return  : the semphore id
 ***	       NULL if error
 *** Restrictions: Semaphores are only valid within
 ***               threads of the same process
 ***/

sema_t *dl_sem_create(char *name,int value) {

    int i;		/* just a counter */

    /* first lock everything */
    if (dl_sem_lock.count!=1 && dl_sem_lock.count!=0) {
	sema_init(&dl_sem_lock, 1, USYNC_THREAD, NULL);
    }
    sema_wait(&dl_sem_lock);

    /* try to find the right semaphore */
    for(i=0;i<DL_SEM_ESIZE;i++) {
	if (!strcmp(name,dl_sem_lut[i].name)) {
	    /* found */
	    sema_post(&dl_sem_lock);
	    return dl_sem_lut[i].semaph;
	}

	if (*(dl_sem_lut[i].name)=='\0') {
	    /* create a new semaphore */
	    if (*name==NULL) {
		/* but first create a new name */
		name=malloc(DL_SEM_NSIZE);
		strcpy(name,"semXXXXXX");
		mktemp(name);
		if (*name=='\0') {
		    /* error in name creation ? */

#ifdef DEBUG
		    fprintf(stderr,"LIBDIST-sem: can't create semaphore name\n");
#endif

		    free(name);
		    sema_post(&dl_sem_lock);
		    return (sema_t *)NULL;
		}
	    } else {
		/* copy name to lookup table */
		strcpy(dl_sem_lut[i].name,name);
	    }
			
	    /* and now create and initialize new sema_t */
	    dl_sem_lut[i].semaph=malloc(sizeof(sema_t));

	    sema_init(dl_sem_lut[i].semaph, value, USYNC_THREAD, NULL);

	    /* free everything again */
	    sema_post(&dl_sem_lock);

	    return dl_sem_lut[i].semaph;
	}
    }

    /* end of table */
    sema_post(&dl_sem_lock);
    return (sema_t *)NULL;
}

/***
 *** void dl_sem_p(sema_t *sem)
 ***
 *** Function: P operation for 'sem'
 *** Return  : -
 ***/

void dl_sem_p(sema_t *sem) {
    sema_wait(sem);
}

/***
 *** void dl_sem_v(sema_t *sem)
 ***
 *** Function: V operation for 'sem'
 *** Return  : -
 ***/

void dl_sem_v(sema_t *sem) {
    sema_post(sem);
}
