mwrap 2.3.0 → 3.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/mwrap_rack.rb CHANGED
@@ -5,9 +5,16 @@ require 'mwrap'
5
5
  require 'rack'
6
6
  require 'cgi'
7
7
 
8
- # MwrapRack is a standalone Rack application which can be
8
+ # MwrapRack is an obsolete standalone Rack application which can be
9
9
  # mounted to run within your application process.
10
10
  #
11
+ # The embedded mwrap-httpd for Unix sockets and mwrap-rproxy for TCP
12
+ # from the Perl version <https://80x24.org/mwrap-perl.git/> replaces
13
+ # this in a non-obtrusive way for code which can't handle Ruby-level
14
+ # threads.
15
+ #
16
+ # The remaining documentation remains for historical purposes:
17
+ #
11
18
  # Using the Rack::Builder API in config.ru, you can map it to
12
19
  # the "/MWRAP/" endpoint. As with the rest of the Mwrap API,
13
20
  # your Rack server needs to be spawned with the mwrap(1)
@@ -22,10 +29,10 @@ class MwrapRack
22
29
  module HtmlResponse # :nodoc:
23
30
  def response
24
31
  [ 200, {
25
- 'Expires' => 'Fri, 01 Jan 1980 00:00:00 GMT',
26
- 'Pragma' => 'no-cache',
27
- 'Cache-Control' => 'no-cache, max-age=0, must-revalidate',
28
- 'Content-Type' => 'text/html; charset=UTF-8',
32
+ 'expires' => 'Fri, 01 Jan 1980 00:00:00 GMT',
33
+ 'pragma' => 'no-cache',
34
+ 'cache-control' => 'no-cache, max-age=0, must-revalidate',
35
+ 'content-type' => 'text/html; charset=UTF-8',
29
36
  }, self ]
30
37
  end
31
38
  end
@@ -89,56 +96,8 @@ class MwrapRack
89
96
  end
90
97
  end
91
98
 
92
- class HeapPages # :nodoc:
93
- include HtmlResponse
94
- HEADER = '<tr><th>address</th><th>generation</th></tr>'
95
-
96
- def hpb_rows
97
- Mwrap::HeapPageBody.stat(stat = Thread.current[:mwrap_hpb_stat] ||= {})
98
- %i(lifespan_max lifespan_min lifespan_mean lifespan_stddev
99
- deathspan_max deathspan_min deathspan_mean deathspan_stddev
100
- resurrects
101
- ).map! do |k|
102
- "<tr><td>#{k}</td><td>#{stat[k]}</td></tr>\n"
103
- end.join
104
- end
105
-
106
- def gc_stat_rows
107
- GC.stat(stat = Thread.current[:mwrap_gc_stat] ||= {})
108
- %i(count heap_allocated_pages heap_eden_pages heap_tomb_pages
109
- total_allocated_pages total_freed_pages).map do |k|
110
- "<tr><td>GC.stat(:#{k})</td><td>#{stat[k]}</td></tr>\n"
111
- end.join
112
- end
113
-
114
- GC_STAT_URL = 'https://docs.ruby-lang.org/en/trunk/GC.html#method-c-stat'
115
- GC_STAT_HELP = <<~EOM
116
- <p>Non-Infinity lifespans can indicate fragmentation.
117
- <p>See <a
118
- href="#{GC_STAT_URL}">#{GC_STAT_URL}</a> for info on GC.stat values.
119
- EOM
120
-
121
- def each
122
- Mwrap.quiet do
123
- yield("<html><head><title>heap pages</title></head>" \
124
- "<body><h1>heap pages</h1>" \
125
- "<table><tr><th>stat</th><th>value</th></tr>\n" \
126
- "#{hpb_rows}" \
127
- "#{gc_stat_rows}" \
128
- "</table>\n" \
129
- "#{GC_STAT_HELP}" \
130
- "<table>#{HEADER}")
131
- Mwrap::HeapPageBody.each do |addr, generation|
132
- addr = -sprintf('0x%x', addr)
133
- yield(-"<tr><td>#{addr}</td><td>#{generation}</td></tr>\n")
134
- end
135
- yield "</table></body></html>\n"
136
- end
137
- end
138
- end
139
-
140
99
  def r404 # :nodoc:
141
- [404,{'Content-Type'=>'text/plain'},["Not found\n"]]
100
+ [404,{'content-type'=>'text/plain'},["Not found\n"]]
142
101
  end
143
102
 
144
103
  # The standard Rack application endpoint for MwrapRack
@@ -152,17 +111,14 @@ class MwrapRack
152
111
  loc = -CGI.unescape($1)
153
112
  loc = Mwrap[loc] or return r404
154
113
  EachAt.new(loc).response
155
- when '/heap_pages'
156
- HeapPages.new.response
157
114
  when '/'
158
115
  n = 2000
159
116
  u = 'https://80x24.org/mwrap/README.html'
160
117
  b = -('<html><head><title>Mwrap demo</title></head>' \
161
118
  "<body><p><a href=\"each/#{n}\">allocations &gt;#{n} bytes</a>" \
162
119
  "<p><a href=\"#{u}\">#{u}</a>" \
163
- "<p><a href=\"heap_pages\">heap pages</a>" \
164
120
  "</body></html>\n")
165
- [ 200, {'Content-Type'=>'text/html','Content-Length'=>-b.size.to_s},[b]]
121
+ [ 200, {'content-type'=>'text/html','content-length'=>-b.size.to_s},[b]]
166
122
  else
167
123
  r404
168
124
  end
data/mwrap.gemspec CHANGED
@@ -1,6 +1,5 @@
1
1
  git_manifest = `git ls-files 2>/dev/null`.split("\n")
2
2
  git_ok = $?.success?
3
- git_manifest << 'lib/mwrap/version.rb'.freeze # generated by ./VERSION-GEN
4
3
  manifest = File.exist?('MANIFEST') ?
5
4
  File.readlines('MANIFEST').map!(&:chomp).delete_if(&:empty?) : git_manifest
6
5
  if git_ok && manifest != git_manifest
@@ -12,11 +11,19 @@ end
12
11
 
13
12
  version = `./VERSION-GEN`.chomp
14
13
  $?.success? or abort './VERSION-GEN failed'
14
+ manifest << 'lib/mwrap/version.rb'.freeze
15
+
16
+ if system(*%w(make -C Documentation man)) ||
17
+ system(*%w(gmake -C Documentation man))
18
+ manifest.concat(%w(Documentation/mwrap.1))
19
+ else
20
+ warn 'failed to build man-page(s), proceeding without them'
21
+ end
15
22
 
16
23
  Gem::Specification.new do |s|
17
24
  s.name = 'mwrap'
18
25
  s.version = version
19
- s.homepage = 'https://80x24.org/mwrap/'
26
+ s.homepage = 'https://80x24.org/mwrap.git/'
20
27
  s.authors = ["mwrap hackers"]
21
28
  s.summary = 'LD_PRELOAD malloc wrapper for Ruby'
22
29
  s.executables = %w(mwrap)
@@ -31,5 +38,5 @@ source location of such calls and bytes allocated at each callsite.
31
38
 
32
39
  s.add_development_dependency('test-unit', '~> 3.0')
33
40
  s.add_development_dependency('rake-compiler', '~> 1.0')
34
- s.licenses = %w(GPL-2.0+)
41
+ s.licenses = %w(GPL-3.0+)
35
42
  end
data/t/httpd.t ADDED
@@ -0,0 +1,191 @@
1
+ #!perl -w
2
+ # Copyright (C) mwrap hackers <mwrap-perl@80x24.org>
3
+ # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
4
+ use v5.12;
5
+ use IO::Socket::UNIX;
6
+ use Fcntl qw(F_GETFD F_SETFD FD_CLOEXEC);
7
+ use POSIX qw(dup2 _exit mkfifo);
8
+ BEGIN { require './t/test_common.perl' };
9
+ my $env = { MWRAP => "socket_dir:$mwrap_tmp" };
10
+ my $f1 = "$mwrap_tmp/f1";
11
+ my $f2 = "$mwrap_tmp/f2";
12
+ mkfifo($f1, 0600) // plan(skip_all => "mkfifo: $!");
13
+ mkfifo($f2, 0600) // plan(skip_all => "mkfifo: $!");
14
+ my $src = $mwrap_src ? # $mwrap_src is Perl-only, Ruby otherwise
15
+ "open my \$f1, '>', '$f1'; close \$f1; open my \$f2, '<', '$f2'" :
16
+ "File.open('$f1', 'w').close; File.open('$f2', 'r').close";
17
+ my $pid = mwrap_run('httpd test', $env, '-e', $src);
18
+ my $spid;
19
+ my $mw_exit;
20
+ my $cleanup = sub {
21
+ if (defined $spid) {
22
+ if (kill('TERM', $spid)) {
23
+ waitpid($spid, 0);
24
+ $? == 0 or warn "rproxy died with \$?=$?";
25
+ } else {
26
+ warn "kill $spid: $!";
27
+ }
28
+ undef $spid;
29
+ }
30
+ use autodie;
31
+ if (defined $pid) {
32
+ my $exit = $?;
33
+ open my $fh, '>', $f2;
34
+ close $fh;
35
+ waitpid($pid, 0);
36
+ $mw_exit = $?;
37
+ undef $pid;
38
+ diag "err: ".slurp($mwrap_err);
39
+ $? = $exit;
40
+ }
41
+ };
42
+ END { $cleanup->() }
43
+
44
+ my $sock = "$mwrap_tmp/$pid.sock";
45
+ my %o = (Peer => $sock , Type => SOCK_STREAM);
46
+ local $SIG{PIPE} = 'IGNORE';
47
+
48
+ open my $fh, '<', $f1;
49
+ is(my $nil = <$fh>, undef, 'FIFO open');
50
+ close $fh;
51
+ ok(-S $sock, 'socket created');
52
+ my $c = IO::Socket::UNIX->new(%o);
53
+ ok($c, 'socket connected');
54
+ is(send($c, 'GET', MSG_NOSIGNAL), 3, 'trickled 3 bytes') or diag "send: $!";
55
+
56
+ my $cout = "$mwrap_tmp/cout";
57
+ my @curl = (qw(curl -sf --unix-socket), $sock, '-o', $cout);
58
+ push @curl, '-vS' if $ENV{V};
59
+ my $rc = system(@curl, "http://0/$pid/each/2000");
60
+ my $curl_unix;
61
+ SKIP: {
62
+ skip 'curl lacks --unix-socket support', 1 if $rc == 512;
63
+ is($rc, 0, 'curl /each');
64
+ unlink($cout);
65
+ $curl_unix = 1;
66
+
67
+ $rc = system(@curl, "http://0/$pid/each/2000");
68
+ is($rc, 0, 'curl /each');
69
+ unlink($cout);
70
+
71
+ $rc = system(@curl, "http://0/$pid/");
72
+ is($rc, 0, 'curl / (PID root)');
73
+ like(slurp($cout), qr/<html>/, 'root shown');
74
+
75
+ $rc = system(@curl, '-XPOST', "http://0/$pid/trim");
76
+ is($rc, 0, 'curl / (PID root)');
77
+ like(slurp($cout), qr/trimming/, 'trim started');
78
+ unlink($cout);
79
+ };
80
+
81
+ {
82
+ my $req = " /$pid/each/20000 HTTP/1.0\r\n\r\n";
83
+ is(send($c, $req, MSG_NOSIGNAL), length($req),
84
+ 'wrote rest of response') or diag "send: $!";
85
+ my $x = do { local $/; <$c> } or diag "readline: $!";
86
+ like($x, qr!</html>\n?\z!s, 'got complete HTML response');
87
+ }
88
+
89
+ SKIP: {
90
+ my (@rproxy, @missing);
91
+ if (-e 'script/mwrap-rproxy') { # Perl version
92
+ @rproxy = ($^X, '-w', './blib/script/mwrap-rproxy');
93
+ } else {
94
+ my $exe = `which mwrap-rproxy`;
95
+ if ($? == 0 && defined($exe)) {
96
+ chomp($rproxy[0] = $exe);
97
+ } else {
98
+ push @missing, 'mwrap-rproxy';
99
+ }
100
+ }
101
+ for my $m (qw(Plack::Util HTTP::Tiny)) {
102
+ eval "require $m" or push(@missing, $m);
103
+ }
104
+ skip join(', ', @missing).' missing', 1 if @missing;
105
+ my $srv = IO::Socket::INET->new(LocalAddr => '127.0.0.1',
106
+ ReuseAddr => 1, Proto => 'tcp',
107
+ Type => SOCK_STREAM,
108
+ Listen => 1024);
109
+ $spid = fork;
110
+ if ($spid == 0) {
111
+ local $ENV{LISTEN_PID} = $$;
112
+ local $ENV{LISTEN_FDS} = 1;
113
+ my $fl = fcntl($srv, F_GETFD, 0);
114
+ fcntl($srv, F_SETFD, $fl &= ~FD_CLOEXEC);
115
+ if (fileno($srv) != 3) {
116
+ dup2(fileno($srv), 3) or die "dup2: $!";
117
+ }
118
+ local $ENV{PLACK_ENV} = 'deployment' if !$ENV{V};
119
+ no warnings 'exec';
120
+ exec @rproxy, "--socket-dir=$mwrap_tmp";
121
+ _exit(1);
122
+ }
123
+ my $http = HTTP::Tiny->new;
124
+ my ($h, $p) = ($srv->sockhost, $srv->sockport);
125
+ undef $srv;
126
+ my $res = $http->get("http://$h:$p/");
127
+ ok($res->{success}, 'listing success');
128
+ like($res->{content}, qr!/$pid/each/\d+!, 'got listing for each');
129
+ $res = $http->get("http://$h:$p/$pid/each/1");
130
+ ok($res->{success}, 'each/1 success');
131
+ my $t = '/at/$LOCATION link in /each/$NUM';
132
+ if ($res->{content} =~ m!href="\.\./at/([^"]+)"!) {
133
+ my $loc = $1;
134
+ ok($t);
135
+ $res = $http->get("http://$h:$p/$pid/at/$1");
136
+ ok($res->{success}, '/at/$LOCATION endpoint');
137
+ like($res->{content}, qr!\blive allocations at\b!,
138
+ 'live allocations shown');
139
+ } else {
140
+ fail($t);
141
+ }
142
+ if ($ENV{INTERACTIVE}) {
143
+ diag "http://$h:$p/$pid/each/1 up for interactive testing";
144
+ diag "- press Enter when done -";
145
+ my $ok = <STDIN>;
146
+ }
147
+ }
148
+
149
+ SKIP: {
150
+ skip 'no reset w/o curl --unix-socket', 1 if !$curl_unix;
151
+ my ($sqlite_v) = (`sqlite3 --version` =~ /([\d+\.]+)/);
152
+ if ($?) {
153
+ diag 'sqlite3 missing or broken';
154
+ $sqlite_v = 0;
155
+ } else {
156
+ my @v = split(/\./, $sqlite_v);
157
+ $sqlite_v = ($v[0] << 16) | ($v[1] << 8) | $v[2];
158
+ diag 'sqlite_v='.sprintf('0x%x', $sqlite_v);
159
+ }
160
+ $rc = system(@curl, "http://0/$pid/each/100.csv");
161
+ is($rc, 0, '.csv retrieved') or skip 'CSV failed', 1;
162
+ my $db = "$mwrap_tmp/t.sqlite3";
163
+
164
+ if ($sqlite_v >= 0x32000) {
165
+ $rc = system(qw(sqlite3), $db,".import --csv $cout mwrap_each");
166
+ is($rc, 0, 'sqlite3 import');
167
+ my $n = `sqlite3 $db 'SELECT COUNT(*) FROM mwrap_each'`;
168
+ is($?, 0, 'sqlite3 count');
169
+ my $exp = split(/\n/, slurp($cout));
170
+ is($n + 1, $exp, 'imported all rows into sqlite');
171
+ } else {
172
+ diag "sqlite 3.32.0+ needed for `.import --csv'";
173
+ }
174
+
175
+ $rc = system(@curl, qw(-d x=y), "http://0/$pid/reset");
176
+ is($rc, 0, 'curl /reset');
177
+ $rc = system(@curl, qw(-HX-Mwrap-BT:10 -XPOST),
178
+ "http://0/$pid/ctl");
179
+ is($rc, 0, 'curl /ctl (X-Mwrap-BT)');
180
+ like(slurp($cout), qr/\bMWRAP=bt:10\b/, 'changed bt depth');
181
+
182
+ $rc = system(@curl, qw(-HX-Mwrap-BT:10 -d blah http://0/ctl));
183
+ is($rc >> 8, 22, '404 w/o PID prefix');
184
+ };
185
+
186
+
187
+ diag slurp($cout) if $ENV{V};
188
+ $cleanup->();
189
+ ok(!-e $sock, 'socket unlinked after cleanup');
190
+ is($mw_exit, 0, 'perl exited with $?==0');
191
+ done_testing;
@@ -0,0 +1,54 @@
1
+ #!perl -w
2
+ # Copyright (C) mwrap hackers <mwrap-perl@80x24.org>
3
+ # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
4
+ package MwrapTest;
5
+ use v5.12;
6
+ use parent qw(Exporter);
7
+ use Test::More;
8
+ use File::Temp 0.19 (); # 0.19 for ->newdir
9
+ our $mwrap_src;
10
+ $mwrap_src = slurp('blib/script/mwrap-perl') if -e 'script/mwrap-perl';
11
+ our $mwrap_tmp = File::Temp->newdir('mwrap-XXXX', TMPDIR => 1);
12
+ our $mwrap_out = "$mwrap_tmp/out";
13
+ our $mwrap_err = "$mwrap_tmp/err";
14
+ our @EXPORT = qw(mwrap_run slurp $mwrap_err $mwrap_out $mwrap_src $mwrap_tmp);
15
+
16
+ sub slurp {
17
+ open my $fh, '<', $_[0] or die "open($_[0]): $!";
18
+ local $/;
19
+ <$fh>;
20
+ }
21
+
22
+ sub mwrap_run {
23
+ my ($msg, $env, @args) = @_;
24
+ my $pid = fork;
25
+ if ($pid == 0) {
26
+ while (my ($k, $v) = each %$env) {
27
+ $ENV{$k} = $v;
28
+ }
29
+ open STDERR, '>', $mwrap_err or die "open: $!";
30
+ open STDOUT, '>', $mwrap_out or die "open: $!";
31
+ if (defined $mwrap_src) {
32
+ unless (grep(/\A-.+\bMwrap\b/, @args)) {
33
+ unshift @args, '-MDevel::Mwrap';
34
+ }
35
+ @ARGV = ($^X, @args);
36
+ eval $mwrap_src;
37
+ } else {
38
+ my $ruby = $ENV{RUBY} // 'ruby';
39
+ exec $ruby, '-Ilib', 'bin/mwrap', $ruby, @args;
40
+ }
41
+ die "fail: $! ($@)";
42
+ }
43
+ if (defined(wantarray)) {
44
+ return $pid if !wantarray;
45
+ die "BUG: list return value not supported\n";
46
+ }
47
+ waitpid($pid, 0);
48
+ is($?, 0, $msg);
49
+ diag "err: ".slurp($mwrap_err) if $?;
50
+ }
51
+ package main;
52
+ MwrapTest->import;
53
+ Test::More->import;
54
+ 1;
data/test/test_mwrap.rb CHANGED
@@ -5,6 +5,8 @@ require 'test/unit'
5
5
  require 'mwrap'
6
6
  require 'rbconfig'
7
7
  require 'tempfile'
8
+ require 'io/wait'
9
+ require 'tmpdir'
8
10
 
9
11
  class TestMwrap < Test::Unit::TestCase
10
12
  RB = "#{RbConfig::CONFIG['bindir']}/#{RbConfig::CONFIG['RUBY_INSTALL_NAME']}"
@@ -59,13 +61,6 @@ class TestMwrap < Test::Unit::TestCase
59
61
  res = system(env, *cmd)
60
62
  assert res, $?.inspect
61
63
  assert_match(/\b1\d{4}\s+[1-9]\d*\s+-e:1$/, tmp.read)
62
-
63
- tmp.rewind
64
- tmp.truncate(0)
65
- env['MWRAP'] = "dump_path:#{tmp.path},dump_heap:5"
66
- res = system(env, *cmd)
67
- assert res, $?.inspect
68
- assert_match %r{lifespan_stddev}, tmp.read
69
64
  end
70
65
  end
71
66
 
@@ -85,6 +80,15 @@ class TestMwrap < Test::Unit::TestCase
85
80
  assert_match(/\b0x[a-f0-9]+\b/s, dump, 'dump output has addresses')
86
81
  end
87
82
 
83
+ def test_spawn_non_ruby
84
+ Dir.mktmpdir do |dir|
85
+ sockdir = "#{dir}/sockdir"
86
+ env = @@env.merge('MWRAP' => "socket_dir:#{sockdir}")
87
+ out = IO.popen(env, %w(ls -alR), { chdir: dir }, &:read)
88
+ assert_match(/\b\d+\.sock\b/, out)
89
+ end
90
+ end
91
+
88
92
  def test_clear
89
93
  cmd = @@cmd + %w(
90
94
  -e ("0"*10000).clear
@@ -122,31 +126,41 @@ class TestMwrap < Test::Unit::TestCase
122
126
 
123
127
  # some URCU flavors use USR1, ensure the one we choose does not
124
128
  def test_sigusr1_works
129
+ err = Tempfile.new('dump')
125
130
  cmd = @@cmd + %w(
126
131
  -e STDOUT.sync=true
127
- -e trap(:USR1){p("HELLO_WORLD")}
132
+ -e trap(:USR1){STDOUT.syswrite("HELLO_WORLD\n")}
128
133
  -e END{Mwrap.dump}
129
- -e puts -e STDIN.read)
134
+ -e puts("HI")
135
+ -e STDIN.read)
130
136
  IO.pipe do |r, w|
131
137
  IO.pipe do |r2, w2|
132
- pid = spawn(@@env, *cmd, in: r2, out: w, err: '/dev/null')
138
+ pid = spawn(@@env, *cmd, in: r2, out: w, err: err)
133
139
  r2.close
134
140
  w.close
135
- assert_equal "\n", r.gets
141
+ assert_equal "HI\n", r.gets, '#puts HI fired'
136
142
  buf = +''
137
143
  10.times { Process.kill(:USR1, pid) }
138
- while IO.select([r], nil, nil, 0.1)
144
+ Thread.pass # sched_yield
145
+ while r.wait_readable(0.5)
139
146
  case tmp = r.read_nonblock(1000, exception: false)
140
- when String
141
- buf << tmp
147
+ when String; buf << tmp; break
148
+ when nil; break
149
+ else
150
+ warn "Unexpected read_nonblock result: #{tmp.inspect}"
142
151
  end
143
152
  end
144
- w2.close
145
- Process.wait(pid)
146
- assert_predicate $?, :success?, $?.inspect
147
- assert_equal(["\"HELLO_WORLD\"\n"], buf.split(/^/).uniq)
153
+ w2.close # break from STDERR.read
154
+ _, st = Process.wait2(pid)
155
+ warn "# buf=#{buf.inspect}" if $DEBUG
156
+ assert_predicate(st, :success?,
157
+ "#{st.inspect} is success buf=#{buf.inspect} "\
158
+ "err=#{err.rewind;err.read.inspect}")
159
+ assert_equal(["HELLO_WORLD\n"], buf.split(/^/).uniq)
148
160
  end
149
161
  end
162
+ ensure
163
+ err.close! if err
150
164
  end
151
165
 
152
166
  def test_reset
@@ -257,7 +271,8 @@ class TestMwrap < Test::Unit::TestCase
257
271
  break
258
272
  end
259
273
  end
260
- addr && addr.frozen? or abort 'Mwrap.each returned unfrozen address'
274
+ addr or abort 'Mwrap.each did not see any addresses'
275
+ addr.frozen? or abort 'Mwrap.each returned unfrozen address'
261
276
  loc = Mwrap[addr] or abort "Mwrap[#{addr}] broken"
262
277
  addr == loc.name or abort 'SourceLocation#name works on address'
263
278
  loc.name.frozen? or abort 'SourceLocation#name not frozen'
@@ -295,35 +310,4 @@ class TestMwrap < Test::Unit::TestCase
295
310
  abort 'freed more than allocated'
296
311
  end;
297
312
  end
298
-
299
- def test_heap_page_body
300
- assert_separately(+"#{<<~"begin;"}\n#{<<~'end;'}")
301
- begin;
302
- require 'mwrap'
303
- require 'rubygems' # use up some memory
304
- ap = GC.stat(:heap_allocated_pages)
305
- h = {}
306
- nr = 0
307
- Mwrap::HeapPageBody.each do |addr, gen|
308
- nr += 1
309
- gen <= GC.count && gen >= 0 or abort "bad generation: #{gen}"
310
- (0 == (addr & 16383)) or abort "addr not aligned: #{'%x' % addr}"
311
- end
312
- if RUBY_VERSION.to_f < 3.1 # 3.1+ uses mmap on platforms we care about
313
- nr == ap or abort "HeapPageBody.each missed page #{nr} != #{ap}"
314
- end
315
- 10.times { (1..20000).to_a.map(&:to_s) }
316
- 3.times { GC.start }
317
- Mwrap::HeapPageBody.stat(h)
318
- Integer === h[:lifespan_max] or abort 'lifespan_max not recorded'
319
- Integer === h[:lifespan_min] or abort 'lifespan_min not recorded'
320
- Float === h[:lifespan_mean] or abort 'lifespan_mean not recorded'
321
- 3.times { GC.start }
322
- 10.times { (1..20000).to_a.map(&:to_s) }
323
- Mwrap::HeapPageBody.stat(h)
324
- h[:deathspan_min] <= h[:deathspan_max] or
325
- abort 'wrong min/max deathtime'
326
- Float === h[:deathspan_mean] or abort 'deathspan_mean not recorded'
327
- end;
328
- end
329
313
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mwrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 3.0.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - mwrap hackers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-03 00:00:00.000000000 Z
11
+ date: 2023-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-unit
@@ -52,22 +52,36 @@ files:
52
52
  - ".gitignore"
53
53
  - ".olddoc.yml"
54
54
  - COPYING
55
+ - Documentation/.gitignore
56
+ - Documentation/GNUmakefile
57
+ - Documentation/mwrap.1
58
+ - Documentation/mwrap.pod
55
59
  - MANIFEST
56
60
  - README
57
61
  - Rakefile
58
62
  - VERSION-GEN
59
63
  - bin/mwrap
64
+ - ext/mwrap/check.h
65
+ - ext/mwrap/dlmalloc_c.h
60
66
  - ext/mwrap/extconf.rb
67
+ - ext/mwrap/gcc.h
68
+ - ext/mwrap/httpd.h
61
69
  - ext/mwrap/jhash.h
62
70
  - ext/mwrap/mwrap.c
71
+ - ext/mwrap/mwrap_core.h
72
+ - ext/mwrap/mymalloc.h
73
+ - ext/mwrap/picohttpparser.h
74
+ - ext/mwrap/picohttpparser_c.h
63
75
  - lib/mwrap/.gitignore
64
76
  - lib/mwrap/version.rb
65
77
  - lib/mwrap_rack.rb
66
78
  - mwrap.gemspec
79
+ - t/httpd.t
80
+ - t/test_common.perl
67
81
  - test/test_mwrap.rb
68
- homepage: https://80x24.org/mwrap/
82
+ homepage: https://80x24.org/mwrap.git/
69
83
  licenses:
70
- - GPL-2.0+
84
+ - GPL-3.0+
71
85
  metadata: {}
72
86
  post_install_message:
73
87
  rdoc_options: []
@@ -80,11 +94,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
80
94
  version: '0'
81
95
  required_rubygems_version: !ruby/object:Gem::Requirement
82
96
  requirements:
83
- - - ">="
97
+ - - ">"
84
98
  - !ruby/object:Gem::Version
85
- version: '0'
99
+ version: 1.3.1
86
100
  requirements: []
87
- rubygems_version: 3.0.2
101
+ rubygems_version: 3.4.1
88
102
  signing_key:
89
103
  specification_version: 4
90
104
  summary: LD_PRELOAD malloc wrapper for Ruby