sleepy_penguin 3.4.1 → 3.5.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 +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
|
}
|