process_shared 0.0.1
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.
- 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