semian 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/ext/semian/semian.c +17 -9
- data/lib/semian.rb +2 -0
- data/lib/semian/version.rb +3 -0
- data/semian.gemspec +5 -1
- data/test/test_semian.rb +20 -6
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85e7688d4e7394755e61fe1223f33646a9245f69
|
4
|
+
data.tar.gz: fc55fda5e5799267fc81f3fed586117f62762dc0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f04b5bc23920ab15e8fb1a73890a66a7ce4719e8286eff31170506460680853dfc302cfc4683eeb33c03cf168b72f7ef9f235a16a66ace28456026ddd60e00bb
|
7
|
+
data.tar.gz: 2eed26a9736cd3114b172bce7ecbd7cfa77d6ef8601acd78ba18ea7c166c6b2fa7103e2cd78b74d9f30b2c75a3229934a198dbf8881529b452ba6b03e10cb75a
|
data/Gemfile.lock
CHANGED
data/ext/semian/semian.c
CHANGED
@@ -23,7 +23,7 @@ typedef VALUE (*my_blocking_fn_t)(void*);
|
|
23
23
|
#endif
|
24
24
|
|
25
25
|
static ID id_timeout;
|
26
|
-
static VALUE eTimeout;
|
26
|
+
static VALUE eSyscall, eTimeout;
|
27
27
|
|
28
28
|
typedef struct {
|
29
29
|
int sem_id;
|
@@ -48,6 +48,12 @@ ms_to_timespec(long ms, struct timespec *ts)
|
|
48
48
|
ts->tv_nsec = (ms % 1000) * 1000000;
|
49
49
|
}
|
50
50
|
|
51
|
+
static void
|
52
|
+
raise_semian_syscall_error(const char *syscall, int error_num)
|
53
|
+
{
|
54
|
+
rb_raise(eSyscall, "%s failed, errno: %d (%s)", syscall, error_num, strerror(error_num));
|
55
|
+
}
|
56
|
+
|
51
57
|
static void
|
52
58
|
semian_resource_mark(void *ptr)
|
53
59
|
{
|
@@ -128,12 +134,12 @@ semian_resource_initialize(VALUE self, VALUE id, VALUE tickets, VALUE default_ti
|
|
128
134
|
|
129
135
|
res->sem_id = semget(key, 1, flags);
|
130
136
|
if (res->sem_id == -1) {
|
131
|
-
|
137
|
+
raise_semian_syscall_error("semget()", errno);
|
132
138
|
}
|
133
139
|
|
134
140
|
if (FIX2LONG(tickets) != 0
|
135
141
|
&& semctl(res->sem_id, 0, SETVAL, FIX2LONG(tickets)) == -1) {
|
136
|
-
|
142
|
+
raise_semian_syscall_error("semctl()", errno);
|
137
143
|
}
|
138
144
|
|
139
145
|
return self;
|
@@ -144,7 +150,7 @@ cleanup_semian_resource_acquire(VALUE self)
|
|
144
150
|
{
|
145
151
|
semian_resource_t *res = NULL;
|
146
152
|
TypedData_Get_Struct(self, semian_resource_t, &semian_resource_type, res);
|
147
|
-
struct sembuf buf = { 0, 1,
|
153
|
+
struct sembuf buf = { 0, 1, SEM_UNDO };
|
148
154
|
if (semop(res->sem_id, &buf, 1) == -1) {
|
149
155
|
res->error = errno;
|
150
156
|
}
|
@@ -195,7 +201,7 @@ semian_resource_acquire(int argc, VALUE *argv, VALUE self)
|
|
195
201
|
if (res.error == EAGAIN) {
|
196
202
|
rb_raise(eTimeout, "timed out waiting for resource '%s'", res.name);
|
197
203
|
} else {
|
198
|
-
|
204
|
+
raise_semian_syscall_error("semop()", res.error);
|
199
205
|
}
|
200
206
|
}
|
201
207
|
|
@@ -209,7 +215,7 @@ semian_resource_destroy(VALUE self)
|
|
209
215
|
|
210
216
|
TypedData_Get_Struct(self, semian_resource_t, &semian_resource_type, res);
|
211
217
|
if (semctl(res->sem_id, 0, IPC_RMID) == -1) {
|
212
|
-
|
218
|
+
raise_semian_syscall_error("semctl()", errno);
|
213
219
|
}
|
214
220
|
|
215
221
|
return Qtrue;
|
@@ -224,7 +230,7 @@ semian_resource_count(VALUE self)
|
|
224
230
|
TypedData_Get_Struct(self, semian_resource_t, &semian_resource_type, res);
|
225
231
|
ret = semctl(res->sem_id, 0, GETVAL);
|
226
232
|
if (ret == -1) {
|
227
|
-
|
233
|
+
raise_semian_syscall_error("semctl()", errno);
|
228
234
|
}
|
229
235
|
|
230
236
|
return LONG2FIX(ret);
|
@@ -232,11 +238,13 @@ semian_resource_count(VALUE self)
|
|
232
238
|
|
233
239
|
void Init_semian()
|
234
240
|
{
|
235
|
-
VALUE cSemian, cResource;
|
241
|
+
VALUE cSemian, cResource, eBaseError;
|
236
242
|
|
237
243
|
cSemian = rb_define_class("Semian", rb_cObject);
|
238
244
|
cResource = rb_define_class("Resource", cSemian);
|
239
|
-
|
245
|
+
eBaseError = rb_define_class_under(cSemian, "BaseError", rb_eStandardError);
|
246
|
+
eSyscall = rb_define_class_under(cSemian, "SyscallError", eBaseError);
|
247
|
+
eTimeout = rb_define_class_under(cSemian, "TimeoutError", eBaseError);
|
240
248
|
|
241
249
|
rb_define_alloc_func(cResource, semian_resource_alloc);
|
242
250
|
rb_define_method(cResource, "initialize", semian_resource_initialize, 3);
|
data/lib/semian.rb
CHANGED
data/semian.gemspec
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'semian/version'
|
4
|
+
|
1
5
|
Gem::Specification.new do |s|
|
2
6
|
s.name = 'semian'
|
3
|
-
s.version =
|
7
|
+
s.version = Semian::VERSION
|
4
8
|
s.summary = 'SysV semaphore based library for shared resource control'
|
5
9
|
s.description = <<-DOC
|
6
10
|
A Ruby C extention that is used to control access to shared resources
|
data/test/test_semian.rb
CHANGED
@@ -5,7 +5,7 @@ require 'fileutils'
|
|
5
5
|
|
6
6
|
class TestSemian < Test::Unit::TestCase
|
7
7
|
def setup
|
8
|
-
Semian[:testing].destroy rescue
|
8
|
+
Semian[:testing].destroy rescue Semian::BaseError
|
9
9
|
end
|
10
10
|
|
11
11
|
def test_register_invalid_args
|
@@ -22,7 +22,7 @@ class TestSemian < Test::Unit::TestCase
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_register_with_no_tickets_raises
|
25
|
-
assert_raises
|
25
|
+
assert_raises Semian::SyscallError do
|
26
26
|
Semian.register :testing
|
27
27
|
end
|
28
28
|
end
|
@@ -50,7 +50,7 @@ class TestSemian < Test::Unit::TestCase
|
|
50
50
|
t = Thread.start do
|
51
51
|
m.synchronize do
|
52
52
|
cond.wait_until { acquired }
|
53
|
-
assert_raises Semian::
|
53
|
+
assert_raises Semian::TimeoutError do
|
54
54
|
Semian[:testing].acquire { refute true }
|
55
55
|
end
|
56
56
|
end
|
@@ -101,7 +101,7 @@ class TestSemian < Test::Unit::TestCase
|
|
101
101
|
pid = fork do
|
102
102
|
Semian.register :testing, timeout: 0.5
|
103
103
|
Semian[:testing].acquire do
|
104
|
-
assert_raises Semian::
|
104
|
+
assert_raises Semian::TimeoutError do
|
105
105
|
Semian[:testing].acquire { }
|
106
106
|
end
|
107
107
|
end
|
@@ -129,7 +129,7 @@ class TestSemian < Test::Unit::TestCase
|
|
129
129
|
end
|
130
130
|
|
131
131
|
sleep 0.1 until File.exists?(path)
|
132
|
-
assert_raises Semian::
|
132
|
+
assert_raises Semian::TimeoutError do
|
133
133
|
Semian[:testing].acquire {}
|
134
134
|
end
|
135
135
|
|
@@ -155,10 +155,24 @@ class TestSemian < Test::Unit::TestCase
|
|
155
155
|
assert acquired
|
156
156
|
end
|
157
157
|
|
158
|
+
def test_sem_undo
|
159
|
+
Semian.register :testing, tickets: 1
|
160
|
+
|
161
|
+
# Ensure we don't hit ERANGE errors caused by lack of SEM_UNDO on semop* calls
|
162
|
+
# by doing an acquire > SEMVMX (32767) times:
|
163
|
+
#
|
164
|
+
# See: http://lxr.free-electrons.com/source/ipc/sem.c?v=3.8#L419
|
165
|
+
(1 << 16).times do # do an acquire 64k times
|
166
|
+
Semian[:testing].acquire do
|
167
|
+
1
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
158
172
|
def test_destroy
|
159
173
|
Semian.register :testing, tickets: 1
|
160
174
|
Semian[:testing].destroy
|
161
|
-
assert_raises
|
175
|
+
assert_raises Semian::SyscallError do
|
162
176
|
Semian[:testing].acquire { }
|
163
177
|
end
|
164
178
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: semian
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Francis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- ext/semian/extconf.rb
|
44
44
|
- ext/semian/semian.c
|
45
45
|
- lib/semian.rb
|
46
|
+
- lib/semian/version.rb
|
46
47
|
- semian.gemspec
|
47
48
|
- test/test_semian.rb
|
48
49
|
homepage: https://github.com/csfrancis/semian
|