ice799-shlock 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README +45 -0
  2. data/ext/extconf.rb +7 -0
  3. data/ext/shlock.c +152 -0
  4. data/shlock.gemspec +17 -0
  5. metadata +57 -0
data/README ADDED
@@ -0,0 +1,45 @@
1
+ What is putex ?
2
+ ===============
3
+
4
+ putex is an interproces mutex that uses shared memory (PUTEX = Process mUTEX).
5
+
6
+
7
+ Why ?
8
+ =====
9
+
10
+ If want to synchronize two ruby processes without using those painful file locks, you can use this.
11
+
12
+
13
+ Sample Usage:
14
+ =============
15
+
16
+ process1.rb:
17
+ require 'putex'
18
+ f = Putex.new("/test-mutex")
19
+ f.lock
20
+ puts("locked the mutex once, grabbing lock again to spin-wait; go run process2.rb once locked up...\n")
21
+ f.lock
22
+ puts("got the lock, exiting\n")
23
+
24
+
25
+ process2.rb:
26
+ require 'putex'
27
+ f = Putex.new("/text-mutex")
28
+ puts "alive, unlocking"
29
+ f.unlock
30
+ puts "done, exiting"
31
+ f.destroy
32
+
33
+
34
+ in your terminal:
35
+ % ruby process1.rb
36
+
37
+ when it tells you to run process2.rb, in another terminal enter:
38
+ % ruby process2.rb
39
+
40
+ you should see process2 unlock process1 and allow it to exit.
41
+
42
+ What's next ?
43
+ =============
44
+
45
+ Maybe some more process-to-process synchronization primitives?
data/ext/extconf.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'mkmf'
2
+ if ( (have_library('c', 'shm_open') or
3
+ have_library('rt', 'shm_open')) and
4
+ (have_library('pthread', 'pthread_mutex_lock')) and
5
+ (have_header('pthread.h')))
6
+ create_makefile ('shlock')
7
+ end
data/ext/shlock.c ADDED
@@ -0,0 +1,152 @@
1
+ #define _GNU_SOURCE
2
+ #include "ruby.h"
3
+ #include <sys/types.h>
4
+ #include <pthread.h>
5
+ #include <sys/mman.h>
6
+ #include <fcntl.h>
7
+ #include <errno.h>
8
+ #include <sys/stat.h>
9
+
10
+ struct mutex_info {
11
+ pthread_mutex_t m;
12
+ int fd;
13
+ };
14
+
15
+ struct rwlock_info {
16
+ pthread_rwlock_t rwlock;
17
+ int fd;
18
+ };
19
+
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));
26
+ return -1;
27
+ }
28
+ }
29
+
30
+ if (fd < 0) {
31
+ printf("error: %s\n", strerror(errno));
32
+ return -1;
33
+ }
34
+
35
+ return fd;
36
+ }
37
+
38
+ static VALUE rb_putex_new (VALUE self, VALUE name) {
39
+ struct mutex_info *ms;
40
+ int fd = shared_mem_open(StringValuePtr(name));
41
+ if (fd < 0)
42
+ return Qnil;
43
+
44
+ ms = (struct mutex_info *)mmap(NULL, sizeof(struct mutex_info), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
45
+ if (ms == MAP_FAILED) {
46
+ printf("mmap error: %s\n", strerror(errno));
47
+ return Qnil;
48
+ }
49
+ ms->fd = fd;
50
+ fsync(fd);
51
+ VALUE obj = Data_Wrap_Struct(self, NULL, NULL, ms);
52
+ return obj;
53
+ }
54
+
55
+ static VALUE rb_putex_destroy (VALUE self) {
56
+ struct mutex_info *m;
57
+ Data_Get_Struct(self, struct mutex_info, m);
58
+ fsync(m->fd);
59
+ close(m->fd);
60
+
61
+ return Qnil;
62
+ }
63
+
64
+ static VALUE rb_putex_lock (VALUE self) {
65
+ struct mutex_info *fs;
66
+ Data_Get_Struct(self, struct mutex_info, fs);
67
+ pthread_mutex_lock(&(fs->m));
68
+
69
+ return Qnil;
70
+ }
71
+
72
+ static VALUE rb_putex_unlock (VALUE self) {
73
+ struct mutex_info *fs;
74
+ Data_Get_Struct(self, struct mutex_info, fs);
75
+ pthread_mutex_unlock(&(fs->m));
76
+
77
+ return Qnil;
78
+ }
79
+
80
+ static VALUE rb_rwlock_new (VALUE self, VALUE name) {
81
+ struct rwlock_info *rws;
82
+ int fd = shared_mem_open (StringValuePtr(name));
83
+ if (fd < 0)
84
+ return Qnil;
85
+
86
+ rws = (struct rwlock_info *)mmap(NULL, sizeof(struct rwlock_info), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
87
+ if (rws == MAP_FAILED) {
88
+ printf("mmap error: %s\n", strerror(errno));
89
+ return Qnil;
90
+ }
91
+ rws->fd = fd;
92
+ fsync(fd);
93
+
94
+ VALUE obj = Data_Wrap_Struct(self, NULL, NULL, rws);
95
+ return obj;
96
+ }
97
+
98
+ static VALUE rb_rwlock_destory (VALUE self) {
99
+ struct rwlock_info *rws;
100
+ Data_Get_Struct(self, struct rwlock_info, rws);
101
+ fsync(rws->fd);
102
+ close(rws->fd);
103
+
104
+ return Qnil;
105
+ }
106
+
107
+ static VALUE rb_rwlock_read_lock (VALUE self) {
108
+ struct rwlock_info *rws;
109
+ Data_Get_Struct(self, struct rwlock_info, rws);
110
+ pthread_rwlock_rdlock(&(rws->rwlock));
111
+
112
+ return Qnil;
113
+ }
114
+
115
+ static VALUE rb_rwlock_write_lock (VALUE self) {
116
+ struct rwlock_info *rws;
117
+ Data_Get_Struct (self, struct rwlock_info, rws);
118
+ pthread_rwlock_wrlock(&(rws->rwlock));
119
+
120
+ return Qnil;
121
+ }
122
+
123
+ static VALUE rb_rwlock_unlock (VALUE self) {
124
+ struct rwlock_info *rws;
125
+ Data_Get_Struct (self, struct rwlock_info, rws);
126
+ int e = pthread_rwlock_unlock(&(rws->rwlock));
127
+
128
+ if (e != 0) {
129
+ printf("error: %d\n", e);
130
+ }
131
+ return Qnil;
132
+ }
133
+
134
+ void Init_shlock() {
135
+ VALUE shared_lock_module = rb_define_module("Shlock");
136
+
137
+ /* Shlock::Putex */
138
+
139
+ VALUE putex_class = rb_define_class_under(shared_lock_module, "Putex", rb_cObject);
140
+ rb_define_singleton_method(putex_class, "new", rb_putex_new, 1);
141
+ rb_define_method(putex_class, "lock", rb_putex_lock, 0);
142
+ rb_define_method(putex_class, "unlock", rb_putex_unlock, 0);
143
+ rb_define_method(putex_class, "destroy", rb_putex_destroy, 0);
144
+
145
+ /* Shlock::Prwlock */
146
+
147
+ VALUE prwlock_class = rb_define_class_under(shared_lock_module, "Prwlock", rb_cObject);
148
+ rb_define_singleton_method(prwlock_class, "new", rb_rwlock_new, 1);
149
+ rb_define_method(prwlock_class, "read_lock", rb_rwlock_read_lock, 0);
150
+ rb_define_method(prwlock_class, "write_lock", rb_rwlock_write_lock, 0);
151
+ rb_define_method(prwlock_class, "unlock", rb_rwlock_unlock, 0);
152
+ }
data/shlock.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'shlock'
3
+ s.version = '0.0.2'
4
+ s.date = '2009-03-20'
5
+ s.summary = 'Inter-process synchronization primitives using shared memory'
6
+ s.email = "ice799@gmail.com"
7
+ s.homepage = "http://github.com/ice799/putex/tree/master"
8
+ s.description = "inter-process synchronization primitives using shared memory"
9
+ s.has_rdoc = false
10
+ s.authors = ["Joe Damato"]
11
+ s.extensions = "ext/extconf.rb"
12
+ s.require_paths << "ext"
13
+ s.files = ["README",
14
+ "shlock.gemspec",
15
+ "ext/shlock.c",
16
+ "ext/extconf.rb"]
17
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ice799-shlock
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Joe Damato
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-20 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: inter-process synchronization primitives using shared memory
17
+ email: ice799@gmail.com
18
+ executables: []
19
+
20
+ extensions:
21
+ - ext/extconf.rb
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README
26
+ - shlock.gemspec
27
+ - ext/shlock.c
28
+ - ext/extconf.rb
29
+ has_rdoc: false
30
+ homepage: http://github.com/ice799/putex/tree/master
31
+ post_install_message:
32
+ rdoc_options: []
33
+
34
+ require_paths:
35
+ - lib
36
+ - ext
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: "0"
42
+ version:
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.2.0
53
+ signing_key:
54
+ specification_version: 2
55
+ summary: Inter-process synchronization primitives using shared memory
56
+ test_files: []
57
+