io-memory 0.0.1
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.
- checksums.yaml +7 -0
- data/lib/io/memory/generic.rb +111 -0
- data/lib/io/memory/linux.rb +152 -0
- data/lib/io/memory/posix.rb +166 -0
- data/lib/io/memory/version.rb +12 -0
- data/lib/io/memory.rb +31 -0
- data/license.md +21 -0
- data/readme.md +80 -0
- data/releases.md +10 -0
- metadata +61 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 65cddba6258b4275777fda4eef9777255547ac351b3ca3c7e9f64c84f0540a5f
|
4
|
+
data.tar.gz: bf3066d3b0a616346326cfd1df300ce7e0d81183675bb778b62ab77eb1329ef7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c256056fa025c5e215c22b41a672b657e4bb92db4f2fe08dddd679e8a5c9397a1b293139e5122250de4644e9e04583c00a89e0b54f47e5caf9901e9ce60fe6cc
|
7
|
+
data.tar.gz: fe1371a70acf30c6e91a4f258bae9aeb82a9ec2e2af148d423c744e8e00f8aedde117ca479ca7f2e781e0bb5c333c0a7f5e766302f656cb1a32a134259429f18
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2025, by Shopify Inc.
|
5
|
+
|
6
|
+
require "tempfile"
|
7
|
+
|
8
|
+
module IO::Memory
|
9
|
+
# Generic implementation of memory-mapped IO using temporary files.
|
10
|
+
# This implementation provides maximum compatibility across platforms
|
11
|
+
# by using Ruby's built-in Tempfile class and file descriptor mapping.
|
12
|
+
# The temporary files are unlinked immediately after creation to behave
|
13
|
+
# like anonymous memory objects.
|
14
|
+
module Generic
|
15
|
+
extend self
|
16
|
+
|
17
|
+
module Implementation
|
18
|
+
# Handle class that wraps the IO and manages tempfile cleanup
|
19
|
+
class Handle
|
20
|
+
def initialize(io, tempfile, size)
|
21
|
+
@io = io
|
22
|
+
@tempfile = tempfile
|
23
|
+
@size = size
|
24
|
+
end
|
25
|
+
|
26
|
+
def io
|
27
|
+
@io
|
28
|
+
end
|
29
|
+
|
30
|
+
def map(size = nil)
|
31
|
+
size ||= @size
|
32
|
+
::IO::Buffer.map(@io, size)
|
33
|
+
end
|
34
|
+
|
35
|
+
def close
|
36
|
+
@io.close unless @io.closed?
|
37
|
+
ensure
|
38
|
+
# Clean up tempfile
|
39
|
+
if @tempfile && !@tempfile.closed?
|
40
|
+
@tempfile.close
|
41
|
+
@tempfile = nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def closed?
|
46
|
+
@io.closed?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.create_handle(size)
|
51
|
+
# Create a temporary file
|
52
|
+
tempfile = Tempfile.new(["io_memory", ".tmp"])
|
53
|
+
|
54
|
+
begin
|
55
|
+
# Set the size
|
56
|
+
tempfile.truncate(size) if tempfile.respond_to?(:truncate)
|
57
|
+
|
58
|
+
# Immediately unlink the file so it's deleted when closed
|
59
|
+
# This makes it behave more like memfd - it exists only in memory/cache
|
60
|
+
File.unlink(tempfile.path)
|
61
|
+
|
62
|
+
# Create IO from file descriptor and wrap in Handle
|
63
|
+
io = ::IO.for_fd(tempfile.fileno, autoclose: false)
|
64
|
+
|
65
|
+
return Handle.new(io, tempfile, size)
|
66
|
+
rescue => error
|
67
|
+
# Clean up on error
|
68
|
+
tempfile.close
|
69
|
+
tempfile.unlink if File.exist?(tempfile.path)
|
70
|
+
raise IO::Memory::MemoryError, "Failed to create temporary file buffer!"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private_constant :Implementation
|
76
|
+
|
77
|
+
# Check if the generic temporary file implementation is supported on this system.
|
78
|
+
# This implementation always returns true as it uses standard Ruby temporary files
|
79
|
+
# which are available on all platforms. It serves as a fallback when platform-specific
|
80
|
+
# implementations like Linux memfd_create or POSIX shm_open are not available.
|
81
|
+
# @returns [Boolean] always true, as temporary files are universally supported
|
82
|
+
def self.supported?
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
# Create a new memory-mapped buffer using a temporary file.
|
87
|
+
# The temporary file is immediately unlinked to behave like
|
88
|
+
# anonymous memory, existing only in the filesystem cache.
|
89
|
+
# @parameter size [Integer] size of the memory buffer in bytes
|
90
|
+
# @returns [Object] a handle object that provides access to the memory buffer
|
91
|
+
def new(size)
|
92
|
+
Implementation.create_handle(size)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Create a memory-mapped buffer and yield it to a block.
|
96
|
+
# The buffer is automatically cleaned up when the block exits,
|
97
|
+
# regardless of whether an exception is raised.
|
98
|
+
# @parameter size [Integer] size of the memory buffer in bytes
|
99
|
+
# @yields {|handle| ...}
|
100
|
+
# @parameter handle [Object] the handle to the memory buffer with access to IO and mapping operations
|
101
|
+
# @returns [Object] the result of the block execution
|
102
|
+
def with(size, &block)
|
103
|
+
handle = new(size)
|
104
|
+
begin
|
105
|
+
yield handle
|
106
|
+
ensure
|
107
|
+
handle.close
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2025, by Shopify Inc.
|
5
|
+
|
6
|
+
require "fiddle"
|
7
|
+
require "fiddle/import"
|
8
|
+
|
9
|
+
module IO::Memory
|
10
|
+
# Linux-specific implementation of memory-mapped IO using memfd_create.
|
11
|
+
# This implementation provides the most efficient memory mapping on Linux
|
12
|
+
# by using the memfd_create system call to create anonymous memory objects
|
13
|
+
# that exist only in memory without being backed by any filesystem.
|
14
|
+
module Linux
|
15
|
+
extend self
|
16
|
+
|
17
|
+
module Implementation
|
18
|
+
extend Fiddle::Importer
|
19
|
+
|
20
|
+
def self.supported?
|
21
|
+
@supported
|
22
|
+
end
|
23
|
+
|
24
|
+
# memfd_create system call constants
|
25
|
+
MFD_CLOEXEC = 0x01
|
26
|
+
|
27
|
+
# Load system functions
|
28
|
+
LIBC = Fiddle.dlopen(nil)
|
29
|
+
|
30
|
+
# Load memfd_create function
|
31
|
+
MEMFD_CREATE = Fiddle::Function.new(
|
32
|
+
LIBC["memfd_create"],
|
33
|
+
[Fiddle::TYPE_VOIDP, Fiddle::TYPE_UINT],
|
34
|
+
Fiddle::TYPE_INT
|
35
|
+
)
|
36
|
+
|
37
|
+
# Load ftruncate function
|
38
|
+
FTRUNCATE = Fiddle::Function.new(
|
39
|
+
LIBC["ftruncate"],
|
40
|
+
[Fiddle::TYPE_INT, Fiddle::TYPE_LONG],
|
41
|
+
Fiddle::TYPE_INT
|
42
|
+
)
|
43
|
+
|
44
|
+
CLOSE = Fiddle::Function.new(
|
45
|
+
LIBC["close"],
|
46
|
+
[Fiddle::TYPE_INT],
|
47
|
+
Fiddle::TYPE_INT
|
48
|
+
)
|
49
|
+
|
50
|
+
# Handle class that wraps the IO
|
51
|
+
class Handle
|
52
|
+
def initialize(io, size)
|
53
|
+
@io = io
|
54
|
+
@size = size
|
55
|
+
end
|
56
|
+
|
57
|
+
def io
|
58
|
+
@io
|
59
|
+
end
|
60
|
+
|
61
|
+
def map(size = nil)
|
62
|
+
size ||= @size
|
63
|
+
::IO::Buffer.map(@io, size)
|
64
|
+
end
|
65
|
+
|
66
|
+
def close
|
67
|
+
@io.close unless @io.closed?
|
68
|
+
end
|
69
|
+
|
70
|
+
def closed?
|
71
|
+
@io.closed?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.create_handle(size)
|
76
|
+
# Create the memory file descriptor
|
77
|
+
file_descriptor = MEMFD_CREATE.call("io_memory", MFD_CLOEXEC)
|
78
|
+
|
79
|
+
if file_descriptor == -1
|
80
|
+
raise IO::Memory::MemoryError, "Failed to create memfd!"
|
81
|
+
end
|
82
|
+
|
83
|
+
# Set the size
|
84
|
+
if FTRUNCATE.call(file_descriptor, size) == -1
|
85
|
+
# Clean up on error
|
86
|
+
begin
|
87
|
+
CLOSE.call(file_descriptor)
|
88
|
+
rescue
|
89
|
+
# Ignore cleanup errors
|
90
|
+
end
|
91
|
+
raise IO::Memory::MemoryError, "Failed to set memfd size!"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Convert to IO object and wrap in Handle
|
95
|
+
io = ::IO.for_fd(file_descriptor, autoclose: true)
|
96
|
+
|
97
|
+
return Handle.new(io, size)
|
98
|
+
rescue => error
|
99
|
+
# Clean up on any error
|
100
|
+
if file_descriptor and file_descriptor != -1
|
101
|
+
begin
|
102
|
+
CLOSE.call(file_descriptor)
|
103
|
+
rescue
|
104
|
+
# Ignore cleanup errors
|
105
|
+
end
|
106
|
+
end
|
107
|
+
raise
|
108
|
+
end
|
109
|
+
|
110
|
+
@supported = true
|
111
|
+
rescue
|
112
|
+
@supported = false
|
113
|
+
end
|
114
|
+
|
115
|
+
private_constant :Implementation
|
116
|
+
|
117
|
+
# Check if the Linux memfd_create implementation is supported on this system.
|
118
|
+
# This implementation uses the memfd_create() system call available on Linux 3.17+
|
119
|
+
# and provides the most efficient memory mapping by creating anonymous memory objects.
|
120
|
+
# @returns [Boolean] true if memfd_create is available, false otherwise
|
121
|
+
def self.supported?
|
122
|
+
Implementation.supported?
|
123
|
+
end
|
124
|
+
|
125
|
+
if supported?
|
126
|
+
# Create a new memory-mapped buffer using Linux memfd_create.
|
127
|
+
# This creates an anonymous memory object that exists only in memory
|
128
|
+
# without being backed by any filesystem.
|
129
|
+
# @parameter size [Integer] size of the memory buffer in bytes
|
130
|
+
# @returns [Object] a handle object that provides access to the memory buffer
|
131
|
+
def new(size)
|
132
|
+
Implementation.create_handle(size)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Create a memory-mapped buffer and yield it to a block.
|
136
|
+
# The buffer is automatically cleaned up when the block exits,
|
137
|
+
# regardless of whether an exception is raised.
|
138
|
+
# @parameter size [Integer] size of the memory buffer in bytes
|
139
|
+
# @yields {|handle| ...}
|
140
|
+
# @parameter handle [Object] the handle to the memory buffer with access to IO and mapping operations
|
141
|
+
# @returns [Object] the result of the block execution
|
142
|
+
def with(size, &block)
|
143
|
+
handle = new(size)
|
144
|
+
begin
|
145
|
+
yield handle
|
146
|
+
ensure
|
147
|
+
handle.close
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2025, by Shopify Inc.
|
5
|
+
|
6
|
+
require "fiddle"
|
7
|
+
require "securerandom"
|
8
|
+
|
9
|
+
module IO::Memory
|
10
|
+
# POSIX implementation of memory-mapped IO using shm_open.
|
11
|
+
# This implementation provides efficient memory mapping on POSIX-compliant
|
12
|
+
# systems (macOS, BSD, etc.) by using the shm_open system call to create
|
13
|
+
# shared memory objects. These objects can be shared between processes
|
14
|
+
# and provide zero-copy memory operations.
|
15
|
+
module POSIX
|
16
|
+
extend self
|
17
|
+
|
18
|
+
module Implementation
|
19
|
+
def self.supported?
|
20
|
+
@supported
|
21
|
+
end
|
22
|
+
|
23
|
+
# Use Ruby's File constants instead of hardcoded values for cross-platform compatibility
|
24
|
+
O_CREAT = IO::CREAT
|
25
|
+
O_EXCL = IO::EXCL
|
26
|
+
O_RDWR = IO::RDWR
|
27
|
+
|
28
|
+
# Load system functions
|
29
|
+
LIBC = Fiddle.dlopen(nil)
|
30
|
+
|
31
|
+
SHM_OPEN = Fiddle::Function.new(
|
32
|
+
LIBC["shm_open"],
|
33
|
+
[Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_INT],
|
34
|
+
Fiddle::TYPE_INT
|
35
|
+
)
|
36
|
+
|
37
|
+
SHM_UNLINK = Fiddle::Function.new(
|
38
|
+
LIBC["shm_unlink"],
|
39
|
+
[Fiddle::TYPE_VOIDP],
|
40
|
+
Fiddle::TYPE_INT
|
41
|
+
)
|
42
|
+
|
43
|
+
FTRUNCATE = Fiddle::Function.new(
|
44
|
+
LIBC["ftruncate"],
|
45
|
+
[Fiddle::TYPE_INT, Fiddle::TYPE_LONG],
|
46
|
+
Fiddle::TYPE_INT
|
47
|
+
)
|
48
|
+
|
49
|
+
class MemoryError < StandardError; end
|
50
|
+
|
51
|
+
# Handle class that wraps the IO and manages shared memory cleanup
|
52
|
+
class Handle
|
53
|
+
def initialize(io, shm_name, size)
|
54
|
+
@io = io
|
55
|
+
@shm_name = shm_name
|
56
|
+
@size = size
|
57
|
+
end
|
58
|
+
|
59
|
+
def io
|
60
|
+
@io
|
61
|
+
end
|
62
|
+
|
63
|
+
def map(size = nil)
|
64
|
+
size ||= @size
|
65
|
+
::IO::Buffer.map(@io, size)
|
66
|
+
end
|
67
|
+
|
68
|
+
def close
|
69
|
+
@io.close unless @io.closed?
|
70
|
+
ensure
|
71
|
+
# Unlink the shared memory object
|
72
|
+
if @shm_name
|
73
|
+
Implementation::SHM_UNLINK.call(@shm_name)
|
74
|
+
@shm_name = nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def closed?
|
79
|
+
@io.closed?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.create_handle(size)
|
84
|
+
# Generate a unique name using multiple entropy sources to avoid collisions
|
85
|
+
# in high-concurrency situations
|
86
|
+
max_attempts = 8
|
87
|
+
last_error = nil
|
88
|
+
|
89
|
+
max_attempts.times do
|
90
|
+
# The most portable maximum length for a POSIX shared memory name is 14 characters:
|
91
|
+
shm_name = "/#{SecureRandom.hex(7)}"
|
92
|
+
|
93
|
+
# Create shared memory object with O_EXCL to ensure uniqueness
|
94
|
+
shm_fd = SHM_OPEN.call(shm_name, O_CREAT | O_EXCL | O_RDWR, 0600)
|
95
|
+
|
96
|
+
if shm_fd >= 0
|
97
|
+
# Success! Set the size of the shared memory object
|
98
|
+
if FTRUNCATE.call(shm_fd, size) == 0
|
99
|
+
# Create IO object from file descriptor
|
100
|
+
io = ::IO.for_fd(shm_fd, autoclose: true)
|
101
|
+
|
102
|
+
# Return Handle that manages both IO and cleanup
|
103
|
+
return Handle.new(io, shm_name, size)
|
104
|
+
else
|
105
|
+
# ftruncate failed, clean up
|
106
|
+
SHM_UNLINK.call(shm_name)
|
107
|
+
raise IO::Memory::MemoryError, "Failed to set shared memory size to #{size}!"
|
108
|
+
end
|
109
|
+
else
|
110
|
+
# Store the error for potential debugging
|
111
|
+
last_error = Fiddle.last_error
|
112
|
+
end
|
113
|
+
# If we get here, shm_open failed (likely name collision), try again with new name
|
114
|
+
end
|
115
|
+
|
116
|
+
# If we've exhausted all attempts:
|
117
|
+
if last_error
|
118
|
+
cause = SystemCallError.new(last_error)
|
119
|
+
end
|
120
|
+
|
121
|
+
raise IO::Memory::MemoryError, "Failed to create shared memory object after #{max_attempts} attempts!", cause: cause
|
122
|
+
end
|
123
|
+
|
124
|
+
@supported = true
|
125
|
+
rescue
|
126
|
+
@supported = false
|
127
|
+
end
|
128
|
+
|
129
|
+
private_constant :Implementation
|
130
|
+
|
131
|
+
# Check if the POSIX shared memory implementation is supported on this system.
|
132
|
+
# This implementation uses shm_open() and is available on POSIX-compliant systems
|
133
|
+
# like macOS, BSD, and some Linux configurations with shared memory support.
|
134
|
+
# @returns [Boolean] true if POSIX shared memory is available, false otherwise
|
135
|
+
def self.supported?
|
136
|
+
Implementation.supported?
|
137
|
+
end
|
138
|
+
|
139
|
+
if supported?
|
140
|
+
# Create a new memory-mapped buffer using POSIX shared memory.
|
141
|
+
# This creates a shared memory object using shm_open that can be
|
142
|
+
# shared between processes and provides zero-copy operations.
|
143
|
+
# @parameter size [Integer] size of the memory buffer in bytes
|
144
|
+
# @returns [Object] a handle object that provides access to the memory buffer
|
145
|
+
def new(size)
|
146
|
+
Implementation.create_handle(size)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Create a memory-mapped buffer and yield it to a block.
|
150
|
+
# The buffer is automatically cleaned up when the block exits,
|
151
|
+
# regardless of whether an exception is raised.
|
152
|
+
# @parameter size [Integer] size of the memory buffer in bytes
|
153
|
+
# @yields {|handle| ...}
|
154
|
+
# @parameter handle [Object] the handle to the memory buffer with access to IO and mapping operations
|
155
|
+
# @returns [Object] the result of the block execution
|
156
|
+
def with(size, &block)
|
157
|
+
handle = new(size)
|
158
|
+
begin
|
159
|
+
yield handle
|
160
|
+
ensure
|
161
|
+
handle.close
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
data/lib/io/memory.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2025, by Shopify Inc.
|
5
|
+
|
6
|
+
require_relative "memory/version"
|
7
|
+
|
8
|
+
require_relative "memory/linux"
|
9
|
+
require_relative "memory/posix"
|
10
|
+
require_relative "memory/generic"
|
11
|
+
|
12
|
+
# Provides memory-mapped IO objects for zero-copy data sharing with cross-platform support.
|
13
|
+
# This module automatically selects the best available implementation based on the platform:
|
14
|
+
# - Linux: Uses memfd_create() for anonymous memory objects
|
15
|
+
# - POSIX: Uses shm_open() for shared memory objects
|
16
|
+
# - Generic: Uses temporary files for maximum compatibility
|
17
|
+
module IO::Memory
|
18
|
+
# Exception raised when memory operations fail.
|
19
|
+
# This includes errors during memory buffer creation, mapping, or cleanup operations.
|
20
|
+
class MemoryError < StandardError; end
|
21
|
+
|
22
|
+
# Select the best available implementation
|
23
|
+
# Priority: Linux (memfd_create) > POSIX (shm_open) > Generic (tempfile)
|
24
|
+
if Linux.supported?
|
25
|
+
extend Linux
|
26
|
+
elsif POSIX.supported?
|
27
|
+
extend POSIX
|
28
|
+
else
|
29
|
+
extend Generic
|
30
|
+
end
|
31
|
+
end
|
data/license.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# MIT License
|
2
|
+
|
3
|
+
Copyright, 2025, by Shopify Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/readme.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# `IO::Memory`
|
2
|
+
|
3
|
+
Memory-mapped IO objects for zero-copy data sharing with cross-platform support for Linux (`memfd_create`), POSIX (`shm_open`), and generic implementations.
|
4
|
+
|
5
|
+
[](https://github.com/socketry/io-memory/actions?workflow=Test)
|
6
|
+
|
7
|
+
## Motivation
|
8
|
+
|
9
|
+
Modern applications increasingly require efficient memory sharing and zero-copy operations, especially in high-performance scenarios like web servers, data processing pipelines, and inter-process communication. `IO::Memory` provides a cross-platform abstraction over memory-mapped files that automatically selects the best available implementation based on your platform:
|
10
|
+
|
11
|
+
- **Linux**: Uses `memfd_create()` for anonymous memory objects with file descriptor passing
|
12
|
+
- **POSIX**: Uses `shm_open()` for POSIX shared memory objects
|
13
|
+
- **Generic**: Falls back to temporary files for maximum compatibility
|
14
|
+
|
15
|
+
This gem is designed to work seamlessly with Ruby's `IO::Buffer` class, providing efficient memory mapping capabilities that integrate well with modern Ruby's IO subsystem.
|
16
|
+
|
17
|
+
## Features
|
18
|
+
|
19
|
+
- **Cross-platform**: Automatically selects the best memory implementation for your platform
|
20
|
+
- **Zero-copy**: Direct memory mapping without data copying
|
21
|
+
- **IO::Buffer integration**: Works seamlessly with Ruby's built-in buffer objects
|
22
|
+
- **File descriptor passing**: Share memory between processes (where supported)
|
23
|
+
- **Automatic cleanup**: Built-in resource management with `with` blocks
|
24
|
+
- **Multiple sizes**: Support for buffers from zero bytes to multiple gigabytes
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
Please see the [project documentation](https://socketry.github.io/io-memory/) for more details.
|
29
|
+
|
30
|
+
- [Getting Started](https://socketry.github.io/io-memory/guides/getting-started/index) - This guide explains how to use `io-memory` for efficient memory operations and zero-copy data sharing.
|
31
|
+
|
32
|
+
- [Process Memory Sharing](https://socketry.github.io/io-memory/guides/process-sharing/index) - This guide demonstrates how to share memory between processes using `io-memory` for high-performance inter-process communication (IPC).
|
33
|
+
|
34
|
+
## Platform Support
|
35
|
+
|
36
|
+
| Platform | Implementation | Features |
|
37
|
+
| --- | --- | --- |
|
38
|
+
| Linux | `memfd_create()` | Anonymous memory, file descriptor passing |
|
39
|
+
| macOS/BSD | `shm_open()` | POSIX shared memory, file descriptor passing |
|
40
|
+
| Windows/Other | Temporary files | File descriptor passing, maximum compatibility |
|
41
|
+
|
42
|
+
## Performance
|
43
|
+
|
44
|
+
`IO::Memory` provides significant performance benefits for memory-intensive operations:
|
45
|
+
|
46
|
+
- **Zero-copy**: No data copying when mapping memory
|
47
|
+
- **OS-optimized**: Uses the most efficient memory primitives available
|
48
|
+
- **Large buffer support**: Handles multi-gigabyte buffers efficiently
|
49
|
+
- **Shared memory**: Enable inter-process communication without serialization
|
50
|
+
|
51
|
+
## Releases
|
52
|
+
|
53
|
+
Please see the [project releases](https://socketry.github.io/io-memory/releases/index) for all releases.
|
54
|
+
|
55
|
+
### v0.0.1
|
56
|
+
|
57
|
+
- Initial implementation with cross-platform memory mapping support
|
58
|
+
- Linux `memfd_create()` implementation for anonymous memory objects
|
59
|
+
- POSIX `shm_open()` implementation for shared memory
|
60
|
+
- Generic temporary file fallback for maximum compatibility
|
61
|
+
- Integration with Ruby's `IO::Buffer` class
|
62
|
+
- Automatic resource cleanup with `with` blocks
|
63
|
+
|
64
|
+
## Contributing
|
65
|
+
|
66
|
+
We welcome contributions to this project.
|
67
|
+
|
68
|
+
1. Fork it.
|
69
|
+
2. Create your feature branch (`git checkout -b my-new-feature`).
|
70
|
+
3. Commit your changes (`git commit -am 'Add some feature'`).
|
71
|
+
4. Push to the branch (`git push origin my-new-feature`).
|
72
|
+
5. Create new Pull Request.
|
73
|
+
|
74
|
+
### Developer Certificate of Origin
|
75
|
+
|
76
|
+
In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
|
77
|
+
|
78
|
+
### Community Guidelines
|
79
|
+
|
80
|
+
This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
|
data/releases.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# Releases
|
2
|
+
|
3
|
+
## v0.0.1
|
4
|
+
|
5
|
+
- Initial implementation with cross-platform memory mapping support
|
6
|
+
- Linux `memfd_create()` implementation for anonymous memory objects
|
7
|
+
- POSIX `shm_open()` implementation for shared memory
|
8
|
+
- Generic temporary file fallback for maximum compatibility
|
9
|
+
- Integration with Ruby's `IO::Buffer` class
|
10
|
+
- Automatic resource cleanup with `with` blocks
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: io-memory
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shopify Inc.
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: fiddle
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
executables: []
|
27
|
+
extensions: []
|
28
|
+
extra_rdoc_files: []
|
29
|
+
files:
|
30
|
+
- lib/io/memory.rb
|
31
|
+
- lib/io/memory/generic.rb
|
32
|
+
- lib/io/memory/linux.rb
|
33
|
+
- lib/io/memory/posix.rb
|
34
|
+
- lib/io/memory/version.rb
|
35
|
+
- license.md
|
36
|
+
- readme.md
|
37
|
+
- releases.md
|
38
|
+
homepage: https://github.com/socketry/io-memory
|
39
|
+
licenses:
|
40
|
+
- MIT
|
41
|
+
metadata:
|
42
|
+
documentation_uri: https://socketry.github.io/io-memory/
|
43
|
+
source_code_uri: https://github.com/socketry/io-memory.git
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '3.2'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubygems_version: 3.6.7
|
59
|
+
specification_version: 4
|
60
|
+
summary: Memory-mapped IO objects for zero-copy data sharing.
|
61
|
+
test_files: []
|