From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS60404 5.2.64.0/20 X-Spam-Status: No, score=-2.7 required=3.0 tests=AWL,BAYES_00, RCVD_IN_MSPIKE_BL,RCVD_IN_MSPIKE_ZBI,RCVD_IN_XBL,RDNS_NONE,SPF_FAIL, SPF_HELO_FAIL shortcircuit=no autolearn=no autolearn_force=no version=3.4.0 Received: from 80x24.org (unknown [5.2.75.25]) by dcvr.yhbt.net (Postfix) with ESMTP id EBE0D20280 for ; Fri, 3 Mar 2017 20:53:34 +0000 (UTC) From: Eric Wong To: kcar-public@bogomips.org Subject: [PATCH 5/5] TypedData C-API conversion Date: Fri, 3 Mar 2017 20:53:07 +0000 Message-Id: <20170303205307.2275-6-e@80x24.org> In-Reply-To: <20170303205307.2275-1-e@80x24.org> References: <20170303205307.2275-1-e@80x24.org> List-Id: 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 -- EW