ice799-shlock 0.0.2 → 0.0.3

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 (4) hide show
  1. data/README +15 -10
  2. data/ext/shlock.c +155 -40
  3. data/shlock.gemspec +1 -1
  4. metadata +1 -1
data/README CHANGED
@@ -1,21 +1,26 @@
1
- What is putex ?
1
+ What is shlock ?
2
2
  ===============
3
+ shlock is a library that provides synchronization primitives that use shared memory.
3
4
 
4
- putex is an interproces mutex that uses shared memory (PUTEX = Process mUTEX).
5
-
5
+ Currently, mutexes (Shlock::Putex) and rwlocks (Shlock::Prwlock) are implemented.
6
6
 
7
7
  Why ?
8
8
  =====
9
-
10
9
  If want to synchronize two ruby processes without using those painful file locks, you can use this.
11
10
 
11
+ TODO
12
+ ====
13
+ - It is probably not safe to use these pthread exposed APIs in this way. I should probably reimplement
14
+ the low-level locking primitives in C using atomic.h and futexes.
12
15
 
13
- Sample Usage:
14
- =============
16
+ - Add documentation about Shlock::Prwlock
17
+
18
+ Sample Usage of Shlock::Putex
19
+ =============================
15
20
 
16
21
  process1.rb:
17
- require 'putex'
18
- f = Putex.new("/test-mutex")
22
+ require 'shlock'
23
+ f = Shlock::Putex.new("/test-mutex")
19
24
  f.lock
20
25
  puts("locked the mutex once, grabbing lock again to spin-wait; go run process2.rb once locked up...\n")
21
26
  f.lock
@@ -23,8 +28,8 @@ puts("got the lock, exiting\n")
23
28
 
24
29
 
25
30
  process2.rb:
26
- require 'putex'
27
- f = Putex.new("/text-mutex")
31
+ require 'shlock'
32
+ f = Shlock::Putex.new("/text-mutex")
28
33
  puts "alive, unlocking"
29
34
  f.unlock
30
35
  puts "done, exiting"
@@ -6,48 +6,67 @@
6
6
  #include <fcntl.h>
7
7
  #include <errno.h>
8
8
  #include <sys/stat.h>
9
+ #include <semaphore.h>
9
10
 
10
11
  struct mutex_info {
11
12
  pthread_mutex_t m;
12
- int fd;
13
13
  };
14
14
 
15
15
  struct rwlock_info {
16
16
  pthread_rwlock_t rwlock;
17
- int fd;
18
17
  };
19
18
 
20
- static int shared_mem_open(const char *name) {
21
- int fd = shm_open (name, O_RDWR, S_IRUSR | S_IWUSR);
22
- if (fd < 0) {
23
- fd = shm_open (name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
24
- if (ftruncate(fd, sizeof(struct mutex_info)) == -1) {
25
- printf("ftruncate error: %s\n", strerror(errno));
19
+ struct sem_info {
20
+ sem_t sem;
21
+ };
22
+
23
+ /**
24
+ * @return ret 0 if the shared memory already existed, 1 if it had to be created.
25
+ */
26
+
27
+ static int shared_mem_open(const char *name, int *fd) {
28
+ int ret = 0;
29
+ int mfd = shm_open (name, O_RDWR, S_IRUSR | S_IWUSR);
30
+ if (mfd < 0) {
31
+ mfd = shm_open (name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
32
+ if (mfd < 0) {
33
+ fprintf(stderr, "shm_open error: %s\n", strerror(errno));
34
+ return -1;
35
+ }
36
+ ret = 1;
37
+ if (ftruncate(mfd, sizeof(struct mutex_info)) == -1) {
38
+ fprintf(stderr,"ftruncate error: %s\n", strerror(errno));
26
39
  return -1;
27
40
  }
28
41
  }
29
42
 
30
- if (fd < 0) {
31
- printf("error: %s\n", strerror(errno));
32
- return -1;
33
- }
34
-
35
- return fd;
43
+ *fd = mfd;
44
+ return ret;
36
45
  }
37
46
 
38
47
  static VALUE rb_putex_new (VALUE self, VALUE name) {
39
48
  struct mutex_info *ms;
40
- int fd = shared_mem_open(StringValuePtr(name));
41
- if (fd < 0)
49
+ int mfd = 0;
50
+ int ret = shared_mem_open(StringValuePtr(name), &mfd);
51
+ if (mfd < 0)
42
52
  return Qnil;
43
53
 
44
- ms = (struct mutex_info *)mmap(NULL, sizeof(struct mutex_info), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
54
+ ms = (struct mutex_info *)mmap(NULL, sizeof(struct mutex_info), PROT_READ|PROT_WRITE, MAP_SHARED, mfd, 0);
55
+ close(mfd);
56
+
45
57
  if (ms == MAP_FAILED) {
46
- printf("mmap error: %s\n", strerror(errno));
58
+ fprintf(stderr, "mmap error: %s\n", strerror(errno));
47
59
  return Qnil;
48
60
  }
49
- ms->fd = fd;
50
- fsync(fd);
61
+
62
+ if (ret) {
63
+ /* mutex was just created so we need to set some attributes and initalize the mutex */
64
+ pthread_mutexattr_t mattr;
65
+ pthread_mutexattr_init(&mattr);
66
+ pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
67
+ pthread_mutex_init(&(ms->m), &mattr);
68
+ }
69
+
51
70
  VALUE obj = Data_Wrap_Struct(self, NULL, NULL, ms);
52
71
  return obj;
53
72
  }
@@ -55,41 +74,58 @@ static VALUE rb_putex_new (VALUE self, VALUE name) {
55
74
  static VALUE rb_putex_destroy (VALUE self) {
56
75
  struct mutex_info *m;
57
76
  Data_Get_Struct(self, struct mutex_info, m);
58
- fsync(m->fd);
59
- close(m->fd);
77
+ if (munmap(m, sizeof(struct mutex_info)) == -1) {
78
+ fprintf(stderr, "munmap error: %s\n", strerror(errno));
79
+ }
60
80
 
61
81
  return Qnil;
62
82
  }
63
83
 
64
84
  static VALUE rb_putex_lock (VALUE self) {
65
85
  struct mutex_info *fs;
86
+ int ret = 0;
66
87
  Data_Get_Struct(self, struct mutex_info, fs);
67
- pthread_mutex_lock(&(fs->m));
88
+ if ((ret = pthread_mutex_lock(&(fs->m))) == -1) {
89
+ fprintf(stderr, "pthread_mutex_lock: %s\n", strerror(ret));
90
+ }
68
91
 
69
92
  return Qnil;
70
93
  }
71
94
 
72
95
  static VALUE rb_putex_unlock (VALUE self) {
73
96
  struct mutex_info *fs;
97
+ int ret = 0;
74
98
  Data_Get_Struct(self, struct mutex_info, fs);
75
- pthread_mutex_unlock(&(fs->m));
99
+ if ((ret = pthread_mutex_unlock(&(fs->m))) == -1) {
100
+ fprintf(stderr, "pthread_mutex_unlock: %s\n", strerror(ret));
101
+ }
76
102
 
77
103
  return Qnil;
78
104
  }
79
105
 
80
106
  static VALUE rb_rwlock_new (VALUE self, VALUE name) {
81
107
  struct rwlock_info *rws;
82
- int fd = shared_mem_open (StringValuePtr(name));
83
- if (fd < 0)
108
+ int mfd = 0;
109
+
110
+ int ret = shared_mem_open (StringValuePtr(name), &mfd);
111
+ if (ret == -1)
84
112
  return Qnil;
85
113
 
86
- rws = (struct rwlock_info *)mmap(NULL, sizeof(struct rwlock_info), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
114
+ rws = (struct rwlock_info *)mmap(NULL, sizeof(struct rwlock_info), PROT_READ|PROT_WRITE, MAP_SHARED, mfd, 0);
115
+ close(mfd);
116
+
87
117
  if (rws == MAP_FAILED) {
88
- printf("mmap error: %s\n", strerror(errno));
118
+ fprintf(stderr, "mmap error: %s\n", strerror(errno));
89
119
  return Qnil;
90
120
  }
91
- rws->fd = fd;
92
- fsync(fd);
121
+
122
+ if (ret) {
123
+ /* rwlock was just created so we need to set some attributes and initalize */
124
+ pthread_rwlockattr_t rwattr;
125
+ pthread_rwlockattr_init(&rwattr);
126
+ pthread_rwlockattr_setpshared(&rwattr, PTHREAD_PROCESS_SHARED);
127
+ pthread_rwlock_init(&(rws->rwlock), &rwattr);
128
+ }
93
129
 
94
130
  VALUE obj = Data_Wrap_Struct(self, NULL, NULL, rws);
95
131
  return obj;
@@ -98,36 +134,109 @@ static VALUE rb_rwlock_new (VALUE self, VALUE name) {
98
134
  static VALUE rb_rwlock_destory (VALUE self) {
99
135
  struct rwlock_info *rws;
100
136
  Data_Get_Struct(self, struct rwlock_info, rws);
101
- fsync(rws->fd);
102
- close(rws->fd);
103
-
137
+ munmap(rws, sizeof(struct rwlock_info));
104
138
  return Qnil;
105
139
  }
106
140
 
107
141
  static VALUE rb_rwlock_read_lock (VALUE self) {
108
142
  struct rwlock_info *rws;
143
+ int ret = 0;
109
144
  Data_Get_Struct(self, struct rwlock_info, rws);
110
- pthread_rwlock_rdlock(&(rws->rwlock));
145
+ if ((ret = pthread_rwlock_rdlock(&(rws->rwlock))) == -1) {
146
+ fprintf(stderr, "pthread_rwlock_rdlock: %s\n", strerror(ret));
147
+ }
111
148
 
112
149
  return Qnil;
113
150
  }
114
151
 
115
152
  static VALUE rb_rwlock_write_lock (VALUE self) {
116
153
  struct rwlock_info *rws;
154
+ int ret = 0;
117
155
  Data_Get_Struct (self, struct rwlock_info, rws);
118
- pthread_rwlock_wrlock(&(rws->rwlock));
156
+ if ((ret = pthread_rwlock_wrlock(&(rws->rwlock))) == -1) {
157
+ fprintf(stderr, "pthread_rwlock_wrlock: %s\n", strerror(ret));
158
+ }
119
159
 
120
160
  return Qnil;
121
161
  }
122
162
 
123
163
  static VALUE rb_rwlock_unlock (VALUE self) {
124
164
  struct rwlock_info *rws;
165
+ int ret = 0;
166
+ Data_Get_Struct (self, struct rwlock_info, rws);
167
+ if ((ret = pthread_rwlock_unlock(&(rws->rwlock))) == -1) {
168
+ fprintf(stderr, "pthread_rwlock_unlock: %s\n", strerror(ret));
169
+ }
170
+
171
+ return Qnil;
172
+ }
173
+
174
+ static VALUE rb_rwlock_destroy (VALUE self) {
175
+ struct rwlock_info *rws;
176
+ int ret = 0;
125
177
  Data_Get_Struct (self, struct rwlock_info, rws);
126
- int e = pthread_rwlock_unlock(&(rws->rwlock));
178
+ if ((ret = pthread_rwlock_destroy(&(rws->rwlock))) == -1) {
179
+ fprintf(stderr, "pthread_rwlock_destroy: %s\n", strerror(ret));
180
+ }
127
181
 
128
- if (e != 0) {
129
- printf("error: %d\n", e);
182
+ return Qnil;
183
+ }
184
+
185
+ static VALUE rb_psem_new (VALUE self, VALUE name, VALUE val) {
186
+ struct sem_info *si;
187
+ int mfd = 0;
188
+
189
+ int ret = shared_mem_open (StringValuePtr(name), &mfd);
190
+ if (ret == -1)
191
+ return Qnil;
192
+
193
+ si = (struct sem_info *)mmap(NULL, sizeof(struct sem_info), PROT_READ|PROT_WRITE, MAP_SHARED, mfd, 0);
194
+ close(mfd);
195
+
196
+ if (si == MAP_FAILED) {
197
+ fprintf(stderr, "mmap error: %s\n", strerror(errno));
198
+ return Qnil;
199
+ }
200
+
201
+ if (ret) {
202
+ /* sem was just created so we need to set some attributes and initalize */
203
+ sem_init(&(si->sem), 1, INT2NUM(val));
204
+ }
205
+
206
+ VALUE obj = Data_Wrap_Struct(self, NULL, NULL, si);
207
+ return obj;
208
+ }
209
+
210
+ static VALUE rb_psem_lock (VALUE self) {
211
+ struct sem_info *si;
212
+ int ret = 0;
213
+ Data_Get_Struct (self, struct sem_info, si);
214
+ if ((ret = sem_wait(&(si->sem))) == -1) {
215
+ fprintf(stderr, "sem_wait: %s\n", strerror(ret));
130
216
  }
217
+
218
+ return Qnil;
219
+ }
220
+
221
+ static VALUE rb_psem_unlock (VALUE self) {
222
+ struct sem_info *si;
223
+ int ret = 0;
224
+ Data_Get_Struct (self, struct sem_info, si);
225
+ if ((ret = sem_post(&(si->sem))) == -1) {
226
+ fprintf(stderr, "sem_post: %s\n", strerror(ret));
227
+ }
228
+
229
+ return Qnil;
230
+ }
231
+
232
+ static VALUE rb_psem_destroy (VALUE self) {
233
+ struct sem_info *si;
234
+ int ret = 0;
235
+ Data_Get_Struct (self, struct sem_info, si);
236
+ if ((ret = sem_destroy(&(si->sem))) == -1) {
237
+ fprintf(stderr, "sem_destroy: %s\n", strerror(ret));
238
+ }
239
+
131
240
  return Qnil;
132
241
  }
133
242
 
@@ -135,7 +244,6 @@ void Init_shlock() {
135
244
  VALUE shared_lock_module = rb_define_module("Shlock");
136
245
 
137
246
  /* Shlock::Putex */
138
-
139
247
  VALUE putex_class = rb_define_class_under(shared_lock_module, "Putex", rb_cObject);
140
248
  rb_define_singleton_method(putex_class, "new", rb_putex_new, 1);
141
249
  rb_define_method(putex_class, "lock", rb_putex_lock, 0);
@@ -143,10 +251,17 @@ void Init_shlock() {
143
251
  rb_define_method(putex_class, "destroy", rb_putex_destroy, 0);
144
252
 
145
253
  /* Shlock::Prwlock */
146
-
147
254
  VALUE prwlock_class = rb_define_class_under(shared_lock_module, "Prwlock", rb_cObject);
148
255
  rb_define_singleton_method(prwlock_class, "new", rb_rwlock_new, 1);
149
256
  rb_define_method(prwlock_class, "read_lock", rb_rwlock_read_lock, 0);
150
257
  rb_define_method(prwlock_class, "write_lock", rb_rwlock_write_lock, 0);
151
258
  rb_define_method(prwlock_class, "unlock", rb_rwlock_unlock, 0);
259
+ rb_define_method(prwlock_class, "destroy", rb_rwlock_destroy, 0);
260
+
261
+ /* Shlock::Psem */
262
+ VALUE psem_class = rb_define_class_under(shared_lock_module, "Psem", rb_cObject);
263
+ rb_define_singleton(psem_class, "new", rb_psem_new, 2);
264
+ rb_define_method(psem_class, "lock", rb_psem_lock, 0);
265
+ rb_define_method(psem_class, "unlock", rb_psem_unlock, 0);
266
+ rb_define_method(psem_class, "destroy", rb_psem_destroy, 0);
152
267
  }
@@ -1,6 +1,6 @@
1
1
  spec = Gem::Specification.new do |s|
2
2
  s.name = 'shlock'
3
- s.version = '0.0.2'
3
+ s.version = '0.0.3'
4
4
  s.date = '2009-03-20'
5
5
  s.summary = 'Inter-process synchronization primitives using shared memory'
6
6
  s.email = "ice799@gmail.com"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ice799-shlock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Damato