mwrap 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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