ice799-shlock 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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