Skip to content

Commit

Permalink
http: TypedData C-API conversion
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Eric Wong committed Dec 13, 2015
1 parent 639cc06 commit 5b5cf89
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 12 deletions.
35 changes: 23 additions & 12 deletions ext/unicorn_http/unicorn_http.rl
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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:
Expand Down
14 changes: 14 additions & 0 deletions test/unit/test_http_parser.rb
Expand Up @@ -851,4 +851,18 @@ def test_memory_leak
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

0 comments on commit 5b5cf89

Please sign in to comment.