process_shared 0.0.4 → 0.1.0

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 (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'