process_shared 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +19 -0
- data/ChangeLog +0 -0
- data/README.rdoc +69 -0
- data/ext/libpsem/bsem.c +188 -0
- data/ext/libpsem/bsem.h +32 -0
- data/ext/libpsem/constants.c +22 -0
- data/ext/libpsem/constants.h +18 -0
- data/ext/libpsem/extconf.rb +36 -0
- data/ext/libpsem/mempcpy.c +7 -0
- data/ext/libpsem/mempcpy.h +13 -0
- data/ext/libpsem/mutex.c +15 -0
- data/ext/libpsem/mutex.h +14 -0
- data/ext/libpsem/psem.c +15 -0
- data/ext/libpsem/psem.h +43 -0
- data/ext/libpsem/psem_error.c +46 -0
- data/ext/libpsem/psem_error.h +11 -0
- data/ext/libpsem/psem_posix.c +130 -0
- data/ext/libpsem/psem_posix.h +10 -0
- data/ext/pthread_sync_helper/extconf.rb +9 -0
- data/ext/pthread_sync_helper/pthread_sync_helper.c +43 -0
- data/ext/semaphore.c +623 -0
- data/lib/process_shared.rb +6 -0
- data/lib/process_shared/abstract_semaphore.rb +50 -0
- data/lib/process_shared/bounded_semaphore.rb +43 -0
- data/lib/process_shared/condition_variable.rb +27 -0
- data/lib/process_shared/libc.rb +36 -0
- data/lib/process_shared/libpsem.bundle +0 -0
- data/lib/process_shared/libpsem.so +0 -0
- data/lib/process_shared/mutex.rb +103 -0
- data/lib/process_shared/posix_call.rb +29 -0
- data/lib/process_shared/process_error.rb +3 -0
- data/lib/process_shared/psem.rb +109 -0
- data/lib/process_shared/rt.rb +21 -0
- data/lib/process_shared/semaphore.rb +60 -0
- data/lib/process_shared/shared_memory.rb +45 -0
- data/lib/process_shared/thread.rb +30 -0
- data/lib/process_shared/with_self.rb +20 -0
- data/lib/scratch.rb +300 -0
- data/spec/process_shared/bounded_semaphore_spec.rb +48 -0
- data/spec/process_shared/libc_spec.rb +9 -0
- data/spec/process_shared/mutex_spec.rb +74 -0
- data/spec/process_shared/psem_spec.rb +136 -0
- data/spec/process_shared/semaphore_spec.rb +76 -0
- data/spec/process_shared/shared_memory_spec.rb +36 -0
- data/spec/spec_helper.rb +35 -0
- metadata +139 -0
data/COPYING
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2011 Patrick Mahoney
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/ChangeLog
ADDED
File without changes
|
data/README.rdoc
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
== Description
|
2
|
+
|
3
|
+
Concurrency primitives that may be used in a cross-process way to
|
4
|
+
coordinate share memory between processes.
|
5
|
+
|
6
|
+
A small C library (libpsem) is compiled to provide portable access to
|
7
|
+
semaphores. This library is then accessed using FFI to implement Ruby
|
8
|
+
classes ProcessShared::Semaphore, ProcessShared::BoundedSemaphore,
|
9
|
+
ProcessShared::Mutex, and ProcessShared::SharedMemory.
|
10
|
+
|
11
|
+
This is an incomplete work in progress.
|
12
|
+
|
13
|
+
== License
|
14
|
+
|
15
|
+
MIT
|
16
|
+
|
17
|
+
== Install
|
18
|
+
Install the gem with:
|
19
|
+
|
20
|
+
gem install process_shared
|
21
|
+
|
22
|
+
== Usage
|
23
|
+
|
24
|
+
require 'process_shared'
|
25
|
+
|
26
|
+
mutex = ProcessShared::Mutex.new
|
27
|
+
mem = ProcessShared::SharedMemory.new(:int) # extends FFI::Pointer
|
28
|
+
mem.put_int(0, 0)
|
29
|
+
|
30
|
+
pid1 = fork do
|
31
|
+
puts "in process 1 (#{Process.pid})"
|
32
|
+
10.times do
|
33
|
+
sleep 0.01
|
34
|
+
mutex.synchronize do
|
35
|
+
value = mem.get_int(0)
|
36
|
+
sleep 0.01
|
37
|
+
puts "process 1 (#{Process.pid}) incrementing"
|
38
|
+
mem.put_int(0, value + 1)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
pid2 = fork do
|
44
|
+
puts "in process 2 (#{Process.pid})"
|
45
|
+
10.times do
|
46
|
+
sleep 0.01
|
47
|
+
mutex.synchronize do
|
48
|
+
value = mem.get_int(0)
|
49
|
+
sleep 0.01
|
50
|
+
puts "process 2 (#{Process.pid}) decrementing"
|
51
|
+
mem.put_int(0, value - 1)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Process.wait(pid1)
|
57
|
+
Process.wait(pid2)
|
58
|
+
|
59
|
+
puts "value should be zero: #{mem.get_int(0)}"
|
60
|
+
|
61
|
+
== Todo
|
62
|
+
|
63
|
+
* Implement ConditionVariable
|
64
|
+
* Implement optional override of core Thread/Mutex classes
|
65
|
+
* Extend libpsem to win32? (See Python's processing library)
|
66
|
+
* Break out tests that use PSem.getvalue() (which isn't supported on Mac OS X)
|
67
|
+
so that the test suite will pass
|
68
|
+
* Add finalizer to Mutex? (finalizer on Semaphore objects may be enough) or a method to
|
69
|
+
explicitly close and release resources?
|
data/ext/libpsem/bsem.c
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
/*
|
2
|
+
* Extensions atop psem. Recursive mutex, bounded semaphore.
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include <stdlib.h> /* malloc, free */
|
6
|
+
|
7
|
+
#include "mempcpy.h" /* includes string.h */
|
8
|
+
#include "psem.h"
|
9
|
+
#include "psem_error.h"
|
10
|
+
#include "bsem.h"
|
11
|
+
|
12
|
+
#define MAX_NAME 128 /* This is much less the POSIX max
|
13
|
+
name. Users of this library must
|
14
|
+
not use longer names. */
|
15
|
+
|
16
|
+
static const char bsem_lock_suffix[] = "-bsem-lock";
|
17
|
+
|
18
|
+
#define MAX_LOCK_NAME (MAX_NAME + strlen(bsem_lock_suffix) + 1)
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Assumes dest has sufficient space to hold "[MAX_NAME]-bsem-lock".
|
22
|
+
*/
|
23
|
+
static int
|
24
|
+
make_lockname(char *dest, const char *name, error_t **err)
|
25
|
+
{
|
26
|
+
int namelen;
|
27
|
+
|
28
|
+
namelen = strlen(name);
|
29
|
+
if (namelen > MAX_NAME) {
|
30
|
+
error_new(err, E_SOURCE_PSEM, E_NAME_TOO_LONG);
|
31
|
+
return ERROR;
|
32
|
+
}
|
33
|
+
|
34
|
+
*((char *) mempcpy(mempcpy(dest, name, namelen),
|
35
|
+
bsem_lock_suffix,
|
36
|
+
strlen(bsem_lock_suffix))) = '\0';
|
37
|
+
}
|
38
|
+
|
39
|
+
size_t sizeof_bsem_t = sizeof (bsem_t);
|
40
|
+
|
41
|
+
bsem_t *
|
42
|
+
bsem_alloc(void) {
|
43
|
+
return malloc(sizeof(bsem_t));
|
44
|
+
}
|
45
|
+
|
46
|
+
void
|
47
|
+
bsem_free(bsem_t *bsem) {
|
48
|
+
free(bsem);
|
49
|
+
}
|
50
|
+
|
51
|
+
#define call_or_return(exp) \
|
52
|
+
do { if ((exp) == ERROR) { return ERROR; } } while (0)
|
53
|
+
|
54
|
+
#define bsem_lock_or_return(bsem, err) call_or_return(bsem_lock((bsem), (err)))
|
55
|
+
|
56
|
+
#define bsem_unlock_or_return(bsem, err) call_or_return(bsem_unlock((bsem), (err)))
|
57
|
+
|
58
|
+
int
|
59
|
+
bsem_open(bsem_t *bsem, const char *name, unsigned int maxvalue, unsigned int value, error_t **err)
|
60
|
+
{
|
61
|
+
char lockname[MAX_LOCK_NAME];
|
62
|
+
|
63
|
+
call_or_return(psem_open(&bsem->psem, name, value, err));
|
64
|
+
call_or_return(make_lockname(lockname, name, err));
|
65
|
+
call_or_return(psem_open(&bsem->lock, lockname, 1, err));
|
66
|
+
|
67
|
+
bsem->maxvalue = maxvalue;
|
68
|
+
|
69
|
+
return OK;
|
70
|
+
}
|
71
|
+
|
72
|
+
static int
|
73
|
+
bsem_lock(bsem_t *bsem, error_t **err)
|
74
|
+
{
|
75
|
+
call_or_return(psem_wait(&bsem->lock, err));
|
76
|
+
return OK;
|
77
|
+
}
|
78
|
+
|
79
|
+
static int
|
80
|
+
bsem_unlock(bsem_t *bsem, error_t **err)
|
81
|
+
{
|
82
|
+
call_or_return(psem_post(&bsem->lock, err));
|
83
|
+
return OK;
|
84
|
+
}
|
85
|
+
|
86
|
+
int
|
87
|
+
bsem_close(bsem_t *bsem, error_t **err)
|
88
|
+
{
|
89
|
+
bsem_lock_or_return(bsem, err);
|
90
|
+
|
91
|
+
if (psem_close(&bsem->psem, err) == ERROR) {
|
92
|
+
bsem_unlock(bsem, NULL);
|
93
|
+
return ERROR;
|
94
|
+
}
|
95
|
+
|
96
|
+
bsem_unlock_or_return(bsem, err);
|
97
|
+
|
98
|
+
call_or_return(psem_close(&bsem->lock, err));
|
99
|
+
return OK;
|
100
|
+
}
|
101
|
+
|
102
|
+
int
|
103
|
+
bsem_unlink(const char *name, error_t **err)
|
104
|
+
{
|
105
|
+
char lockname[MAX_LOCK_NAME];
|
106
|
+
|
107
|
+
call_or_return(psem_unlink(name, err));
|
108
|
+
call_or_return(make_lockname(lockname, name, err));
|
109
|
+
call_or_return(psem_unlink(lockname, err));
|
110
|
+
return OK;
|
111
|
+
}
|
112
|
+
|
113
|
+
int
|
114
|
+
bsem_post(bsem_t *bsem, error_t **err)
|
115
|
+
{
|
116
|
+
int sval;
|
117
|
+
|
118
|
+
bsem_lock_or_return(bsem, err);
|
119
|
+
|
120
|
+
/* FIXME: maxvalue is broken on some systems... (cygwin? mac?) */
|
121
|
+
if (psem_getvalue(&bsem->psem, &sval, err) == ERROR) {
|
122
|
+
bsem_unlock(bsem, err);
|
123
|
+
return ERROR;
|
124
|
+
}
|
125
|
+
|
126
|
+
if (sval >= bsem->maxvalue) {
|
127
|
+
/* ignored silently */
|
128
|
+
bsem_unlock(bsem, err);
|
129
|
+
return OK;
|
130
|
+
}
|
131
|
+
|
132
|
+
if (psem_post(&bsem->psem, err) == ERROR) {
|
133
|
+
bsem_unlock(bsem, err);
|
134
|
+
return ERROR;
|
135
|
+
}
|
136
|
+
|
137
|
+
bsem_unlock_or_return(bsem, err);
|
138
|
+
return OK;
|
139
|
+
}
|
140
|
+
|
141
|
+
int
|
142
|
+
bsem_wait(bsem_t *bsem, error_t **err)
|
143
|
+
{
|
144
|
+
call_or_return(psem_wait(&bsem->psem, err));
|
145
|
+
return OK;
|
146
|
+
}
|
147
|
+
|
148
|
+
int
|
149
|
+
bsem_trywait(bsem_t *bsem, error_t **err)
|
150
|
+
{
|
151
|
+
bsem_lock_or_return(bsem, err);
|
152
|
+
|
153
|
+
if (psem_trywait(&bsem->psem, err) == ERROR) {
|
154
|
+
bsem_unlock(bsem, NULL);
|
155
|
+
return ERROR;
|
156
|
+
}
|
157
|
+
|
158
|
+
bsem_unlock_or_return(bsem, err);
|
159
|
+
return OK;
|
160
|
+
}
|
161
|
+
|
162
|
+
int
|
163
|
+
bsem_timedwait(bsem_t *bsem, float timeout_s, error_t **err)
|
164
|
+
{
|
165
|
+
bsem_lock_or_return(bsem, err);
|
166
|
+
|
167
|
+
if (psem_timedwait(&bsem->psem, timeout_s, err) == ERROR) {
|
168
|
+
bsem_unlock(bsem, NULL);
|
169
|
+
return ERROR;
|
170
|
+
}
|
171
|
+
|
172
|
+
bsem_unlock_or_return(bsem, err);
|
173
|
+
return OK;
|
174
|
+
}
|
175
|
+
|
176
|
+
int
|
177
|
+
bsem_getvalue(bsem_t *bsem, int *sval, error_t **err)
|
178
|
+
{
|
179
|
+
bsem_lock_or_return(bsem, err);
|
180
|
+
|
181
|
+
if (psem_getvalue(&bsem->psem, sval, err) == ERROR) {
|
182
|
+
bsem_unlock(bsem, NULL);
|
183
|
+
return ERROR;
|
184
|
+
}
|
185
|
+
|
186
|
+
bsem_unlock_or_return(bsem, err);
|
187
|
+
return OK;
|
188
|
+
}
|
data/ext/libpsem/bsem.h
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#ifndef __BSEM_H__
|
2
|
+
#define __BSEM_H__
|
3
|
+
|
4
|
+
#include "psem.h"
|
5
|
+
#include "psem_error.h"
|
6
|
+
|
7
|
+
struct bsem {
|
8
|
+
psem_t psem;
|
9
|
+
psem_t lock;
|
10
|
+
int maxvalue;
|
11
|
+
};
|
12
|
+
|
13
|
+
typedef struct bsem bsem_t;
|
14
|
+
|
15
|
+
extern size_t sizeof_bsem_t;
|
16
|
+
|
17
|
+
bsem_t * bsem_alloc();
|
18
|
+
void bsem_free(bsem_t *bsem);
|
19
|
+
|
20
|
+
int bsem_open(bsem_t *, const char *, unsigned int, unsigned int, error_t **);
|
21
|
+
int bsem_close(bsem_t *, error_t **);
|
22
|
+
int bsem_unlink(const char *, error_t **);
|
23
|
+
|
24
|
+
int bsem_post(bsem_t *, error_t **);
|
25
|
+
int bsem_wait(bsem_t *, error_t **);
|
26
|
+
int bsem_trywait(bsem_t *, error_t **);
|
27
|
+
int bsem_timedwait(bsem_t *, float, error_t **);
|
28
|
+
|
29
|
+
int bsem_getvalue(bsem_t *, int *, error_t **);
|
30
|
+
|
31
|
+
#endif /* __BSEM_H__ */
|
32
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
/**
|
2
|
+
* Define and extern various constants defined as macros.
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include <sys/mman.h> /* PROT_*, MAP_* */
|
6
|
+
#include <fcntl.h> /* O_* */
|
7
|
+
|
8
|
+
#include "constants.h"
|
9
|
+
|
10
|
+
int o_rdwr = O_RDWR;
|
11
|
+
int o_creat = O_CREAT;
|
12
|
+
int o_excl = O_EXCL;
|
13
|
+
|
14
|
+
int prot_read = PROT_READ;
|
15
|
+
int prot_write = PROT_WRITE;
|
16
|
+
int prot_exec = PROT_EXEC;
|
17
|
+
int prot_none = PROT_NONE;
|
18
|
+
|
19
|
+
void * map_failed = MAP_FAILED;
|
20
|
+
|
21
|
+
int map_shared = MAP_SHARED;
|
22
|
+
int map_private = MAP_PRIVATE;
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#ifndef __CONSTANTS_H__
|
2
|
+
#define __CONSTANTS_H__
|
3
|
+
|
4
|
+
extern int o_rdwr;
|
5
|
+
extern int o_creat;
|
6
|
+
extern int o_excl;
|
7
|
+
|
8
|
+
extern int prot_read;
|
9
|
+
extern int prot_write;
|
10
|
+
extern int prot_exec;
|
11
|
+
extern int prot_none;
|
12
|
+
|
13
|
+
extern void * map_failed;
|
14
|
+
|
15
|
+
extern int map_shared;
|
16
|
+
extern int map_private;
|
17
|
+
|
18
|
+
#endif
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
$objs = []
|
4
|
+
|
5
|
+
# posix semaphores
|
6
|
+
if have_func('sem_open', 'semaphore.h')
|
7
|
+
have_func('floorf', 'math.h') or abort("Missing required floorf() in math.h")
|
8
|
+
have_library('m', 'floorf')
|
9
|
+
|
10
|
+
unless have_func('mempcpy', 'string.h')
|
11
|
+
$objs << 'mempcpy.o'
|
12
|
+
end
|
13
|
+
|
14
|
+
have_library('rt', 'sem_open')
|
15
|
+
end
|
16
|
+
|
17
|
+
c_sources = ['psem.c', 'psem_error.c', 'psem_posix.c', 'bsem.c', 'constants.c']
|
18
|
+
$objs += ['psem.o', 'psem_error.o', 'bsem.o', 'constants.o']
|
19
|
+
|
20
|
+
depend_rules <<-END
|
21
|
+
psem.c: psem.h psem_posix.c
|
22
|
+
psem_error.c: psem_error.h
|
23
|
+
|
24
|
+
bsem.h: psem.h psem_error.h
|
25
|
+
bsem.c: psem.h psem_error.h bsem.h
|
26
|
+
|
27
|
+
constants.c: constants.h
|
28
|
+
mempcpy.c: mempcpy.h
|
29
|
+
|
30
|
+
#{$objs.map { |o| "#{o}: #{o.chomp(".o")}.c" }.join("\n")}
|
31
|
+
|
32
|
+
libpsem.o: #{$objs.join(' ')}
|
33
|
+
END
|
34
|
+
|
35
|
+
|
36
|
+
create_makefile('libpsem')
|
data/ext/libpsem/mutex.c
ADDED