From 5b5cf896871efdb110ae831fd7fc34fb78ec2243 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 16 Nov 2014 08:32:16 +0000 Subject: http: 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/unicorn_http/unicorn_http.rl | 35 +++++++++++++++++++++++------------ test/unit/test_http_parser.rb | 14 ++++++++++++++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/ext/unicorn_http/unicorn_http.rl b/ext/unicorn_http/unicorn_http.rl index 046ccb5..957a5e3 100644 --- a/ext/unicorn_http/unicorn_http.rl +++ b/ext/unicorn_http/unicorn_http.rl @@ -442,11 +442,31 @@ post_exec: /* "_out:" also goes here */ assert(hp->offset <= len && "offset longer than length"); } +static void hp_mark(void *ptr) +{ + struct http_parser *hp = ptr; + + rb_gc_mark(hp->buf); + rb_gc_mark(hp->env); + rb_gc_mark(hp->cont); +} + +static size_t hp_memsize(const void *ptr) +{ + return sizeof(struct http_parser); +} + +static const rb_data_type_t hp_type = { + "unicorn_http", + { hp_mark, RUBY_TYPED_DEFAULT_FREE, hp_memsize, /* reserved */ }, + /* parent, data, [ flags ] */ +}; + static struct http_parser *data_get(VALUE self) { struct http_parser *hp; - Data_Get_Struct(self, struct http_parser, hp); + TypedData_Get_Struct(self, struct http_parser, &hp_type, hp); assert(hp && "failed to extract http_parser struct"); return hp; } @@ -552,21 +572,12 @@ static void finalize_header(struct http_parser *hp) rb_hash_aset(hp->env, g_query_string, rb_str_new(NULL, 0)); } -static void hp_mark(void *ptr) -{ - struct http_parser *hp = ptr; - - rb_gc_mark(hp->buf); - rb_gc_mark(hp->env); - rb_gc_mark(hp->cont); -} - static VALUE HttpParser_alloc(VALUE klass) { struct http_parser *hp; - return Data_Make_Struct(klass, struct http_parser, hp_mark, -1, hp); -} + return TypedData_Make_Struct(klass, struct http_parser, &hp_type, hp); +} /** * call-seq: diff --git a/test/unit/test_http_parser.rb b/test/unit/test_http_parser.rb index 431ede5..c72f7f2 100644 --- a/test/unit/test_http_parser.rb +++ b/test/unit/test_http_parser.rb @@ -851,4 +851,18 @@ class HttpParserTest < Test::Unit::TestCase File.readable?(LINUX_PROC_PID_STATUS) && !defined?(RUBY_ENGINE) + def test_memsize + require 'objspace' + if ObjectSpace.respond_to?(:memsize_of) + n = ObjectSpace.memsize_of(Unicorn::HttpParser.new) + assert_kind_of Integer, n + # need to update this when 128-bit machines come out + # n.b. actual struct size on 64-bit is 56 bytes + 40 bytes for RVALUE + # Ruby <= 2.2 objspace did not count the 40-byte RVALUE, 2.3 does. + assert_operator n, :<=, 96 + assert_operator n, :>, 0 + end + rescue LoadError + # not all Ruby implementations have objspace + end end -- cgit v1.2.3-24-ge0c7