raindrops 0.13.0 → 0.20.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 +7 -0
- data/.document +1 -2
- data/.gitattributes +4 -0
- data/.gitignore +1 -1
- data/.manifest +7 -5
- data/.olddoc.yml +16 -0
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +1 -2
- data/LATEST +6 -11
- data/LICENSE +3 -3
- data/NEWS +158 -0
- data/README +33 -40
- data/TODO +2 -0
- data/archive/.gitignore +3 -0
- data/archive/slrnpull.conf +4 -0
- data/examples/linux-listener-stats.rb +1 -2
- data/examples/watcher_demo.ru +1 -1
- data/examples/yahns.conf.rb +30 -0
- data/examples/zbatery.conf.rb +4 -1
- data/ext/raindrops/extconf.rb +107 -2
- data/ext/raindrops/linux_inet_diag.c +94 -101
- data/ext/raindrops/raindrops.c +75 -21
- data/ext/raindrops/tcp_info.c +245 -0
- data/lib/raindrops/aggregate/last_data_recv.rb +1 -5
- data/lib/raindrops/aggregate/pmq.rb +23 -17
- data/lib/raindrops/aggregate.rb +1 -1
- data/lib/raindrops/linux.rb +5 -6
- data/lib/raindrops/middleware/proxy.rb +2 -2
- data/lib/raindrops/middleware.rb +4 -6
- data/lib/raindrops/watcher.rb +13 -13
- data/lib/raindrops.rb +25 -1
- data/pkg.mk +26 -50
- data/raindrops.gemspec +14 -21
- data/test/ipv6_enabled.rb +4 -4
- data/test/test_aggregate_pmq.rb +1 -1
- data/test/test_inet_diag_socket.rb +1 -1
- data/test/test_last_data_recv_unicorn.rb +1 -1
- data/test/test_linux.rb +10 -2
- data/test/test_linux_all_tcp_listen_stats_leak.rb +2 -2
- data/test/test_linux_ipv6.rb +8 -0
- data/test/test_raindrops.rb +43 -1
- data/test/{test_linux_tcp_info.rb → test_tcp_info.rb} +34 -14
- data/test/test_watcher.rb +15 -10
- metadata +59 -171
- data/.wrongdoc.yml +0 -6
- data/ChangeLog +0 -1920
- data/Rakefile +0 -28
- data/ext/raindrops/linux_tcp_info.c +0 -173
@@ -1,45 +1,24 @@
|
|
1
1
|
#include <ruby.h>
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#else
|
5
|
-
# include <st.h>
|
6
|
-
#endif
|
2
|
+
#include <stdarg.h>
|
3
|
+
#include <ruby/st.h>
|
7
4
|
#include "my_fileno.h"
|
8
5
|
#ifdef __linux__
|
9
6
|
|
10
|
-
/* Ruby 1.8.6+ macros (for compatibility with Ruby 1.9) */
|
11
|
-
#ifndef RSTRING_LEN
|
12
|
-
# define RSTRING_LEN(s) (RSTRING(s)->len)
|
13
|
-
#endif
|
14
|
-
|
15
|
-
/* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
|
16
|
-
#if !defined(HAVE_RB_THREAD_BLOCKING_REGION) && \
|
17
|
-
!defined(HAVE_RB_THREAD_IO_BLOCKING_REGION)
|
18
|
-
# include <rubysig.h>
|
19
|
-
# define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
|
20
|
-
typedef void rb_unblock_function_t(void *);
|
21
|
-
typedef VALUE rb_blocking_function_t(void *);
|
22
|
-
static VALUE
|
23
|
-
rb_thread_blocking_region(
|
24
|
-
rb_blocking_function_t *func, void *data1,
|
25
|
-
rb_unblock_function_t *ubf, void *data2)
|
26
|
-
{
|
27
|
-
VALUE rv;
|
28
|
-
|
29
|
-
TRAP_BEG;
|
30
|
-
rv = func(data1);
|
31
|
-
TRAP_END;
|
32
|
-
|
33
|
-
return rv;
|
34
|
-
}
|
35
|
-
#endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
|
36
|
-
|
37
7
|
#ifdef HAVE_RB_THREAD_IO_BLOCKING_REGION
|
8
|
+
/* Ruby 1.9.3 and 2.0.0 */
|
38
9
|
VALUE rb_thread_io_blocking_region(rb_blocking_function_t *, void *, int);
|
10
|
+
# define rd_fd_region(fn,data,fd) \
|
11
|
+
rb_thread_io_blocking_region((fn),(data),(fd))
|
12
|
+
#elif defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && \
|
13
|
+
defined(HAVE_RUBY_THREAD_H) && HAVE_RUBY_THREAD_H
|
14
|
+
/* in case Ruby 2.0+ ever drops rb_thread_io_blocking_region: */
|
15
|
+
# include <ruby/thread.h>
|
16
|
+
# define COMPAT_FN (void *(*)(void *))
|
17
|
+
# define rd_fd_region(fn,data,fd) \
|
18
|
+
rb_thread_call_without_gvl(COMPAT_FN(fn),(data),RUBY_UBF_IO,NULL)
|
39
19
|
#else
|
40
|
-
#
|
41
|
-
|
42
|
-
#endif /* HAVE_RB_THREAD_IO_BLOCKING_REGION */
|
20
|
+
# error Ruby <= 1.8 not supported
|
21
|
+
#endif
|
43
22
|
|
44
23
|
#include <assert.h>
|
45
24
|
#include <errno.h>
|
@@ -213,91 +192,89 @@ static const char *addr_any(sa_family_t family)
|
|
213
192
|
return ipv6;
|
214
193
|
}
|
215
194
|
|
216
|
-
|
195
|
+
#ifdef __GNUC__
|
196
|
+
static void bug_warn_nogvl(const char *, ...)
|
197
|
+
__attribute__((format(printf,1,2)));
|
198
|
+
#endif
|
199
|
+
static void bug_warn_nogvl(const char *fmt, ...)
|
217
200
|
{
|
201
|
+
va_list ap;
|
202
|
+
|
203
|
+
va_start(ap, fmt);
|
204
|
+
vfprintf(stderr, fmt, ap);
|
205
|
+
va_end(ap);
|
206
|
+
|
218
207
|
fprintf(stderr, "Please report how you produced this at "\
|
219
|
-
"raindrops@
|
208
|
+
"raindrops-public@yhbt.net\n");
|
220
209
|
fflush(stderr);
|
221
210
|
}
|
222
211
|
|
223
212
|
static struct listen_stats *stats_for(st_table *table, struct inet_diag_msg *r)
|
224
213
|
{
|
225
|
-
char *key, *port, *old_key;
|
214
|
+
char *host, *key, *port, *old_key;
|
226
215
|
size_t alloca_len;
|
227
216
|
struct listen_stats *stats;
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
switch ((sa.ss.ss_family = r->idiag_family)) {
|
217
|
+
socklen_t hostlen;
|
218
|
+
socklen_t portlen = (socklen_t)sizeof("65535");
|
219
|
+
int n;
|
220
|
+
const void *src = r->id.idiag_src;
|
221
|
+
|
222
|
+
switch (r->idiag_family) {
|
236
223
|
case AF_INET: {
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
alloca_len = keylen + 1 + portlen;
|
241
|
-
key = alloca(alloca_len);
|
242
|
-
key[keylen] = 0; /* will be ':' later */
|
243
|
-
port = key + keylen + 1;
|
244
|
-
rc = getnameinfo(&sa.sa, len,
|
245
|
-
key, keylen, port, portlen, flags);
|
224
|
+
hostlen = INET_ADDRSTRLEN;
|
225
|
+
alloca_len = hostlen + portlen;
|
226
|
+
host = key = alloca(alloca_len);
|
246
227
|
break;
|
247
228
|
}
|
248
229
|
case AF_INET6: {
|
249
|
-
|
250
|
-
|
251
|
-
keylen = INET6_ADDRSTRLEN;
|
252
|
-
/* [ ] */
|
253
|
-
alloca_len = 1 + keylen + 1 + 1 + portlen;
|
230
|
+
hostlen = INET6_ADDRSTRLEN;
|
231
|
+
alloca_len = 1 + hostlen + 1 + portlen;
|
254
232
|
key = alloca(alloca_len);
|
255
|
-
|
256
|
-
key[1 + keylen + 1] = 0; /* will be ':' later */
|
257
|
-
port = 1 + key + keylen + 1 + 1;
|
258
|
-
rc = getnameinfo(&sa.sa, len,
|
259
|
-
key + 1, keylen, port, portlen, flags);
|
233
|
+
host = key + 1;
|
260
234
|
break;
|
261
235
|
}
|
262
236
|
default:
|
263
237
|
assert(0 && "unsupported address family, could that be IPv7?!");
|
264
238
|
}
|
265
|
-
if (
|
266
|
-
|
267
|
-
|
268
|
-
*
|
239
|
+
if (!inet_ntop(r->idiag_family, src, host, hostlen)) {
|
240
|
+
bug_warn_nogvl("BUG: inet_ntop: %s\n", strerror(errno));
|
241
|
+
*key = '\0';
|
242
|
+
*host = '\0';
|
269
243
|
}
|
270
|
-
|
271
|
-
|
272
|
-
portlen = strlen(port);
|
273
|
-
|
274
|
-
switch (sa.ss.ss_family) {
|
244
|
+
hostlen = (socklen_t)strlen(host);
|
245
|
+
switch (r->idiag_family) {
|
275
246
|
case AF_INET:
|
276
|
-
|
277
|
-
|
247
|
+
host[hostlen] = ':';
|
248
|
+
port = host + hostlen + 1;
|
278
249
|
break;
|
279
250
|
case AF_INET6:
|
280
|
-
key[
|
281
|
-
|
282
|
-
|
283
|
-
|
251
|
+
key[0] = '[';
|
252
|
+
host[hostlen] = ']';
|
253
|
+
host[hostlen + 1] = ':';
|
254
|
+
port = host + hostlen + 2;
|
284
255
|
break;
|
285
256
|
default:
|
286
257
|
assert(0 && "unsupported address family, could that be IPv7?!");
|
287
258
|
}
|
288
259
|
|
260
|
+
n = snprintf(port, portlen, "%u", ntohs(r->id.idiag_sport));
|
261
|
+
if (n <= 0) {
|
262
|
+
bug_warn_nogvl("BUG: snprintf port: %d\n", n);
|
263
|
+
*key = '\0';
|
264
|
+
}
|
265
|
+
|
289
266
|
if (st_lookup(table, (st_data_t)key, (st_data_t *)&stats))
|
290
267
|
return stats;
|
291
268
|
|
292
269
|
old_key = key;
|
293
270
|
|
294
271
|
if (r->idiag_state == TCP_ESTABLISHED) {
|
295
|
-
|
296
|
-
addr_any(
|
272
|
+
n = snprintf(key, alloca_len, "%s:%u",
|
273
|
+
addr_any(r->idiag_family),
|
297
274
|
ntohs(r->id.idiag_sport));
|
298
275
|
if (n <= 0) {
|
299
|
-
|
300
|
-
|
276
|
+
bug_warn_nogvl("BUG: snprintf: %d\n", n);
|
277
|
+
*key = '\0';
|
301
278
|
}
|
302
279
|
if (st_lookup(table, (st_data_t)key, (st_data_t *)&stats))
|
303
280
|
return stats;
|
@@ -310,8 +287,9 @@ static struct listen_stats *stats_for(st_table *table, struct inet_diag_msg *r)
|
|
310
287
|
memcpy(key, old_key, n + 1);
|
311
288
|
}
|
312
289
|
} else {
|
313
|
-
|
314
|
-
|
290
|
+
size_t old_len = strlen(old_key) + 1;
|
291
|
+
key = xmalloc(old_len);
|
292
|
+
memcpy(key, old_key, old_len);
|
315
293
|
}
|
316
294
|
stats = xcalloc(1, sizeof(struct listen_stats));
|
317
295
|
st_insert(table, (st_data_t)key, (st_data_t)stats);
|
@@ -391,8 +369,8 @@ static void prep_diag_args(
|
|
391
369
|
|
392
370
|
nladdr->nl_family = AF_NETLINK;
|
393
371
|
|
394
|
-
req->nlh.nlmsg_len = sizeof(struct diag_req) +
|
395
|
-
RTA_LENGTH(args->iov[2].iov_len);
|
372
|
+
req->nlh.nlmsg_len = (unsigned int)(sizeof(struct diag_req) +
|
373
|
+
RTA_LENGTH(args->iov[2].iov_len));
|
396
374
|
req->nlh.nlmsg_type = TCPDIAG_GETSOCK;
|
397
375
|
req->nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
398
376
|
req->nlh.nlmsg_pid = getpid();
|
@@ -465,12 +443,12 @@ static VALUE diag(void *ptr)
|
|
465
443
|
}
|
466
444
|
}
|
467
445
|
out:
|
468
|
-
|
446
|
+
/* prepare to raise, free memory before reacquiring GVL */
|
447
|
+
if (err && args->table) {
|
469
448
|
int save_errno = errno;
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
}
|
449
|
+
|
450
|
+
st_foreach(args->table, st_free_data, 0);
|
451
|
+
st_free_table(args->table);
|
474
452
|
errno = save_errno;
|
475
453
|
}
|
476
454
|
return (VALUE)err;
|
@@ -584,6 +562,10 @@ static void gen_bytecode(struct iovec *iov, union any_addr *inet)
|
|
584
562
|
}
|
585
563
|
}
|
586
564
|
|
565
|
+
/*
|
566
|
+
* n.b. we may safely raise here because an error will cause diag()
|
567
|
+
* to free args->table
|
568
|
+
*/
|
587
569
|
static void nl_errcheck(VALUE r)
|
588
570
|
{
|
589
571
|
const char *err = (const char *)r;
|
@@ -604,11 +586,18 @@ static VALUE tcp_stats(struct nogvl_args *args, VALUE addr)
|
|
604
586
|
gen_bytecode(&args->iov[2], &query_addr);
|
605
587
|
|
606
588
|
memset(&args->stats, 0, sizeof(struct listen_stats));
|
607
|
-
nl_errcheck(
|
589
|
+
nl_errcheck(rd_fd_region(diag, args, args->fd));
|
608
590
|
|
609
591
|
return rb_listen_stats(&args->stats);
|
610
592
|
}
|
611
593
|
|
594
|
+
static int drop_placeholders(st_data_t k, st_data_t v, st_data_t ign)
|
595
|
+
{
|
596
|
+
if ((VALUE)v == Qtrue)
|
597
|
+
return ST_DELETE;
|
598
|
+
return ST_CONTINUE;
|
599
|
+
}
|
600
|
+
|
612
601
|
/*
|
613
602
|
* call-seq:
|
614
603
|
* Raindrops::Linux.tcp_listener_stats([addrs[, sock]]) => hash
|
@@ -649,10 +638,9 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
|
|
649
638
|
case T_ARRAY: {
|
650
639
|
long i;
|
651
640
|
long len = RARRAY_LEN(addrs);
|
652
|
-
VALUE cur;
|
653
641
|
|
654
642
|
if (len == 1) {
|
655
|
-
cur = rb_ary_entry(addrs, 0);
|
643
|
+
VALUE cur = rb_ary_entry(addrs, 0);
|
656
644
|
|
657
645
|
rb_hash_aset(rv, cur, tcp_stats(&args, cur));
|
658
646
|
return rv;
|
@@ -662,7 +650,7 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
|
|
662
650
|
VALUE cur = rb_ary_entry(addrs, i);
|
663
651
|
|
664
652
|
parse_addr(&check, cur);
|
665
|
-
rb_hash_aset(rv, cur, Qtrue);
|
653
|
+
rb_hash_aset(rv, cur, Qtrue /* placeholder */);
|
666
654
|
}
|
667
655
|
/* fall through */
|
668
656
|
}
|
@@ -675,11 +663,14 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
|
|
675
663
|
"addr must be an array of strings, a string, or nil");
|
676
664
|
}
|
677
665
|
|
678
|
-
nl_errcheck(
|
666
|
+
nl_errcheck(rd_fd_region(diag, &args, args.fd));
|
679
667
|
|
680
668
|
st_foreach(args.table, NIL_P(addrs) ? st_to_hash : st_AND_hash, rv);
|
681
669
|
st_free_table(args.table);
|
682
670
|
|
671
|
+
if (RHASH_SIZE(rv) > 1)
|
672
|
+
rb_hash_foreach(rv, drop_placeholders, Qfalse);
|
673
|
+
|
683
674
|
/* let GC deal with corner cases */
|
684
675
|
if (argc < 2) rb_io_close(sock);
|
685
676
|
return rv;
|
@@ -687,11 +678,12 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
|
|
687
678
|
|
688
679
|
void Init_raindrops_linux_inet_diag(void)
|
689
680
|
{
|
690
|
-
VALUE cRaindrops =
|
681
|
+
VALUE cRaindrops = rb_define_class("Raindrops", rb_cObject);
|
691
682
|
VALUE mLinux = rb_define_module_under(cRaindrops, "Linux");
|
683
|
+
VALUE Socket;
|
692
684
|
|
693
685
|
rb_require("socket");
|
694
|
-
|
686
|
+
Socket = rb_const_get(rb_cObject, rb_intern("Socket"));
|
695
687
|
id_new = rb_intern("new");
|
696
688
|
|
697
689
|
/*
|
@@ -700,10 +692,11 @@ void Init_raindrops_linux_inet_diag(void)
|
|
700
692
|
* This is a subclass of +Socket+ specifically for talking
|
701
693
|
* to the inet_diag facility of Netlink.
|
702
694
|
*/
|
703
|
-
cIDSock = rb_define_class_under(cRaindrops, "InetDiagSocket",
|
695
|
+
cIDSock = rb_define_class_under(cRaindrops, "InetDiagSocket", Socket);
|
704
696
|
rb_define_singleton_method(cIDSock, "new", ids_s_new, 0);
|
705
697
|
|
706
698
|
cListenStats = rb_const_get(cRaindrops, rb_intern("ListenStats"));
|
699
|
+
rb_gc_register_mark_object(cListenStats); /* pin */
|
707
700
|
|
708
701
|
rb_define_module_function(mLinux, "tcp_listener_stats",
|
709
702
|
tcp_listener_stats, -1);
|
data/ext/raindrops/raindrops.c
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
#include <assert.h>
|
5
5
|
#include <errno.h>
|
6
6
|
#include <stddef.h>
|
7
|
+
#include <string.h>
|
7
8
|
#include "raindrops_atomic.h"
|
8
9
|
|
9
10
|
#ifndef SIZET2NUM
|
@@ -34,11 +35,19 @@ struct raindrops {
|
|
34
35
|
size_t size;
|
35
36
|
size_t capa;
|
36
37
|
pid_t pid;
|
38
|
+
VALUE io;
|
37
39
|
struct raindrop *drops;
|
38
40
|
};
|
39
41
|
|
40
42
|
/* called by GC */
|
41
|
-
static void
|
43
|
+
static void rd_mark(void *ptr)
|
44
|
+
{
|
45
|
+
struct raindrops *r = ptr;
|
46
|
+
rb_gc_mark(r->io);
|
47
|
+
}
|
48
|
+
|
49
|
+
/* called by GC */
|
50
|
+
static void rd_free(void *ptr)
|
42
51
|
{
|
43
52
|
struct raindrops *r = ptr;
|
44
53
|
|
@@ -51,11 +60,24 @@ static void gcfree(void *ptr)
|
|
51
60
|
xfree(ptr);
|
52
61
|
}
|
53
62
|
|
63
|
+
static size_t rd_memsize(const void *ptr)
|
64
|
+
{
|
65
|
+
const struct raindrops *r = ptr;
|
66
|
+
|
67
|
+
return r->drops == MAP_FAILED ? 0 : raindrop_size * r->capa;
|
68
|
+
}
|
69
|
+
|
70
|
+
static const rb_data_type_t rd_type = {
|
71
|
+
"raindrops",
|
72
|
+
{ rd_mark, rd_free, rd_memsize, /* reserved */ },
|
73
|
+
/* parent, data, [ flags ] */
|
74
|
+
};
|
75
|
+
|
54
76
|
/* automatically called at creation (before initialize) */
|
55
77
|
static VALUE alloc(VALUE klass)
|
56
78
|
{
|
57
79
|
struct raindrops *r;
|
58
|
-
VALUE rv =
|
80
|
+
VALUE rv = TypedData_Make_Struct(klass, struct raindrops, &rd_type, r);
|
59
81
|
|
60
82
|
r->drops = MAP_FAILED;
|
61
83
|
return rv;
|
@@ -65,7 +87,7 @@ static struct raindrops *get(VALUE self)
|
|
65
87
|
{
|
66
88
|
struct raindrops *r;
|
67
89
|
|
68
|
-
|
90
|
+
TypedData_Get_Struct(self, struct raindrops, &rd_type, r);
|
69
91
|
|
70
92
|
if (r->drops == MAP_FAILED)
|
71
93
|
rb_raise(rb_eStandardError, "invalid or freed Raindrops");
|
@@ -74,16 +96,10 @@ static struct raindrops *get(VALUE self)
|
|
74
96
|
}
|
75
97
|
|
76
98
|
/*
|
77
|
-
*
|
78
|
-
*
|
79
|
-
*
|
80
|
-
* Initializes a Raindrops object to hold +size+ counters. +size+ is
|
81
|
-
* only a hint and the actual number of counters the object has is
|
82
|
-
* dependent on the CPU model, number of cores, and page size of
|
83
|
-
* the machine. The actual size of the object will always be equal
|
84
|
-
* or greater than the specified +size+.
|
99
|
+
* This is the _actual_ implementation of #initialize - the Ruby wrapper
|
100
|
+
* handles keyword-argument handling then calls this method.
|
85
101
|
*/
|
86
|
-
static VALUE
|
102
|
+
static VALUE init_cimpl(VALUE self, VALUE size, VALUE io, VALUE zero)
|
87
103
|
{
|
88
104
|
struct raindrops *r = DATA_PTR(self);
|
89
105
|
int tries = 1;
|
@@ -100,11 +116,23 @@ static VALUE init(VALUE self, VALUE size)
|
|
100
116
|
r->capa = tmp / raindrop_size;
|
101
117
|
assert(PAGE_ALIGN(raindrop_size * r->capa) == tmp && "not aligned");
|
102
118
|
|
119
|
+
r->io = io;
|
120
|
+
|
103
121
|
retry:
|
104
|
-
r->
|
105
|
-
|
122
|
+
if (RTEST(r->io)) {
|
123
|
+
int fd = NUM2INT(rb_funcall(r->io, rb_intern("fileno"), 0));
|
124
|
+
rb_funcall(r->io, rb_intern("truncate"), 1, SIZET2NUM(tmp));
|
125
|
+
r->drops = mmap(NULL, tmp,
|
126
|
+
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
127
|
+
} else {
|
128
|
+
r->drops = mmap(NULL, tmp,
|
129
|
+
PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED,
|
130
|
+
-1, 0);
|
131
|
+
}
|
106
132
|
if (r->drops == MAP_FAILED) {
|
107
|
-
|
133
|
+
int err = errno;
|
134
|
+
|
135
|
+
if ((err == EAGAIN || err == ENOMEM) && tries-- > 0) {
|
108
136
|
rb_gc();
|
109
137
|
goto retry;
|
110
138
|
}
|
@@ -112,6 +140,9 @@ retry:
|
|
112
140
|
}
|
113
141
|
r->pid = getpid();
|
114
142
|
|
143
|
+
if (RTEST(zero))
|
144
|
+
memset(r->drops, 0, tmp);
|
145
|
+
|
115
146
|
return self;
|
116
147
|
}
|
117
148
|
|
@@ -140,7 +171,9 @@ static void resize(struct raindrops *r, size_t new_rd_size)
|
|
140
171
|
|
141
172
|
rv = mremap(old_address, old_size, new_size, MREMAP_MAYMOVE);
|
142
173
|
if (rv == MAP_FAILED) {
|
143
|
-
|
174
|
+
int err = errno;
|
175
|
+
|
176
|
+
if (err == EAGAIN || err == ENOMEM) {
|
144
177
|
rb_gc();
|
145
178
|
rv = mremap(old_address, old_size, new_size, 0);
|
146
179
|
}
|
@@ -200,14 +233,16 @@ static VALUE capa(VALUE self)
|
|
200
233
|
* call-seq:
|
201
234
|
* rd.dup -> rd_copy
|
202
235
|
*
|
203
|
-
* Duplicates and snapshots the current state of a Raindrops object.
|
236
|
+
* Duplicates and snapshots the current state of a Raindrops object. Even
|
237
|
+
* if the given Raindrops object is backed by a file, the copy will be backed
|
238
|
+
* by independent, anonymously mapped memory.
|
204
239
|
*/
|
205
240
|
static VALUE init_copy(VALUE dest, VALUE source)
|
206
241
|
{
|
207
242
|
struct raindrops *dst = DATA_PTR(dest);
|
208
243
|
struct raindrops *src = get(source);
|
209
244
|
|
210
|
-
|
245
|
+
init_cimpl(dest, SIZET2NUM(src->size), Qnil, Qfalse);
|
211
246
|
memcpy(dst->drops, src->drops, raindrop_size * src->size);
|
212
247
|
|
213
248
|
return dest;
|
@@ -323,7 +358,9 @@ static VALUE aref(VALUE self, VALUE index)
|
|
323
358
|
|
324
359
|
#ifdef __linux__
|
325
360
|
void Init_raindrops_linux_inet_diag(void);
|
326
|
-
|
361
|
+
#endif
|
362
|
+
#ifdef HAVE_TYPE_STRUCT_TCP_INFO
|
363
|
+
void Init_raindrops_tcp_info(void);
|
327
364
|
#endif
|
328
365
|
|
329
366
|
#ifndef _SC_NPROCESSORS_CONF
|
@@ -356,6 +393,20 @@ static VALUE evaporate_bang(VALUE self)
|
|
356
393
|
return Qnil;
|
357
394
|
}
|
358
395
|
|
396
|
+
/*
|
397
|
+
* call-seq:
|
398
|
+
* to_io -> IO
|
399
|
+
*
|
400
|
+
* Returns the IO object backing the memory for this raindrop, if
|
401
|
+
* one was specified when constructing this Raindrop. If this
|
402
|
+
* Raindrop is backed by anonymous memory, this method returns nil.
|
403
|
+
*/
|
404
|
+
static VALUE to_io(VALUE self)
|
405
|
+
{
|
406
|
+
struct raindrops *r = get(self);
|
407
|
+
return r->io;
|
408
|
+
}
|
409
|
+
|
359
410
|
void Init_raindrops_ext(void)
|
360
411
|
{
|
361
412
|
VALUE cRaindrops = rb_define_class("Raindrops", rb_cObject);
|
@@ -414,7 +465,7 @@ void Init_raindrops_ext(void)
|
|
414
465
|
|
415
466
|
rb_define_alloc_func(cRaindrops, alloc);
|
416
467
|
|
417
|
-
|
468
|
+
rb_define_private_method(cRaindrops, "initialize_cimpl", init_cimpl, 3);
|
418
469
|
rb_define_method(cRaindrops, "incr", incr, -1);
|
419
470
|
rb_define_method(cRaindrops, "decr", decr, -1);
|
420
471
|
rb_define_method(cRaindrops, "to_ary", to_ary, 0);
|
@@ -425,9 +476,12 @@ void Init_raindrops_ext(void)
|
|
425
476
|
rb_define_method(cRaindrops, "capa", capa, 0);
|
426
477
|
rb_define_method(cRaindrops, "initialize_copy", init_copy, 1);
|
427
478
|
rb_define_method(cRaindrops, "evaporate!", evaporate_bang, 0);
|
479
|
+
rb_define_method(cRaindrops, "to_io", to_io, 0);
|
428
480
|
|
429
481
|
#ifdef __linux__
|
430
482
|
Init_raindrops_linux_inet_diag();
|
431
|
-
|
483
|
+
#endif
|
484
|
+
#ifdef HAVE_TYPE_STRUCT_TCP_INFO
|
485
|
+
Init_raindrops_tcp_info();
|
432
486
|
#endif
|
433
487
|
}
|