sleepy_penguin 3.4.1 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.document +1 -0
- data/.olddoc.yml +3 -4
- data/GIT-VERSION-GEN +1 -1
- data/LICENSE +3 -3
- data/README +7 -4
- data/TODO +1 -0
- data/ext/sleepy_penguin/cfr.c +62 -0
- data/ext/sleepy_penguin/epoll.c +34 -24
- data/ext/sleepy_penguin/eventfd.c +6 -5
- data/ext/sleepy_penguin/extconf.rb +6 -0
- data/ext/sleepy_penguin/init.c +83 -12
- data/ext/sleepy_penguin/inotify.c +48 -36
- data/ext/sleepy_penguin/kqueue.c +22 -21
- data/ext/sleepy_penguin/sendfile.c +120 -0
- data/ext/sleepy_penguin/sleepy_penguin.h +15 -28
- data/ext/sleepy_penguin/sp_copy.h +33 -0
- data/ext/sleepy_penguin/splice.c +174 -0
- data/ext/sleepy_penguin/timerfd.c +1 -5
- data/ext/sleepy_penguin/util.c +12 -0
- data/lib/sleepy_penguin.rb +28 -0
- data/lib/sleepy_penguin/cfr.rb +29 -0
- data/lib/sleepy_penguin/epoll.rb +13 -10
- data/lib/sleepy_penguin/kqueue.rb +6 -6
- data/lib/sleepy_penguin/sp.rb +1 -1
- data/lib/sleepy_penguin/splice.rb +125 -0
- data/pkg.mk +5 -12
- data/sleepy_penguin.gemspec +13 -15
- data/test/helper.rb +2 -7
- data/test/test_cfr.rb +35 -0
- data/test/test_constants.rb +2 -4
- data/test/test_epoll.rb +35 -6
- data/test/test_epoll_gc.rb +2 -5
- data/test/test_epoll_io.rb +3 -6
- data/test/test_epoll_optimizations.rb +2 -2
- data/test/test_eventfd.rb +2 -5
- data/test/test_inotify.rb +2 -4
- data/test/test_kqueue.rb +35 -7
- data/test/test_kqueue_io.rb +2 -5
- data/test/test_pipesize.rb +22 -0
- data/test/test_sendfile.rb +26 -0
- data/test/test_splice.rb +250 -0
- data/test/test_splice_eintr.rb +31 -0
- data/test/test_timerfd.rb +2 -5
- metadata +27 -34
- data/lib/sleepy_penguin/epoll/io.rb +0 -28
- data/lib/sleepy_penguin/kqueue/io.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dff861d3873bfcd1a028f7cdc0ae46a1065d4092
|
4
|
+
data.tar.gz: 19244c89ef9f4a8719e31eaed7354ce88640ff5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a82315acdb00dead8609707ed1fe9c5d649c58997170b0fbd0d600a0531bc100f6d57b09fc1fe9ebe4e3f1b1d0e0a967dd0627b26e87e1928f4439aa17b454c
|
7
|
+
data.tar.gz: 48ff2a95beb3a28150504ddcf7d5e3f475a92b4379aad96db219dd8556872cd0e4351392f72e91ab5fd608cc597e80374134f4340227d31a4f6a5f5a6840eaae
|
data/.document
CHANGED
data/.olddoc.yml
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
---
|
2
|
-
cgit_url:
|
2
|
+
cgit_url: https://bogomips.org/sleepy_penguin.git
|
3
3
|
git_url: git://bogomips.org/sleepy_penguin.git
|
4
|
-
rdoc_url:
|
5
|
-
ml_url:
|
6
|
-
private_email: bofh@bogomips.org
|
4
|
+
rdoc_url: https://bogomips.org/sleepy_penguin/
|
5
|
+
ml_url: https://bogomips.org/sleepy-penguin/
|
7
6
|
public_email: sleepy-penguin@bogomips.org
|
data/GIT-VERSION-GEN
CHANGED
data/LICENSE
CHANGED
@@ -3,8 +3,8 @@ logs in revision control for names and email addresses of all of them.
|
|
3
3
|
|
4
4
|
You can redistribute it and/or modify it under the terms of the GNU
|
5
5
|
Lesser General Public License (LGPL) as published by the Free Software
|
6
|
-
Foundation, version {2.1}[
|
7
|
-
(at your option) any later version.
|
6
|
+
Foundation, version {2.1}[https://www.gnu.org/licenses/lgpl-2.1.txt]
|
7
|
+
or (at your option) any later version.
|
8
8
|
|
9
9
|
sleepy_penguin is distributed in the hope that it will be useful, but
|
10
10
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
@@ -12,4 +12,4 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
|
12
12
|
General Public License for more details.
|
13
13
|
|
14
14
|
You should have received a copy of the GNU Lesser General Public License
|
15
|
-
along with this library; if not, see
|
15
|
+
along with this library; if not, see https://www.gnu.org/licenses/
|
data/README
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
sleepy_penguin provides access to newer, Linux-only system calls to wait
|
4
4
|
on events from traditionally non-I/O sources. Bindings to the eventfd,
|
5
5
|
timerfd, inotify, and epoll interfaces are provided. Experimental support
|
6
|
-
for kqueue on FreeBSD (and likely OpenBSD/NetBSD)
|
6
|
+
for kqueue on FreeBSD (and likely OpenBSD/NetBSD) is also provided.
|
7
7
|
|
8
8
|
== Features
|
9
9
|
|
@@ -31,7 +31,7 @@ If you use RubyGems:
|
|
31
31
|
|
32
32
|
Otherwise grab the latest tarball from:
|
33
33
|
|
34
|
-
|
34
|
+
https://bogomips.org/sleepy_penguin/files/
|
35
35
|
|
36
36
|
Unpack it, and run "ruby setup.rb"
|
37
37
|
|
@@ -45,7 +45,7 @@ You can get the latest source via git from the following locations:
|
|
45
45
|
You may browse the code from the web and download the latest snapshot
|
46
46
|
tarballs here:
|
47
47
|
|
48
|
-
*
|
48
|
+
* https://bogomips.org/sleepy_penguin.git
|
49
49
|
* http://repo.or.cz/w/sleepy_penguin.git (gitweb)
|
50
50
|
|
51
51
|
Inline patches (from "git format-patch") to the mailing list are
|
@@ -62,4 +62,7 @@ don't email the git mailing list or maintainer with sleepy_penguin patches.
|
|
62
62
|
All feedback (bug reports, user/development discussion, patches, pull
|
63
63
|
requests) go to the mailing list: mailto:sleepy-penguin@bogomips.org
|
64
64
|
|
65
|
-
* Mailing list archives:
|
65
|
+
* Mailing list archives: https://bogomips.org/sleepy-penguin/
|
66
|
+
|
67
|
+
* Also available over NNTP:
|
68
|
+
nntp://news.public-inbox.org/inbox.comp.lang.ruby.sleepy-penguin
|
data/TODO
CHANGED
@@ -0,0 +1,62 @@
|
|
1
|
+
#include "sleepy_penguin.h"
|
2
|
+
#include "sp_copy.h"
|
3
|
+
#include <unistd.h>
|
4
|
+
|
5
|
+
#ifdef __NR_copy_file_range
|
6
|
+
static ssize_t my_cfr(int fd_in, off_t *off_in, int fd_out, off_t *off_out,
|
7
|
+
size_t len, unsigned int flags)
|
8
|
+
{
|
9
|
+
long n = syscall(__NR_copy_file_range,
|
10
|
+
fd_in, off_in, fd_out, off_out, len, flags);
|
11
|
+
|
12
|
+
return (ssize_t)n;
|
13
|
+
}
|
14
|
+
# define copy_file_range(fd_in,off_in,fd_out,off_out,len,flags) \
|
15
|
+
my_cfr((fd_in),(off_in),(fd_out),(off_out),(len),(flags))
|
16
|
+
#endif
|
17
|
+
|
18
|
+
#if defined(HAVE_COPY_FILE_RANGE) || \
|
19
|
+
(defined(__linux__) && defined(__NR_copy_file_range))
|
20
|
+
static void *nogvl_cfr(void *ptr)
|
21
|
+
{
|
22
|
+
struct copy_args *a = ptr;
|
23
|
+
|
24
|
+
return (void *)copy_file_range(a->fd_in, a->off_in,
|
25
|
+
a->fd_out, a->off_out, a->len, a->flags);
|
26
|
+
}
|
27
|
+
|
28
|
+
/* :nodoc: */
|
29
|
+
static VALUE rb_sp_cfr(VALUE mod, VALUE io_in, VALUE off_in,
|
30
|
+
VALUE io_out, VALUE off_out,
|
31
|
+
VALUE len, VALUE flags)
|
32
|
+
{
|
33
|
+
off_t i = 0, o = 0;
|
34
|
+
struct copy_args a;
|
35
|
+
ssize_t bytes;
|
36
|
+
|
37
|
+
a.off_in = NIL_P(off_in) ? NULL : (i = NUM2OFFT(off_in), &i);
|
38
|
+
a.off_out = NIL_P(off_out) ? NULL : (o = NUM2OFFT(off_out), &o);
|
39
|
+
a.len = NUM2SIZET(len);
|
40
|
+
a.flags = NUM2UINT(flags);
|
41
|
+
|
42
|
+
for (;;) {
|
43
|
+
a.fd_in = rb_sp_fileno(io_in);
|
44
|
+
a.fd_out = rb_sp_fileno(io_out);
|
45
|
+
bytes = (ssize_t)IO_RUN(nogvl_cfr, &a);
|
46
|
+
if (bytes < 0) {
|
47
|
+
switch (errno) {
|
48
|
+
case EINTR: continue;
|
49
|
+
default: rb_sys_fail("copy_file_range");
|
50
|
+
}
|
51
|
+
}
|
52
|
+
return SSIZET2NUM(bytes);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
void sleepy_penguin_init_cfr(void)
|
57
|
+
{
|
58
|
+
VALUE mod = rb_define_module("SleepyPenguin");
|
59
|
+
|
60
|
+
rb_define_singleton_method(mod, "__cfr", rb_sp_cfr, 6);
|
61
|
+
}
|
62
|
+
#endif /* !HAVE_COPY_FILE_RANGE */
|
data/ext/sleepy_penguin/epoll.c
CHANGED
@@ -49,7 +49,7 @@ static int ep_fd_check(struct ep_per_thread *ept)
|
|
49
49
|
return 1;
|
50
50
|
}
|
51
51
|
|
52
|
-
static struct ep_per_thread *ept_get(
|
52
|
+
static struct ep_per_thread *ept_get(int maxevents)
|
53
53
|
{
|
54
54
|
struct ep_per_thread *ept;
|
55
55
|
size_t size;
|
@@ -66,8 +66,6 @@ static struct ep_per_thread *ept_get(VALUE self, int maxevents)
|
|
66
66
|
ept = rb_sp_gettlsbuf(&size);
|
67
67
|
ept->capa = maxevents;
|
68
68
|
ept->maxevents = maxevents;
|
69
|
-
ept->io = self;
|
70
|
-
ept->fd = rb_sp_fileno(ept->io);
|
71
69
|
|
72
70
|
return ept;
|
73
71
|
}
|
@@ -82,15 +80,13 @@ static struct ep_per_thread *ept_get(VALUE self, int maxevents)
|
|
82
80
|
static VALUE s_new(VALUE klass, VALUE _flags)
|
83
81
|
{
|
84
82
|
int default_flags = RB_SP_CLOEXEC(EPOLL_CLOEXEC);
|
85
|
-
int flags = rb_sp_get_flags(
|
83
|
+
int flags = rb_sp_get_flags(cEpoll, _flags, default_flags);
|
86
84
|
int fd = epoll_create1(flags);
|
87
85
|
VALUE rv;
|
88
86
|
|
89
87
|
if (fd < 0) {
|
90
|
-
if (errno
|
91
|
-
rb_gc();
|
88
|
+
if (rb_sp_gc_for_fd(errno))
|
92
89
|
fd = epoll_create1(flags);
|
93
|
-
}
|
94
90
|
if (fd < 0)
|
95
91
|
rb_sys_fail("epoll_create1");
|
96
92
|
}
|
@@ -106,7 +102,7 @@ static VALUE s_new(VALUE klass, VALUE _flags)
|
|
106
102
|
* Register, modify, or register a watch for a given +io+ for events.
|
107
103
|
*
|
108
104
|
* +op+ may be one of +EPOLL_CTL_ADD+, +EPOLL_CTL_MOD+, or +EPOLL_CTL_DEL+
|
109
|
-
* +io+ is an IO object or one which proxies via the +to_io+ method.
|
105
|
+
* +io+ is an +IO+ object or one which proxies via the +to_io+ method.
|
110
106
|
* +events+ is an integer mask of events to watch for.
|
111
107
|
*
|
112
108
|
* Returns nil on success.
|
@@ -179,6 +175,7 @@ static VALUE real_epwait(struct ep_per_thread *ept)
|
|
179
175
|
long n;
|
180
176
|
uint64_t expire_at = ept->timeout > 0 ? now_ms() + ept->timeout : 0;
|
181
177
|
|
178
|
+
ept->fd = rb_sp_fileno(ept->io);
|
182
179
|
do {
|
183
180
|
n = (long)rb_sp_fd_region(nogvl_wait, ept, ept->fd);
|
184
181
|
} while (n < 0 && epoll_resume_p(expire_at, ept));
|
@@ -190,7 +187,7 @@ static VALUE real_epwait(struct ep_per_thread *ept)
|
|
190
187
|
* call-seq:
|
191
188
|
* ep_io.epoll_wait([maxevents[, timeout]]) { |events, io| ... }
|
192
189
|
*
|
193
|
-
* Calls epoll_wait(2) and yields Integer +events+ and IO objects watched
|
190
|
+
* Calls epoll_wait(2) and yields Integer +events+ and +IO+ objects watched
|
194
191
|
* for. +maxevents+ is the maximum number of events to process at once,
|
195
192
|
* lower numbers may prevent starvation when used by epoll_wait in multiple
|
196
193
|
* threads. Larger +maxevents+ reduces syscall overhead for
|
@@ -202,14 +199,17 @@ static VALUE epwait(int argc, VALUE *argv, VALUE self)
|
|
202
199
|
{
|
203
200
|
VALUE timeout, maxevents;
|
204
201
|
struct ep_per_thread *ept;
|
202
|
+
int t;
|
205
203
|
|
206
204
|
rb_need_block();
|
207
205
|
rb_scan_args(argc, argv, "02", &maxevents, &timeout);
|
206
|
+
t = NIL_P(timeout) ? -1 : NUM2INT(timeout);
|
208
207
|
|
209
|
-
ept = ept_get(
|
210
|
-
ept->timeout =
|
208
|
+
ept = ept_get(NIL_P(maxevents) ? 64 : NUM2INT(maxevents));
|
209
|
+
ept->timeout = t;
|
210
|
+
ept->io = self;
|
211
211
|
|
212
|
-
return real_epwait(ept);
|
212
|
+
return rb_ensure(real_epwait, (VALUE)ept, rb_sp_puttlsbuf, (VALUE)ept);
|
213
213
|
}
|
214
214
|
|
215
215
|
/* :nodoc: */
|
@@ -251,7 +251,7 @@ void sleepy_penguin_init_epoll(void)
|
|
251
251
|
*
|
252
252
|
* The Epoll class provides high-level access to epoll(7)
|
253
253
|
* functionality in the Linux 2.6 and later kernels. It provides
|
254
|
-
* fork and GC-safety for Ruby objects stored within the IO object
|
254
|
+
* fork and GC-safety for Ruby objects stored within the +IO+ object
|
255
255
|
* and may be passed as an argument to IO.select.
|
256
256
|
*/
|
257
257
|
cEpoll = rb_define_class_under(mSleepyPenguin, "Epoll", rb_cObject);
|
@@ -260,7 +260,7 @@ void sleepy_penguin_init_epoll(void)
|
|
260
260
|
* Document-class: SleepyPenguin::Epoll::IO
|
261
261
|
*
|
262
262
|
* Epoll::IO is a low-level class. It does not provide fork nor
|
263
|
-
* GC-safety, so Ruby IO objects added via epoll_ctl must be retained
|
263
|
+
* GC-safety, so Ruby +IO+ objects added via epoll_ctl must be retained
|
264
264
|
* by the application until IO#close is called.
|
265
265
|
*/
|
266
266
|
cEpoll_IO = rb_define_class_under(cEpoll, "IO", rb_cIO);
|
@@ -271,13 +271,13 @@ void sleepy_penguin_init_epoll(void)
|
|
271
271
|
|
272
272
|
rb_define_method(cEpoll, "__event_flags", event_flags, 1);
|
273
273
|
|
274
|
-
/* registers
|
274
|
+
/* registers a target +IO+ object via epoll_ctl */
|
275
275
|
rb_define_const(cEpoll, "CTL_ADD", INT2NUM(EPOLL_CTL_ADD));
|
276
276
|
|
277
|
-
/* unregisters
|
277
|
+
/* unregisters a target +IO+ object via epoll_ctl */
|
278
278
|
rb_define_const(cEpoll, "CTL_DEL", INT2NUM(EPOLL_CTL_DEL));
|
279
279
|
|
280
|
-
/* modifies the registration of
|
280
|
+
/* modifies the registration of a target +IO+ object via epoll_ctl */
|
281
281
|
rb_define_const(cEpoll, "CTL_MOD", INT2NUM(EPOLL_CTL_MOD));
|
282
282
|
|
283
283
|
/* specifies whether close-on-exec flag is set for Epoll.new */
|
@@ -306,18 +306,29 @@ void sleepy_penguin_init_epoll(void)
|
|
306
306
|
rb_define_const(cEpoll, "WAKEUP", UINT2NUM(EPOLLWAKEUP));
|
307
307
|
#endif
|
308
308
|
|
309
|
+
#ifdef EPOLLEXCLUSIVE
|
310
|
+
/*
|
311
|
+
* Sets an exclusive wakeup mode for the epoll object
|
312
|
+
* that is being attached to the target +IO+. This
|
313
|
+
* avoids thundering herd scenarios when the same
|
314
|
+
* target +IO+ is shared among multiple epoll objects.
|
315
|
+
* Available since Linux 4.5
|
316
|
+
*/
|
317
|
+
rb_define_const(cEpoll, "EXCLUSIVE", UINT2NUM(EPOLLEXCLUSIVE));
|
318
|
+
#endif
|
319
|
+
|
309
320
|
/* watch for urgent read(2) data */
|
310
321
|
rb_define_const(cEpoll, "PRI", UINT2NUM(EPOLLPRI));
|
311
322
|
|
312
323
|
/*
|
313
324
|
* watch for errors, there is no need to specify this,
|
314
|
-
* it is always monitored when an IO is watched
|
325
|
+
* it is always monitored when an +IO+ is watched
|
315
326
|
*/
|
316
327
|
rb_define_const(cEpoll, "ERR", UINT2NUM(EPOLLERR));
|
317
328
|
|
318
329
|
/*
|
319
330
|
* watch for hangups, there is no need to specify this,
|
320
|
-
* it is always monitored when an IO is watched
|
331
|
+
* it is always monitored when an +IO+ is watched
|
321
332
|
*/
|
322
333
|
rb_define_const(cEpoll, "HUP", UINT2NUM(EPOLLHUP));
|
323
334
|
|
@@ -329,10 +340,9 @@ void sleepy_penguin_init_epoll(void)
|
|
329
340
|
|
330
341
|
id_for_fd = rb_intern("for_fd");
|
331
342
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
rb_require("sleepy_penguin/epoll");
|
343
|
+
/*
|
344
|
+
* the high-level interface is implemented in Ruby,
|
345
|
+
* see lib/sleepy_penguin/epoll.rb
|
346
|
+
*/
|
337
347
|
}
|
338
348
|
#endif /* HAVE_SYS_EPOLL_H */
|
@@ -31,10 +31,8 @@ static VALUE s_new(int argc, VALUE *argv, VALUE klass)
|
|
31
31
|
|
32
32
|
fd = eventfd(initval, flags);
|
33
33
|
if (fd < 0) {
|
34
|
-
if (errno
|
35
|
-
rb_gc();
|
34
|
+
if (rb_sp_gc_for_fd(errno))
|
36
35
|
fd = eventfd(initval, flags);
|
37
|
-
}
|
38
36
|
if (fd < 0)
|
39
37
|
rb_sys_fail("eventfd");
|
40
38
|
}
|
@@ -84,7 +82,9 @@ static VALUE incr(int argc, VALUE *argv, VALUE self)
|
|
84
82
|
|
85
83
|
rb_scan_args(argc, argv, "11", &value, &nonblock);
|
86
84
|
x.fd = rb_sp_fileno(self);
|
87
|
-
RTEST(nonblock)
|
85
|
+
if (RTEST(nonblock))
|
86
|
+
rb_sp_set_nonblock(x.fd);
|
87
|
+
|
88
88
|
x.val = (uint64_t)NUM2ULL(value);
|
89
89
|
retry:
|
90
90
|
w = (ssize_t)rb_sp_fd_region(efd_write, &x, x.fd);
|
@@ -121,7 +121,8 @@ static VALUE getvalue(int argc, VALUE *argv, VALUE self)
|
|
121
121
|
|
122
122
|
rb_scan_args(argc, argv, "01", &nonblock);
|
123
123
|
x.fd = rb_sp_fileno(self);
|
124
|
-
RTEST(nonblock)
|
124
|
+
if (RTEST(nonblock))
|
125
|
+
rb_sp_set_nonblock(x.fd);
|
125
126
|
retry:
|
126
127
|
w = (ssize_t)rb_sp_fd_region(efd_read, &x, x.fd);
|
127
128
|
if (w < 0) {
|
@@ -6,6 +6,7 @@ if have_header('sys/event.h')
|
|
6
6
|
end
|
7
7
|
have_header('sys/mount.h')
|
8
8
|
have_header('sys/eventfd.h')
|
9
|
+
have_header('sys/sendfile.h')
|
9
10
|
|
10
11
|
# it's impossible to use signalfd reliably with Ruby since Ruby currently
|
11
12
|
# manages # (and overrides) all signal handling
|
@@ -19,8 +20,13 @@ unless have_macro('CLOCK_MONOTONIC', 'time.h')
|
|
19
20
|
end
|
20
21
|
have_type('clockid_t', 'time.h')
|
21
22
|
have_func('clock_gettime', 'time.h')
|
23
|
+
have_func('copy_file_range')
|
22
24
|
have_func('epoll_create1', %w(sys/epoll.h))
|
23
25
|
have_func('inotify_init1', %w(sys/inotify.h))
|
26
|
+
have_func('splice', %w(fcntl.h))
|
27
|
+
have_func('tee', %w(fcntl.h))
|
28
|
+
have_macro('F_GETPIPE_SZ', %w(fcntl.h))
|
29
|
+
have_macro('F_SETPIPE_SZ', %w(fcntl.h))
|
24
30
|
have_func('rb_thread_call_without_gvl')
|
25
31
|
have_func('rb_thread_blocking_region')
|
26
32
|
have_func('rb_thread_io_blocking_region')
|
data/ext/sleepy_penguin/init.c
CHANGED
@@ -11,8 +11,15 @@
|
|
11
11
|
#define L1_CACHE_LINE_MAX 128 /* largest I've seen (Pentium 4) */
|
12
12
|
size_t rb_sp_l1_cache_line_size;
|
13
13
|
static pthread_key_t rb_sp_key;
|
14
|
+
enum rb_sp_tls_buf_type {
|
15
|
+
RB_SP_TLS_INUSE = -1,
|
16
|
+
RB_SP_TLS_READY = 0,
|
17
|
+
RB_SP_TLS_MALLOCED = 1
|
18
|
+
};
|
19
|
+
|
14
20
|
struct rb_sp_tlsbuf {
|
15
|
-
|
21
|
+
uint32_t capa;
|
22
|
+
enum rb_sp_tls_buf_type buf_type;
|
16
23
|
unsigned char ptr[FLEX_ARRAY];
|
17
24
|
};
|
18
25
|
|
@@ -52,6 +59,22 @@ void sleepy_penguin_init_signalfd(void);
|
|
52
59
|
# define sleepy_penguin_init_signalfd() for(;0;)
|
53
60
|
#endif
|
54
61
|
|
62
|
+
#ifdef HAVE_SPLICE
|
63
|
+
void sleepy_penguin_init_splice(void);
|
64
|
+
#else
|
65
|
+
# define sleepy_penguin_init_splice() for(;0;)
|
66
|
+
#endif
|
67
|
+
|
68
|
+
#if defined(HAVE_COPY_FILE_RANGE) || \
|
69
|
+
(defined(__linux__) && defined(__NR_copy_file_range))
|
70
|
+
void sleepy_penguin_init_cfr(void);
|
71
|
+
#else
|
72
|
+
# define sleepy_penguin_init_cfr() for (;0;)
|
73
|
+
#endif
|
74
|
+
|
75
|
+
/* everyone */
|
76
|
+
void sleepy_penguin_init_sendfile(void);
|
77
|
+
|
55
78
|
static size_t l1_cache_line_size_detect(void)
|
56
79
|
{
|
57
80
|
#ifdef _SC_LEVEL1_DCACHE_LINESIZE
|
@@ -73,12 +96,36 @@ static void sp_once(void)
|
|
73
96
|
}
|
74
97
|
}
|
75
98
|
|
99
|
+
static struct rb_sp_tlsbuf *alloc_tlsbuf(size_t size)
|
100
|
+
{
|
101
|
+
size_t bytes = size + sizeof(struct rb_sp_tlsbuf);
|
102
|
+
struct rb_sp_tlsbuf *buf;
|
103
|
+
void *ptr;
|
104
|
+
int err = posix_memalign(&ptr, rb_sp_l1_cache_line_size, bytes);
|
105
|
+
|
106
|
+
if (err) {
|
107
|
+
errno = err;
|
108
|
+
rb_memerror(); /* fatal */
|
109
|
+
}
|
110
|
+
|
111
|
+
buf = ptr;
|
112
|
+
buf->capa = size;
|
113
|
+
|
114
|
+
return buf;
|
115
|
+
}
|
116
|
+
|
76
117
|
void *rb_sp_gettlsbuf(size_t *size)
|
77
118
|
{
|
78
119
|
struct rb_sp_tlsbuf *buf = pthread_getspecific(rb_sp_key);
|
79
|
-
void *ptr;
|
80
120
|
int err;
|
81
|
-
|
121
|
+
|
122
|
+
assert(buf ? buf->buf_type != RB_SP_TLS_MALLOCED : 1);
|
123
|
+
|
124
|
+
if (buf && buf->buf_type != RB_SP_TLS_READY) {
|
125
|
+
buf = alloc_tlsbuf(*size);
|
126
|
+
buf->buf_type = RB_SP_TLS_MALLOCED;
|
127
|
+
return buf->ptr;
|
128
|
+
}
|
82
129
|
|
83
130
|
if (buf && buf->capa >= *size) {
|
84
131
|
*size = buf->capa;
|
@@ -86,24 +133,45 @@ void *rb_sp_gettlsbuf(size_t *size)
|
|
86
133
|
}
|
87
134
|
|
88
135
|
free(buf);
|
89
|
-
|
90
|
-
err = posix_memalign(&ptr, rb_sp_l1_cache_line_size, bytes);
|
91
|
-
if (err) {
|
92
|
-
errno = err;
|
93
|
-
rb_memerror(); /* fatal */
|
94
|
-
}
|
95
|
-
|
96
|
-
buf = ptr;
|
97
|
-
buf->capa = *size;
|
136
|
+
buf = alloc_tlsbuf(*size);
|
98
137
|
err = pthread_setspecific(rb_sp_key, buf);
|
99
138
|
if (err != 0) {
|
139
|
+
free(buf);
|
100
140
|
errno = err;
|
101
141
|
rb_sys_fail("BUG: pthread_setspecific");
|
102
142
|
}
|
103
143
|
out:
|
144
|
+
buf->buf_type = RB_SP_TLS_INUSE;
|
104
145
|
return buf->ptr;
|
105
146
|
}
|
106
147
|
|
148
|
+
#define container_of(ptr, type, member) \
|
149
|
+
(type *)((uintptr_t)(ptr) - offsetof(type, member))
|
150
|
+
|
151
|
+
VALUE rb_sp_puttlsbuf(VALUE p)
|
152
|
+
{
|
153
|
+
struct rb_sp_tlsbuf *tls = pthread_getspecific(rb_sp_key);
|
154
|
+
void *ptr = (void *)p;
|
155
|
+
struct rb_sp_tlsbuf *buf;
|
156
|
+
|
157
|
+
if (!ptr)
|
158
|
+
return Qfalse;
|
159
|
+
|
160
|
+
buf = container_of(ptr, struct rb_sp_tlsbuf, ptr);
|
161
|
+
|
162
|
+
switch (buf->buf_type) {
|
163
|
+
case RB_SP_TLS_INUSE:
|
164
|
+
assert(tls == buf && "rb_sp_puttlsbuf mismatch");
|
165
|
+
buf->buf_type = RB_SP_TLS_READY;
|
166
|
+
break;
|
167
|
+
case RB_SP_TLS_READY:
|
168
|
+
assert(0 && "rb_sp_gettlsbuf not called");
|
169
|
+
case RB_SP_TLS_MALLOCED:
|
170
|
+
free(buf);
|
171
|
+
}
|
172
|
+
return Qfalse;
|
173
|
+
}
|
174
|
+
|
107
175
|
void Init_sleepy_penguin_ext(void)
|
108
176
|
{
|
109
177
|
VALUE mSleepyPenguin;
|
@@ -127,4 +195,7 @@ void Init_sleepy_penguin_ext(void)
|
|
127
195
|
sleepy_penguin_init_eventfd();
|
128
196
|
sleepy_penguin_init_inotify();
|
129
197
|
sleepy_penguin_init_signalfd();
|
198
|
+
sleepy_penguin_init_splice();
|
199
|
+
sleepy_penguin_init_cfr();
|
200
|
+
sleepy_penguin_init_sendfile();
|
130
201
|
}
|