Remove no-longer-used libpsem and related code and tests.
This commit is contained in:
		
							parent
							
								
									8158666e90
								
							
						
					
					
						commit
						842ff179ec
					
				
							
								
								
									
										4
									
								
								Rakefile
								
								
								
								
							
							
						
						
									
										4
									
								
								Rakefile
								
								
								
								
							| 
						 | 
				
			
			@ -6,10 +6,6 @@ def gemspec
 | 
			
		|||
  @gemspec ||= eval(File.read('process_shared.gemspec'), binding, 'process_shared.gemspec')
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
Rake::ExtensionTask.new('libpsem') do |ext|
 | 
			
		||||
  ext.lib_dir = 'lib/process_shared'
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
Rake::ExtensionTask.new('helper') do |ext|
 | 
			
		||||
  ext.lib_dir = 'lib/process_shared/posix'
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,188 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,32 +0,0 @@
 | 
			
		|||
#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__ */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,22 +0,0 @@
 | 
			
		|||
/**
 | 
			
		||||
 * 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,18 +0,0 @@
 | 
			
		|||
#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
 | 
			
		||||
| 
						 | 
				
			
			@ -1,40 +0,0 @@
 | 
			
		|||
require 'mkmf'
 | 
			
		||||
 | 
			
		||||
$objs = []
 | 
			
		||||
 | 
			
		||||
# posix semaphores
 | 
			
		||||
if have_func('sem_open', 'semaphore.h') ||
 | 
			
		||||
    ($libs << '-lpthread' && 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')
 | 
			
		||||
else
 | 
			
		||||
  abort('Win32 or platform without sem_open not supported (yet?)')
 | 
			
		||||
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']
 | 
			
		||||
 | 
			
		||||
if respond_to? :depend_rules
 | 
			
		||||
  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
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
create_makefile('libpsem')
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +0,0 @@
 | 
			
		|||
#include "mempcpy.h"
 | 
			
		||||
 | 
			
		||||
void *
 | 
			
		||||
mempcpy(void *dest, const void *src, size_t n)
 | 
			
		||||
{
 | 
			
		||||
  return (char *) memcpy(dest, src, n) + n;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,13 +0,0 @@
 | 
			
		|||
#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__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,15 +0,0 @@
 | 
			
		|||
#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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
#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__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,15 +0,0 @@
 | 
			
		|||
#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);
 | 
			
		||||
| 
						 | 
				
			
			@ -1,45 +0,0 @@
 | 
			
		|||
#ifndef __PSEM_H__
 | 
			
		||||
#define __PSEM_H__
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Portable semaphore interface focusing on cross-process use.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>		/* size_t */
 | 
			
		||||
 | 
			
		||||
#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__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,46 +0,0 @@
 | 
			
		|||
/**
 | 
			
		||||
 * 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 */
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,11 +0,0 @@
 | 
			
		|||
#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__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,160 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +0,0 @@
 | 
			
		|||
#ifndef __PSEM_POSIX_H__
 | 
			
		||||
#define __PSEM_POSIX_H__
 | 
			
		||||
 | 
			
		||||
#include <semaphore.h>
 | 
			
		||||
 | 
			
		||||
struct psem {
 | 
			
		||||
  sem_t *sem;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif  /* __PSEM_POSIX_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,36 +0,0 @@
 | 
			
		|||
require 'ffi'
 | 
			
		||||
 | 
			
		||||
require 'process_shared/posix_call'
 | 
			
		||||
require 'process_shared/psem'
 | 
			
		||||
 | 
			
		||||
module ProcessShared
 | 
			
		||||
  module LibC
 | 
			
		||||
    extend FFI::Library
 | 
			
		||||
    extend PosixCall
 | 
			
		||||
 | 
			
		||||
    ffi_lib FFI::Library::LIBC
 | 
			
		||||
 | 
			
		||||
    MAP_FAILED = FFI::Pointer.new(-1)
 | 
			
		||||
    MAP_SHARED = PSem.map_shared
 | 
			
		||||
    MAP_PRIVATE = PSem.map_private
 | 
			
		||||
 | 
			
		||||
    PROT_READ = PSem.prot_read
 | 
			
		||||
    PROT_WRITE = PSem.prot_write
 | 
			
		||||
    PROT_EXEC = PSem.prot_exec
 | 
			
		||||
    PROT_NONE = PSem.prot_none
 | 
			
		||||
 | 
			
		||||
    O_RDWR = PSem.o_rdwr
 | 
			
		||||
    O_CREAT = PSem.o_creat
 | 
			
		||||
    O_EXCL = PSem.o_excl
 | 
			
		||||
 | 
			
		||||
    attach_variable :errno, :int
 | 
			
		||||
 | 
			
		||||
    attach_function :mmap, [:pointer, :size_t, :int, :int, :int, :off_t], :pointer
 | 
			
		||||
    attach_function :munmap, [:pointer, :size_t], :int
 | 
			
		||||
    attach_function :ftruncate, [:int, :off_t], :int
 | 
			
		||||
    attach_function :close, [:int], :int
 | 
			
		||||
 | 
			
		||||
    error_check(:mmap) { |v| v == MAP_FAILED }
 | 
			
		||||
    error_check(:munmap, :ftruncate, :close)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,113 +0,0 @@
 | 
			
		|||
require 'ffi'
 | 
			
		||||
 | 
			
		||||
module ProcessShared
 | 
			
		||||
  module PSem
 | 
			
		||||
    class Error < FFI::Struct
 | 
			
		||||
      layout(:source, :int,
 | 
			
		||||
             :errno, :int)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    extend FFI::Library
 | 
			
		||||
 | 
			
		||||
    # Workaround FFI dylib/bundle issue.  See https://github.com/ffi/ffi/issues/42
 | 
			
		||||
    suffix = if FFI::Platform.mac?
 | 
			
		||||
               'bundle'
 | 
			
		||||
             else
 | 
			
		||||
               FFI::Platform::LIBSUFFIX
 | 
			
		||||
             end
 | 
			
		||||
 | 
			
		||||
    ffi_lib File.join(File.expand_path(File.dirname(__FILE__)),
 | 
			
		||||
                      'libpsem.' + suffix)
 | 
			
		||||
 | 
			
		||||
    class << self
 | 
			
		||||
      # Replace methods in `syms` with error checking wrappers that
 | 
			
		||||
      # invoke the original psem method and raise an appropriate
 | 
			
		||||
      # error.
 | 
			
		||||
      #
 | 
			
		||||
      # The last argument is assumed to be a pointer to a pointer
 | 
			
		||||
      # where either a psem error or NULL will be stored.
 | 
			
		||||
      def psem_error_check(*syms)
 | 
			
		||||
        syms.each do |sym|
 | 
			
		||||
          method = self.method(sym)
 | 
			
		||||
 | 
			
		||||
          block = lambda do |*args|
 | 
			
		||||
            if method.call(*args) < 0
 | 
			
		||||
              errp = args[-1]
 | 
			
		||||
              unless errp.nil?
 | 
			
		||||
                begin
 | 
			
		||||
                  err = Error.new(errp.read_pointer)
 | 
			
		||||
                  errp.write_pointer(nil)
 | 
			
		||||
                  if err[:source] == PSem.e_source_system
 | 
			
		||||
                    raise SystemCallError.new("error in #{sym}", err[:errno])
 | 
			
		||||
                  else
 | 
			
		||||
                    raise "error in #{sym}: #{err.get_integer(1)}"
 | 
			
		||||
                  end
 | 
			
		||||
                ensure
 | 
			
		||||
                  psem_error_free(err)
 | 
			
		||||
                end
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          define_method(sym, &block)
 | 
			
		||||
          define_singleton_method(sym, &block)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Generic constants
 | 
			
		||||
 | 
			
		||||
    int_consts = [:o_rdwr,
 | 
			
		||||
                  :o_creat,
 | 
			
		||||
                  :o_excl,
 | 
			
		||||
                  
 | 
			
		||||
                  :prot_read,
 | 
			
		||||
                  :prot_write,
 | 
			
		||||
                  :prot_exec,
 | 
			
		||||
                  :prot_none,
 | 
			
		||||
                  
 | 
			
		||||
                  :map_shared,
 | 
			
		||||
                  :map_private]
 | 
			
		||||
    int_consts.each { |sym| attach_variable sym, :int }
 | 
			
		||||
 | 
			
		||||
    # Other constants, functions
 | 
			
		||||
 | 
			
		||||
    attach_function :psem_error_free, :error_free, [:pointer], :void
 | 
			
		||||
 | 
			
		||||
    attach_variable :e_source_system, :E_SOURCE_SYSTEM, :int
 | 
			
		||||
    attach_variable :e_source_psem, :E_SOURCE_PSEM, :int
 | 
			
		||||
 | 
			
		||||
    attach_variable :e_name_too_long, :E_NAME_TOO_LONG, :int
 | 
			
		||||
 | 
			
		||||
    attach_variable :sizeof_psem_t, :size_t
 | 
			
		||||
    attach_variable :sizeof_bsem_t, :size_t
 | 
			
		||||
 | 
			
		||||
    # PSem functions
 | 
			
		||||
 | 
			
		||||
    attach_function :psem_open, [:pointer, :string, :uint, :pointer], :int
 | 
			
		||||
    attach_function :psem_close, [:pointer, :pointer], :int
 | 
			
		||||
    attach_function :psem_unlink, [:string, :pointer], :int
 | 
			
		||||
    attach_function :psem_post, [:pointer, :pointer], :int
 | 
			
		||||
    attach_function :psem_wait, [:pointer, :pointer], :int
 | 
			
		||||
    attach_function :psem_trywait, [:pointer, :pointer], :int
 | 
			
		||||
    attach_function :psem_timedwait, [:pointer, :float, :pointer], :int
 | 
			
		||||
    attach_function :psem_getvalue, [:pointer, :pointer, :pointer], :int
 | 
			
		||||
 | 
			
		||||
    psem_error_check(:psem_open, :psem_close, :psem_unlink, :psem_post,
 | 
			
		||||
                     :psem_wait, :psem_trywait, :psem_timedwait, :psem_getvalue)
 | 
			
		||||
 | 
			
		||||
    # BSem functions
 | 
			
		||||
    
 | 
			
		||||
    attach_function :bsem_open, [:pointer, :string, :uint, :uint, :pointer], :int
 | 
			
		||||
    attach_function :bsem_close, [:pointer, :pointer], :int
 | 
			
		||||
    attach_function :bsem_unlink, [:string, :pointer], :int
 | 
			
		||||
    attach_function :bsem_post, [:pointer, :pointer], :int
 | 
			
		||||
    attach_function :bsem_wait, [:pointer, :pointer], :int
 | 
			
		||||
    attach_function :bsem_trywait, [:pointer, :pointer], :int
 | 
			
		||||
    attach_function :bsem_timedwait, [:pointer, :float, :pointer], :int
 | 
			
		||||
    attach_function :bsem_getvalue, [:pointer, :pointer, :pointer], :int
 | 
			
		||||
 | 
			
		||||
    psem_error_check(:bsem_open, :bsem_close, :bsem_unlink, :bsem_post,
 | 
			
		||||
                     :bsem_wait, :bsem_trywait, :bsem_timedwait, :bsem_getvalue)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,3 @@
 | 
			
		|||
require 'process_shared/rt'
 | 
			
		||||
require 'process_shared/libc'
 | 
			
		||||
require 'process_shared/with_self'
 | 
			
		||||
require 'process_shared/shared_memory_io'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +0,0 @@
 | 
			
		|||
require 'process_shared/libc'
 | 
			
		||||
 | 
			
		||||
module ProcessShared
 | 
			
		||||
  describe LibC do
 | 
			
		||||
    it 'throws exceptions with invalid args' do
 | 
			
		||||
      proc { LibC.mmap nil,2,0,0,1,0 }.must_raise(Errno::EINVAL)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,136 +0,0 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
require 'process_shared/psem'
 | 
			
		||||
 | 
			
		||||
module ProcessShared
 | 
			
		||||
  describe PSem do
 | 
			
		||||
    before do
 | 
			
		||||
      extend PSem
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    before(:each) do
 | 
			
		||||
      @err = FFI::MemoryPointer.new(:pointer)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    describe '.psem_open' do
 | 
			
		||||
      it 'opens a psem' do
 | 
			
		||||
        psem = FFI::MemoryPointer.new(PSem.sizeof_psem_t)
 | 
			
		||||
        psem_open(psem, "psem-test", 1, @err)
 | 
			
		||||
        psem_unlink("psem-test", @err)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'raises excpetion if name alredy exists' do
 | 
			
		||||
        psem1 = FFI::MemoryPointer.new(PSem.sizeof_psem_t)
 | 
			
		||||
        psem2 = FFI::MemoryPointer.new(PSem.sizeof_psem_t)
 | 
			
		||||
        psem_open(psem1, "psem-test", 1, @err)
 | 
			
		||||
        proc { psem_open(psem2, "psem-test", 1, @err) }.must_raise(Errno::EEXIST)
 | 
			
		||||
 | 
			
		||||
        psem_unlink("psem-test", @err)
 | 
			
		||||
        psem_open(psem2, "psem-test", 1, @err)
 | 
			
		||||
        psem_unlink("psem-test", @err)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    describe '.psem_wait' do
 | 
			
		||||
      before(:each) do
 | 
			
		||||
        @psem = FFI::MemoryPointer.new(PSem.sizeof_psem_t)
 | 
			
		||||
        psem_open(@psem, 'psem-test', 1, @err)
 | 
			
		||||
        psem_unlink('psem-test', @err)
 | 
			
		||||
 | 
			
		||||
        @int = FFI::MemoryPointer.new(:int)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      after(:each) do
 | 
			
		||||
        #psem_close(@psem, @err)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def value
 | 
			
		||||
        psem_getvalue(@psem, @int, @err)
 | 
			
		||||
        @int.get_int(0)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'decrements psem value' do
 | 
			
		||||
        value.must_equal 1
 | 
			
		||||
        psem_wait(@psem, @err)
 | 
			
		||||
        value.must_equal(0)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'waits until another process posts' do
 | 
			
		||||
        psem_wait(@psem, @err)
 | 
			
		||||
 | 
			
		||||
        # child exits with ~ time spent waiting
 | 
			
		||||
        child = fork do
 | 
			
		||||
          start = Time.now
 | 
			
		||||
          psem_wait(@psem, @err)
 | 
			
		||||
          exit (Time.now - start).ceil
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        t = 1.5
 | 
			
		||||
        sleep t
 | 
			
		||||
        psem_post(@psem, @err)
 | 
			
		||||
        _pid, status = Process.wait2(child)
 | 
			
		||||
        status.exitstatus.must_equal 2
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    describe '.bsem_open' do
 | 
			
		||||
      it 'opens a bsem' do
 | 
			
		||||
        bsem = FFI::MemoryPointer.new(PSem.sizeof_bsem_t)
 | 
			
		||||
        bsem_open(bsem, "bsem-test", 1, 1, @err)
 | 
			
		||||
        bsem_unlink("bsem-test", @err)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'raises excpetion if name alredy exists' do
 | 
			
		||||
        bsem1 = FFI::MemoryPointer.new(PSem.sizeof_bsem_t)
 | 
			
		||||
        bsem2 = FFI::MemoryPointer.new(PSem.sizeof_bsem_t)
 | 
			
		||||
        bsem_open(bsem1, "bsem-test", 1, 1, @err)
 | 
			
		||||
        proc { bsem_open(bsem2, "bsem-test", 1, 1, @err) }.must_raise(Errno::EEXIST)
 | 
			
		||||
 | 
			
		||||
        bsem_unlink("bsem-test", @err)
 | 
			
		||||
        bsem_open(bsem2, "bsem-test", 1, 1, @err)
 | 
			
		||||
        bsem_unlink("bsem-test", @err)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    describe '.bsem_wait' do
 | 
			
		||||
      before(:each) do
 | 
			
		||||
        @bsem = FFI::MemoryPointer.new(PSem.sizeof_bsem_t)
 | 
			
		||||
        bsem_open(@bsem, 'bsem-test', 1, 1, @err)
 | 
			
		||||
        bsem_unlink('bsem-test', @err)
 | 
			
		||||
 | 
			
		||||
        @int = FFI::MemoryPointer.new(:int)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      after do
 | 
			
		||||
        #bsem_close(@bsem, @err)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def value
 | 
			
		||||
        bsem_getvalue(@bsem, @int, @err)
 | 
			
		||||
        @int.get_int(0)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'decrements bsem value' do
 | 
			
		||||
        value.must_equal 1
 | 
			
		||||
        bsem_wait(@bsem, @err)
 | 
			
		||||
        value.must_equal 0
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'waits until another process posts' do
 | 
			
		||||
        bsem_wait(@bsem, @err)
 | 
			
		||||
 | 
			
		||||
        # child exits with ~ time spent waiting
 | 
			
		||||
        child = fork do
 | 
			
		||||
          start = Time.now
 | 
			
		||||
          bsem_wait(@bsem, @err)
 | 
			
		||||
          exit (Time.now - start).ceil
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        t = 1.5
 | 
			
		||||
        sleep t
 | 
			
		||||
        bsem_post(@bsem, @err)
 | 
			
		||||
        _pid, status = Process.wait2(child)
 | 
			
		||||
        status.exitstatus.must_equal 2
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
		Reference in New Issue