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.
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__ */