Skip to content

Commit a35d0d7

Browse files
committed
Made fallback boot-time instead of runtime, remove unneeded functions
1 parent 5e55f6e commit a35d0d7

11 files changed

+81
-115
lines changed

ext/semian/semian_shared_memory_object.c

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -82,25 +82,29 @@ semian_shm_object_sizeof(VALUE klass, VALUE type)
8282
return INT2NUM(sizeof(long));
8383
// Can definitely add more
8484
else
85-
return INT2NUM(0);
85+
rb_raise(rb_eTypeError, "%s is not a valid C type", rb_id2name(SYM2ID(type)));
8686
}
8787

8888

8989
VALUE
90-
semian_shm_object_acquire(VALUE self, VALUE name, VALUE byte_size, VALUE permissions)
90+
semian_shm_object_acquire(VALUE self, VALUE name, VALUE data_layout, VALUE permissions)
9191
{
9292
semian_shm_object *ptr;
9393
TypedData_Get_Struct(self, semian_shm_object, &semian_shm_object_type, ptr);
9494

9595
if (TYPE(name) != T_SYMBOL && TYPE(name) != T_STRING)
9696
rb_raise(rb_eTypeError, "id must be a symbol or string");
97-
if (TYPE(byte_size) != T_FIXNUM)
98-
rb_raise(rb_eTypeError, "expected integer for byte_size");
97+
if (TYPE(data_layout) != T_ARRAY)
98+
rb_raise(rb_eTypeError, "expected array for data_layout");
9999
if (TYPE(permissions) != T_FIXNUM)
100100
rb_raise(rb_eTypeError, "expected integer for permissions");
101101

102-
if (NUM2SIZET(byte_size) <= 0)
103-
rb_raise(rb_eArgError, "byte_size must be larger than 0");
102+
int byte_size = 0;
103+
for (int i = 0; i < RARRAY_LEN(data_layout); ++i)
104+
byte_size += NUM2INT(semian_shm_object_sizeof(rb_cObject, RARRAY_PTR(data_layout)[i]));
105+
106+
if (byte_size <= 0)
107+
rb_raise(rb_eArgError, "total size must be larger than 0");
104108

105109
const char *id_str = NULL;
106110
if (TYPE(name) == T_SYMBOL) {
@@ -109,7 +113,7 @@ semian_shm_object_acquire(VALUE self, VALUE name, VALUE byte_size, VALUE permiss
109113
id_str = RSTRING_PTR(name);
110114
}
111115
ptr->key = generate_key(id_str);
112-
ptr->byte_size = NUM2SIZET(byte_size); // byte_size >=1 or error would have been raised earlier
116+
ptr->byte_size = byte_size; // byte_size >=1 or error would have been raised earlier
113117
ptr->semid = -1; // id's default to -1
114118
ptr->shmid = -1;
115119
ptr->shm_address = 0; // address defaults to NULL
@@ -124,7 +128,9 @@ semian_shm_object_acquire(VALUE self, VALUE name, VALUE byte_size, VALUE permiss
124128
semian_shm_object_acquire_semaphore(self);
125129
semian_shm_object_synchronize(self);
126130

127-
return self;
131+
132+
133+
return Qtrue;
128134
}
129135

130136
VALUE
@@ -349,13 +355,10 @@ semian_shm_object_synchronize_memory_and_size(VALUE self, VALUE is_master_obj) {
349355
} else {
350356
void *old_shm_address = ptr->shm_address;
351357
size_t old_byte_size = ptr->byte_size;
352-
void *old_memory_content = NULL;
358+
unsigned char old_memory_content[old_byte_size];
353359

354-
char old_memory_content_tmp[old_byte_size];
355-
memcpy(old_memory_content_tmp, old_shm_address, old_byte_size);
360+
memcpy(old_memory_content, old_shm_address, old_byte_size);
356361
semian_shm_object_cleanup_memory(self);
357-
old_memory_content = malloc(old_byte_size);
358-
memcpy(old_memory_content, old_memory_content_tmp, old_byte_size);
359362

360363
if (-1 == (ptr->shmid = shmget(key, requested_byte_size, IPC_CREAT | IPC_EXCL | ptr->permissions))) {
361364
rb_raise(eSyscall, "shmget failed to create new resized memory with key %d shmid %d errno %d (%s)", key, ptr->shmid, errno, strerror(errno));
@@ -366,7 +369,6 @@ semian_shm_object_synchronize_memory_and_size(VALUE self, VALUE is_master_obj) {
366369
ptr->byte_size = requested_byte_size;
367370

368371
ptr->initialize_memory(ptr->byte_size, ptr->shm_address, old_memory_content, old_byte_size);
369-
free(old_memory_content);
370372
}
371373
}
372374
return self;
@@ -419,30 +421,19 @@ semian_shm_object_shmid(VALUE self)
419421
return INT2NUM(ptr->shmid);
420422
}
421423

422-
static VALUE
423-
semian_shm_object_byte_size(VALUE self)
424-
{
425-
semian_shm_object *ptr;
426-
TypedData_Get_Struct(self, semian_shm_object, &semian_shm_object_type, ptr);
427-
semian_shm_object_synchronize(self);
428-
return INT2NUM(ptr->byte_size);
429-
}
430-
431424
void
432425
Init_semian_shm_object (void) {
433426

434427
VALUE cSemianModule = rb_const_get(rb_cObject, rb_intern("Semian"));
435428
VALUE cSysVSharedMemory = rb_const_get(cSemianModule, rb_intern("SysVSharedMemory"));
436429

437-
rb_define_method(cSysVSharedMemory, "_acquire", semian_shm_object_acquire, 3);
438-
rb_define_method(cSysVSharedMemory, "_destroy", semian_shm_object_destroy, 0);
439-
rb_define_method(cSysVSharedMemory, "_synchronize", semian_shm_object_synchronize, 0);
430+
rb_define_method(cSysVSharedMemory, "acquire_memory_object", semian_shm_object_acquire, 3);
431+
rb_define_method(cSysVSharedMemory, "destroy", semian_shm_object_destroy, 0);
432+
rb_define_method(cSysVSharedMemory, "synchronize", semian_shm_object_synchronize, 0);
440433

441434
rb_define_method(cSysVSharedMemory, "semid", semian_shm_object_semid, 0);
442435
rb_define_method(cSysVSharedMemory, "shmid", semian_shm_object_shmid, 0);
443-
rb_define_method(cSysVSharedMemory, "byte_size", semian_shm_object_byte_size, 0);
444436

445-
rb_define_singleton_method(cSysVSharedMemory, "_sizeof", semian_shm_object_sizeof, 1);
446437
rb_define_singleton_method(cSysVSharedMemory, "replace_alloc", semian_shm_object_replace_alloc, 1);
447438

448439
decrement.sem_num = kSHMIndexTicketLock;

lib/semian/sysv_shared_memory.rb

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
module Semian
22
module SysVSharedMemory #:nodoc:
3-
@type_size = {}
4-
def self.sizeof(type)
5-
size = (@type_size[type.to_sym] ||= (respond_to?(:_sizeof) ? _sizeof(type.to_sym) : 0))
6-
raise TypeError.new("#{type} is not a valid C type") if size <= 0
7-
size
8-
end
9-
103
def self.included(base)
114
def base.do_with_sync(*names)
125
names.each do |name|
@@ -30,38 +23,20 @@ def shmid
3023
-1
3124
end
3225

33-
def synchronize(&block)
34-
if respond_to?(:_synchronize) && @using_shared_memory
35-
_synchronize(&block)
36-
else
37-
yield if block_given?
38-
end
26+
def synchronize
27+
yield if block_given?
3928
end
4029

41-
alias_method :transaction, :synchronize
42-
4330
def destroy
44-
if respond_to?(:_destroy) && @using_shared_memory
45-
_destroy
46-
else
47-
super
48-
end
31+
super
4932
end
5033

5134
private
5235

53-
def shared?
54-
@using_shared_memory
55-
end
56-
57-
def acquire_memory_object(name, data_layout, permissions)
58-
return @using_shared_memory = false unless Semian.semaphores_enabled? && respond_to?(:_acquire)
59-
60-
byte_size = data_layout.inject(0) { |sum, type| sum + ::Semian::SysVSharedMemory.sizeof(type) }
61-
raise TypeError.new("Given data layout is 0 bytes: #{data_layout.inspect}") if byte_size <= 0
62-
# Calls C layer to acquire/create a memory block, calling #initialize_memory in the process, see below
63-
_acquire(name, byte_size, permissions)
64-
@using_shared_memory = true
36+
def acquire_memory_object(*)
37+
# Concrete classes must call this method before accessing shared memory
38+
# If SysV is enabled, a C method overrides this stub and returns true if acquiring succeeds
39+
false
6540
end
6641

6742
def bind_initialize_memory_callback

lib/semian/sysv_state.rb

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,25 @@ class State < Semian::Simple::State #:nodoc:
66
include SysVSharedMemory
77
extend Forwardable
88

9-
def_delegators :@integer, :semid, :shmid, :synchronize, :transaction,
10-
:shared?, :acquire_memory_object, :initialize_memory
11-
private :shared?, :acquire_memory_object, :initialize_memory
9+
SYM_TO_NUM = {closed: 0, open: 1, half_open: 2}.freeze
10+
NUM_TO_SYM = SYM_TO_NUM.invert.freeze
11+
12+
def_delegators :@integer, :semid, :shmid, :synchronize, :acquire_memory_object,
13+
:bind_initialize_memory_callback, :destroy
14+
private :acquire_memory_object, :bind_initialize_memory_callback
1215

1316
def initialize(name:, permissions:)
1417
@integer = Semian::SysV::Integer.new(name: name, permissions: permissions)
15-
initialize_lookup
16-
end
17-
18-
def destroy
19-
super
20-
@integer.destroy
2118
end
2219

2320
def value
24-
@num_to_sym.fetch(@integer.value) { raise ArgumentError }
21+
NUM_TO_SYM.fetch(@integer.value) { raise ArgumentError }
2522
end
2623

2724
private
2825

2926
def value=(sym)
30-
@integer.value = @sym_to_num.fetch(sym) { raise ArgumentError }
31-
end
32-
33-
def initialize_lookup
34-
# Assume symbol_list[0] is mapped to 0
35-
# Cannot just use #object_id since #object_id for symbols is different in every run
36-
# For now, implement a C-style enum type backed by integers
37-
38-
@sym_to_num = {closed: 0, open: 1, half_open: 2}
39-
@num_to_sym = @sym_to_num.invert
27+
@integer.value = SYM_TO_NUM.fetch(sym) { raise ArgumentError }
4028
end
4129
end
4230
end

test/circuit_breaker_test.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ def test_shared_fresh_worker_killed_should_not_reset_circuit_breaker_data
140140
reader.gets
141141
Semian.register(:unique_res, tickets: 1, exceptions: [SomeError], error_threshold: 2, error_timeout: 5, success_threshold: 1)
142142
Process.kill(9, pid)
143+
Process.waitall
143144
assert_circuit_opened Semian[:unique_res]
144145
end
145146

test/resource_test.rb

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,19 +108,29 @@ def test_acquire_timeout_override
108108
end
109109

110110
def test_acquire_with_fork
111-
resource = create_resource :testing, tickets: 2, timeout: 0.5
112-
113-
resource.acquire do
114-
fork do
115-
resource.acquire do
116-
assert_raises Semian::TimeoutError do
117-
resource.acquire {}
118-
end
111+
pids = []
112+
113+
2.times do
114+
reader, writer = IO.pipe
115+
pids << fork do
116+
create_resource(:testing, tickets: 2, timeout: 0.5).acquire do
117+
reader.close
118+
writer.puts "Acquired"
119+
writer.close
120+
sleep
119121
end
120122
end
123+
reader.gets
124+
end
125+
126+
assert_raises Semian::TimeoutError do
127+
create_resource(:testing, tickets: 2, timeout: 0.5).acquire {}
128+
end
121129

122-
Process.wait
130+
pids.each do |pid|
131+
Process.kill(9, pid)
123132
end
133+
Process.waitall
124134
end
125135

126136
def test_acquire_releases_on_kill

test/simple_integer_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
require 'test_helper'
22

33
class TestSimpleInteger < MiniTest::Unit::TestCase
4-
CLASS = ::Semian::Simple::Integer
4+
KLASS = ::Semian::Simple::Integer
55

66
def setup
7-
@integer = CLASS.new
7+
@integer = KLASS.new
88
end
99

1010
def teardown

test/simple_sliding_window_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
require 'test_helper'
22

33
class TestSimpleSlidingWindow < MiniTest::Unit::TestCase
4-
CLASS = ::Semian::Simple::SlidingWindow
4+
KLASS = ::Semian::Simple::SlidingWindow
55

66
def setup
7-
@sliding_window = CLASS.new(max_size: 6)
7+
@sliding_window = KLASS.new(max_size: 6)
88
@sliding_window.clear
99
end
1010

test/simple_state_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
require 'test_helper'
22

33
class TestSimpleState < MiniTest::Unit::TestCase
4-
CLASS = ::Semian::Simple::State
4+
KLASS = ::Semian::Simple::State
55

66
def setup
7-
@state = CLASS.new
7+
@state = KLASS.new
88
end
99

1010
def teardown

test/sysv_integer_test.rb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
require 'test_helper'
22

33
class TestSysVInteger < MiniTest::Unit::TestCase
4-
CLASS = ::Semian::SysV::Integer
4+
KLASS = ::Semian::SysV::Integer
55

66
def setup
7-
@integer = CLASS.new(name: 'TestSysVInteger', permissions: 0660)
7+
@integer = KLASS.new(name: 'TestSysVInteger', permissions: 0660)
88
@integer.reset
99
end
1010

@@ -15,7 +15,7 @@ def teardown
1515
include TestSimpleInteger::IntegerTestCases
1616

1717
def test_memory_is_shared
18-
integer_2 = CLASS.new(name: 'TestSysVInteger', permissions: 0660)
18+
integer_2 = KLASS.new(name: 'TestSysVInteger', permissions: 0660)
1919
integer_2.value = 100
2020
assert_equal 100, @integer.value
2121
@integer.value = 200
@@ -26,13 +26,13 @@ def test_memory_is_shared
2626

2727
def test_memory_not_reset_when_at_least_one_worker_using_it
2828
@integer.value = 109
29-
integer_2 = CLASS.new(name: 'TestSysVInteger', permissions: 0660)
29+
integer_2 = KLASS.new(name: 'TestSysVInteger', permissions: 0660)
3030
assert_equal @integer.value, integer_2.value
3131

3232
reader, writer = IO.pipe
3333
pid = fork do
3434
reader.close
35-
integer_3 = CLASS.new(name: 'TestSysVInteger', permissions: 0660)
35+
integer_3 = KLASS.new(name: 'TestSysVInteger', permissions: 0660)
3636
assert_equal 109, integer_3.value
3737
integer_3.value = 110
3838
writer.puts "Done"
@@ -47,11 +47,11 @@ def test_memory_not_reset_when_at_least_one_worker_using_it
4747

4848
def test_memory_reset_when_no_workers_using_it
4949
fork do
50-
integer = CLASS.new(name: 'TestSysVInteger_2', permissions: 0660)
50+
integer = KLASS.new(name: 'TestSysVInteger_2', permissions: 0660)
5151
integer.value = 109
5252
end
5353
Process.waitall
54-
@integer = CLASS.new(name: 'TestSysVInteger_2', permissions: 0660)
54+
@integer = KLASS.new(name: 'TestSysVInteger_2', permissions: 0660)
5555
assert_equal 0, @integer.value
5656
end
5757
end

0 commit comments

Comments
 (0)