mwrap 2.1.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: abf683546f4fb8c006364863d126489983a232239dce12e98ab006a667a24220
4
- data.tar.gz: 3d23cf41c24d12f9e0422179c92389d63f90219307f9c7dfe71104cfd67e6060
3
+ metadata.gz: b967676ac9ff95d0771147fc464a06ce6a88c9a7e07c3eef97b0cf0a273ff822
4
+ data.tar.gz: f99e5f3a27adecf190e11a921a58f46c9514e28a88d83602c2421dbd8cecc90b
5
5
  SHA512:
6
- metadata.gz: 2617b3932aeb6b7b3cd72fba57b0d87513b45dee6b79c5a9c3bdf9b331e9e06757cc1c896840c8111a6f6d223cbf4fdad4d3ef4b64d8e97b3502f96e48864ed9
7
- data.tar.gz: 6eaab1b74b63c5800e0fd151a5662e3095d12f56ad228302aa8d0d733634e34e0ce3aa824003a06cc09414820660414cc21032afbf38a9eaa1c8805bd65a6000
6
+ metadata.gz: 6f3a089d3bf14258b0382d13f8d4428ffd0291d6e9af8fa33331696e5b55e5a279f0dafc30fb1018e73a199d9d3b8cbe826dd814dfd80941ae059581fa6f330c
7
+ data.tar.gz: 54a2bc06918d050e161ff0c9457ca67ebc3573a5795495d5ab57637d0bb37830e442f3073cede28d672938baaba7e7057b9d0fa8f40c64b85864add6e81e53d0
data/.document CHANGED
@@ -1,2 +1,3 @@
1
1
  ext/mwrap/mwrap.c
2
2
  lib/mwrap_rack.rb
3
+ README
data/.gitignore CHANGED
@@ -4,3 +4,6 @@
4
4
  /pkg
5
5
  /*.gem
6
6
  /doc
7
+ /NEWS
8
+ /NEWS.atom.xml
9
+ /LATEST
data/.olddoc.yml CHANGED
@@ -5,4 +5,6 @@ rdoc_url: https://80x24.org/mwrap/
5
5
  ml_url: https://80x24.org/mwrap-public/
6
6
  public_email: mwrap-public@80x24.org
7
7
  nntp_url:
8
- - nntp://news.public-inbox.org/inbox.comp.lang.ruby.mwrap
8
+ - nntps://news.public-inbox.org/inbox.comp.lang.ruby.mwrap
9
+ imap_url:
10
+ - imaps://;AUTH=ANONYMOUS@80x24.org/inbox.comp.lang.ruby.mwrap.0
data/MANIFEST CHANGED
@@ -5,10 +5,13 @@ COPYING
5
5
  MANIFEST
6
6
  README
7
7
  Rakefile
8
+ VERSION-GEN
8
9
  bin/mwrap
9
10
  ext/mwrap/extconf.rb
10
11
  ext/mwrap/jhash.h
11
12
  ext/mwrap/mwrap.c
13
+ lib/mwrap/.gitignore
12
14
  lib/mwrap_rack.rb
13
15
  mwrap.gemspec
14
16
  test/test_mwrap.rb
17
+ lib/mwrap/version.rb
data/README CHANGED
@@ -23,7 +23,7 @@ It does not require recompiling or rebuilding Ruby, but only
23
23
  supports Ruby trunk (2.6.0dev+) on a few platforms:
24
24
 
25
25
  * GNU/Linux
26
- * FreeBSD (tested 11.1)
26
+ * FreeBSD (tested 11.1 on Ruby 2.6, currently broken with Ruby 3.x)
27
27
 
28
28
  It may work on NetBSD, OpenBSD and DragonFly BSD.
29
29
 
@@ -67,16 +67,18 @@ first two columns to find the hottest malloc locations.
67
67
  mwrap 2.0.0+ also supports a Rack application endpoint,
68
68
  it is documented at:
69
69
 
70
- https://80x24.org/mwrap/MwrapRack.html
70
+ https://80x24.org/mwrap/MwrapRack.html
71
71
 
72
72
  == Known problems
73
73
 
74
74
  * 32-bit machines are prone to overflow (WONTFIX)
75
75
 
76
- == Mail archives and list:
76
+ == Public mail archives and contact info:
77
77
 
78
- https://80x24.org/mwrap-public/
79
- nntp://80x24.org/inbox.comp.lang.ruby.mwrap
78
+ * https://80x24.org/mwrap-public/
79
+ * nntps://80x24.org/inbox.comp.lang.ruby.mwrap
80
+ * imaps://;AUTH=ANONYMOUS@80x24.org/inbox.comp.lang.ruby.mwrap.0
81
+ * https://80x24.org/mwrap-public/_/text/help/#pop3
80
82
 
81
83
  No subscription will ever be required to post, but HTML mail
82
84
  will be rejected:
@@ -88,7 +90,7 @@ will be rejected:
88
90
  git clone https://80x24.org/mwrap.git
89
91
 
90
92
  Send all patches and pull requests (use "git request-pull" to format) to
91
- the mailing list. We do not use centralized or proprietary messaging
93
+ mwrap-public@80x24.org. We do not use centralized or proprietary messaging
92
94
  systems.
93
95
 
94
96
  == License
data/Rakefile CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2018 mwrap hackers <mwrap-public@80x24.org>
1
+ # Copyright (C) mwrap hackers <mwrap-public@80x24.org>
2
2
  # License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
3
3
  require 'rake/testtask'
4
4
  begin
@@ -14,3 +14,31 @@ task :default => :compile
14
14
 
15
15
  c_files = File.readlines('MANIFEST').grep(%r{ext/.*\.[ch]$}).map!(&:chomp!)
16
16
  task 'compile:mwrap' => c_files
17
+
18
+ olddoc = ENV['OLDDOC'] || 'olddoc'
19
+ rdoc = ENV['RDOC'] || 'rdoc'
20
+ task :rsync_docs do
21
+ require 'fileutils'
22
+ top = %w(README COPYING LATEST NEWS NEWS.atom.xml)
23
+ system("git", "set-file-times")
24
+ dest = ENV["RSYNC_DEST"] || "80x24.org:/srv/80x24/mwrap/"
25
+ FileUtils.rm_rf('doc')
26
+ sh "#{olddoc} prepare"
27
+ sh "#{rdoc} -f dark216" # dark216 requires olddoc 1.7+
28
+ File.unlink('doc/created.rid') rescue nil
29
+ File.unlink('doc/index.html') rescue nil
30
+ FileUtils.cp(top, 'doc')
31
+ sh "#{olddoc} merge"
32
+
33
+ Dir['doc/**/*'].each do |txt|
34
+ st = File.stat(txt)
35
+ if st.file?
36
+ gz = "#{txt}.gz"
37
+ tmp = "#{gz}.#$$"
38
+ sh("gzip --rsyncable -9 <#{txt} >#{tmp}")
39
+ File.utime(st.atime, st.mtime, tmp) # make nginx gzip_static happy
40
+ File.rename(tmp, gz)
41
+ end
42
+ end
43
+ sh("rsync --chmod=Fugo=r #{ENV['RSYNC_OPT']} -av doc/ #{dest}/")
44
+ end
data/VERSION-GEN ADDED
@@ -0,0 +1,36 @@
1
+ #!/bin/sh
2
+ VF=lib/mwrap/version.rb
3
+ DEF_VER=v2.3.0
4
+ VN=$(git describe HEAD 2>/dev/null)
5
+ if test $? -eq 0
6
+ then
7
+ case "$VN" in
8
+ v[0-9]*)
9
+ set -e
10
+ git update-index -q --refresh
11
+ set +e
12
+ git diff-index --quiet HEAD -- || VN="$VN-dirty"
13
+ set -e
14
+ VN=$(echo $VN | tr '-' '.')
15
+ ;;
16
+ esac
17
+ fi
18
+ set -e
19
+
20
+ case $VN in
21
+ '') VN="$DEF_VER" ;;
22
+ esac
23
+
24
+ VN=$(expr "$VN" : v*'\(.*\)')
25
+ VC=unset
26
+ if test -r $VF
27
+ then
28
+ VC="$(cat $VF)"
29
+ fi
30
+
31
+ new="module Mwrap; VERSION = '$VN'.freeze; end"
32
+ if test x"$new" != x"$VC"
33
+ then
34
+ echo "$new" >$VF
35
+ fi
36
+ echo $VN
data/bin/mwrap CHANGED
@@ -1,7 +1,26 @@
1
1
  #!/usr/bin/ruby
2
2
  # frozen_string_literal: true
3
- # Copyright (C) 2018 mwrap hackers <mwrap-public@80x24.org>
3
+ # Copyright (C) mwrap hackers <mwrap-public@80x24.org>
4
4
  # License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
5
+ help = <<EOM
6
+ usage: mwrap COMMAND [ARGS]
7
+ see https://80x24.org/mwrap/README.html for more info
8
+ EOM
9
+ ARGV.empty? and abort help
10
+ ARGV.each do |x|
11
+ case x
12
+ when '--version', '-v'
13
+ require 'mwrap/version'
14
+ puts "mwrap #{Mwrap::VERSION} - #{RUBY_DESCRIPTION}"
15
+ exit 0
16
+ when '--help', '-h'
17
+ puts help
18
+ exit 0
19
+ else # don't intercept --version/--help intended for commands we wrap
20
+ break
21
+ end
22
+ end
23
+
5
24
  require 'mwrap'
6
25
  mwrap_so = $".grep(%r{/mwrap\.so\z})[0] or abort "mwrap.so not loaded"
7
26
  cur = ENV['LD_PRELOAD']
data/ext/mwrap/extconf.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- # Copyright (C) 2018 mwrap hackers <mwrap-public@80x24.org>
2
+ # Copyright (C) mwrap hackers <mwrap-public@80x24.org>
3
3
  # License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
4
4
  require 'mkmf'
5
5
 
@@ -11,18 +11,25 @@ have_library 'dl'
11
11
  have_library 'c'
12
12
  have_library 'execinfo' # FreeBSD
13
13
 
14
- if try_link(<<'')
14
+ if try_link(<<EOC)
15
15
  int main(void) { return __builtin_add_overflow_p(0,0,(int)1); }
16
-
16
+ EOC
17
17
  $defs << '-DHAVE_BUILTIN_ADD_OVERFLOW_P'
18
18
  end
19
19
 
20
- if try_link(<<'')
20
+ if try_link(<<EOC)
21
21
  int main(int a) { return __builtin_add_overflow(0,0,&a); }
22
-
22
+ EOC
23
23
  $defs << '-DHAVE_BUILTIN_ADD_OVERFLOW_P'
24
24
  else
25
25
  abort 'missing __builtin_add_overflow'
26
26
  end
27
27
 
28
+ begin
29
+ if n = GC::INTERNAL_CONSTANTS[:HEAP_PAGE_SIZE]
30
+ $defs << "-DHEAP_PAGE_SIZE=#{n}"
31
+ end
32
+ rescue NameError
33
+ end
34
+
28
35
  create_makefile 'mwrap'
data/ext/mwrap/mwrap.c CHANGED
@@ -1,9 +1,9 @@
1
1
  /*
2
- * Copyright (C) 2018 mwrap hackers <mwrap-public@80x24.org>
2
+ * Copyright (C) mwrap hackers <mwrap-public@80x24.org>
3
3
  * License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
4
4
  */
5
5
  #define _LGPL_SOURCE /* allows URCU to inline some stuff */
6
- #include <ruby/ruby.h>
6
+ #include <ruby.h> /* defines HAVE_RUBY_RACTOR_H on 3.0+ */
7
7
  #include <ruby/thread.h>
8
8
  #include <ruby/io.h>
9
9
  #include <execinfo.h>
@@ -22,15 +22,29 @@
22
22
  #include <urcu/rculist.h>
23
23
  #include "jhash.h"
24
24
 
25
+ #if __STDC_VERSION__ >= 201112
26
+ # define MWRAP_TSD _Thread_local
27
+ #elif defined(__GNUC__)
28
+ # define MWRAP_TSD __thread
29
+ #else
30
+ # error _Thread_local nor __thread supported
31
+ #endif
32
+
25
33
  static ID id_uminus;
26
34
  const char *rb_source_location_cstr(int *line); /* requires 2.6.0dev */
27
- extern int __attribute__((weak)) ruby_thread_has_gvl_p(void);
35
+
36
+ #ifdef HAVE_RUBY_RACTOR_H /* Ruby 3.0+ */
37
+ extern MWRAP_TSD void * __attribute__((weak)) ruby_current_ec;
38
+ #else /* Ruby 2.6-2.7 */
28
39
  extern void * __attribute__((weak)) ruby_current_execution_context_ptr;
40
+ # define ruby_current_ec ruby_current_execution_context_ptr
41
+ #endif
29
42
  extern void * __attribute__((weak)) ruby_current_vm_ptr; /* for rb_gc_count */
30
43
  extern size_t __attribute__((weak)) rb_gc_count(void);
31
44
  extern VALUE __attribute__((weak)) rb_cObject;
32
45
  extern VALUE __attribute__((weak)) rb_eTypeError;
33
46
  extern VALUE __attribute__((weak)) rb_yield(VALUE);
47
+ int __attribute__((weak)) ruby_thread_has_gvl_p(void);
34
48
 
35
49
  static size_t total_bytes_inc, total_bytes_dec;
36
50
 
@@ -40,18 +54,16 @@ static size_t total_bytes_inc, total_bytes_dec;
40
54
  /* match values in Ruby gc.c */
41
55
  #define HEAP_PAGE_ALIGN_LOG 14
42
56
  enum {
43
- HEAP_PAGE_ALIGN = (1UL << HEAP_PAGE_ALIGN_LOG),
57
+ HEAP_PAGE_ALIGN = (1UL << HEAP_PAGE_ALIGN_LOG)
58
+ #ifndef HEAP_PAGE_SIZE /* Ruby 2.6-2.7 only */
59
+ ,
44
60
  REQUIRED_SIZE_BY_MALLOC = (sizeof(size_t) * 5),
45
61
  HEAP_PAGE_SIZE = (HEAP_PAGE_ALIGN - REQUIRED_SIZE_BY_MALLOC)
62
+ #endif
46
63
  };
47
64
 
48
65
  #define IS_HEAP_PAGE_BODY ((struct src_loc *)-1)
49
66
 
50
- int __attribute__((weak)) ruby_thread_has_gvl_p(void)
51
- {
52
- return 0;
53
- }
54
-
55
67
  #ifdef __FreeBSD__
56
68
  void *__malloc(size_t);
57
69
  void __free(void *);
@@ -75,7 +87,7 @@ static int resolving_malloc;
75
87
  } \
76
88
  } while (0)
77
89
 
78
- static __thread size_t locating;
90
+ static MWRAP_TSD size_t locating;
79
91
  static size_t generation;
80
92
  static size_t page_size;
81
93
  static struct cds_lfht *totals;
@@ -87,9 +99,43 @@ union padded_mutex {
87
99
  /* a round-robin pool of mutexes */
88
100
  #define MUTEX_NR (1 << 6)
89
101
  #define MUTEX_MASK (MUTEX_NR - 1)
102
+ #ifdef __FreeBSD__
103
+ # define STATIC_MTX_INIT_OK (0)
104
+ #else /* only tested on Linux + glibc */
105
+ # define STATIC_MTX_INIT_OK (1)
106
+ #endif
90
107
  static size_t mutex_i;
91
108
  static union padded_mutex mutexes[MUTEX_NR] = {
109
+ #if STATIC_MTX_INIT_OK
92
110
  [0 ... (MUTEX_NR-1)].mtx = PTHREAD_MUTEX_INITIALIZER
111
+ #endif
112
+ };
113
+
114
+ #define ACC_INIT(name) { .nr=0, .min=INT64_MAX, .max=-1, .m2=0, .mean=0 }
115
+ struct acc {
116
+ uint64_t nr;
117
+ int64_t min;
118
+ int64_t max;
119
+ double m2;
120
+ double mean;
121
+ };
122
+
123
+ /* for tracking 16K-aligned heap page bodies (protected by GVL) */
124
+ struct {
125
+ pthread_mutex_t lock;
126
+ struct cds_list_head bodies;
127
+ struct cds_list_head freed;
128
+
129
+ struct acc alive;
130
+ struct acc reborn;
131
+ } hpb_stats = {
132
+ #if STATIC_MTX_INIT_OK
133
+ .lock = PTHREAD_MUTEX_INITIALIZER,
134
+ #endif
135
+ .bodies = CDS_LIST_HEAD_INIT(hpb_stats.bodies),
136
+ .freed = CDS_LIST_HEAD_INIT(hpb_stats.freed),
137
+ .alive = ACC_INIT(hpb_stats.alive),
138
+ .reborn = ACC_INIT(hpb_stats.reborn)
93
139
  };
94
140
 
95
141
  static pthread_mutex_t *mutex_assign(void)
@@ -108,12 +154,11 @@ __attribute__((constructor)) static void resolve_malloc(void)
108
154
  int err;
109
155
  ++locating;
110
156
 
111
- #ifdef __FreeBSD__
112
157
  /*
113
158
  * PTHREAD_MUTEX_INITIALIZER on FreeBSD means lazy initialization,
114
159
  * which happens at pthread_mutex_lock, and that calls calloc
115
160
  */
116
- {
161
+ if (!STATIC_MTX_INIT_OK) {
117
162
  size_t i;
118
163
 
119
164
  for (i = 0; i < MUTEX_NR; i++) {
@@ -123,24 +168,30 @@ __attribute__((constructor)) static void resolve_malloc(void)
123
168
  _exit(1);
124
169
  }
125
170
  }
171
+ err = pthread_mutex_init(&hpb_stats.lock, 0);
172
+ if (err) {
173
+ fprintf(stderr, "error: %s\n", strerror(err));
174
+ _exit(1);
175
+ }
126
176
  /* initialize mutexes used by urcu-bp */
127
177
  rcu_read_lock();
128
178
  rcu_read_unlock();
179
+ #ifndef __FreeBSD__
180
+ } else {
181
+ if (!real_malloc) {
182
+ resolving_malloc = 1;
183
+ real_malloc = dlsym(RTLD_NEXT, "malloc");
184
+ }
185
+ real_free = dlsym(RTLD_NEXT, "free");
186
+ if (!real_malloc || !real_free) {
187
+ fprintf(stderr, "missing malloc/aligned_alloc/free\n"
188
+ "\t%p %p\n", real_malloc, real_free);
189
+ _exit(1);
190
+ }
191
+ #endif /* !__FreeBSD__ */
129
192
  }
130
- #else /* !FreeBSD (tested on GNU/Linux) */
131
- if (!real_malloc) {
132
- resolving_malloc = 1;
133
- real_malloc = dlsym(RTLD_NEXT, "malloc");
134
- }
135
- real_free = dlsym(RTLD_NEXT, "free");
136
- if (!real_malloc || !real_free) {
137
- fprintf(stderr, "missing malloc/aligned_alloc/free\n"
138
- "\t%p %p\n", real_malloc, real_free);
139
- _exit(1);
140
- }
141
- #endif /* !FreeBSD */
142
- totals = lfht_new();
143
- if (!totals)
193
+ CMM_STORE_SHARED(totals, lfht_new());
194
+ if (!CMM_LOAD_SHARED(totals))
144
195
  fprintf(stderr, "failed to allocate totals table\n");
145
196
 
146
197
  err = pthread_atfork(call_rcu_before_fork,
@@ -152,11 +203,18 @@ __attribute__((constructor)) static void resolve_malloc(void)
152
203
  --locating;
153
204
  }
154
205
 
206
+ #ifdef NDEBUG
207
+ #define QUIET_CC_WARNING(var) (void)var;
208
+ #else
209
+ #define QUIET_CC_WARNING(var)
210
+ #endif
211
+
155
212
  static void
156
213
  mutex_lock(pthread_mutex_t *m)
157
214
  {
158
215
  int err = pthread_mutex_lock(m);
159
216
  assert(err == 0);
217
+ QUIET_CC_WARNING(err)
160
218
  }
161
219
 
162
220
  static void
@@ -164,6 +222,7 @@ mutex_unlock(pthread_mutex_t *m)
164
222
  {
165
223
  int err = pthread_mutex_unlock(m);
166
224
  assert(err == 0);
225
+ QUIET_CC_WARNING(err)
167
226
  }
168
227
 
169
228
  #ifndef HAVE_MEMPCPY
@@ -213,36 +272,10 @@ static char *int2str(int num, char *dst, size_t * size)
213
272
  */
214
273
  static int has_ec_p(void)
215
274
  {
216
- return (ruby_thread_has_gvl_p() && ruby_current_vm_ptr &&
217
- ruby_current_execution_context_ptr);
275
+ return ruby_thread_has_gvl_p && ruby_thread_has_gvl_p() &&
276
+ ruby_current_vm_ptr && ruby_current_ec;
218
277
  }
219
278
 
220
- struct acc {
221
- uint64_t nr;
222
- int64_t min;
223
- int64_t max;
224
- double m2;
225
- double mean;
226
- };
227
-
228
- #define ACC_INIT(name) { .nr=0, .min=INT64_MAX, .max=-1, .m2=0, .mean=0 }
229
-
230
- /* for tracking 16K-aligned heap page bodies (protected by GVL) */
231
- struct {
232
- pthread_mutex_t lock;
233
- struct cds_list_head bodies;
234
- struct cds_list_head freed;
235
-
236
- struct acc alive;
237
- struct acc reborn;
238
- } hpb_stats = {
239
- .lock = PTHREAD_MUTEX_INITIALIZER,
240
- .bodies = CDS_LIST_HEAD_INIT(hpb_stats.bodies),
241
- .freed = CDS_LIST_HEAD_INIT(hpb_stats.freed),
242
- .alive = ACC_INIT(hpb_stats.alive),
243
- .reborn = ACC_INIT(hpb_stats.reborn)
244
- };
245
-
246
279
  /* allocated via real_malloc/real_free */
247
280
  struct src_loc {
248
281
  pthread_mutex_t *mtx;
@@ -367,7 +400,7 @@ acc_stddev(const struct acc *acc)
367
400
  return DBL2NUM(acc_stddev_dbl(acc));
368
401
  }
369
402
 
370
- static struct src_loc *totals_add_rcu(struct src_loc *k)
403
+ static struct src_loc *totals_add_rcu(const struct src_loc *k)
371
404
  {
372
405
  struct cds_lfht_iter iter;
373
406
  struct cds_lfht_node *cur;
@@ -375,7 +408,7 @@ static struct src_loc *totals_add_rcu(struct src_loc *k)
375
408
  struct cds_lfht *t;
376
409
 
377
410
  again:
378
- t = rcu_dereference(totals);
411
+ t = CMM_LOAD_SHARED(totals);
379
412
  if (!t) goto out_unlock;
380
413
  cds_lfht_lookup(t, k->hval, loc_eq, k, &iter);
381
414
  cur = cds_lfht_iter_get_node(&iter);
@@ -417,7 +450,7 @@ static struct src_loc *update_stats_rcu_lock(size_t size, uintptr_t caller)
417
450
  static const size_t xlen = sizeof(caller);
418
451
  char *dst;
419
452
 
420
- if (caa_unlikely(!totals)) return 0;
453
+ if (caa_unlikely(!CMM_LOAD_SHARED(totals))) return 0;
421
454
  if (locating++) goto out; /* do not recurse into another *alloc */
422
455
 
423
456
  uatomic_add(&total_bytes_inc, size);
@@ -632,9 +665,9 @@ internal_memalign(void **pp, size_t alignment, size_t size, uintptr_t caller)
632
665
  p = ptr_align(p, alignment);
633
666
  h = ptr2hdr(p);
634
667
  alloc_insert_rcu(l, h, size, real);
635
- update_stats_rcu_unlock(l);
636
668
  *pp = p;
637
669
  }
670
+ update_stats_rcu_unlock(l);
638
671
  }
639
672
 
640
673
  return real ? 0 : ENOMEM;
@@ -643,16 +676,14 @@ internal_memalign(void **pp, size_t alignment, size_t size, uintptr_t caller)
643
676
  static void *
644
677
  memalign_result(int err, void *p)
645
678
  {
646
- if (caa_unlikely(err)) {
679
+ if (caa_unlikely(err))
647
680
  errno = err;
648
- return 0;
649
- }
650
681
  return p;
651
682
  }
652
683
 
653
684
  void *memalign(size_t alignment, size_t size)
654
685
  {
655
- void *p;
686
+ void *p = NULL;
656
687
  int err = internal_memalign(&p, alignment, size, RETURN_ADDRESS(0));
657
688
  return memalign_result(err, p);
658
689
  }
@@ -667,7 +698,7 @@ void cfree(void *) __attribute__((alias("free")));
667
698
 
668
699
  void *valloc(size_t size)
669
700
  {
670
- void *p;
701
+ void *p = NULL;
671
702
  int err = internal_memalign(&p, page_size, size, RETURN_ADDRESS(0));
672
703
  return memalign_result(err, p);
673
704
  }
@@ -685,7 +716,7 @@ void *valloc(size_t size)
685
716
  void *pvalloc(size_t size)
686
717
  {
687
718
  size_t alignment = page_size;
688
- void *p;
719
+ void *p = NULL;
689
720
  int err;
690
721
 
691
722
  if (add_overflow_p(size, alignment)) {
@@ -808,7 +839,7 @@ static void *dump_to_file(void *x)
808
839
 
809
840
  ++locating;
810
841
  rcu_read_lock();
811
- t = rcu_dereference(totals);
842
+ t = CMM_LOAD_SHARED(totals);
812
843
  if (!t)
813
844
  goto out_unlock;
814
845
  cds_lfht_for_each_entry(t, &iter, l, hnode) {
@@ -877,7 +908,7 @@ static void *totals_reset(void *ign)
877
908
  uatomic_set(&total_bytes_dec, 0);
878
909
 
879
910
  rcu_read_lock();
880
- t = rcu_dereference(totals);
911
+ t = CMM_LOAD_SHARED(totals);
881
912
  cds_lfht_for_each_entry(t, &iter, l, hnode) {
882
913
  uatomic_set(&l->total, 0);
883
914
  uatomic_set(&l->allocations, 0);
@@ -945,7 +976,7 @@ static VALUE dump_each_rcu(VALUE x)
945
976
  struct cds_lfht_iter iter;
946
977
  struct src_loc *l;
947
978
 
948
- t = rcu_dereference(totals);
979
+ t = CMM_LOAD_SHARED(totals);
949
980
  cds_lfht_for_each_entry(t, &iter, l, hnode) {
950
981
  VALUE v[6];
951
982
  if (l->total <= a->min) continue;
@@ -1049,9 +1080,9 @@ static VALUE mwrap_aref(VALUE mod, VALUE loc)
1049
1080
 
1050
1081
  if (!k) return val;
1051
1082
 
1083
+ t = CMM_LOAD_SHARED(totals);
1084
+ if (!t) return val;
1052
1085
  rcu_read_lock();
1053
- t = rcu_dereference(totals);
1054
- if (!t) goto out_unlock;
1055
1086
 
1056
1087
  cds_lfht_lookup(t, k->hval, loc_eq, k, &iter);
1057
1088
  cur = cds_lfht_iter_get_node(&iter);
@@ -1059,7 +1090,6 @@ static VALUE mwrap_aref(VALUE mod, VALUE loc)
1059
1090
  l = caa_container_of(cur, struct src_loc, hnode);
1060
1091
  val = TypedData_Wrap_Struct(cSrcLoc, &src_loc_type, l);
1061
1092
  }
1062
- out_unlock:
1063
1093
  rcu_read_unlock();
1064
1094
  return val;
1065
1095
  }
@@ -0,0 +1 @@
1
+ version.rb
@@ -0,0 +1 @@
1
+ module Mwrap; VERSION = '2.3.0'.freeze; end
data/lib/mwrap_rack.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2018 all contributors <mwrap@80x24.org>
1
+ # Copyright (C) all contributors <mwrap-public@80x24.org>
2
2
  # License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
3
3
  # frozen_string_literal: true
4
4
  require 'mwrap'
@@ -17,9 +17,6 @@ require 'cgi'
17
17
  # map('/MWRAP') { run(MwrapRack.new) }
18
18
  # map('/') { run(your_normal_app) }
19
19
  #
20
- # A live demo is available at https://80x24.org/MWRAP/
21
- # (warning the demo machine is 32-bit, so counters will overflow)
22
- #
23
20
  # This module is only available in mwrap 2.0.0+
24
21
  class MwrapRack
25
22
  module HtmlResponse # :nodoc:
@@ -115,10 +112,11 @@ class MwrapRack
115
112
  end
116
113
 
117
114
  GC_STAT_URL = 'https://docs.ruby-lang.org/en/trunk/GC.html#method-c-stat'
118
- GC_STAT_HELP = <<~""
115
+ GC_STAT_HELP = <<~EOM
119
116
  <p>Non-Infinity lifespans can indicate fragmentation.
120
117
  <p>See <a
121
118
  href="#{GC_STAT_URL}">#{GC_STAT_URL}</a> for info on GC.stat values.
119
+ EOM
122
120
 
123
121
  def each
124
122
  Mwrap.quiet do
data/mwrap.gemspec CHANGED
@@ -1,20 +1,23 @@
1
1
  git_manifest = `git ls-files 2>/dev/null`.split("\n")
2
+ git_ok = $?.success?
3
+ git_manifest << 'lib/mwrap/version.rb'.freeze # generated by ./VERSION-GEN
2
4
  manifest = File.exist?('MANIFEST') ?
3
5
  File.readlines('MANIFEST').map!(&:chomp).delete_if(&:empty?) : git_manifest
4
- if git_manifest[0] && manifest != git_manifest
6
+ if git_ok && manifest != git_manifest
5
7
  tmp = "MANIFEST.#$$.tmp"
6
8
  File.open(tmp, 'w') { |fp| fp.puts(git_manifest.join("\n")) }
7
9
  File.rename(tmp, 'MANIFEST')
8
10
  system('git add MANIFEST')
9
11
  end
10
12
 
11
- desc = `git describe --abbrev=4 HEAD`.strip.tr('-', '.').delete_prefix('v')
13
+ version = `./VERSION-GEN`.chomp
14
+ $?.success? or abort './VERSION-GEN failed'
12
15
 
13
16
  Gem::Specification.new do |s|
14
17
  s.name = 'mwrap'
15
- s.version = desc.empty? ? '2.1.0' : desc
18
+ s.version = version
16
19
  s.homepage = 'https://80x24.org/mwrap/'
17
- s.authors = ["Ruby hackers"]
20
+ s.authors = ["mwrap hackers"]
18
21
  s.summary = 'LD_PRELOAD malloc wrapper for Ruby'
19
22
  s.executables = %w(mwrap)
20
23
  s.files = manifest
data/test/test_mwrap.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- # Copyright (C) 2018 mwrap hackers <mwrap-public@80x24.org>
2
+ # Copyright (C) mwrap hackers <mwrap-public@80x24.org>
3
3
  # License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
4
4
  require 'test/unit'
5
5
  require 'mwrap'
@@ -29,7 +29,8 @@ class TestMwrap < Test::Unit::TestCase
29
29
  tmp.rewind
30
30
  lines = tmp.readlines
31
31
  line_1 = lines.grep(/\s-e:1\b/)[0].strip
32
- assert_equal '10001', line_1.split(/\s+/)[0]
32
+ bytes = line_1.split(/\s+/)[0].to_i
33
+ assert_operator bytes, :>=, 10001
33
34
  end
34
35
  end
35
36
 
@@ -42,7 +43,7 @@ class TestMwrap < Test::Unit::TestCase
42
43
  res = system(env, *cmd, { 5 => tmp })
43
44
  assert res, $?.inspect
44
45
  tmp.rewind
45
- assert_match(/\b10001\s+1\s+-e:1$/, tmp.read)
46
+ assert_match(/\b1\d{4}\s+[1-9]\d*\s+-e:1$/, tmp.read)
46
47
 
47
48
  env['MWRAP'] = 'dump_fd:1,dump_min:10000'
48
49
  tmp.rewind
@@ -50,14 +51,14 @@ class TestMwrap < Test::Unit::TestCase
50
51
  res = system(env, *cmd, { 1 => tmp })
51
52
  assert res, $?.inspect
52
53
  tmp.rewind
53
- assert_match(/\b10001\s+1\s+-e:1$/, tmp.read)
54
+ assert_match(/\b1\d{4}\s+[1-9]\d*\s+-e:1$/, tmp.read)
54
55
 
55
56
  tmp.rewind
56
57
  tmp.truncate(0)
57
58
  env['MWRAP'] = "dump_path:#{tmp.path},dump_min:10000"
58
59
  res = system(env, *cmd)
59
60
  assert res, $?.inspect
60
- assert_match(/\b10001\s+1\s+-e:1$/, tmp.read)
61
+ assert_match(/\b1\d{4}\s+[1-9]\d*\s+-e:1$/, tmp.read)
61
62
 
62
63
  tmp.rewind
63
64
  tmp.truncate(0)
@@ -98,7 +99,7 @@ class TestMwrap < Test::Unit::TestCase
98
99
  tmp.rewind
99
100
  buf = tmp.read
100
101
  assert_not_match(/\s+-e:1$/, buf)
101
- assert_match(/\b20001\s+1\s+-e:3$/, buf)
102
+ assert_match(/\b2\d{4}\s+[0-9]\d*\s+-e:3$/, buf)
102
103
  end
103
104
  end
104
105
 
@@ -176,8 +177,8 @@ class TestMwrap < Test::Unit::TestCase
176
177
  -e GC.disable
177
178
  -e keep=("0"*10000)
178
179
  -e loc=Mwrap["-e:3"]
179
- -e loc.each{|size,gen|p([size,gen,count])}
180
- )
180
+ -e
181
+ ) + [ 'loc.each{|size,gen|p([size,gen,count]) if size > 10000}' ]
181
182
  buf = IO.popen(@@env, cmd, &:read)
182
183
  assert_predicate $?, :success?
183
184
  assert_match(/\A\[\s*\d+,\s*\d+,\s*\d+\]\s*\z/s, buf)
@@ -230,7 +231,8 @@ class TestMwrap < Test::Unit::TestCase
230
231
  loc.name == k or abort 'SourceLocation#name broken'
231
232
  loc.total >= 10000 or abort 'SourceLocation#total broken'
232
233
  loc.frees == 0 or abort 'SourceLocation#frees broken'
233
- loc.allocations == 1 or abort 'SourceLocation#allocations broken'
234
+ loc.allocations >= 1 or
235
+ abort "SourceLocation#allocations broken: #{loc.allocations}"
234
236
  seen = false
235
237
  loc.each do |*x| seen = x end
236
238
  seen[1] == loc.total or 'SourceLocation#each broken'
@@ -240,7 +242,9 @@ class TestMwrap < Test::Unit::TestCase
240
242
  freed = false
241
243
  until freed
242
244
  freed = true
243
- loc.each do freed = false end
245
+ loc.each do |size, gen|
246
+ freed = false if size >= 10000
247
+ end
244
248
  end
245
249
  loc.frees == 1 or abort 'SourceLocation#frees broken (after free)'
246
250
  Float === loc.mean_lifespan or abort 'mean_lifespan broken'
@@ -264,8 +268,9 @@ class TestMwrap < Test::Unit::TestCase
264
268
  assert_separately(+"#{<<~"begin;"}\n#{<<~'end;'}")
265
269
  begin;
266
270
  require 'mwrap'
267
- before = __LINE__
271
+ before = nil
268
272
  res = Mwrap.quiet do |depth|
273
+ before = __LINE__
269
274
  depth == 1 or abort 'depth is not 1'
270
275
  ('a' * 10000).clear
271
276
  Mwrap.quiet { |d| d == 2 or abort 'depth is not 2' }
@@ -304,7 +309,9 @@ class TestMwrap < Test::Unit::TestCase
304
309
  gen <= GC.count && gen >= 0 or abort "bad generation: #{gen}"
305
310
  (0 == (addr & 16383)) or abort "addr not aligned: #{'%x' % addr}"
306
311
  end
307
- nr == ap or abort 'HeapPageBody.each missed page'
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
308
315
  10.times { (1..20000).to_a.map(&:to_s) }
309
316
  3.times { GC.start }
310
317
  Mwrap::HeapPageBody.stat(h)
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.1.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
- - Ruby hackers
7
+ - mwrap hackers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-11 00:00:00.000000000 Z
11
+ date: 2022-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-unit
@@ -55,10 +55,13 @@ files:
55
55
  - MANIFEST
56
56
  - README
57
57
  - Rakefile
58
+ - VERSION-GEN
58
59
  - bin/mwrap
59
60
  - ext/mwrap/extconf.rb
60
61
  - ext/mwrap/jhash.h
61
62
  - ext/mwrap/mwrap.c
63
+ - lib/mwrap/.gitignore
64
+ - lib/mwrap/version.rb
62
65
  - lib/mwrap_rack.rb
63
66
  - mwrap.gemspec
64
67
  - test/test_mwrap.rb
@@ -81,8 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
84
  - !ruby/object:Gem::Version
82
85
  version: '0'
83
86
  requirements: []
84
- rubyforge_project:
85
- rubygems_version: 2.7.7
87
+ rubygems_version: 3.0.2
86
88
  signing_key:
87
89
  specification_version: 4
88
90
  summary: LD_PRELOAD malloc wrapper for Ruby