Initial commit.

This commit is contained in:
Patrick Mahoney committed 2011-12-11 21:39:55 -06:00
commit cf45ab9891
42 files changed
+1704

No files matched your search

+188
View File
@@ -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;
}
+32
View File
@@ -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__ */
+22
View File
@@ -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;
+18
View File
@@ -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
+36
View File
@@ -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')
+7
View File
@@ -0,0 +1,7 @@
#include "mempcpy.h"
void *
mempcpy(void *dest, const void *src, size_t n)
{
return (char *) memcpy(dest, src, n) + n;
}
+13
View File
@@ -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__ */
+15
View File
@@ -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);
}
+14
View File
@@ -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__ */
+15
View File
@@ -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);
+43
View File
@@ -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__ */
+46
View File
@@ -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 */
}
}
+11
View File
@@ -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__ */
+130
View File
@@ -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);
}
+10
View File
@@ -0,0 +1,10 @@
#ifndef __PSEM_POSIX_H__
#define __PSEM_POSIX_H__
#include <semaphore.h>
struct psem {
sem_t *sem;
};
#endif /* __PSEM_POSIX_H__ */