1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Import fiddle-1.0.4 (#3860)

I don't use tool/sync_default_gem.rb because the last sync was incomplete.

Co-authored-by: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Co-authored-by: sinisterchipmunk <sinisterchipmunk@gmail.com>
Co-authored-by: Sutou Kouhei <kou@clear-code.com>
This commit is contained in:
Kenta Murata 2020-12-11 09:41:12 +09:00 committed by GitHub
parent 6b1d2de6cc
commit 9b0c36b390
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
Notes: git 2020-12-11 09:41:40 +09:00
Merged-By: mrkn <mrkn@ruby-lang.org>
23 changed files with 1816 additions and 252 deletions

View file

@ -2,8 +2,14 @@
* $Id$
*/
#include <stdbool.h>
#include <ruby/ruby.h>
#include <ruby/io.h>
#ifdef HAVE_RUBY_MEMORY_VIEW_H
# include <ruby/memory_view.h>
#endif
#include <ctype.h>
#include <fiddle.h>
@ -24,6 +30,7 @@ struct ptr_data {
void *ptr;
long size;
freefunc_t free;
bool freed;
VALUE wrap[2];
};
@ -57,14 +64,19 @@ fiddle_ptr_mark(void *ptr)
}
static void
fiddle_ptr_free(void *ptr)
fiddle_ptr_free_ptr(void *ptr)
{
struct ptr_data *data = ptr;
if (data->ptr) {
if (data->free) {
(*(data->free))(data->ptr);
}
if (data->ptr && data->free && !data->freed) {
data->freed = true;
(*(data->free))(data->ptr);
}
}
static void
fiddle_ptr_free(void *ptr)
{
fiddle_ptr_free_ptr(ptr);
xfree(ptr);
}
@ -80,6 +92,38 @@ static const rb_data_type_t fiddle_ptr_data_type = {
{fiddle_ptr_mark, fiddle_ptr_free, fiddle_ptr_memsize,},
};
#ifdef FIDDLE_MEMORY_VIEW
static struct ptr_data *
fiddle_ptr_check_memory_view(VALUE obj)
{
struct ptr_data *data;
TypedData_Get_Struct(obj, struct ptr_data, &fiddle_ptr_data_type, data);
if (data->ptr == NULL || data->size == 0) return NULL;
return data;
}
static int
fiddle_ptr_memory_view_available_p(VALUE obj)
{
return fiddle_ptr_check_memory_view(obj) != NULL;
}
static int
fiddle_ptr_get_memory_view(VALUE obj, rb_memory_view_t *view, int flags)
{
struct ptr_data *data = fiddle_ptr_check_memory_view(obj);
rb_memory_view_init_as_byte_array(view, obj, data->ptr, data->size, true);
return 1;
}
static const rb_memory_view_entry_t fiddle_ptr_memory_view_entry = {
fiddle_ptr_get_memory_view,
NULL,
fiddle_ptr_memory_view_available_p
};
#endif
static VALUE
rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
{
@ -89,6 +133,7 @@ rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
val = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
data->ptr = ptr;
data->free = func;
data->freed = false;
data->size = size;
return val;
@ -101,13 +146,13 @@ rb_fiddle_ptr_new(void *ptr, long size, freefunc_t func)
}
static VALUE
rb_fiddle_ptr_malloc(long size, freefunc_t func)
rb_fiddle_ptr_malloc(VALUE klass, long size, freefunc_t func)
{
void *ptr;
ptr = ruby_xmalloc((size_t)size);
memset(ptr,0,(size_t)size);
return rb_fiddle_ptr_new(ptr, size, func);
return rb_fiddle_ptr_new2(klass, ptr, size, func);
}
static void *
@ -140,6 +185,7 @@ rb_fiddle_ptr_s_allocate(VALUE klass)
data->ptr = 0;
data->size = 0;
data->free = 0;
data->freed = false;
return obj;
}
@ -191,17 +237,31 @@ rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
return Qnil;
}
static VALUE
rb_fiddle_ptr_call_free(VALUE self);
/*
* call-seq:
* Fiddle::Pointer.malloc(size, freefunc = nil) => fiddle pointer instance
* Fiddle::Pointer.malloc(size, freefunc) { |pointer| ... } => ...
*
* == Examples
*
* # Automatically freeing the pointer when the block is exited - recommended
* Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) do |pointer|
* ...
* end
*
* # Manually freeing but relying on the garbage collector otherwise
* pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
* ...
* pointer.call_free
*
* # Relying on the garbage collector - may lead to unlimited memory allocated before freeing any, but safe
* pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
* ...
*
* # Manual freeing
* # Only manually freeing
* pointer = Fiddle::Pointer.malloc(size)
* begin
* ...
@ -214,13 +274,16 @@ rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
* ...
*
* Allocate +size+ bytes of memory and associate it with an optional
* +freefunc+ that will be called when the pointer is garbage collected.
* +freefunc+ must be an address pointing to a function or an instance of
* +Fiddle::Function+. Using +freefunc+ may lead to unlimited memory being
* allocated before any is freed as the native memory the pointer references
* does not contribute to triggering the Ruby garbage collector. Consider
* manually freeing the memory as illustrated above. You cannot combine
* the techniques as this may lead to a double-free.
* +freefunc+.
*
* If a block is supplied, the pointer will be yielded to the block instead of
* being returned, and the return value of the block will be returned. A
* +freefunc+ must be supplied if a block is.
*
* If a +freefunc+ is supplied it will be called once, when the pointer is
* garbage collected or when the block is left if a block is supplied or
* when the user calls +call_free+, whichever happens first. +freefunc+ must be
* an address pointing to a function or an instance of +Fiddle::Function+.
*/
static VALUE
rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
@ -242,10 +305,17 @@ rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
rb_bug("rb_fiddle_ptr_s_malloc");
}
obj = rb_fiddle_ptr_malloc(s,f);
obj = rb_fiddle_ptr_malloc(klass, s,f);
if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
return obj;
if (rb_block_given_p()) {
if (!f) {
rb_raise(rb_eArgError, "a free function must be supplied to Fiddle::Pointer.malloc when it is called with a block");
}
return rb_ensure(rb_yield, obj, rb_fiddle_ptr_call_free, obj);
} else {
return obj;
}
}
/*
@ -370,6 +440,34 @@ rb_fiddle_ptr_free_get(VALUE self)
return rb_fiddle_new_function(address, arg_types, ret_type);
}
/*
* call-seq: call_free => nil
*
* Call the free function for this pointer. Calling more than once will do
* nothing. Does nothing if there is no free function attached.
*/
static VALUE
rb_fiddle_ptr_call_free(VALUE self)
{
struct ptr_data *pdata;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
fiddle_ptr_free_ptr(pdata);
return Qnil;
}
/*
* call-seq: freed? => bool
*
* Returns if the free function for this pointer has been called.
*/
static VALUE
rb_fiddle_ptr_freed_p(VALUE self)
{
struct ptr_data *pdata;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
return pdata->freed ? Qtrue : Qfalse;
}
/*
* call-seq:
*
@ -711,6 +809,8 @@ Init_fiddle_pointer(void)
rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
rb_define_method(rb_cPointer, "free", rb_fiddle_ptr_free_get, 0);
rb_define_method(rb_cPointer, "call_free", rb_fiddle_ptr_call_free, 0);
rb_define_method(rb_cPointer, "freed?", rb_fiddle_ptr_freed_p, 0);
rb_define_method(rb_cPointer, "to_i", rb_fiddle_ptr_to_i, 0);
rb_define_method(rb_cPointer, "to_int", rb_fiddle_ptr_to_i, 0);
rb_define_method(rb_cPointer, "to_value", rb_fiddle_ptr_to_value, 0);
@ -732,6 +832,10 @@ Init_fiddle_pointer(void)
rb_define_method(rb_cPointer, "size", rb_fiddle_ptr_size_get, 0);
rb_define_method(rb_cPointer, "size=", rb_fiddle_ptr_size_set, 1);
#ifdef FIDDLE_MEMORY_VIEW
rb_memory_view_register(rb_cPointer, &fiddle_ptr_memory_view_entry);
#endif
/* Document-const: NULL
*
* A NULL pointer