process_shared 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/ext/helper/extconf.rb +14 -0
  2. data/ext/helper/helper.c +70 -0
  3. data/lib/mach.rb +12 -0
  4. data/lib/mach/clock.rb +24 -0
  5. data/lib/mach/error.rb +56 -0
  6. data/lib/mach/functions.rb +342 -0
  7. data/lib/mach/host.rb +28 -0
  8. data/lib/mach/port.rb +143 -0
  9. data/lib/mach/semaphore.rb +74 -0
  10. data/lib/mach/task.rb +42 -0
  11. data/lib/mach/time_spec.rb +16 -0
  12. data/lib/process_shared.rb +17 -1
  13. data/lib/process_shared/binary_semaphore.rb +18 -7
  14. data/lib/process_shared/mach.rb +93 -0
  15. data/lib/process_shared/mach/semaphore.rb +39 -0
  16. data/lib/process_shared/posix/errno.rb +40 -0
  17. data/lib/process_shared/posix/libc.rb +78 -0
  18. data/lib/process_shared/posix/semaphore.rb +125 -0
  19. data/lib/process_shared/posix/shared_array.rb +71 -0
  20. data/lib/process_shared/posix/shared_memory.rb +82 -0
  21. data/lib/process_shared/posix/time_spec.rb +13 -0
  22. data/lib/process_shared/posix/time_val.rb +23 -0
  23. data/lib/process_shared/semaphore.rb +26 -73
  24. data/lib/process_shared/shared_array.rb +3 -1
  25. data/lib/process_shared/shared_memory.rb +10 -52
  26. data/lib/process_shared/time_spec.rb +22 -0
  27. data/spec/mach/port_spec.rb +21 -0
  28. data/spec/mach/scratch.rb +67 -0
  29. data/spec/mach/scratch2.rb +78 -0
  30. data/spec/mach/semaphore_spec.rb +60 -0
  31. data/spec/mach/task_spec.rb +31 -0
  32. data/spec/process_shared/scratch.rb +21 -0
  33. data/spec/process_shared/semaphore_spec.rb +12 -11
  34. data/spec/process_shared/shared_memory_spec.rb +1 -1
  35. metadata +46 -36
  36. data/ext/libpsem/bsem.c +0 -188
  37. data/ext/libpsem/bsem.h +0 -32
  38. data/ext/libpsem/constants.c +0 -22
  39. data/ext/libpsem/constants.h +0 -18
  40. data/ext/libpsem/extconf.rb +0 -40
  41. data/ext/libpsem/mempcpy.c +0 -7
  42. data/ext/libpsem/mempcpy.h +0 -13
  43. data/ext/libpsem/mutex.c +0 -15
  44. data/ext/libpsem/mutex.h +0 -14
  45. data/ext/libpsem/psem.c +0 -15
  46. data/ext/libpsem/psem.h +0 -45
  47. data/ext/libpsem/psem_error.c +0 -46
  48. data/ext/libpsem/psem_error.h +0 -11
  49. data/ext/libpsem/psem_posix.c +0 -160
  50. data/ext/libpsem/psem_posix.h +0 -10
  51. data/lib/process_shared/bounded_semaphore.rb +0 -46
  52. data/lib/process_shared/libc.rb +0 -36
  53. data/lib/process_shared/libpsem.bundle +0 -0
  54. data/lib/process_shared/libpsem.so +0 -0
  55. data/lib/process_shared/psem.rb +0 -113
  56. data/spec/process_shared/bounded_semaphore_spec.rb +0 -48
  57. data/spec/process_shared/libc_spec.rb +0 -9
  58. data/spec/process_shared/psem_spec.rb +0 -136
@@ -0,0 +1,14 @@
1
+ require 'mkmf'
2
+
3
+ have_header('fcntl.h')
4
+
5
+ have_header('sys/mman.h')
6
+
7
+ have_header('semaphore.h')
8
+ have_type('sem_t', 'semaphore.h')
9
+
10
+ have_header('pthread.h')
11
+ have_type('pthread_mutex_t', 'pthread.h')
12
+ have_type('pthread_mutexattr_t', 'pthread.h')
13
+
14
+ create_makefile('helper')
@@ -0,0 +1,70 @@
1
+ /****************************/
2
+ /* File descriptor controls */
3
+ /****************************/
4
+
5
+ #ifdef HAVE_FCNTL_H
6
+ #include <fcntl.h>
7
+ extern int o_rdwr;
8
+ int o_rdwr = O_RDWR;
9
+ extern int o_creat;
10
+ int o_creat = O_CREAT;
11
+ extern int o_excl;
12
+ int o_excl = O_EXCL;
13
+ #endif
14
+
15
+ /************************/
16
+ /* Memory Map constants */
17
+ /************************/
18
+
19
+ #ifdef HAVE_SYS_MMAN_H
20
+ #include <sys/mman.h>
21
+
22
+ extern int prot_read;
23
+ extern int prot_write;
24
+ extern int prot_exec;
25
+ extern int prot_none;
26
+
27
+ extern void * map_failed;
28
+ extern int map_shared;
29
+ extern int map_private;
30
+
31
+ int prot_read = PROT_READ;
32
+ int prot_write = PROT_WRITE;
33
+ int prot_exec = PROT_EXEC;
34
+ int prot_none = PROT_NONE;
35
+
36
+ void * map_failed = MAP_FAILED;
37
+ int map_shared = MAP_SHARED;
38
+ int map_private = MAP_PRIVATE;
39
+ #endif
40
+
41
+ /****************************************/
42
+ /* PThread and related types and macros */
43
+ /****************************************/
44
+
45
+ #ifdef HAVE_PTHREAD_H
46
+ #include <pthread.h>
47
+ extern int pthread_process_shared;
48
+ int pthread_process_shared = PTHREAD_PROCESS_SHARED;
49
+ #endif
50
+
51
+ #ifdef HAVE_TYPE_PTHREAD_MUTEX_T
52
+ extern size_t sizeof_pthread_mutex_t;
53
+ size_t sizeof_pthread_mutex_t = sizeof (pthread_mutex_t);
54
+ size_t sizeof_pthread_mutexattr_t = sizeof (pthread_mutexattr_t);
55
+ #endif
56
+
57
+ #ifdef HAVE_TYPE_PTHREAD_MUTEXATTR_T
58
+ extern size_t sizeof_pthread_mutexattr_t;
59
+ #endif
60
+
61
+ /******************/
62
+ /* Semaphore type */
63
+ /******************/
64
+
65
+ #ifdef HAVE_TYPE_SEM_T
66
+ #include <semaphore.h>
67
+ extern size_t sizeof_sem_t;
68
+ size_t sizeof_sem_t = sizeof (sem_t);
69
+ #endif
70
+
@@ -0,0 +1,12 @@
1
+ require 'mach/port'
2
+ require 'mach/semaphore'
3
+ require 'mach/task'
4
+ require 'mach/functions'
5
+
6
+ module Mach
7
+ # @return [Port] the original bootstrap port; different from that
8
+ # affected by {get,set}_special_port
9
+ def self.bootstrap_port
10
+ @bootstrap_port ||= Mach::Port.new(:port => Mach::Functions::bootstrap_port)
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ require 'mach/functions'
2
+ require 'mach/port'
3
+ require 'mach/time_spec'
4
+
5
+ module Mach
6
+ class Clock
7
+ include Functions
8
+
9
+ def initialize(clock_id)
10
+ @clock_id = clock_id
11
+ end
12
+
13
+ def to_s
14
+ "#<#{self.class} #{@clock_id.to_i}>"
15
+ end
16
+
17
+ def get_time
18
+ time = TimeSpec.new
19
+ clock_get_time(@clock_id.to_i, time)
20
+ time
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,56 @@
1
+ require 'ffi'
2
+
3
+ require 'mach/functions'
4
+
5
+ module Mach
6
+ class Error < StandardError
7
+ class INVALID_ADDRESS < Error; end
8
+ class PROTECTION_FAILURE < Error; end
9
+ class NO_SPACE < Error; end
10
+ class INVALID_ARGUMENT < Error; end
11
+ class FAILURE < Error; end
12
+ class ABORTED < Error; end
13
+ class INVALID_NAME < Error; end
14
+ class OPERATION_TIMED_OUT < Error; end
15
+
16
+ include Functions
17
+
18
+ def self.new(msg, errno)
19
+ klass = case errno
20
+ when 1; then INVALID_ADDRESS
21
+ when 2; then PROTECTION_FAILURE
22
+ when 3; then NO_SPACE
23
+ when 4; then INVALID_ARGUMENT
24
+ when 5; then FAILURE
25
+ when 14; then ABORTED
26
+ when 15; then INVALID_NAME
27
+ when 49; then OPERATION_TIMED_OUT
28
+ else FAILURE
29
+ end
30
+
31
+ e = klass.allocate
32
+ e.send(:initialize, msg, errno)
33
+ e
34
+ end
35
+
36
+ attr_reader :errno
37
+
38
+ def initialize(msg, errno)
39
+ super(msg)
40
+ @errno = errno
41
+ end
42
+
43
+ def to_s
44
+ "#{super}: #{error_string(errno)}"
45
+ end
46
+
47
+ protected
48
+
49
+ # NOTE: api does not say this string must be freed; assuming it
50
+ # does not
51
+ def error_string(errno)
52
+ ptr = mach_error_string(errno)
53
+ ptr.null? ? nil : ptr.read_string()
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,342 @@
1
+ require 'ffi'
2
+
3
+ require 'mach/time_spec'
4
+
5
+ module Mach
6
+ # FFI wrapper around a subset of the Mach API (likely Mac OS X
7
+ # specific).
8
+ module Functions
9
+ extend FFI::Library
10
+
11
+ ffi_lib 'c'
12
+
13
+ typedef :__darwin_mach_port_t, :mach_port_t
14
+ typedef :__darwin_natural_t, :natural_t
15
+
16
+ typedef :int, :integer_t
17
+ typedef :int, :kern_return_t # true for 64 bit??
18
+ typedef :int, :mach_error_t
19
+ typedef :int, :sync_policy_t # SyncPolicy
20
+ typedef :int, :clock_id_t
21
+ typedef :int, :clock_res_t
22
+
23
+ typedef :string, :name_t
24
+
25
+ typedef :mach_port_t, :host_t
26
+ typedef :mach_port_t, :task_t
27
+ typedef :mach_port_t, :ipc_space_t
28
+ typedef :mach_port_t, :semaphore_t
29
+ typedef :pointer, :mach_port_pointer_t
30
+
31
+ typedef :natural_t, :mach_port_name_t
32
+ typedef :natural_t, :mach_port_right_t # MachPortRight
33
+ typedef :pointer, :mach_port_name_array_t
34
+ typedef :pointer, :mach_port_name_pointer_t
35
+
36
+ typedef :uint, :mach_msg_type_name_t
37
+ typedef :uint, :mach_msg_bits_t
38
+ typedef :uint, :mach_msg_trailer_type_t
39
+ typedef :uint, :mach_msg_trailer_size_t
40
+ typedef :uint, :mach_msg_descriptor_type_t
41
+ typedef :natural_t, :mach_msg_timeout_t
42
+
43
+ typedef :natural_t, :mach_msg_size_t
44
+ typedef :integer_t, :mach_msg_id_t
45
+ typedef :integer_t, :mach_msg_options_t
46
+ typedef :integer_t, :mach_msg_option_t
47
+
48
+ class MsgHeader < FFI::Struct
49
+ layout(:bits, :mach_msg_bits_t,
50
+ :size, :mach_msg_size_t,
51
+ :remote_port, :mach_port_t,
52
+ :local_port, :mach_port_t,
53
+ :reserved, :mach_msg_size_t,
54
+ :id, :mach_msg_id_t)
55
+ end
56
+
57
+ class MsgBody < FFI::Struct
58
+ layout(:descriptor_count, :mach_msg_size_t)
59
+ end
60
+
61
+ class MsgBase < FFI::Struct
62
+ layout(:header, MsgHeader,
63
+ :body, MsgBody)
64
+ end
65
+
66
+ class MsgTrailer < FFI::Struct
67
+ layout(:type, :mach_msg_trailer_type_t,
68
+ :size, :mach_msg_trailer_size_t)
69
+ end
70
+
71
+ class MsgPortDescriptor < FFI::Struct
72
+ layout(:name, :mach_port_t,
73
+ :pad1, :mach_msg_size_t, # FIXME: leave oout on __LP64__
74
+ :pad2, :uint16, # :uint
75
+ :disposition, :uint8, # :mach_msg_type_name_t
76
+ :type, :uint8) # :mach_msg_descriptor_type_t
77
+ end
78
+
79
+ SyncPolicy = enum( :fifo, 0x0,
80
+ :fixed_priority, 0x1,
81
+ :reversed, 0x2,
82
+ :order_mask, 0x3,
83
+ :lifo, 0x0 | 0x2, # um...
84
+ :max, 0x7 )
85
+
86
+ MachPortRight = enum( :send, 0,
87
+ :receive,
88
+ :send_once,
89
+ :port_set,
90
+ :dead_name,
91
+ :labelh,
92
+ :number )
93
+
94
+ # port type
95
+ def self.pt(*syms)
96
+ acc = 0
97
+ syms.each do |sym|
98
+ acc |= (1 << (MachPortRight[sym] + 16))
99
+ end
100
+ acc
101
+ end
102
+
103
+ MACH_PORT_NULL = 0
104
+ MACH_MSG_TIMEOUT_NONE = 0
105
+
106
+ MachPortType =
107
+ enum(:none, 0,
108
+ :send, pt(:send),
109
+ :receive, pt(:receive),
110
+ :send_once, pt(:send_once),
111
+ :port_set, pt(:port_set),
112
+ :dead_name, pt(:dead_name),
113
+ :labelh, pt(:labelh),
114
+
115
+ :send_receive, pt(:send, :receive),
116
+ :send_rights, pt(:send, :send_once),
117
+ :port_rights, pt(:send, :send_once, :receive),
118
+ :port_or_dead, pt(:send, :send_once, :receive, :dead_name),
119
+ :all_rights, pt(:send, :send_once, :receive, :dead_name, :port_set))
120
+
121
+ MachMsgType =
122
+ enum( :move_receive, 16, # must hold receive rights
123
+ :move_send, # must hold send rights
124
+ :move_send_once, # must hold sendonce rights
125
+ :copy_send, # must hold send rights
126
+ :make_send, # must hold receive rights
127
+ :make_send_once, # must hold receive rights
128
+ :copy_receive ) # must hold receive rights
129
+
130
+ MachSpecialPort =
131
+ enum( :kernel, 1,
132
+ :host,
133
+ :name,
134
+ :bootstrap )
135
+
136
+ KERN_SUCCESS = 0
137
+
138
+ # Replace methods in +syms+ with error checking wrappers that
139
+ # invoke the original method and raise a {SystemCallError}.
140
+ #
141
+ # The original method is invoked, and it's return value is passed
142
+ # to the block (or a default check). The block should return true
143
+ # if the return value indicates an error state.
144
+ def self.error_check(*syms, &is_err)
145
+ unless block_given?
146
+ is_err = lambda { |v| (v != KERN_SUCCESS) }
147
+ end
148
+
149
+ syms.each do |sym|
150
+ method = self.method(sym)
151
+
152
+ new_method_body = proc do |*args|
153
+ ret = method.call(*args)
154
+ if is_err.call(ret)
155
+ raise Error.new("error in #{sym}", ret)
156
+ else
157
+ ret
158
+ end
159
+ end
160
+
161
+ define_singleton_method(sym, &new_method_body)
162
+ define_method(sym, &new_method_body)
163
+ end
164
+ end
165
+
166
+ # Replace methods in +syms+ with error checking wrappers that
167
+ # invoke the original method and raise a {SystemCallError}.
168
+ #
169
+ # The original method is invoked, and it's return value is passed
170
+ # to the block (or a default check). The block should return true
171
+ # if the return value indicates an error state.
172
+ def self.error_check_bootstrap(*syms, &is_err)
173
+ unless block_given?
174
+ is_err = lambda { |v| (v != KERN_SUCCESS) }
175
+ end
176
+
177
+ syms.each do |sym|
178
+ method = self.method(sym)
179
+
180
+ new_method_body = proc do |*args|
181
+ ret = method.call(*args)
182
+ if is_err.call(ret)
183
+ ptr = bootstrap_strerror(ret)
184
+ msg = ptr.null? ? nil : ptr.read_string()
185
+ raise "error in #{sym}: #{msg}"
186
+ else
187
+ ret
188
+ end
189
+ end
190
+
191
+ define_singleton_method(sym, &new_method_body)
192
+ define_method(sym, &new_method_body)
193
+ end
194
+ end
195
+
196
+ # Attach a function as with +attach_function+, but check the
197
+ # return value and raise an exception on errors.
198
+ def self.attach_mach_function(sym, argtypes, rettype)
199
+ attach_function(sym, argtypes, rettype)
200
+ error_check(sym)
201
+ end
202
+
203
+ def self.new_memory_pointer(type)
204
+ FFI::MemoryPointer.new(find_type(type))
205
+ end
206
+
207
+ def new_memory_pointer(type)
208
+ Mach::Functions.new_memory_pointer(type)
209
+ end
210
+
211
+ attach_function :mach_task_self, [], :task_t
212
+ attach_function :mach_error_string, [:mach_error_t], :pointer
213
+
214
+ #######################
215
+ # Bootstrap functions #
216
+ #######################
217
+
218
+ attach_variable :bootstrap_port, :mach_port_t
219
+
220
+ attach_function(:bootstrap_strerror,
221
+ [:kern_return_t],
222
+ :pointer)
223
+
224
+ attach_function(:bootstrap_register,
225
+ [:mach_port_t, :name_t, :mach_port_t],
226
+ :kern_return_t)
227
+ error_check_bootstrap :bootstrap_register
228
+
229
+ ##################
230
+ # Port functions #
231
+ ##################
232
+
233
+ attach_mach_function(:mach_port_allocate,
234
+ [:ipc_space_t,
235
+ MachPortRight,
236
+ :mach_port_name_pointer_t],
237
+ :kern_return_t)
238
+
239
+ attach_mach_function(:mach_port_destroy,
240
+ [:ipc_space_t,
241
+ :mach_port_name_t],
242
+ :kern_return_t)
243
+
244
+ attach_mach_function(:mach_port_deallocate,
245
+ [:ipc_space_t,
246
+ :mach_port_name_t],
247
+ :kern_return_t)
248
+
249
+ attach_mach_function(:mach_port_insert_right,
250
+ [:ipc_space_t,
251
+ :mach_port_name_t,
252
+ :mach_port_t,
253
+ MachMsgType],
254
+ :kern_return_t)
255
+
256
+ ##################
257
+ # Host functions #
258
+ ##################
259
+
260
+ attach_function :mach_host_self, [], :mach_port_t
261
+
262
+ attach_mach_function(:host_get_clock_service,
263
+ [:host_t,
264
+ :clock_id_t,
265
+ :pointer],
266
+ :kern_return_t)
267
+
268
+ ##################
269
+ # Task functions #
270
+ ##################
271
+
272
+ attach_mach_function(:task_get_special_port,
273
+ [:task_t,
274
+ MachSpecialPort,
275
+ :mach_port_pointer_t],
276
+ :kern_return_t)
277
+
278
+ attach_mach_function(:task_set_special_port,
279
+ [:task_t,
280
+ MachSpecialPort,
281
+ :mach_port_t],
282
+ :kern_return_t)
283
+
284
+ ###################
285
+ # Clock functions #
286
+ ###################
287
+
288
+ attach_mach_function(:clock_get_time,
289
+ [:clock_id_t,
290
+ TimeSpec],
291
+ :kern_return_t)
292
+
293
+ #####################
294
+ # Message functions #
295
+ #####################
296
+
297
+ attach_mach_function(:mach_msg_send,
298
+ [:pointer], # msg_header_t
299
+ :kern_return_t)
300
+
301
+ attach_mach_function(:mach_msg,
302
+ [:pointer, # msg_header_t
303
+ :mach_msg_option_t,
304
+ :mach_msg_size_t,
305
+ :mach_msg_size_t,
306
+ :mach_port_name_t,
307
+ :mach_msg_timeout_t,
308
+ :mach_port_name_t],
309
+ :kern_return_t)
310
+
311
+ attach_mach_function(:mach_msg_receive,
312
+ [:pointer], # msg_header_t
313
+ :kern_return_t)
314
+
315
+ #######################
316
+ # Semaphore functions #
317
+ #######################
318
+
319
+ attach_mach_function(:semaphore_create,
320
+ [:task_t, :pointer, SyncPolicy, :int],
321
+ :kern_return_t)
322
+ attach_mach_function(:semaphore_destroy,
323
+ [:task_t, :semaphore_t],
324
+ :kern_return_t)
325
+
326
+ attach_mach_function(:semaphore_signal,
327
+ [:semaphore_t],
328
+ :kern_return_t)
329
+ attach_mach_function(:semaphore_signal_all,
330
+ [:semaphore_t],
331
+ :kern_return_t)
332
+ attach_mach_function(:semaphore_wait,
333
+ [:semaphore_t],
334
+ :kern_return_t)
335
+ attach_mach_function(:semaphore_timedwait,
336
+ [:semaphore_t, TimeSpec.val],
337
+ :kern_return_t)
338
+
339
+ end
340
+ end
341
+
342
+ require 'mach/error'