Skip to content

Commit

Permalink
Entire SysV::Integer code and associated shared libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
kyewei committed Nov 23, 2015
1 parent 9cb6184 commit 0e1174a
Show file tree
Hide file tree
Showing 10 changed files with 761 additions and 37 deletions.
2 changes: 1 addition & 1 deletion ext/semian/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
have_func 'rb_thread_blocking_region'
have_func 'rb_thread_call_without_gvl'

$CFLAGS = "-D_GNU_SOURCE -Werror -Wall "
$CFLAGS = "-D_GNU_SOURCE -Werror -Wall -std=c99 "
if ENV.key?('DEBUG')
$CFLAGS << "-O0 -g"
else
Expand Down
45 changes: 9 additions & 36 deletions ext/semian/semian.c
Original file line number Diff line number Diff line change
@@ -1,38 +1,6 @@
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>

#include <ruby.h>
#include <ruby/util.h>
#include <ruby/io.h>

#include <openssl/sha.h>

#include <stdio.h>

union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};

#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && defined(HAVE_RUBY_THREAD_H)
// 2.0
#include <ruby/thread.h>
#define WITHOUT_GVL(fn,a,ubf,b) rb_thread_call_without_gvl((fn),(a),(ubf),(b))
#elif defined(HAVE_RB_THREAD_BLOCKING_REGION)
// 1.9
typedef VALUE (*my_blocking_fn_t)(void*);
#define WITHOUT_GVL(fn,a,ubf,b) rb_thread_blocking_region((my_blocking_fn_t)(fn),(a),(ubf),(b))
#endif
#include "semian.h"

static ID id_timeout;
static VALUE eSyscall, eTimeout, eInternal;
static int system_max_semaphore_count;

static const int kIndexTickets = 0;
Expand All @@ -48,7 +16,7 @@ typedef struct {
char *name;
} semian_resource_t;

static key_t
key_t
generate_key(const char *name)
{
union {
Expand All @@ -67,7 +35,7 @@ ms_to_timespec(long ms, struct timespec *ts)
ts->tv_nsec = (ms % 1000) * 1000000;
}

static void
void
raise_semian_syscall_error(const char *syscall, int error_num)
{
rb_raise(eSyscall, "%s failed, errno: %d (%s)", syscall, error_num, strerror(error_num));
Expand Down Expand Up @@ -115,7 +83,7 @@ semian_resource_alloc(VALUE klass)
return obj;
}

static void
void
set_semaphore_permissions(int sem_id, int permissions)
{
union semun sem_opts;
Expand Down Expand Up @@ -447,6 +415,9 @@ semian_resource_id(VALUE self)
return LONG2FIX(res->sem_id);
}


void Init_semian_shm_object();

void Init_semian()
{
VALUE cSemian, cResource;
Expand Down Expand Up @@ -504,4 +475,6 @@ void Init_semian()

/* Maximum number of tickets available on this system. */
rb_define_const(cSemian, "MAX_TICKETS", INT2FIX(system_max_semaphore_count));

Init_semian_shm_object();
}
49 changes: 49 additions & 0 deletions ext/semian/semian.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>

#include <ruby.h>
#include <ruby/util.h>
#include <ruby/io.h>

#include <openssl/sha.h>

#include <stdio.h>

#include <sys/shm.h>
#include <unistd.h>

#include <math.h>

union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};

#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && defined(HAVE_RUBY_THREAD_H)
// 2.0
#include <ruby/thread.h>
#define WITHOUT_GVL(fn,a,ubf,b) rb_thread_call_without_gvl((fn),(a),(ubf),(b))
#elif defined(HAVE_RB_THREAD_BLOCKING_REGION)
// 1.9
typedef VALUE (*my_blocking_fn_t)(void*);
#define WITHOUT_GVL(fn,a,ubf,b) rb_thread_blocking_region((my_blocking_fn_t)(fn),(a),(ubf),(b))
#endif

VALUE eSyscall, eTimeout, eInternal;

key_t
generate_key(const char *name);

void
raise_semian_syscall_error(const char *syscall, int error_num);


void
set_semaphore_permissions(int sem_id, int permissions);
109 changes: 109 additions & 0 deletions ext/semian/semian_integer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include "semian_shared_memory_object.h"

typedef struct {
int value;
} semian_int;

static void semian_integer_initialize_memory (size_t byte_size, void *dest, void *prev_data, size_t prev_data_byte_size);
static VALUE semian_integer_bind_initialize_memory_callback(VALUE self);
static VALUE semian_integer_get_value(VALUE self);
static VALUE semian_integer_set_value(VALUE self, VALUE num);
static VALUE semian_integer_increment(int argc, VALUE *argv, VALUE self);

static void
semian_integer_initialize_memory (size_t byte_size, void *dest, void *prev_data, size_t prev_data_byte_size)
{
semian_int *ptr = dest;
semian_int *old = prev_data;
if (prev_data){
ptr->value = old->value;
} else {
ptr->value=0;
}
}

static VALUE
semian_integer_bind_initialize_memory_callback(VALUE self)
{
semian_shm_object *ptr;
TypedData_Get_Struct(self, semian_shm_object, &semian_shm_object_type, ptr);
ptr->initialize_memory = &semian_integer_initialize_memory;
return self;
}

static VALUE
semian_integer_get_value(VALUE self)
{
semian_shm_object *ptr;
TypedData_Get_Struct(self, semian_shm_object, &semian_shm_object_type, ptr);

// check shared memory for NULL
if (0 == ptr->shm_address)
return Qnil;

int value = ((semian_int *)(ptr->shm_address))->value;
return INT2NUM(value);
}

static VALUE
semian_integer_set_value(VALUE self, VALUE num)
{
semian_shm_object *ptr;
TypedData_Get_Struct(self, semian_shm_object, &semian_shm_object_type, ptr);

if (0 == ptr->shm_address)
return Qnil;

if (TYPE(num) != T_FIXNUM && TYPE(num) != T_FLOAT)
return Qnil;

((semian_int *)(ptr->shm_address))->value = NUM2INT(num);

return num;
}

static VALUE
semian_integer_reset(VALUE self)
{
return semian_integer_set_value(self, INT2NUM(0));
}

static VALUE
semian_integer_increment(int argc, VALUE *argv, VALUE self)
{
VALUE num;
rb_scan_args(argc, argv, "01", &num);
if (num == Qnil)
num = INT2NUM(1);

semian_shm_object *ptr;
TypedData_Get_Struct(self, semian_shm_object, &semian_shm_object_type, ptr);

if (0 == ptr->shm_address)
return Qnil;

if (TYPE(num) != T_FIXNUM && TYPE(num) != T_FLOAT)
return Qnil;

((semian_int *)(ptr->shm_address))->value += NUM2INT(num);

return self;
}

void
Init_semian_integer (void)
{
// Bind methods to Integer
VALUE cSemianModule = rb_const_get(rb_cObject, rb_intern("Semian"));
VALUE cSysVSharedMemory = rb_const_get(cSemianModule, rb_intern("SysVSharedMemory"));
VALUE cSysVModule = rb_const_get(cSemianModule, rb_intern("SysV"));
VALUE cInteger = rb_const_get(cSysVModule, rb_intern("Integer"));

semian_shm_object_replace_alloc(cSysVSharedMemory, cInteger);

rb_define_private_method(cInteger, "bind_initialize_memory_callback", semian_integer_bind_initialize_memory_callback, 0);
define_method_with_synchronize(cInteger, "value", semian_integer_get_value, 0);
define_method_with_synchronize(cInteger, "value=", semian_integer_set_value, 1);
define_method_with_synchronize(cInteger, "reset", semian_integer_reset, 0);
define_method_with_synchronize(cInteger, "increment", semian_integer_increment, -1);
}
Loading

0 comments on commit 0e1174a

Please sign in to comment.