Initial commit.
This commit is contained in:
commit
cf45ab9891
42 files changed
+1704
No files matched your search
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Extensions atop psem. Recursive mutex, bounded semaphore.
|
||||
*/
|
||||
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
|
||||
#include "mempcpy.h" /* includes string.h */
|
||||
#include "psem.h"
|
||||
#include "psem_error.h"
|
||||
#include "bsem.h"
|
||||
|
||||
#define MAX_NAME 128 /* This is much less the POSIX max
|
||||
name. Users of this library must
|
||||
not use longer names. */
|
||||
|
||||
static const char bsem_lock_suffix[] = "-bsem-lock";
|
||||
|
||||
#define MAX_LOCK_NAME (MAX_NAME + strlen(bsem_lock_suffix) + 1)
|
||||
|
||||
/**
|
||||
* Assumes dest has sufficient space to hold "[MAX_NAME]-bsem-lock".
|
||||
*/
|
||||
static int
|
||||
make_lockname(char *dest, const char *name, error_t **err)
|
||||
{
|
||||
int namelen;
|
||||
|
||||
namelen = strlen(name);
|
||||
if (namelen > MAX_NAME) {
|
||||
error_new(err, E_SOURCE_PSEM, E_NAME_TOO_LONG);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
*((char *) mempcpy(mempcpy(dest, name, namelen),
|
||||
bsem_lock_suffix,
|
||||
strlen(bsem_lock_suffix))) = '\0';
|
||||
}
|
||||
|
||||
size_t sizeof_bsem_t = sizeof (bsem_t);
|
||||
|
||||
bsem_t *
|
||||
bsem_alloc(void) {
|
||||
return malloc(sizeof(bsem_t));
|
||||
}
|
||||
|
||||
void
|
||||
bsem_free(bsem_t *bsem) {
|
||||
free(bsem);
|
||||
}
|
||||
|
||||
#define call_or_return(exp) \
|
||||
do { if ((exp) == ERROR) { return ERROR; } } while (0)
|
||||
|
||||
#define bsem_lock_or_return(bsem, err) call_or_return(bsem_lock((bsem), (err)))
|
||||
|
||||
#define bsem_unlock_or_return(bsem, err) call_or_return(bsem_unlock((bsem), (err)))
|
||||
|
||||
int
|
||||
bsem_open(bsem_t *bsem, const char *name, unsigned int maxvalue, unsigned int value, error_t **err)
|
||||
{
|
||||
char lockname[MAX_LOCK_NAME];
|
||||
|
||||
call_or_return(psem_open(&bsem->psem, name, value, err));
|
||||
call_or_return(make_lockname(lockname, name, err));
|
||||
call_or_return(psem_open(&bsem->lock, lockname, 1, err));
|
||||
|
||||
bsem->maxvalue = maxvalue;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
bsem_lock(bsem_t *bsem, error_t **err)
|
||||
{
|
||||
call_or_return(psem_wait(&bsem->lock, err));
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
bsem_unlock(bsem_t *bsem, error_t **err)
|
||||
{
|
||||
call_or_return(psem_post(&bsem->lock, err));
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
bsem_close(bsem_t *bsem, error_t **err)
|
||||
{
|
||||
bsem_lock_or_return(bsem, err);
|
||||
|
||||
if (psem_close(&bsem->psem, err) == ERROR) {
|
||||
bsem_unlock(bsem, NULL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
bsem_unlock_or_return(bsem, err);
|
||||
|
||||
call_or_return(psem_close(&bsem->lock, err));
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
bsem_unlink(const char *name, error_t **err)
|
||||
{
|
||||
char lockname[MAX_LOCK_NAME];
|
||||
|
||||
call_or_return(psem_unlink(name, err));
|
||||
call_or_return(make_lockname(lockname, name, err));
|
||||
call_or_return(psem_unlink(lockname, err));
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
bsem_post(bsem_t *bsem, error_t **err)
|
||||
{
|
||||
int sval;
|
||||
|
||||
bsem_lock_or_return(bsem, err);
|
||||
|
||||
/* FIXME: maxvalue is broken on some systems... (cygwin? mac?) */
|
||||
if (psem_getvalue(&bsem->psem, &sval, err) == ERROR) {
|
||||
bsem_unlock(bsem, err);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (sval >= bsem->maxvalue) {
|
||||
/* ignored silently */
|
||||
bsem_unlock(bsem, err);
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (psem_post(&bsem->psem, err) == ERROR) {
|
||||
bsem_unlock(bsem, err);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
bsem_unlock_or_return(bsem, err);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
bsem_wait(bsem_t *bsem, error_t **err)
|
||||
{
|
||||
call_or_return(psem_wait(&bsem->psem, err));
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
bsem_trywait(bsem_t *bsem, error_t **err)
|
||||
{
|
||||
bsem_lock_or_return(bsem, err);
|
||||
|
||||
if (psem_trywait(&bsem->psem, err) == ERROR) {
|
||||
bsem_unlock(bsem, NULL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
bsem_unlock_or_return(bsem, err);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
bsem_timedwait(bsem_t *bsem, float timeout_s, error_t **err)
|
||||
{
|
||||
bsem_lock_or_return(bsem, err);
|
||||
|
||||
if (psem_timedwait(&bsem->psem, timeout_s, err) == ERROR) {
|
||||
bsem_unlock(bsem, NULL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
bsem_unlock_or_return(bsem, err);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
bsem_getvalue(bsem_t *bsem, int *sval, error_t **err)
|
||||
{
|
||||
bsem_lock_or_return(bsem, err);
|
||||
|
||||
if (psem_getvalue(&bsem->psem, sval, err) == ERROR) {
|
||||
bsem_unlock(bsem, NULL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
bsem_unlock_or_return(bsem, err);
|
||||
return OK;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef __BSEM_H__
|
||||
#define __BSEM_H__
|
||||
|
||||
#include "psem.h"
|
||||
#include "psem_error.h"
|
||||
|
||||
struct bsem {
|
||||
psem_t psem;
|
||||
psem_t lock;
|
||||
int maxvalue;
|
||||
};
|
||||
|
||||
typedef struct bsem bsem_t;
|
||||
|
||||
extern size_t sizeof_bsem_t;
|
||||
|
||||
bsem_t * bsem_alloc();
|
||||
void bsem_free(bsem_t *bsem);
|
||||
|
||||
int bsem_open(bsem_t *, const char *, unsigned int, unsigned int, error_t **);
|
||||
int bsem_close(bsem_t *, error_t **);
|
||||
int bsem_unlink(const char *, error_t **);
|
||||
|
||||
int bsem_post(bsem_t *, error_t **);
|
||||
int bsem_wait(bsem_t *, error_t **);
|
||||
int bsem_trywait(bsem_t *, error_t **);
|
||||
int bsem_timedwait(bsem_t *, float, error_t **);
|
||||
|
||||
int bsem_getvalue(bsem_t *, int *, error_t **);
|
||||
|
||||
#endif /* __BSEM_H__ */
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Define and extern various constants defined as macros.
|
||||
*/
|
||||
|
||||
#include <sys/mman.h> /* PROT_*, MAP_* */
|
||||
#include <fcntl.h> /* O_* */
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
int o_rdwr = O_RDWR;
|
||||
int o_creat = O_CREAT;
|
||||
int o_excl = O_EXCL;
|
||||
|
||||
int prot_read = PROT_READ;
|
||||
int prot_write = PROT_WRITE;
|
||||
int prot_exec = PROT_EXEC;
|
||||
int prot_none = PROT_NONE;
|
||||
|
||||
void * map_failed = MAP_FAILED;
|
||||
|
||||
int map_shared = MAP_SHARED;
|
||||
int map_private = MAP_PRIVATE;
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef __CONSTANTS_H__
|
||||
#define __CONSTANTS_H__
|
||||
|
||||
extern int o_rdwr;
|
||||
extern int o_creat;
|
||||
extern int o_excl;
|
||||
|
||||
extern int prot_read;
|
||||
extern int prot_write;
|
||||
extern int prot_exec;
|
||||
extern int prot_none;
|
||||
|
||||
extern void * map_failed;
|
||||
|
||||
extern int map_shared;
|
||||
extern int map_private;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
require 'mkmf'
|
||||
|
||||
$objs = []
|
||||
|
||||
# posix semaphores
|
||||
if have_func('sem_open', 'semaphore.h')
|
||||
have_func('floorf', 'math.h') or abort("Missing required floorf() in math.h")
|
||||
have_library('m', 'floorf')
|
||||
|
||||
unless have_func('mempcpy', 'string.h')
|
||||
$objs << 'mempcpy.o'
|
||||
end
|
||||
|
||||
have_library('rt', 'sem_open')
|
||||
end
|
||||
|
||||
c_sources = ['psem.c', 'psem_error.c', 'psem_posix.c', 'bsem.c', 'constants.c']
|
||||
$objs += ['psem.o', 'psem_error.o', 'bsem.o', 'constants.o']
|
||||
|
||||
depend_rules <<-END
|
||||
psem.c: psem.h psem_posix.c
|
||||
psem_error.c: psem_error.h
|
||||
|
||||
bsem.h: psem.h psem_error.h
|
||||
bsem.c: psem.h psem_error.h bsem.h
|
||||
|
||||
constants.c: constants.h
|
||||
mempcpy.c: mempcpy.h
|
||||
|
||||
#{$objs.map { |o| "#{o}: #{o.chomp(".o")}.c" }.join("\n")}
|
||||
|
||||
libpsem.o: #{$objs.join(' ')}
|
||||
END
|
||||
|
||||
|
||||
create_makefile('libpsem')
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "mempcpy.h"
|
||||
|
||||
void *
|
||||
mempcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
return (char *) memcpy(dest, src, n) + n;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef __MEMPCPY_H__
|
||||
#define __MEMPCPY_H__
|
||||
|
||||
#ifdef HAVE_MEMPCPY
|
||||
#define __USE_GNU
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
void *mempcpy(void *, const void *, size_t);
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#endif /* __MEMPCPY_H__ */
|
||||
@@ -0,0 +1,15 @@
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
|
||||
#include "mutex.h"
|
||||
|
||||
size_t sizeof_mutex_t = sizeof (mutex_t);
|
||||
|
||||
mutex_t *
|
||||
mutex_alloc(void) {
|
||||
return malloc(sizeof(mutex_t));
|
||||
}
|
||||
|
||||
void
|
||||
mutex_free(mutex_t * mutex) {
|
||||
free(mutex);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef __MUTEX_H__
|
||||
#define __MUTEX_H__
|
||||
|
||||
#include "bsem.h"
|
||||
|
||||
struct mutex {
|
||||
bsem_t *bsem;
|
||||
};
|
||||
|
||||
typedef struct mutex mutex_t;
|
||||
|
||||
extern size_t sizeof_mutex_t;
|
||||
|
||||
#endif /* __MUTEX_H__ */
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "psem.h"
|
||||
|
||||
int OK = 0;
|
||||
int ERROR = -1;
|
||||
|
||||
int E_SOURCE_SYSTEM = 1;
|
||||
int E_SOURCE_PSEM = 2;
|
||||
|
||||
int E_NAME_TOO_LONG = 1;
|
||||
|
||||
#ifdef HAVE_SEM_OPEN
|
||||
#include "psem_posix.c"
|
||||
#endif
|
||||
|
||||
size_t sizeof_psem_t = sizeof (psem_t);
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef __PSEM_H__
|
||||
#define __PSEM_H__
|
||||
|
||||
/**
|
||||
* Portable semaphore interface focusing on cross-process use.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SEM_OPEN
|
||||
#include "psem_posix.h"
|
||||
#endif
|
||||
|
||||
#include "psem_error.h"
|
||||
|
||||
typedef struct psem psem_t;
|
||||
|
||||
extern size_t sizeof_psem_t;
|
||||
|
||||
extern int OK;
|
||||
extern int ERROR;
|
||||
|
||||
extern int E_SOURCE_SYSTEM;
|
||||
extern int E_SOURCE_PSEM;
|
||||
|
||||
extern int E_NAME_TOO_LONG;
|
||||
|
||||
int psem_errno();
|
||||
|
||||
psem_t * psem_alloc();
|
||||
void psem_free(psem_t *);
|
||||
|
||||
int psem_open(psem_t *, const char *, unsigned int, error_t **);
|
||||
int psem_close(psem_t *, error_t **);
|
||||
int psem_unlink(const char *, error_t **);
|
||||
|
||||
int psem_post(psem_t *, error_t **);
|
||||
|
||||
int psem_wait(psem_t *, error_t **);
|
||||
int psem_trywait(psem_t *, error_t **);
|
||||
int psem_timedwait(psem_t *, float, error_t **);
|
||||
|
||||
int psem_getvalue(psem_t *, int *, error_t **);
|
||||
|
||||
#endif /* __PSEM_H__ */
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Similar to GError from GLib.
|
||||
*/
|
||||
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
|
||||
#include "psem_error.h"
|
||||
|
||||
struct error {
|
||||
int error_source;
|
||||
int error_number;
|
||||
};
|
||||
|
||||
error_t *
|
||||
error_alloc()
|
||||
{
|
||||
return (error_t *) malloc(sizeof (error_t));
|
||||
}
|
||||
|
||||
void
|
||||
error_free(error_t *err)
|
||||
{
|
||||
free(err);
|
||||
}
|
||||
|
||||
void
|
||||
error_set(error_t *err, int source, int value)
|
||||
{
|
||||
err->error_source = source;
|
||||
err->error_number = value;
|
||||
}
|
||||
|
||||
void
|
||||
error_new(error_t **err, int source, int value)
|
||||
{
|
||||
if (err != NULL) {
|
||||
if (*err == NULL) {
|
||||
*err = error_alloc();
|
||||
error_set(*err, source, value);
|
||||
} else {
|
||||
/* tried to create a new error atop an existing error... */
|
||||
}
|
||||
} else {
|
||||
/* error is being ignored by caller */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef __PSEM_ERROR_H__
|
||||
#define __PSEM_ERROR_H__
|
||||
|
||||
typedef struct error error_t;
|
||||
|
||||
error_t * error_alloc();
|
||||
void error_free(error_t *);
|
||||
|
||||
void error_set(error_t *, int, int);
|
||||
|
||||
#endif /* __PSEM_ERROR_H__ */
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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; \
|
||||
} \
|
||||
return OK; \
|
||||
} 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);
|
||||
}
|
||||
|
||||
int
|
||||
psem_close(psem_t *psem, error_t **err)
|
||||
{
|
||||
errcheck(sem_close(psem->sem), err);
|
||||
}
|
||||
|
||||
int
|
||||
psem_unlink(const char *name, error_t **err)
|
||||
{
|
||||
errcheck(sem_unlink(name), err);
|
||||
}
|
||||
|
||||
int
|
||||
psem_post(psem_t *psem, error_t **err)
|
||||
{
|
||||
errcheck(sem_post(psem->sem), err);
|
||||
}
|
||||
|
||||
int
|
||||
psem_wait(psem_t *psem, error_t **err)
|
||||
{
|
||||
errcheck(sem_wait(psem->sem), err);
|
||||
}
|
||||
|
||||
int
|
||||
psem_trywait(psem_t *psem, error_t **err)
|
||||
{
|
||||
errcheck(sem_trywait(psem->sem), err);
|
||||
}
|
||||
|
||||
int
|
||||
psem_timedwait(psem_t *psem, float timeout_s, error_t **err)
|
||||
{
|
||||
struct timespec abs_timeout;
|
||||
|
||||
abs_timeout.tv_sec = floorf(timeout_s);
|
||||
abs_timeout.tv_nsec =
|
||||
floorf((timeout_s - abs_timeout.tv_sec) * (1000 * 1000 * 1000));
|
||||
|
||||
errcheck(sem_timedwait(psem->sem, &abs_timeout), err);
|
||||
}
|
||||
|
||||
int
|
||||
psem_getvalue(psem_t *psem, int *sval, error_t **err)
|
||||
{
|
||||
errcheck(sem_getvalue(psem->sem, sval), err);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef __PSEM_POSIX_H__
|
||||
#define __PSEM_POSIX_H__
|
||||
|
||||
#include <semaphore.h>
|
||||
|
||||
struct psem {
|
||||
sem_t *sem;
|
||||
};
|
||||
|
||||
#endif /* __PSEM_POSIX_H__ */
|
||||
Reference in new issue
Block a user