/*
 *  semaphore.c
 *  RatLib
 *
 *  Created by Curtis Jones on 2008.10.20.
 *  Copyright 2008 Curtis Jones. All rights reserved.
 *
 */

#include "semaphore.h"
#include "logger.h"
#include "opool.h"
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

static uint32_t gSemName;
static uint32_t gSemRand;

#pragma mark -
#pragma mark structors

/**
 *
 *
 */
int
semaphore_init (semaphore_t *semaphore, opool_t *pool)
{
	int error;
	
	if (unlikely(semaphore == NULL))
		LOG_ERROR_AND_RETURN(-1, "%s.. null semaphore_t\n", __PRETTY_FUNCTION__);
	
	if (gSemRand == 0)
		gSemRand = random() % 10000;
	
	snprintf(semaphore->name, sizeof(semaphore->name), "chatter-%04x-%04d", gSemRand, ++gSemName);
	
	if (unlikely(0 != (error = cobject_init(&semaphore->cobject, (cobject_destroy_func)semaphore_destroy, pool))))
		LOG_ERROR_AND_RETURN(-101, "%s.. failed to cobject_init, 0x%08X [%d]\n", __PRETTY_FUNCTION__, error, error);
	
	if (SEM_FAILED == (semaphore->sem = sem_open(semaphore->name, O_CREAT | O_EXCL, S_IRWXU, 0)))
		LOG_ERROR_AND_RETURN(-102, "%s.. failed to sem_open(%s), %s\n", __PRETTY_FUNCTION__, semaphore->name, strerror(errno));
	
	LOG3("%s.. opened semaphore, %s\n", __PRETTY_FUNCTION__, semaphore->name);
	
	return 0;
}

/**
 *
 *
 */
int
semaphore_destroy (semaphore_t *semaphore)
{
	int error;
	
	if (unlikely(semaphore == NULL))
		LOG_ERROR_AND_RETURN(-1, "%s.. null semaphore_t\n", __PRETTY_FUNCTION__);
	
	if (unlikely(semaphore->sem != NULL && 0 != (error = sem_close(semaphore->sem))))
		LOG_ERROR_AND_RETURN(-101, "%s.. failed to sem_close, %s\n", __PRETTY_FUNCTION__, strerror(errno));
	
	if (unlikely(0 != (error = cobject_destroy(&semaphore->cobject))))
		LOG_ERROR_AND_RETURN(-102, "%s.. failed to cobject_destroy, 0x%08X [%d]\n", __PRETTY_FUNCTION__, error, error);
	
	return 0;
}





#pragma mark -
#pragma mark accessors

/**
 *
 *
 */
inline int
semaphore_post (semaphore_t *semaphore)
{
	int error;
	
	if (unlikely(semaphore == NULL))
		LOG_ERROR_AND_RETURN(-1, "%s.. null semaphore_t\n", __PRETTY_FUNCTION__);
	
	if (unlikely(0 != (error = sem_post(semaphore->sem))))
		LOG_ERROR_AND_RETURN(-101, "%s.. failed to sem_post, %s\n", __PRETTY_FUNCTION__, strerror(errno));
	
	return 0;
}

/**
 *
 *
 */
inline int
semaphore_wait (semaphore_t *semaphore)
{
	int error;
	
	if (unlikely(semaphore == NULL))
		LOG_ERROR_AND_RETURN(-1, "%s.. null semaphore_t\n", __PRETTY_FUNCTION__);
	
	if (unlikely(0 != (error = sem_wait(semaphore->sem))))
		LOG_ERROR_AND_RETURN(-101, "%s.. failed to sem_wait, %s\n", __PRETTY_FUNCTION__, strerror(errno));
	
	return 0;
}





#pragma mark -
#pragma mark cobject stuff

/**
 *
 *
 */
inline semaphore_t*
semaphore_retain (semaphore_t *semaphore)
{
	if (unlikely(semaphore == NULL))
		LOG_ERROR_AND_RETURN(NULL, "%s.. null semaphore_t\n", __PRETTY_FUNCTION__);
	
	return (semaphore_t*)cobject_retain(&semaphore->cobject);
}

/**
 *
 *
 */
inline void
semaphore_release (semaphore_t *semaphore)
{
	if (unlikely(semaphore == NULL))
		LOG_ERROR_AND_RETURN(, "%s.. null semaphore_t\n", __PRETTY_FUNCTION__);
	
	cobject_release(&semaphore->cobject);
}
