Skip to content

Commit

Permalink
Backport C-API needed for OpenSSL C-ext 2.x.
Browse files Browse the repository at this point in the history
  • Loading branch information
brixen committed Jun 15, 2015
1 parent a97b41b commit 203f021
Show file tree
Hide file tree
Showing 8 changed files with 425 additions and 20 deletions.
53 changes: 49 additions & 4 deletions vm/builtin/data.cpp
Expand Up @@ -33,8 +33,8 @@ namespace rubinius {
RDataShadow* rdata = reinterpret_cast<RDataShadow*>(handle->as_rdata(0));

rdata->data = data_ptr;
rdata->dmark = mark;
rdata->dfree = free;
rdata->d.untyped.dmark = mark;
rdata->d.untyped.dfree = free;

data->internal_ = rdata;

Expand All @@ -47,16 +47,60 @@ namespace rubinius {
return data;
}

Data* Data::create_typed(STATE, void* data_ptr, const struct rb_data_type_struct_shadow* type) {
Data* data;

data = state->new_object<Data>(G(data));
data->freed_ = false;

// Data is just a heap alias for the handle, so go ahead and create
// the handle and populate it as an RData now.
capi::Handle* handle = data->handle(state);

assert(!handle && "can't already have a handle, it's brand new!");

handle = state->memory()->add_capi_handle(state, data);

// Don't call ->ref() on handle! We don't want the handle to keep the object
// alive by default. The handle needs to have the lifetime of the object.

RDataShadow* rdata = reinterpret_cast<RDataShadow*>(handle->as_rtypeddata(0));

rdata->data = data_ptr;
rdata->d.typed.typed = 1;
rdata->d.typed.type = type;

data->internal_ = rdata;

if(type->function.dmark || type->function.dfree) {
state->memory()->needs_finalization(data, (FinalizerFunction)&Data::finalize);
}

state->vm()->metrics().m.ruby_metrics.memory_data_objects_total++;

return data;
}

void* Data::data() {
return rdata()->data;
}

Data::FreeFunctor Data::free() {
return rdata()->dfree;
RDataShadow* data = rdata();
if(typed()) {
return data->d.typed.type->function.dfree;
} else {
return data->d.untyped.dfree;
}
}

Data::MarkFunctor Data::mark() {
return rdata()->dmark;
RDataShadow* data = rdata();
if(typed()) {
return data->d.typed.type->function.dmark;
} else {
return data->d.untyped.dmark;
}
}

void Data::finalize(STATE, Data* data) {
Expand Down Expand Up @@ -126,4 +170,5 @@ namespace rubinius {
capi::set_current_mark(cur);
}
}

}
47 changes: 46 additions & 1 deletion vm/builtin/data.hpp
Expand Up @@ -7,9 +7,40 @@ namespace rubinius {
// Copied from here because you can't include capi/include/ruby.h into
// our C++ files.

struct RDataShadow {
struct rb_data_type_struct_shadow {
const char *wrap_struct_name;
struct {
void (*dmark)(void*);
void (*dfree)(void*);
size_t (*dsize)(const void *);
void *reserved[2]; /* For future extension.
This array *must* be filled with ZERO. */
} function;
const struct rb_data_type_struct_shadow* parent;
void *data; /* This area can be used for any purpose
by a programmer who define the type. */
};

// This union crazyness is needed because these should be compatible
// for the data pointer. It is valid behavior to use DATA_PTR on both
// typed and untyped and get a valid result back.
// MRI constructs this differently, but this approach allows us to
// use this in a slightly more type safe and explicit way.
struct RUntypedDataShadow {
void (*dmark)(void*);
void (*dfree)(void*);
};

struct RTypedDataShadow {
const struct rb_data_type_struct_shadow* type;
native_int typed;
};

struct RDataShadow {
union {
RUntypedDataShadow untyped;
RTypedDataShadow typed;
} d;
void *data;
};

Expand All @@ -36,6 +67,9 @@ namespace rubinius {
/** New Data instance. */
static Data* create(STATE, void* data, MarkFunctor mark, FreeFunctor free);

/** New typed Data instance. */
static Data* create_typed(STATE, void* data, const struct rb_data_type_struct_shadow* type);

static void finalize(STATE, Data* data);

bool freed_p() const {
Expand All @@ -54,6 +88,17 @@ namespace rubinius {
return internal_;
}

bool typed() {
return rdata()->d.typed.typed == 1;
}

const struct rb_data_type_struct_shadow* data_type() {
if(typed()) {
return rdata()->d.typed.type;
}
return NULL;
}

void* data();
FreeFunctor free();
MarkFunctor mark();
Expand Down
77 changes: 77 additions & 0 deletions vm/capi/data.cpp
Expand Up @@ -33,6 +33,29 @@ namespace rubinius {
return rdata;
}
}

RTypedData* Handle::as_rtypeddata(NativeMethodEnvironment* env) {
Data* data = c_as<Data>(object_);

if(data->freed_p()) {
rb_raise(rb_eArgError, "Data object has already been freed");
}

if(type_ == cRData) {
return as_.rtypeddata;
} else {
type_ = cRData;

RTypedData* rtypeddata = new RTypedData;
rtypeddata->data = 0;
rtypeddata->type = 0;
rtypeddata->typed_flag = 1;

as_.rtypeddata = rtypeddata;

return rtypeddata;
}
}
}
}

Expand Down Expand Up @@ -60,4 +83,58 @@ extern "C" {

return env->get_handle(data);
}

struct RTypedData* capi_rtypeddata_struct(VALUE data_handle) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();

Handle* handle = Handle::from(data_handle);
env->check_tracked_handle(handle, false);

return handle->as_rtypeddata(env);
}

VALUE rb_data_typed_object_alloc(VALUE klass, void* ptr, const rb_data_type_t* type) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();

if(!klass) klass = rb_cObject;

Class* data_klass = c_as<Class>(env->get_object(klass));

Data* data = Data::create_typed(env->state(), ptr, reinterpret_cast<const struct rb_data_type_struct_shadow*>(type));

data->klass(env->state(), data_klass);

return env->get_handle(data);
}

int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent) {
while (child) {
if (child == parent) return 1;
child = child->parent;
}
return 0;
}

void* rb_check_typeddata(VALUE obj, const rb_data_type_t* data_type) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
const char* mesg = "wrong argument type %s (expected %s)";
Data* data = c_as<Data>(env->get_object(obj));
if(!data->typed()) {
rb_raise(rb_eTypeError, mesg, rb_obj_classname(obj), data_type->wrap_struct_name);
}

const rb_data_type_t* other_type = reinterpret_cast<const rb_data_type_t*>(data->data_type());

if (!rb_typeddata_inherited_p(other_type, data_type)) {
rb_raise(rb_eTypeError, mesg, other_type->wrap_struct_name, data_type->wrap_struct_name);
}
return data->data();
}

int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Data* data = try_as<Data>(env->get_object(obj));
if(!data || !data->typed()) return 0;
return rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type);
}
}
27 changes: 27 additions & 0 deletions vm/capi/file.cpp
Expand Up @@ -28,11 +28,38 @@ extern "C" {
return Handle::from(file)->as_rfile(env);
}

int rb_cloexec_dup(int fd) {
return fcntl(fd, F_DUPFD_CLOEXEC, 3);
}

VALUE rb_file_open(const char* name, const char* mode) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
VALUE n = env->get_handle(String::create(env->state(), name));
VALUE m = env->get_handle(String::create(env->state(), mode));

return rb_funcall(rb_cFile, rb_intern("open"), 2, n, m);
}

FILE * rb_io_stdio_file(rb_io_t *fptr) {
return fptr->f;
}

VALUE rb_file_path_value(volatile VALUE* obj) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
STATE = env->state();

if(!kind_of<String>(env->get_object(*obj))) {
*obj = rb_funcall(env->get_handle(G(type)), rb_intern("coerce_to_path"), 1, *obj);
}

return *obj;
}

VALUE rb_file_open_str(VALUE name, const char* mode) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
VALUE m = env->get_handle(String::create(env->state(), mode));

FilePathValue(name);
return rb_funcall(rb_cFile, rb_intern("open"), 2, name, m);
}
}
5 changes: 4 additions & 1 deletion vm/capi/handle.hpp
Expand Up @@ -3,7 +3,7 @@

#include "detection.hpp"

#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
#if defined(__APPLE__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
#ifndef RBX_HAVE_TR1_HASH
#include "missing/leopard_hashtable.hpp"
#endif
Expand All @@ -23,6 +23,7 @@
struct RArray;
struct RString;
struct RData;
struct RTypedData;
struct RFloat;
struct RIO;
struct RFile;
Expand Down Expand Up @@ -58,6 +59,7 @@ namespace rubinius {
RArray* rarray;
RString* rstring;
RData* rdata;
RTypedData* rtypeddata;
RFloat* rfloat;
RIO* rio;
RFile* rfile;
Expand Down Expand Up @@ -191,6 +193,7 @@ namespace rubinius {
}

RData* as_rdata(NativeMethodEnvironment* env);
RTypedData* as_rtypeddata(NativeMethodEnvironment* env);
RArray* as_rarray(NativeMethodEnvironment* env);
RString* as_rstring(NativeMethodEnvironment* env, int cache_level);
RFloat* as_rfloat(NativeMethodEnvironment* env);
Expand Down
15 changes: 13 additions & 2 deletions vm/capi/hash.cpp
Expand Up @@ -43,11 +43,16 @@ extern "C" {
}

VALUE rb_hash_lookup(VALUE self, VALUE key) {
VALUE entry = capi_fast_call(self, rb_intern("find_item"), 1, key);
return rb_hash_lookup2(self, key, Qnil);
}

VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def) {
VALUE entry = capi_fast_call(hash, rb_intern("find_item"), 1, key);

if(entry != Qnil) {
return capi_fast_call(entry, rb_intern("value"), 0);
} else {
return Qnil;
return def;
}
}

Expand Down Expand Up @@ -83,4 +88,10 @@ extern "C" {
}
}
}

VALUE rb_hash_set_ifnone(VALUE hash, VALUE def) {
capi_fast_call(hash, rb_intern("default="), 1, def);

return hash;
}
}
4 changes: 4 additions & 0 deletions vm/capi/symbol.cpp
Expand Up @@ -40,4 +40,8 @@ extern "C" {
Object* p = reinterpret_cast<Symbol*>(sym)->is_cvar_p(env->state());
return CBOOL(p) ? Qtrue : Qfalse;
}

VALUE rb_sym2str(VALUE sym) {
return rb_id2str(SYM2ID(sym));
}
}

0 comments on commit 203f021

Please sign in to comment.