win32-mmap 0.2.4 → 0.3.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.
data/lib/win32/mmap.rb CHANGED
@@ -1,397 +1,392 @@
1
- require 'windows/file'
2
- require 'windows/file_mapping'
3
- require 'windows/error'
4
- require 'windows/handle'
5
- require 'windows/msvcrt/buffer'
6
- require 'windows/synchronize'
7
- require 'windows/memory'
8
-
9
- # The Win32 module serves as a namespace only.
10
- #
11
- module Win32
12
-
13
- # The MMap class encapsulates functions for memory mapped files.
14
- #
15
- class MMap
16
-
17
- # The version of the win32-mmap library.
18
- VERSION = '0.2.4'
19
-
20
- # Error typically raised in any method of Win32::MMap should fail.
21
- #
22
- class Error < StandardError; end
23
-
24
- include Windows::Error
25
- include Windows::File
26
- include Windows::FileMapping
27
- include Windows::Handle
28
- include Windows::MSVCRT::Buffer
29
- include Windows::Synchronize
30
- include Windows::Memory
31
-
32
- # The name of the file from which to create a mapping object. This
33
- # value may be nil.
34
- #
35
- attr_accessor :file
36
-
37
- # The protection for the file view. This may be any of the following
38
- # values:
39
- #
40
- # * PAGE_READONLY
41
- # * PAGE_READWRITE
42
- # * PAGE_WRITECOPY
43
- # * PAGE_WRITECOPY
44
- # * PAGE_EXECUTE_READ
45
- # * PAGE_EXECUTE_READWRITE
46
- #
47
- # You can OR the protection value with any of these section attributes:
48
- #
49
- # * SEC_COMMIT
50
- # * SEC_IMAGE
51
- # * SEC_LARGE_PAGES
52
- # * SEC_NOCACHE
53
- # * SEC_RESERVE
54
- #
55
- # The default protection is PAGE_READWRITE.
56
- #
57
- attr_accessor :protection
58
-
59
- # A string that determines the name of the mapping object.
60
- # By default this value is nil, i.e. anonymous. If you specify a +name+
61
- # that already exists then an attempt is made to access that object.
62
- #
63
- attr_accessor :name
64
-
65
- # The maximum size for the file mapping object. If a +file+ is
66
- # specified, this value defaults to the size of +file+. Otherwise
67
- # it defaults to zero (though you should set it manually).
68
- #
69
- attr_accessor :size
70
-
71
- # Access desired to the file mapping object. This may be
72
- # any of the following values:
73
- #
74
- # * FILE_MAP_WRITE
75
- # * FILE_MAP_READ
76
- # * FILE_MAP_COPY
77
- # * FILE_MAP_ALL_ACCESS
78
- #
79
- # The default access is FILE_MAP_WRITE.
80
- #
81
- attr_accessor :access
82
-
83
- # The address of the file view mapping.
84
- #
85
- attr_reader :address
86
-
87
- # Suggested starting address of mapped view. If this value is not
88
- # specified, the system will choose the base mapping address. If you do
89
- # specify a value, it must be a multiple of the system's allocation
90
- # granularity.
91
- #
92
- # Note: The MSDN documentation recommends that, in most case cases, you
93
- # should not set this value.
94
- #--
95
- # A system's allocation granularity can be found via GetSystemInfo()
96
- # and the dwAllocationGranularity member of the SYSTEM_INFO struct.
97
- #
98
- attr_accessor :base_address
99
-
100
- # Sets whether or not a semaphore lock is automatically placed on the
101
- # mapped view for read and write operations. This is true by default.
102
- #
103
- attr_writer :autolock
104
-
105
- # The value, in milliseconds, used to wait on the semaphore lock. Only
106
- # used if the +autolock+ option is true. The default is 10 milliseconds.
107
- #
108
- attr_accessor :timeout
109
-
110
- # :call-seq:
111
- # MMap.new(opts = {})
112
- # MMap.new(opts = {}){ |address| block }
113
- #
114
- # Creates and returns a new Win32::MMap object. If +file+ is set, then
115
- # that file is used to create the mapping. If a block is provided the
116
- # address is yielded and the mapping object is automatically closed at the
117
- # end of the block.
118
- #
119
- # Accepts any one of the following hash attributes:
120
- #
121
- # * protection
122
- # * size
123
- # * access
124
- # * inherit
125
- # * name
126
- # * base_address
127
- # * autolock
128
- # * timeout
129
- # * file
130
- #
131
- # Please see the documentation on the individual attributes for
132
- # further details. Note that, although these are accessors, they
133
- # *must* be set in the constructor (if set at all). Setting them
134
- # after the call to MMap.new will not have any effect.
135
- #
136
- # == Example
137
- # require 'win32/mmap'
138
- # require 'windows/msvcrt/string'
139
- # include Windows::MSVCRT::String
140
- # include Win32
141
- #
142
- # # Reverse the contents of a file.
143
- # mmap = MMap.new(:file => 'test.txt') do |addr|
144
- # strrev(addr)
145
- # end
146
- #
147
- def initialize(opts = {})
148
- valid = %w/
149
- file name protection access inherit size
150
- base_address open autolock timeout
151
- /
152
-
153
- @open = nil
154
- @file = nil
155
- @autolock = nil
156
-
157
- opts.each{ |key, value|
158
- key = key.to_s.downcase
159
- unless valid.include?(key)
160
- raise ArgumentError, "Invalid key '#{key}'"
161
- end
162
- if key == 'inherit'
163
- self.inherit = value # To force inherit= method call
164
- else
165
- instance_variable_set("@#{key}", value)
166
- end
167
- }
168
-
169
- @protection ||= PAGE_READWRITE
170
- @access ||= FILE_MAP_WRITE
171
- @size ||= 0
172
- @inherit ||= 0
173
- @base_address ||= 0
174
- @timeout ||= 10 # Milliseconds
175
-
176
- @hash = {}
177
-
178
- # Anything except an explicit false means the autolock is on.
179
- @autolock = true unless @autolock == false
180
-
181
- @lock_flag = 0 # Internal use only
182
-
183
- if @file
184
- if File.exists?(@file)
185
- fsize = File.size(@file)
186
- raise Error, 'cannot open 0 byte file' if fsize.zero?
187
- @size = fsize if @size < fsize
188
- end
189
-
190
- rights = GENERIC_READ|GENERIC_WRITE
191
-
192
- @fh = CreateFile(@file, rights, 0, 0, OPEN_ALWAYS, 0, 0)
193
-
194
- if @fh == INVALID_HANDLE_VALUE
195
- raise Error, get_last_error
196
- end
197
- else
198
- @fh = INVALID_HANDLE_VALUE
199
- end
200
-
201
- if @open
202
- @mh = OpenFileMapping(@access, @inherit, @name)
203
- else
204
- @mh = CreateFileMapping(@fh, @inherit, @protection, 0, @size, @name)
205
- end
206
-
207
- if @mh == 0
208
- raise Error, get_last_error
209
- end
210
-
211
- if @open
212
- @address = MapViewOfFileEx(@mh, @access, 0, 0, 0, @base_address)
213
- @size = get_view_size()
214
- else
215
- @address = MapViewOfFileEx(@mh, @access, 0, 0, 0, @base_address)
216
- end
217
-
218
- if @address == 0
219
- raise Error, get_last_error
220
- end
221
-
222
- if @autolock
223
- @semaphore = CreateSemaphore(nil, 1, 1, "#{@name}.ruby_lock")
224
- if @semaphore == 0
225
- raise Error, get_last_error
226
- end
227
- end
228
-
229
- if block_given?
230
- begin
231
- yield @address
232
- ensure
233
- close
234
- end
235
- end
236
-
237
- @address
238
- end
239
-
240
- # Opens an existing file mapping using +name+. You may pass a hash
241
- # of +opts+ as you would to MMap.new. If you don't specify a size
242
- # as part of the +opts+, it will be dynamically determined for you
243
- # (in blocks equal to your system's page size, typically 4k).
244
- #
245
- # This method is otherwise identical to MMap.new.
246
- #--
247
- # This forces MMap.new to use OpenFileMapping() behind the scenes.
248
- #
249
- def self.open(name, opts={}, &block)
250
- opts[:name] = name
251
- opts[:open] = true
252
- self.new(opts, &block)
253
- end
254
-
255
- # Sets whether or not the mapping handle can be inherited
256
- # by child processes.
257
- #--
258
- # If true, we have to create a SECURITY_ATTRIBUTES struct and set
259
- # its nLength member to 12 and its bInheritHandle member to TRUE.
260
- #
261
- def inherit=(bool)
262
- if bool
263
- buf = 0.chr * 12 # sizeof(SECURITY_ATTRIBUTES)
264
- buf[0,4] = [12].pack('L')
265
- buf[8,4] = [1].pack('L') # 1 == TRUE
266
- @inherit = buf
267
- else
268
- @inherit = 0
269
- end
270
- end
271
-
272
- # Returns whether or not the mapping handle can be
273
- # inherited by child processes. The default is false.
274
- #
275
- def inherit?
276
- @inherit != 0
277
- end
278
-
279
- # Writes +num_bytes+ to the disk within a mapped view of a file, or to
280
- # the end of the mapping if +num_bytes+ is not specified.
281
- #
282
- def flush(num_bytes = 0)
283
- unless FlushViewOfFile(@address, num_bytes)
284
- raise Error, get_last_error
285
- end
286
- end
287
-
288
- # Unmaps the file view and closes all open file handles. You should
289
- # always call this when you are finished with the object (when using
290
- # the non-block form).
291
- #
292
- def close
293
- UnmapViewOfFile(@address) if @address
294
- CloseHandle(@fh) if @fh
295
- CloseHandle(@mh) if @mh
296
- ReleaseSemaphore(@semaphore, 1, nil) if @semaphore
297
- end
298
-
299
- # Returns whether or not a semaphore lock is automatically placed on the
300
- # mapped view for read and write operations. This is true by default.
301
- #
302
- def autolock?
303
- @autolock
304
- end
305
-
306
- private
307
-
308
- # :stopdoc:
309
-
310
- # This is used to allow dynamic getters and setters between memory
311
- # mapped objects.
312
- #--
313
- # This replaces the getvar/setvar API from 0.1.0.
314
- #
315
- def method_missing(method_id, *args)
316
- method = method_id.id2name
317
- args = args.first if args.length == 1
318
-
319
- if method[-1,1] == '=' # Setter
320
- method.chop!
321
- @hash["#{method}"] = args
322
-
323
- if @autolock
324
- if mmap_lock
325
- instance_variable_set("@#{method}", args)
326
- marshal = Marshal.dump(@hash)
327
- memcpy(@address, marshal)
328
- mmap_unlock
329
- end
330
- else
331
- instance_variable_set("@#{method}", args)
332
- marshal = Marshal.dump(@hash)
333
- memcpy(@address, marshal)
334
- end
335
- else # Getter
336
- buf = 0.chr * @size
337
- if @autolock
338
- if mmap_lock
339
- memcpy(buf, @address, @size)
340
- hash = Marshal.load(buf)
341
- val = hash["#{method}"]
342
- instance_variable_set("@#{method}", val)
343
- mmap_unlock
344
- end
345
- else
346
- memcpy(buf, @address, @size)
347
- hash = Marshal.load(buf)
348
- val = hash["#{method}"]
349
- instance_variable_set("@#{method}", val)
350
- end
351
- return instance_variable_get("@#{method}")
352
- end
353
- end
354
-
355
- # Adds a semaphore lock the mapping. Only used if +autolock+ is set
356
- # to true in the constructor.
357
- #
358
- def mmap_lock
359
- bool = false
360
-
361
- if(@lock_flag == 0)
362
- if WaitForSingleObject(@semaphore, @timeout) == WAIT_OBJECT_0
363
- bool = true
364
- end
365
- end
366
-
367
- @lock_flag += 1
368
- bool
369
- end
370
-
371
- # Releases a semaphore lock on the view. Only used if +autolock+ is
372
- # set to true in the constructor.
373
- #
374
- def mmap_unlock
375
- @lock_flag -= 1
376
-
377
- if @lock_flag != 0
378
- return false
379
- end
380
-
381
- if ReleaseSemaphore(@semaphore, 1, nil) == 0
382
- raise Error, get_last_error
383
- end
384
-
385
- true
386
- end
387
-
388
- # Gets the size of an existing mapping based on the address. Used by
389
- # the MMap.open method when a size isn't specified.
390
- #
391
- def get_view_size
392
- mbi = [0,0,0,0,0,0,0].pack('LLLLLLL') # MEMORY_BASIC_INFORMATION
393
- VirtualQuery(@address, mbi, mbi.size)
394
- mbi[12,4].unpack('L').first # RegionSize
395
- end
396
- end
397
- end
1
+ require File.join(File.dirname(__FILE__), 'windows', 'constants')
2
+ require File.join(File.dirname(__FILE__), 'windows', 'structs')
3
+ require File.join(File.dirname(__FILE__), 'windows', 'functions')
4
+
5
+ # The Win32 module serves as a namespace only.
6
+ #
7
+ module Win32
8
+ # The MMap class encapsulates functions for memory mapped files.
9
+ #
10
+ class MMap
11
+ # The version of the win32-mmap library.
12
+ VERSION = '0.3.0'
13
+
14
+ include Windows::Constants
15
+ include Windows::Functions
16
+ include Windows::Structs
17
+
18
+ # The name of the file from which to create a mapping object. This
19
+ # value may be nil.
20
+ #
21
+ attr_accessor :file
22
+
23
+ # The protection for the file view. This may be any of the following
24
+ # values:
25
+ #
26
+ # * PAGE_READONLY
27
+ # * PAGE_READWRITE
28
+ # * PAGE_WRITECOPY
29
+ # * PAGE_WRITECOPY
30
+ # * PAGE_EXECUTE_READ
31
+ # * PAGE_EXECUTE_READWRITE
32
+ #
33
+ # You can OR the protection value with any of these section attributes:
34
+ #
35
+ # * SEC_COMMIT
36
+ # * SEC_IMAGE
37
+ # * SEC_LARGE_PAGES
38
+ # * SEC_NOCACHE
39
+ # * SEC_RESERVE
40
+ #
41
+ # The default protection is PAGE_READWRITE.
42
+ #
43
+ attr_accessor :protection
44
+
45
+ # A string that determines the name of the mapping object.
46
+ # By default this value is nil, i.e. anonymous. If you specify a +name+
47
+ # that already exists then an attempt is made to access that object.
48
+ #
49
+ attr_accessor :name
50
+
51
+ # The maximum size for the file mapping object. If a +file+ is
52
+ # specified, this value defaults to the size of +file+. Otherwise
53
+ # it defaults to zero (though you should set it manually).
54
+ #
55
+ attr_accessor :size
56
+
57
+ # Access desired to the file mapping object. This may be
58
+ # any of the following values:
59
+ #
60
+ # * FILE_MAP_WRITE
61
+ # * FILE_MAP_READ
62
+ # * FILE_MAP_COPY
63
+ # * FILE_MAP_ALL_ACCESS
64
+ #
65
+ # The default access is FILE_MAP_WRITE.
66
+ #
67
+ attr_accessor :access
68
+
69
+ # The address of the file view mapping.
70
+ #
71
+ attr_reader :address
72
+
73
+ # Suggested starting address of mapped view. If this value is not
74
+ # specified, the system will choose the base mapping address. If you do
75
+ # specify a value, it must be a multiple of the system's allocation
76
+ # granularity.
77
+ #
78
+ # Note: The MSDN documentation recommends that, in most case cases, you
79
+ # should not set this value.
80
+ #--
81
+ # A system's allocation granularity can be found via GetSystemInfo()
82
+ # and the dwAllocationGranularity member of the SYSTEM_INFO struct.
83
+ #
84
+ attr_accessor :base_address
85
+
86
+ # Sets whether or not a semaphore lock is automatically placed on the
87
+ # mapped view for read and write operations. This is true by default.
88
+ #
89
+ attr_writer :autolock
90
+
91
+ # The value, in milliseconds, used to wait on the semaphore lock. Only
92
+ # used if the +autolock+ option is true. The default is 10 milliseconds.
93
+ #
94
+ attr_accessor :timeout
95
+
96
+ # :call-seq:
97
+ # MMap.new(opts = {})
98
+ # MMap.new(opts = {}){ |address| block }
99
+ #
100
+ # Creates and returns a new Win32::MMap object. If +file+ is set, then
101
+ # that file is used to create the mapping. If a block is provided the
102
+ # address is yielded and the mapping object is automatically closed at the
103
+ # end of the block.
104
+ #
105
+ # Accepts any one of the following hash attributes:
106
+ #
107
+ # * protection
108
+ # * size
109
+ # * access
110
+ # * inherit
111
+ # * name
112
+ # * base_address
113
+ # * autolock
114
+ # * timeout
115
+ # * file
116
+ #
117
+ # Please see the documentation on the individual attributes for
118
+ # further details. Note that, although these are accessors, they
119
+ # *must* be set in the constructor (if set at all). Setting them
120
+ # after the call to MMap.new will not have any effect.
121
+ #
122
+ # == Example
123
+ # require 'win32/mmap'
124
+ # require 'windows/msvcrt/string'
125
+ # include Windows::MSVCRT::String
126
+ # include Win32
127
+ #
128
+ # # Reverse the contents of a file.
129
+ # mmap = MMap.new(:file => 'test.txt') do |addr|
130
+ # strrev(addr)
131
+ # end
132
+ #
133
+ def initialize(opts = {})
134
+ valid = %w[
135
+ file name protection access inherit size
136
+ base_address open autolock timeout
137
+ ]
138
+
139
+ @open = nil
140
+ @file = nil
141
+ @autolock = nil
142
+
143
+ # Validate the keys, handle inherit specially.
144
+ opts.each{ |key, value|
145
+ key = key.to_s.downcase
146
+
147
+ unless valid.include?(key)
148
+ raise ArgumentError, "Invalid key '#{key}'"
149
+ end
150
+
151
+ if key == 'inherit'
152
+ self.inherit = value # To force inherit= method call
153
+ else
154
+ instance_variable_set("@#{key}", value)
155
+ end
156
+ }
157
+
158
+ @protection ||= PAGE_READWRITE
159
+ @access ||= FILE_MAP_WRITE
160
+ @size ||= 0
161
+ @inherit ||= nil
162
+ @base_address ||= 0
163
+ @timeout ||= 10 # Milliseconds
164
+
165
+ self.inherit = false unless @inherit
166
+
167
+ @hash = {}
168
+
169
+ # Anything except an explicit false means the autolock is on.
170
+ @autolock = true unless @autolock == false
171
+
172
+ @lock_flag = 0 # Internal use only
173
+
174
+ if @file
175
+ if File.exists?(@file)
176
+ fsize = File.size(@file)
177
+ raise ArgumentError, 'cannot open 0 byte file' if fsize.zero?
178
+ @size = fsize if @size < fsize
179
+ end
180
+
181
+ rights = GENERIC_READ|GENERIC_WRITE
182
+
183
+ @fh = CreateFile(@file, rights, 0, 0, OPEN_ALWAYS, 0, 0)
184
+
185
+ if @fh == INVALID_HANDLE_VALUE
186
+ raise SystemCallError.new('CreateFile', FFI.errno)
187
+ end
188
+ else
189
+ @fh = INVALID_HANDLE_VALUE
190
+ end
191
+
192
+ if @open
193
+ @mh = OpenFileMapping(@access, @inherit[:bInheritHandle], @name)
194
+ raise SystemCallError.new('OpenFileMapping', FFI.errno) if @mh == 0
195
+ else
196
+ @mh = CreateFileMapping(@fh, @inherit, @protection, 0, @size, @name)
197
+ raise SystemCallError.new('CreateFileMapping', FFI.errno) if @mh == 0
198
+ end
199
+
200
+ if @open
201
+ @address = MapViewOfFileEx(@mh, @access, 0, 0, 0, @base_address)
202
+ @size = get_view_size()
203
+ else
204
+ @address = MapViewOfFileEx(@mh, @access, 0, 0, 0, @base_address)
205
+ end
206
+
207
+ if @address == 0
208
+ raise SystemCallError.new('MapviewOfFileEx', FFI.errno)
209
+ end
210
+
211
+ if @autolock
212
+ @semaphore = CreateSemaphore(nil, 1, 1, "#{@name}.ruby_lock")
213
+ if @semaphore == 0
214
+ raise Error, get_last_error
215
+ end
216
+ end
217
+
218
+ if block_given?
219
+ begin
220
+ yield @address
221
+ ensure
222
+ close
223
+ end
224
+ end
225
+
226
+ @address
227
+ end
228
+
229
+ # Opens an existing file mapping using +name+. You may pass a hash
230
+ # of +opts+ as you would to MMap.new. If you don't specify a size
231
+ # as part of the +opts+, it will be dynamically determined for you
232
+ # (in blocks equal to your system's page size, typically 4k).
233
+ #
234
+ # This method is otherwise identical to MMap.new.
235
+ #--
236
+ # This forces MMap.new to use OpenFileMapping() behind the scenes.
237
+ #
238
+ def self.open(name, opts={}, &block)
239
+ opts[:name] = name
240
+ opts[:open] = true
241
+ self.new(opts, &block)
242
+ end
243
+
244
+ # Sets whether or not the mapping handle can be inherited
245
+ # by child processes.
246
+ #--
247
+ # If true, we have to create a SECURITY_ATTRIBUTES struct and set
248
+ # its nLength member to 12 and its bInheritHandle member to TRUE.
249
+ #
250
+ def inherit=(bool)
251
+ @inherit = SECURITY_ATTRIBUTES.new
252
+ @inherit[:nLength] = SECURITY_ATTRIBUTES.size
253
+
254
+ if bool
255
+ @inherit[:bInheritHandle] = true
256
+ else
257
+ @inherit[:bInheritHandle] = false
258
+ end
259
+ end
260
+
261
+ # Returns whether or not the mapping handle can be
262
+ # inherited by child processes. The default is false.
263
+ #
264
+ def inherit?
265
+ @inherit and @inherit[:bInheritHandle]
266
+ end
267
+
268
+ # Writes +num_bytes+ to the disk within a mapped view of a file, or to
269
+ # the end of the mapping if +num_bytes+ is not specified.
270
+ #
271
+ def flush(num_bytes = 0)
272
+ unless FlushViewOfFile(@address, num_bytes)
273
+ SystemCallError.new('FlushViewOfFile', FFI.errno)
274
+ end
275
+ end
276
+
277
+ # Unmaps the file view and closes all open file handles. You should
278
+ # always call this when you are finished with the object (when using
279
+ # the non-block form).
280
+ #
281
+ def close
282
+ UnmapViewOfFile(@address) if @address
283
+ CloseHandle(@fh) if @fh
284
+ CloseHandle(@mh) if @mh
285
+ ReleaseSemaphore(@semaphore, 1, nil) if @semaphore
286
+ end
287
+
288
+ # Returns whether or not a semaphore lock is automatically placed on the
289
+ # mapped view for read and write operations. This is true by default.
290
+ #
291
+ def autolock?
292
+ @autolock
293
+ end
294
+
295
+ private
296
+
297
+ # :stopdoc:
298
+
299
+ # This is used to allow dynamic getters and setters between memory
300
+ # mapped objects.
301
+ #--
302
+ # This replaces the getvar/setvar API from 0.1.0.
303
+ #
304
+ # TODO: FIX!
305
+ #
306
+ def method_missing(method_id, *args)
307
+ method = method_id.id2name
308
+ args = args.first if args.length == 1
309
+
310
+ if method[-1,1] == '=' # Setter
311
+ method.chop!
312
+ @hash["#{method}"] = args
313
+
314
+ if @autolock
315
+ if mmap_lock
316
+ instance_variable_set("@#{method}", args)
317
+ marshal = Marshal.dump(@hash)
318
+ ptr = FFI::Pointer.new(:char, @address)
319
+ ptr.write_string(marshal,marshal.length)
320
+ mmap_unlock
321
+ end
322
+ else
323
+ instance_variable_set("@#{method}", args)
324
+ marshal = Marshal.dump(@hash)
325
+ ptr = FFI::Pointer.new(:char, @address)
326
+ ptr.write_string(marshal,marshal.length)
327
+ end
328
+ else # Getter
329
+ buf = FFI::MemoryPointer.new(:char, @size)
330
+
331
+ if @autolock
332
+ if mmap_lock
333
+ ptr = FFI::Pointer.new(:char, @address)
334
+ buf = ptr.read_string(@size)
335
+ hash = Marshal.load(buf)
336
+ val = hash["#{method}"]
337
+ instance_variable_set("@#{method}", val)
338
+ mmap_unlock
339
+ end
340
+ else
341
+ ptr = FFI::Pointer.new(:char, @address)
342
+ buf = ptr.read_string(@size)
343
+ hash = Marshal.load(buf)
344
+ val = hash["#{method}"]
345
+ instance_variable_set("@#{method}", val)
346
+ end
347
+
348
+ return instance_variable_get("@#{method}")
349
+ end
350
+ end
351
+
352
+ # Adds a semaphore lock the mapping. Only used if +autolock+ is set
353
+ # to true in the constructor.
354
+ #
355
+ def mmap_lock
356
+ bool = false
357
+
358
+ if(@lock_flag == 0)
359
+ if WaitForSingleObject(@semaphore, @timeout) == WAIT_OBJECT_0
360
+ bool = true
361
+ end
362
+ end
363
+
364
+ @lock_flag += 1
365
+ bool
366
+ end
367
+
368
+ # Releases a semaphore lock on the view. Only used if +autolock+ is
369
+ # set to true in the constructor.
370
+ #
371
+ def mmap_unlock
372
+ @lock_flag -= 1
373
+
374
+ return false if @lock_flag != 0
375
+
376
+ if ReleaseSemaphore(@semaphore, 1, nil) == 0
377
+ raise SystemCallError.new('ReleaseSemaphore', FFI.errno)
378
+ end
379
+
380
+ true
381
+ end
382
+
383
+ # Gets the size of an existing mapping based on the address. This
384
+ # is used by the MMap.open method when a size isn't specified.
385
+ #
386
+ def get_view_size
387
+ mbi = MEMORY_BASIC_INFORMATION.new
388
+ VirtualQuery(@address, mbi, mbi.size)
389
+ mbi[:RegionSize]
390
+ end
391
+ end # MMap
392
+ end # Win32