Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EDIT: This branch is the iteration target. Implementing a per-host circuit breaker state using shared memory and semaphores #54

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f224e95
Initial commit implementing a per-host circuit breaker state using sh…
kyewei Sep 28, 2015
711ffa9
Refactor to include some suggestions:
kyewei Sep 30, 2015
cad8497
Refactor naming, some shared dependencies
kyewei Oct 1, 2015
9faca9a
Refactor: split acquire_memory up into separate functions
kyewei Oct 2, 2015
a59e4a9
Refactored: added tests, created superclass SharedMemoryObject and in…
kyewei Oct 6, 2015
e3bba16
Separate out SysV and non-SysV classes, use #increment, fix style for…
kyewei Nov 2, 2015
51762bb
Enum implements Forwardable, fix bugs in SharedMemoryOBject implement…
kyewei Nov 5, 2015
b1bb06c
Made #shared private, removed uses of it
kyewei Nov 5, 2015
56c103a
Use keyword parameters for init, test by importing modules, initializ…
kyewei Nov 9, 2015
1b178f5
Rebased, small changes had to be done
kyewei Nov 10, 2015
7103df0
Redistribute under Simple and SysV namespace
kyewei Nov 10, 2015
7ab2f36
Change API a bit
kyewei Nov 11, 2015
2e9cd7a
Change to State from Enum, updated to match merged PR, removed Mutex …
kyewei Nov 12, 2015
4896c3c
Rename SharedMemoryObject to SysVSharedMemory and made it a mixin mod…
kyewei Nov 12, 2015
1aa5cf4
Small Changes
kyewei Nov 12, 2015
6e49d3d
Unified use of #synchronize, removed potentially unsafe lock and unlo…
kyewei Nov 13, 2015
882da9d
Changed naming to initialize_memory and bind_initialize_memory_callback
kyewei Nov 17, 2015
3e99639
Nitpick
kyewei Nov 17, 2015
2f09204
Cleanup lock, unlock, delete memory code, rename to cleanup_memory
kyewei Nov 17, 2015
5e55f6e
Refactored resizing and initializing code, reduced size from 300~ lin…
kyewei Nov 19, 2015
a35d0d7
Made fallback boot-time instead of runtime, remove unneeded functions
kyewei Nov 20, 2015
2bbd717
Small changes to code
kyewei Nov 26, 2015
d6ce4aa
Abstract away passing in symbols for data_layout, remove unless
kyewei Dec 3, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/.bundle/
/lib/semian/*.so
/lib/semian/*.bundle
/lib/**/*.so
/lib/**/*.bundle
/tmp/*
*.gem
/html/
Expand Down
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();
}
48 changes: 48 additions & 0 deletions ext/semian/semian.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider doing a follow-up where we implement the blocking ones ourselves (where they're needed) for OS X support.


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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The <type>\n<fname> idiom is not used for header files in Ruby. Just keep them on the same line.

105 changes: 105 additions & 0 deletions ext/semian/semian_integer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#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);
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;
}

static VALUE
semian_integer_calculate_byte_size(VALUE klass)
{
return SIZET2NUM(sizeof(int));
}

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);
rb_define_method(cInteger, "calculate_byte_size", semian_integer_calculate_byte_size, 0);
}
Loading