process_shared 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/COPYING +19 -0
  2. data/ChangeLog +0 -0
  3. data/README.rdoc +69 -0
  4. data/ext/libpsem/bsem.c +188 -0
  5. data/ext/libpsem/bsem.h +32 -0
  6. data/ext/libpsem/constants.c +22 -0
  7. data/ext/libpsem/constants.h +18 -0
  8. data/ext/libpsem/extconf.rb +36 -0
  9. data/ext/libpsem/mempcpy.c +7 -0
  10. data/ext/libpsem/mempcpy.h +13 -0
  11. data/ext/libpsem/mutex.c +15 -0
  12. data/ext/libpsem/mutex.h +14 -0
  13. data/ext/libpsem/psem.c +15 -0
  14. data/ext/libpsem/psem.h +43 -0
  15. data/ext/libpsem/psem_error.c +46 -0
  16. data/ext/libpsem/psem_error.h +11 -0
  17. data/ext/libpsem/psem_posix.c +130 -0
  18. data/ext/libpsem/psem_posix.h +10 -0
  19. data/ext/pthread_sync_helper/extconf.rb +9 -0
  20. data/ext/pthread_sync_helper/pthread_sync_helper.c +43 -0
  21. data/ext/semaphore.c +623 -0
  22. data/lib/process_shared.rb +6 -0
  23. data/lib/process_shared/abstract_semaphore.rb +50 -0
  24. data/lib/process_shared/bounded_semaphore.rb +43 -0
  25. data/lib/process_shared/condition_variable.rb +27 -0
  26. data/lib/process_shared/libc.rb +36 -0
  27. data/lib/process_shared/libpsem.bundle +0 -0
  28. data/lib/process_shared/libpsem.so +0 -0
  29. data/lib/process_shared/mutex.rb +103 -0
  30. data/lib/process_shared/posix_call.rb +29 -0
  31. data/lib/process_shared/process_error.rb +3 -0
  32. data/lib/process_shared/psem.rb +109 -0
  33. data/lib/process_shared/rt.rb +21 -0
  34. data/lib/process_shared/semaphore.rb +60 -0
  35. data/lib/process_shared/shared_memory.rb +45 -0
  36. data/lib/process_shared/thread.rb +30 -0
  37. data/lib/process_shared/with_self.rb +20 -0
  38. data/lib/scratch.rb +300 -0
  39. data/spec/process_shared/bounded_semaphore_spec.rb +48 -0
  40. data/spec/process_shared/libc_spec.rb +9 -0
  41. data/spec/process_shared/mutex_spec.rb +74 -0
  42. data/spec/process_shared/psem_spec.rb +136 -0
  43. data/spec/process_shared/semaphore_spec.rb +76 -0
  44. data/spec/process_shared/shared_memory_spec.rb +36 -0
  45. data/spec/spec_helper.rb +35 -0
  46. 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.
File without changes
@@ -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?
@@ -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
+ }
@@ -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')
@@ -0,0 +1,7 @@
1
+ #include "mempcpy.h"
2
+
3
+ void *
4
+ mempcpy(void *dest, const void *src, size_t n)
5
+ {
6
+ return (char *) memcpy(dest, src, n) + n;
7
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef __MEMPCPY_H__
2
+ #define __MEMPCPY_H__
3
+
4
+ #ifdef HAVE_MEMPCPY
5
+ #define __USE_GNU
6
+ #else
7
+ #include <stdlib.h>
8
+ void *mempcpy(void *, const void *, size_t);
9
+ #endif
10
+
11
+ #include <string.h>
12
+
13
+ #endif /* __MEMPCPY_H__ */
@@ -0,0 +1,15 @@
1
+ #include <stdlib.h> /* malloc, free */
2
+
3
+ #include "mutex.h"
4
+
5
+ size_t sizeof_mutex_t = sizeof (mutex_t);
6
+
7
+ mutex_t *
8
+ mutex_alloc(void) {
9
+ return malloc(sizeof(mutex_t));
10
+ }
11
+
12
+ void
13
+ mutex_free(mutex_t * mutex) {
14
+ free(mutex);
15
+ }
@@ -0,0 +1,14 @@
1
+ #ifndef __MUTEX_H__
2
+ #define __MUTEX_H__
3
+
4
+ #include "bsem.h"
5
+
6
+ struct mutex {
7
+ bsem_t *bsem;
8
+ };
9
+
10
+ typedef struct mutex mutex_t;
11
+
12
+ extern size_t sizeof_mutex_t;
13
+
14
+ #endif /* __MUTEX_H__ */