From eb039c203735c44868cf03e9d41758727d4dc21c Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 3 Mar 2017 20:53:07 +0000 Subject: TypedData C-API conversion This provides some extra type safety if combined with other C extensions, as well as allowing us to account for memory usage of the HTTP parser in ObjectSpace. This requires Ruby 1.9.3+ and has remained a stable API since then. This will become officially supported when Ruby 2.3.0 is released later this month. This API has only been documented in doc/extension.rdoc (formerly README.EXT) in the Ruby source tree since April 2015, r50318 --- ext/kcar/kcar.rl | 36 ++++++++++++++++++++++++------------ test/test_parser.rb | 8 ++++++++ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/ext/kcar/kcar.rl b/ext/kcar/kcar.rl index 1130b75..4c66fb5 100644 --- a/ext/kcar/kcar.rl +++ b/ext/kcar/kcar.rl @@ -409,29 +409,41 @@ post_exec: /* "_out:" also goes here */ assert(hp->offset <= len && "offset longer than length"); } -static struct http_parser *data_get(VALUE self) +static void kcar_mark(void *ptr) { - struct http_parser *hp; + struct http_parser *hp = ptr; - Data_Get_Struct(self, struct http_parser, hp); - assert(hp && "failed to extract http_parser struct"); - return hp; + rb_gc_mark(hp->cont); + rb_gc_mark(hp->status); } -static void mark(void *ptr) +static size_t kcar_memsize(const void *ptr) { - struct http_parser *hp = ptr; + return sizeof(struct http_parser); +} - rb_gc_mark(hp->cont); - rb_gc_mark(hp->status); +static const rb_data_type_t kcar_type = { + "kcar_parser", + { kcar_mark, RUBY_TYPED_DEFAULT_FREE, kcar_memsize, /* reserved */ }, + /* parent, data, [ flags ] */ +}; + +static VALUE kcar_alloc(VALUE klass) +{ + struct http_parser *hp; + return TypedData_Make_Struct(klass, struct http_parser, &kcar_type, hp); } -static VALUE alloc(VALUE klass) +static struct http_parser *data_get(VALUE self) { struct http_parser *hp; - return Data_Make_Struct(klass, struct http_parser, mark, -1, hp); + + TypedData_Get_Struct(self, struct http_parser, &kcar_type, hp); + assert(hp && "failed to extract http_parser struct"); + return hp; } + /** * call-seq: * Kcar::Parser.new => parser @@ -678,7 +690,7 @@ void Init_kcar_ext(void) eParserError = rb_define_class_under(mKcar, "ParserError", rb_eIOError); - rb_define_alloc_func(cParser, alloc); + rb_define_alloc_func(cParser, kcar_alloc); rb_define_method(cParser, "initialize", initialize, 0); rb_define_method(cParser, "reset", initialize, 0); rb_define_method(cParser, "headers", headers, 2); diff --git a/test/test_parser.rb b/test/test_parser.rb index dab2e77..c8eaa4d 100644 --- a/test/test_parser.rb +++ b/test/test_parser.rb @@ -289,4 +289,12 @@ class TestParser < Test::Unit::TestCase assert @hp.headers(env = {}, resp) assert_equal '', env['Host'] end + + def test_memsize + require 'objspace' + n = ObjectSpace.memsize_of(@hp) + assert_kind_of Integer, n + rescue LoadError + warn 'ObjectSpace not available' + end end -- cgit v1.2.3-24-ge0c7