161 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 *  A type which wraps a semaphore
 | 
						|
 *
 | 
						|
 *  semaphore.c
 | 
						|
 *
 | 
						|
 *  Copyright (c) 2006-2008, R Oudkerk
 | 
						|
 *
 | 
						|
 *  All rights reserved.
 | 
						|
 *
 | 
						|
 *  Redistribution and use in source and binary forms, with or without
 | 
						|
 *  modification, are permitted provided that the following conditions
 | 
						|
 *  are met:
 | 
						|
 *
 | 
						|
 *  1. Redistributions of source code must retain the above copyright
 | 
						|
 *     notice, this list of conditions and the following disclaimer.
 | 
						|
 *
 | 
						|
 *  2. Redistributions in binary form must reproduce the above
 | 
						|
 *     copyright notice, this list of conditions and the following
 | 
						|
 *     disclaimer in the documentation and/or other materials provided
 | 
						|
 *     with the distribution.
 | 
						|
 *
 | 
						|
 *  3. Neither the name of author nor the names of any contributors
 | 
						|
 *     may be used to endorse or promote products derived from this
 | 
						|
 *     software without specific prior written permission.
 | 
						|
 *
 | 
						|
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS"
 | 
						|
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 | 
						|
 *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 | 
						|
 *  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
 | 
						|
 *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
						|
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
						|
 *  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 | 
						|
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 | 
						|
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
						|
 *  POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * Modifications Copyright (c) 2011, Patrick Mahoney
 | 
						|
 */
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
#include <fcntl.h>		/* For O_* constants */
 | 
						|
#include <sys/stat.h>		/* For mode constants */
 | 
						|
#include <semaphore.h>
 | 
						|
#include <stdlib.h>		/* malloc, free */
 | 
						|
#include <math.h>		/* floorf */
 | 
						|
#include <time.h>		/* timespec */
 | 
						|
 | 
						|
#include "psem.h"
 | 
						|
#include "psem_posix.h"
 | 
						|
 | 
						|
psem_t *
 | 
						|
psem_alloc(void) {
 | 
						|
  return (psem_t *) malloc(sizeof(psem_t));
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
psem_free(psem_t *psem) {
 | 
						|
  free(psem);
 | 
						|
}
 | 
						|
 | 
						|
#define errcheck_val(expr, errval, err)			\
 | 
						|
  do {							\
 | 
						|
    if ((expr) == (errval)) {				\
 | 
						|
      error_new((err), E_SOURCE_SYSTEM, errno);		\
 | 
						|
      return ERROR;					\
 | 
						|
    }							\
 | 
						|
  } while (0)
 | 
						|
 | 
						|
#define errcheck(expr, err) errcheck_val((expr), -1, (err))
 | 
						|
 | 
						|
int
 | 
						|
psem_open(psem_t *psem, const char *name, unsigned int value, error_t **err)
 | 
						|
{
 | 
						|
  errcheck_val(psem->sem = sem_open(name, O_CREAT | O_EXCL, 0600, value),
 | 
						|
	       SEM_FAILED,
 | 
						|
	       err);
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
psem_close(psem_t *psem, error_t **err)
 | 
						|
{
 | 
						|
  errcheck(sem_close(psem->sem), err);
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
psem_unlink(const char *name, error_t **err)
 | 
						|
{
 | 
						|
  errcheck(sem_unlink(name), err);
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
psem_post(psem_t *psem, error_t **err)
 | 
						|
{
 | 
						|
  errcheck(sem_post(psem->sem), err);
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
psem_wait(psem_t *psem, error_t **err)
 | 
						|
{
 | 
						|
  errcheck(sem_wait(psem->sem), err);
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
psem_trywait(psem_t *psem, error_t **err)
 | 
						|
{
 | 
						|
  errcheck(sem_trywait(psem->sem), err);
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
#define NS_PER_S (1000 * 1000 * 1000)
 | 
						|
#define US_PER_NS (1000)
 | 
						|
#define TV_NSEC_MAX (NS_PER_S - 1)
 | 
						|
 | 
						|
int
 | 
						|
psem_timedwait(psem_t *psem, float timeout_s, error_t **err)
 | 
						|
{
 | 
						|
  struct timeval now;
 | 
						|
  struct timespec abs_timeout;
 | 
						|
 | 
						|
  errcheck(gettimeofday(&now, NULL), err);
 | 
						|
  abs_timeout.tv_sec = now.tv_sec;
 | 
						|
  abs_timeout.tv_nsec = now.tv_usec * US_PER_NS;
 | 
						|
 | 
						|
  /* Fun with rounding: careful adding reltive timeout to abs time */
 | 
						|
  {
 | 
						|
    time_t sec;		/* relative timeout */
 | 
						|
    long nsec;
 | 
						|
  
 | 
						|
    sec = floorf(timeout_s);
 | 
						|
    nsec = floorf((timeout_s - floorf(timeout_s)) * NS_PER_S);
 | 
						|
 | 
						|
    abs_timeout.tv_sec += sec;
 | 
						|
    abs_timeout.tv_nsec += nsec;
 | 
						|
 | 
						|
    while (abs_timeout.tv_nsec > TV_NSEC_MAX) {
 | 
						|
      abs_timeout.tv_sec += 1;
 | 
						|
      abs_timeout.tv_nsec -= NS_PER_S;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  errcheck(sem_timedwait(psem->sem, &abs_timeout), err);
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
psem_getvalue(psem_t *psem, int *sval, error_t **err)
 | 
						|
{
 | 
						|
  errcheck(sem_getvalue(psem->sem, sval), err);
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 |