Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* raise Vips::Error if `copy_memory` fails [VitaliiLazebnyi]
* `Source.new_from_memory` keeps a reference to the memory area [jeremy]
* release the GVL during `copy_memory` and `write_to_memory` [andrewfader]

## Version 2.3.0 (2025-12-10)

Expand Down
6 changes: 4 additions & 2 deletions lib/vips/image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ module Vips
attach_function :vips_image_new_matrix_from_array,
[:int, :int, :pointer, :int], :pointer

attach_function :vips_image_copy_memory, [:pointer], :pointer
# these two evaluate the whole pipeline, so release the GVL while they run
attach_function :vips_image_copy_memory, [:pointer], :pointer,
blocking: true

attach_function :vips_image_set_progress, [:pointer, :int], :void
attach_function :vips_image_set_kill, [:pointer, :int], :void
Expand All @@ -31,7 +33,7 @@ module Vips
end

attach_function :vips_image_write_to_memory,
[:pointer, SizeStruct.ptr], :pointer
[:pointer, SizeStruct.ptr], :pointer, blocking: true

attach_function :vips_image_get_typeof, [:pointer, :string], :GType
attach_function :vips_image_get,
Expand Down
30 changes: 30 additions & 0 deletions spec/image_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,36 @@
expect { img.copy_memory }.to raise_exception(Vips::Error)
end

# copy_memory and write_to_memory evaluate the whole pipeline, so they must
# release the GVL, or every other Ruby thread stalls until they return
def ticks_during
ticks = 0
running = true
ticker = Thread.new do
while running
ticks += 1
sleep 0.001
end
end
sleep 0.01 until ticks > 0
before = ticks
yield
during = ticks - before
running = false
ticker.join
during
end

it "lets other threads run during copy_memory" do
image = Vips::Image.gaussnoise(2000, 2000).gaussblur(4)
expect(ticks_during { image.copy_memory }).to be > 0
end

it "lets other threads run during write_to_memory" do
image = Vips::Image.gaussnoise(2000, 2000).gaussblur(4)
expect(ticks_during { image.write_to_memory }).to be > 0
end

it "throws an error when trying to load an image from memory with unknown size" do
data = FFI::Pointer.new(1)
expect { Vips::Image.new_from_memory(data, 16, 16, 1, :uchar) }.to raise_error(Vips::Error)
Expand Down
Loading