semian 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/semian/resource.h +2 -2
- data/ext/semian/semian.c +0 -190
- data/ext/semian/semian.h +0 -53
- data/ext/semian/sysv_semaphores.c +128 -0
- data/ext/semian/sysv_semaphores.h +78 -0
- data/ext/semian/tickets.c +72 -0
- data/ext/semian/tickets.h +17 -0
- data/lib/semian/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5952a089360c3f99f037dd49e4bfdec80e010d3b
|
4
|
+
data.tar.gz: e1862220b675cba619fdddbdde1cccce6c24cd87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d6024b8df7dd42b1a6eb517cb8619c8138f20074529a0ffb1f7181dd5d81f9cdeeb9e2b7752ca7d234f400de2880a1d84ff592affc8f92806e2ce15f6d72f28
|
7
|
+
data.tar.gz: c7f64858fb8fc83a51b6f43a729cdc2dab9f24633c2a9016b50f3be945921de2893f9bea0eec4ae8419577eb715f108e70bae45ab44134be96b7161e75b6743b
|
data/ext/semian/resource.h
CHANGED
@@ -3,12 +3,12 @@ For core semian resource functions exposed directly to ruby.
|
|
3
3
|
|
4
4
|
Functions here are associated with rubyland operations.
|
5
5
|
*/
|
6
|
-
|
7
6
|
#ifndef SEMIAN_RESOURCE_H
|
8
7
|
#define SEMIAN_RESOURCE_H
|
9
8
|
|
10
|
-
#include "semian.h" // FIXME remove this once temporary declarations are removed
|
11
9
|
#include "types.h"
|
10
|
+
#include "tickets.h"
|
11
|
+
#include "sysv_semaphores.h"
|
12
12
|
|
13
13
|
// Ruby variables
|
14
14
|
ID id_timeout;
|
data/ext/semian/semian.c
CHANGED
@@ -1,195 +1,5 @@
|
|
1
1
|
#include "semian.h"
|
2
2
|
|
3
|
-
// Time to wait for timed ops to complete
|
4
|
-
#define INTERNAL_TIMEOUT 5 // seconds
|
5
|
-
|
6
|
-
key_t
|
7
|
-
generate_key(const char *name)
|
8
|
-
{
|
9
|
-
char semset_size_key[20];
|
10
|
-
char *uniq_id_str;
|
11
|
-
|
12
|
-
// It is necessary for the cardinatily of the semaphore set to be part of the key
|
13
|
-
// or else sem_get will complain that we have requested an incorrect number of sems
|
14
|
-
// for the desired key, and have changed the number of semaphores for a given key
|
15
|
-
sprintf(semset_size_key, "_NUM_SEMS_%d", SI_NUM_SEMAPHORES);
|
16
|
-
uniq_id_str = malloc(strlen(name)+strlen(semset_size_key)+1);
|
17
|
-
strcpy(uniq_id_str, name);
|
18
|
-
strcat(uniq_id_str, semset_size_key);
|
19
|
-
|
20
|
-
union {
|
21
|
-
unsigned char str[SHA_DIGEST_LENGTH];
|
22
|
-
key_t key;
|
23
|
-
} digest;
|
24
|
-
SHA1((const unsigned char *) uniq_id_str, strlen(uniq_id_str), digest.str);
|
25
|
-
free(uniq_id_str);
|
26
|
-
/* TODO: compile-time assertion that sizeof(key_t) > SHA_DIGEST_LENGTH */
|
27
|
-
return digest.key;
|
28
|
-
}
|
29
|
-
|
30
|
-
void
|
31
|
-
raise_semian_syscall_error(const char *syscall, int error_num)
|
32
|
-
{
|
33
|
-
rb_raise(eSyscall, "%s failed, errno: %d (%s)", syscall, error_num, strerror(error_num));
|
34
|
-
}
|
35
|
-
|
36
|
-
void
|
37
|
-
set_semaphore_permissions(int sem_id, long permissions)
|
38
|
-
{
|
39
|
-
union semun sem_opts;
|
40
|
-
struct semid_ds stat_buf;
|
41
|
-
|
42
|
-
sem_opts.buf = &stat_buf;
|
43
|
-
semctl(sem_id, 0, IPC_STAT, sem_opts);
|
44
|
-
if ((stat_buf.sem_perm.mode & 0xfff) != permissions) {
|
45
|
-
stat_buf.sem_perm.mode &= ~0xfff;
|
46
|
-
stat_buf.sem_perm.mode |= permissions;
|
47
|
-
semctl(sem_id, 0, IPC_SET, sem_opts);
|
48
|
-
}
|
49
|
-
}
|
50
|
-
|
51
|
-
static const int kInternalTimeout = 5; /* seconds */
|
52
|
-
|
53
|
-
static int
|
54
|
-
get_max_tickets(int sem_id)
|
55
|
-
{
|
56
|
-
int ret = semctl(sem_id, SI_SEM_CONFIGURED_TICKETS, GETVAL);
|
57
|
-
if (ret == -1) {
|
58
|
-
rb_raise(eInternal, "error getting max ticket count, errno: %d (%s)", errno, strerror(errno));
|
59
|
-
}
|
60
|
-
return ret;
|
61
|
-
}
|
62
|
-
|
63
|
-
int
|
64
|
-
perform_semop(int sem_id, short index, short op, short flags, struct timespec *ts)
|
65
|
-
{
|
66
|
-
struct sembuf buf = { 0 };
|
67
|
-
|
68
|
-
buf.sem_num = index;
|
69
|
-
buf.sem_op = op;
|
70
|
-
buf.sem_flg = flags;
|
71
|
-
|
72
|
-
if (ts) {
|
73
|
-
return semtimedop(sem_id, &buf, 1, ts);
|
74
|
-
} else {
|
75
|
-
return semop(sem_id, &buf, 1);
|
76
|
-
}
|
77
|
-
}
|
78
|
-
|
79
|
-
static VALUE
|
80
|
-
update_ticket_count(update_ticket_count_t *tc)
|
81
|
-
{
|
82
|
-
short delta;
|
83
|
-
struct timespec ts = { 0 };
|
84
|
-
ts.tv_sec = kInternalTimeout;
|
85
|
-
|
86
|
-
if (get_max_tickets(tc->sem_id) != tc->tickets) {
|
87
|
-
delta = tc->tickets - get_max_tickets(tc->sem_id);
|
88
|
-
|
89
|
-
if (perform_semop(tc->sem_id, SI_SEM_TICKETS, delta, 0, &ts) == -1) {
|
90
|
-
rb_raise(eInternal, "error setting ticket count, errno: %d (%s)", errno, strerror(errno));
|
91
|
-
}
|
92
|
-
|
93
|
-
if (semctl(tc->sem_id, SI_SEM_CONFIGURED_TICKETS, SETVAL, tc->tickets) == -1) {
|
94
|
-
rb_raise(eInternal, "error updating max ticket count, errno: %d (%s)", errno, strerror(errno));
|
95
|
-
}
|
96
|
-
}
|
97
|
-
|
98
|
-
return Qnil;
|
99
|
-
}
|
100
|
-
|
101
|
-
void
|
102
|
-
configure_tickets(int sem_id, int tickets, int should_initialize)
|
103
|
-
{
|
104
|
-
struct timespec ts = { 0 };
|
105
|
-
unsigned short init_vals[SI_NUM_SEMAPHORES];
|
106
|
-
struct timeval start_time, cur_time;
|
107
|
-
update_ticket_count_t tc;
|
108
|
-
int state;
|
109
|
-
|
110
|
-
if (should_initialize) {
|
111
|
-
init_vals[SI_SEM_TICKETS] = init_vals[SI_SEM_CONFIGURED_TICKETS] = tickets;
|
112
|
-
init_vals[SI_SEM_LOCK] = 1;
|
113
|
-
if (semctl(sem_id, 0, SETALL, init_vals) == -1) {
|
114
|
-
raise_semian_syscall_error("semctl()", errno);
|
115
|
-
}
|
116
|
-
} else if (tickets > 0) {
|
117
|
-
/* it's possible that we haven't actually initialized the
|
118
|
-
semaphore structure yet - wait a bit in that case */
|
119
|
-
if (get_max_tickets(sem_id) == 0) {
|
120
|
-
gettimeofday(&start_time, NULL);
|
121
|
-
while (get_max_tickets(sem_id) == 0) {
|
122
|
-
usleep(10000); /* 10ms */
|
123
|
-
gettimeofday(&cur_time, NULL);
|
124
|
-
if ((cur_time.tv_sec - start_time.tv_sec) > kInternalTimeout) {
|
125
|
-
rb_raise(eInternal, "timeout waiting for semaphore initialization");
|
126
|
-
}
|
127
|
-
}
|
128
|
-
}
|
129
|
-
|
130
|
-
/*
|
131
|
-
If the current max ticket count is not the same as the requested ticket
|
132
|
-
count, we need to resize the count. We do this by adding the delta of
|
133
|
-
(tickets - current_max_tickets) to the semaphore value.
|
134
|
-
*/
|
135
|
-
if (get_max_tickets(sem_id) != tickets) {
|
136
|
-
ts.tv_sec = kInternalTimeout;
|
137
|
-
|
138
|
-
if (perform_semop(sem_id, SI_SEM_LOCK, -1, SEM_UNDO, &ts) == -1) {
|
139
|
-
raise_semian_syscall_error("error acquiring internal semaphore lock, semtimedop()", errno);
|
140
|
-
}
|
141
|
-
|
142
|
-
tc.sem_id = sem_id;
|
143
|
-
tc.tickets = tickets;
|
144
|
-
rb_protect((VALUE (*)(VALUE)) update_ticket_count, (VALUE) &tc, &state);
|
145
|
-
|
146
|
-
if (perform_semop(sem_id, SI_SEM_LOCK, 1, SEM_UNDO, NULL) == -1) {
|
147
|
-
raise_semian_syscall_error("error releasing internal semaphore lock, semop()", errno);
|
148
|
-
}
|
149
|
-
|
150
|
-
if (state) {
|
151
|
-
rb_jump_tag(state);
|
152
|
-
}
|
153
|
-
}
|
154
|
-
}
|
155
|
-
}
|
156
|
-
|
157
|
-
int
|
158
|
-
create_semaphore(int key, long permissions, int *created)
|
159
|
-
{
|
160
|
-
int semid = 0;
|
161
|
-
int flags = 0;
|
162
|
-
|
163
|
-
*created = 0;
|
164
|
-
flags = IPC_EXCL | IPC_CREAT | permissions;
|
165
|
-
|
166
|
-
semid = semget(key, SI_NUM_SEMAPHORES, flags);
|
167
|
-
if (semid >= 0) {
|
168
|
-
*created = 1;
|
169
|
-
} else if (semid == -1 && errno == EEXIST) {
|
170
|
-
flags &= ~IPC_EXCL;
|
171
|
-
semid = semget(key, SI_NUM_SEMAPHORES, flags);
|
172
|
-
}
|
173
|
-
return semid;
|
174
|
-
}
|
175
|
-
|
176
|
-
void *
|
177
|
-
acquire_semaphore_without_gvl(void *p)
|
178
|
-
{
|
179
|
-
semian_resource_t *res = (semian_resource_t *) p;
|
180
|
-
res->error = 0;
|
181
|
-
if (perform_semop(res->sem_id, SI_SEM_TICKETS, -1, SEM_UNDO, &res->timeout) == -1) {
|
182
|
-
res->error = errno;
|
183
|
-
}
|
184
|
-
return NULL;
|
185
|
-
}
|
186
|
-
|
187
|
-
int
|
188
|
-
get_semaphore(int key)
|
189
|
-
{
|
190
|
-
return semget(key, SI_NUM_SEMAPHORES, 0);
|
191
|
-
}
|
192
|
-
|
193
3
|
void Init_semian()
|
194
4
|
{
|
195
5
|
VALUE cSemian, cResource;
|
data/ext/semian/semian.h
CHANGED
@@ -7,61 +7,8 @@ Implements Init_semian, which is used as C/Ruby entrypoint.
|
|
7
7
|
#ifndef SEMIAN_H
|
8
8
|
#define SEMIAN_H
|
9
9
|
|
10
|
-
// System includes
|
11
|
-
#include <errno.h>
|
12
|
-
#include <string.h>
|
13
|
-
#include <stdio.h>
|
14
|
-
|
15
|
-
// 3rd party includes
|
16
|
-
#include <openssl/sha.h>
|
17
|
-
#include <ruby.h>
|
18
|
-
#include <ruby/util.h>
|
19
|
-
#include <ruby/io.h>
|
20
|
-
|
21
|
-
//semian includes
|
22
|
-
#include "types.h"
|
23
10
|
#include "resource.h"
|
24
11
|
|
25
|
-
// FIXME: This is needed here temporarily
|
26
|
-
// Defines for ruby threading primitives
|
27
|
-
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && defined(HAVE_RUBY_THREAD_H)
|
28
|
-
// 2.0
|
29
|
-
#include <ruby/thread.h>
|
30
|
-
#define WITHOUT_GVL(fn,a,ubf,b) rb_thread_call_without_gvl((fn),(a),(ubf),(b))
|
31
|
-
#elif defined(HAVE_RB_THREAD_BLOCKING_REGION)
|
32
|
-
// 1.9
|
33
|
-
typedef VALUE (*my_blocking_fn_t)(void*);
|
34
|
-
#define WITHOUT_GVL(fn,a,ubf,b) rb_thread_blocking_region((my_blocking_fn_t)(fn),(a),(ubf),(b))
|
35
|
-
#endif
|
36
|
-
|
37
|
-
VALUE eSyscall, eTimeout, eInternal;
|
38
|
-
|
39
12
|
void Init_semian();
|
40
13
|
|
41
|
-
// FIXME: These are needed here temporarily while we move functions around
|
42
|
-
// Will be removed once there are new header files that the should belong to.
|
43
|
-
void
|
44
|
-
configure_tickets(int sem_id, int tickets, int should_initialize);
|
45
|
-
|
46
|
-
key_t
|
47
|
-
generate_key(const char *name);
|
48
|
-
|
49
|
-
void
|
50
|
-
set_semaphore_permissions(int sem_id, long permissions);
|
51
|
-
|
52
|
-
int
|
53
|
-
create_semaphore(int key, long permissions, int *created);
|
54
|
-
|
55
|
-
int
|
56
|
-
get_semaphore(int key);
|
57
|
-
|
58
|
-
void
|
59
|
-
raise_semian_syscall_error(const char *syscall, int error_num);
|
60
|
-
|
61
|
-
int
|
62
|
-
perform_semop(int sem_id, short index, short op, short flags, struct timespec *ts);
|
63
|
-
|
64
|
-
void *
|
65
|
-
acquire_semaphore_without_gvl(void *p);
|
66
|
-
|
67
14
|
#endif //SEMIAN_H
|
@@ -0,0 +1,128 @@
|
|
1
|
+
#include <sysv_semaphores.h>
|
2
|
+
|
3
|
+
void
|
4
|
+
raise_semian_syscall_error(const char *syscall, int error_num)
|
5
|
+
{
|
6
|
+
rb_raise(eSyscall, "%s failed, errno: %d (%s)", syscall, error_num, strerror(error_num));
|
7
|
+
}
|
8
|
+
|
9
|
+
key_t
|
10
|
+
generate_key(const char *name)
|
11
|
+
{
|
12
|
+
char semset_size_key[20];
|
13
|
+
char *uniq_id_str;
|
14
|
+
|
15
|
+
// It is necessary for the cardinatily of the semaphore set to be part of the key
|
16
|
+
// or else sem_get will complain that we have requested an incorrect number of sems
|
17
|
+
// for the desired key, and have changed the number of semaphores for a given key
|
18
|
+
sprintf(semset_size_key, "_NUM_SEMS_%d", SI_NUM_SEMAPHORES);
|
19
|
+
uniq_id_str = malloc(strlen(name)+strlen(semset_size_key)+1);
|
20
|
+
strcpy(uniq_id_str, name);
|
21
|
+
strcat(uniq_id_str, semset_size_key);
|
22
|
+
|
23
|
+
union {
|
24
|
+
unsigned char str[SHA_DIGEST_LENGTH];
|
25
|
+
key_t key;
|
26
|
+
} digest;
|
27
|
+
SHA1((const unsigned char *) uniq_id_str, strlen(uniq_id_str), digest.str);
|
28
|
+
free(uniq_id_str);
|
29
|
+
/* TODO: compile-time assertion that sizeof(key_t) > SHA_DIGEST_LENGTH */
|
30
|
+
return digest.key;
|
31
|
+
}
|
32
|
+
|
33
|
+
void
|
34
|
+
set_semaphore_permissions(int sem_id, long permissions)
|
35
|
+
{
|
36
|
+
union semun sem_opts;
|
37
|
+
struct semid_ds stat_buf;
|
38
|
+
|
39
|
+
sem_opts.buf = &stat_buf;
|
40
|
+
semctl(sem_id, 0, IPC_STAT, sem_opts);
|
41
|
+
if ((stat_buf.sem_perm.mode & 0xfff) != permissions) {
|
42
|
+
stat_buf.sem_perm.mode &= ~0xfff;
|
43
|
+
stat_buf.sem_perm.mode |= permissions;
|
44
|
+
semctl(sem_id, 0, IPC_SET, sem_opts);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
int
|
49
|
+
create_semaphore(int key, long permissions, int *created)
|
50
|
+
{
|
51
|
+
int semid = 0;
|
52
|
+
int flags = 0;
|
53
|
+
|
54
|
+
*created = 0;
|
55
|
+
flags = IPC_EXCL | IPC_CREAT | permissions;
|
56
|
+
|
57
|
+
semid = semget(key, SI_NUM_SEMAPHORES, flags);
|
58
|
+
if (semid >= 0) {
|
59
|
+
*created = 1;
|
60
|
+
} else if (semid == -1 && errno == EEXIST) {
|
61
|
+
flags &= ~IPC_EXCL;
|
62
|
+
semid = semget(key, SI_NUM_SEMAPHORES, flags);
|
63
|
+
}
|
64
|
+
return semid;
|
65
|
+
}
|
66
|
+
|
67
|
+
|
68
|
+
int
|
69
|
+
perform_semop(int sem_id, short index, short op, short flags, struct timespec *ts)
|
70
|
+
{
|
71
|
+
struct sembuf buf = { 0 };
|
72
|
+
|
73
|
+
buf.sem_num = index;
|
74
|
+
buf.sem_op = op;
|
75
|
+
buf.sem_flg = flags;
|
76
|
+
|
77
|
+
if (ts) {
|
78
|
+
return semtimedop(sem_id, &buf, 1, ts);
|
79
|
+
} else {
|
80
|
+
return semop(sem_id, &buf, 1);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
int
|
85
|
+
get_max_tickets(int sem_id)
|
86
|
+
{
|
87
|
+
int ret = semctl(sem_id, SI_SEM_CONFIGURED_TICKETS, GETVAL);
|
88
|
+
if (ret == -1) {
|
89
|
+
rb_raise(eInternal, "error getting max ticket count, errno: %d (%s)", errno, strerror(errno));
|
90
|
+
}
|
91
|
+
return ret;
|
92
|
+
}
|
93
|
+
|
94
|
+
void
|
95
|
+
sem_meta_lock(int sem_id)
|
96
|
+
{
|
97
|
+
struct timespec ts = { 0 };
|
98
|
+
ts.tv_sec = INTERNAL_TIMEOUT;
|
99
|
+
|
100
|
+
if (perform_semop(sem_id, SI_SEM_LOCK, -1, SEM_UNDO, &ts) == -1) {
|
101
|
+
raise_semian_syscall_error("error acquiring internal semaphore lock, semtimedop()", errno);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
void
|
106
|
+
sem_meta_unlock(int sem_id)
|
107
|
+
{
|
108
|
+
if (perform_semop(sem_id, SI_SEM_LOCK, 1, SEM_UNDO, NULL) == -1) {
|
109
|
+
raise_semian_syscall_error("error releasing internal semaphore lock, semop()", errno);
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
int
|
114
|
+
get_semaphore(int key)
|
115
|
+
{
|
116
|
+
return semget(key, SI_NUM_SEMAPHORES, 0);
|
117
|
+
}
|
118
|
+
|
119
|
+
void *
|
120
|
+
acquire_semaphore_without_gvl(void *p)
|
121
|
+
{
|
122
|
+
semian_resource_t *res = (semian_resource_t *) p;
|
123
|
+
res->error = 0;
|
124
|
+
if (perform_semop(res->sem_id, SI_SEM_TICKETS, -1, SEM_UNDO, &res->timeout) == -1) {
|
125
|
+
res->error = errno;
|
126
|
+
}
|
127
|
+
return NULL;
|
128
|
+
}
|
@@ -0,0 +1,78 @@
|
|
1
|
+
/*
|
2
|
+
For manipulating the semian's semaphore set
|
3
|
+
|
4
|
+
Semian semaphore operations and initialization,
|
5
|
+
and functions associated directly weth semops.
|
6
|
+
*/
|
7
|
+
#ifndef SEMIAN_SEMSET_H
|
8
|
+
#define SEMIAN_SEMSET_H
|
9
|
+
|
10
|
+
#include <errno.h>
|
11
|
+
#include <stdio.h>
|
12
|
+
#include <string.h>
|
13
|
+
|
14
|
+
#include <openssl/sha.h>
|
15
|
+
#include <ruby.h>
|
16
|
+
#include <ruby/util.h>
|
17
|
+
#include <ruby/io.h>
|
18
|
+
|
19
|
+
#include <types.h>
|
20
|
+
|
21
|
+
// Defines for ruby threading primitives
|
22
|
+
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && defined(HAVE_RUBY_THREAD_H)
|
23
|
+
// 2.0
|
24
|
+
#include <ruby/thread.h>
|
25
|
+
#define WITHOUT_GVL(fn,a,ubf,b) rb_thread_call_without_gvl((fn),(a),(ubf),(b))
|
26
|
+
#elif defined(HAVE_RB_THREAD_BLOCKING_REGION)
|
27
|
+
// 1.9
|
28
|
+
typedef VALUE (*my_blocking_fn_t)(void*);
|
29
|
+
#define WITHOUT_GVL(fn,a,ubf,b) rb_thread_blocking_region((my_blocking_fn_t)(fn),(a),(ubf),(b))
|
30
|
+
#endif
|
31
|
+
|
32
|
+
// Time to wait for timed ops to complete
|
33
|
+
#define INTERNAL_TIMEOUT 5 /* seconds */
|
34
|
+
|
35
|
+
VALUE eSyscall, eTimeout, eInternal;
|
36
|
+
|
37
|
+
// Helper for syscall verbose debugging
|
38
|
+
void
|
39
|
+
raise_semian_syscall_error(const char *syscall, int error_num);
|
40
|
+
|
41
|
+
// Genurates a unique key for the semaphore from the resource id
|
42
|
+
key_t
|
43
|
+
generate_key(const char *name);
|
44
|
+
|
45
|
+
// Set semaphore UNIX octal permissions
|
46
|
+
void
|
47
|
+
set_semaphore_permissions(int sem_id, long permissions);
|
48
|
+
|
49
|
+
// Create a new sysV IPC semaphore set
|
50
|
+
int
|
51
|
+
create_semaphore(int key, long permissions, int *created);
|
52
|
+
|
53
|
+
// Wrapper to performs a semop call
|
54
|
+
// The call may be timed or untimed
|
55
|
+
int
|
56
|
+
perform_semop(int sem_id, short index, short op, short flags, struct timespec *ts);
|
57
|
+
|
58
|
+
// Retrieve the current number of tickets in a semaphore by its semaphore index
|
59
|
+
int
|
60
|
+
get_max_tickets(int sem_id);
|
61
|
+
|
62
|
+
// Obtain an exclusive lock on the semaphore set critical section
|
63
|
+
void
|
64
|
+
sem_meta_lock(int sem_id);
|
65
|
+
|
66
|
+
// Release an exclusive lock on the semaphore set critical section
|
67
|
+
void
|
68
|
+
sem_meta_unlock(int sem_id);
|
69
|
+
|
70
|
+
// Retrieve a semaphore's ID from its key
|
71
|
+
int
|
72
|
+
get_semaphore(int key);
|
73
|
+
|
74
|
+
// Decrements the ticket semaphore within the semaphore set
|
75
|
+
void *
|
76
|
+
acquire_semaphore_without_gvl(void *p);
|
77
|
+
|
78
|
+
#endif // SEMIAN_SEMSET_H
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#include <tickets.h>
|
2
|
+
|
3
|
+
VALUE
|
4
|
+
update_ticket_count(update_ticket_count_t *tc)
|
5
|
+
{
|
6
|
+
short delta;
|
7
|
+
struct timespec ts = { 0 };
|
8
|
+
ts.tv_sec = INTERNAL_TIMEOUT;
|
9
|
+
|
10
|
+
if (get_max_tickets(tc->sem_id) != tc->tickets) {
|
11
|
+
delta = tc->tickets - get_max_tickets(tc->sem_id);
|
12
|
+
|
13
|
+
if (perform_semop(tc->sem_id, SI_SEM_TICKETS, delta, 0, &ts) == -1) {
|
14
|
+
rb_raise(eInternal, "error setting ticket count, errno: %d (%s)", errno, strerror(errno));
|
15
|
+
}
|
16
|
+
|
17
|
+
if (semctl(tc->sem_id, SI_SEM_CONFIGURED_TICKETS, SETVAL, tc->tickets) == -1) {
|
18
|
+
rb_raise(eInternal, "error updating max ticket count, errno: %d (%s)", errno, strerror(errno));
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
return Qnil;
|
23
|
+
}
|
24
|
+
|
25
|
+
void
|
26
|
+
configure_tickets(int sem_id, int tickets, int should_initialize)
|
27
|
+
{
|
28
|
+
unsigned short init_vals[SI_NUM_SEMAPHORES];
|
29
|
+
struct timeval start_time, cur_time;
|
30
|
+
update_ticket_count_t tc;
|
31
|
+
int state;
|
32
|
+
|
33
|
+
if (should_initialize) {
|
34
|
+
init_vals[SI_SEM_TICKETS] = init_vals[SI_SEM_CONFIGURED_TICKETS] = tickets;
|
35
|
+
init_vals[SI_SEM_LOCK] = 1;
|
36
|
+
if (semctl(sem_id, 0, SETALL, init_vals) == -1) {
|
37
|
+
raise_semian_syscall_error("semctl()", errno);
|
38
|
+
}
|
39
|
+
} else if (tickets > 0) {
|
40
|
+
/* it's possible that we haven't actually initialized the
|
41
|
+
semaphore structure yet - wait a bit in that case */
|
42
|
+
if (get_max_tickets(sem_id) == 0) {
|
43
|
+
gettimeofday(&start_time, NULL);
|
44
|
+
while (get_max_tickets(sem_id) == 0) {
|
45
|
+
usleep(10000); /* 10ms */
|
46
|
+
gettimeofday(&cur_time, NULL);
|
47
|
+
if ((cur_time.tv_sec - start_time.tv_sec) > INTERNAL_TIMEOUT) {
|
48
|
+
rb_raise(eInternal, "timeout waiting for semaphore initialization");
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
/*
|
54
|
+
If the current max ticket count is not the same as the requested ticket
|
55
|
+
count, we need to resize the count. We do this by adding the delta of
|
56
|
+
(tickets - current_max_tickets) to the semaphore value.
|
57
|
+
*/
|
58
|
+
if (get_max_tickets(sem_id) != tickets) {
|
59
|
+
sem_meta_lock(sem_id);
|
60
|
+
|
61
|
+
tc.sem_id = sem_id;
|
62
|
+
tc.tickets = tickets;
|
63
|
+
rb_protect((VALUE (*)(VALUE)) update_ticket_count, (VALUE) &tc, &state);
|
64
|
+
|
65
|
+
sem_meta_unlock(sem_id);
|
66
|
+
|
67
|
+
if (state) {
|
68
|
+
rb_jump_tag(state);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
/*
|
2
|
+
For logic specific to manipulating semian ticket counts
|
3
|
+
*/
|
4
|
+
#ifndef SEMIAN_TICKETS_H
|
5
|
+
#define SEMIAN_TICKETS_H
|
6
|
+
|
7
|
+
#include <sysv_semaphores.h>
|
8
|
+
|
9
|
+
// Update the ticket count for static ticket tracking
|
10
|
+
VALUE
|
11
|
+
update_ticket_count(update_ticket_count_t *tc);
|
12
|
+
|
13
|
+
// Set initial ticket values upon resource creation
|
14
|
+
void
|
15
|
+
configure_tickets(int sem_id, int tickets, int should_initialize);
|
16
|
+
|
17
|
+
#endif // SEMIAN_TICKETS_H
|
data/lib/semian/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: semian
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Francis
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-02-
|
12
|
+
date: 2017-02-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake-compiler
|
@@ -137,6 +137,10 @@ files:
|
|
137
137
|
- ext/semian/resource.h
|
138
138
|
- ext/semian/semian.c
|
139
139
|
- ext/semian/semian.h
|
140
|
+
- ext/semian/sysv_semaphores.c
|
141
|
+
- ext/semian/sysv_semaphores.h
|
142
|
+
- ext/semian/tickets.c
|
143
|
+
- ext/semian/tickets.h
|
140
144
|
- ext/semian/types.h
|
141
145
|
- lib/semian.rb
|
142
146
|
- lib/semian/adapter.rb
|