evt 0.1.3 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +54 -0
- data/.gitignore +1 -0
- data/Gemfile +1 -1
- data/README.md +67 -13
- data/evt.gemspec +3 -3
- data/ext/evt/epoll.h +89 -0
- data/ext/evt/evt.c +26 -205
- data/ext/evt/evt.h +72 -1
- data/ext/evt/extconf.rb +20 -2
- data/ext/evt/iocp.h +126 -0
- data/ext/evt/kqueue.h +87 -0
- data/ext/evt/select.h +36 -0
- data/ext/evt/uring.h +200 -0
- data/lib/evt.rb +1 -2
- data/lib/evt/scheduler.rb +51 -92
- data/lib/evt/version.rb +1 -1
- metadata +11 -8
- data/.travis.yml +0 -25
- data/Gemfile.lock +0 -24
- data/lib/evt/io.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcbae12e6f731dbbd29a341c60bbb41ef1fabb6095b0bc581f1bce0a51d6a729
|
4
|
+
data.tar.gz: 46497ea730a052a6c8e0a390fa031e8b81dd7b2eb84f05152e85df286db9f20a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 782544e4c98db9600fbacdeef1fdf85748494ed75e7ca4edbc154d483bf09da6ce4ff764600695368e6b7e47c26c0415523d303f74f1174b8c6c41e5130ac6b7
|
7
|
+
data.tar.gz: e763ec572a4289c1c14ed83503502ffa4ffd346a239e30510fe699eb46e72cbf5fad07e67caa3f8b416a5a42c2851bc483cc81d418e9dd02550afac39d8751a2
|
@@ -0,0 +1,54 @@
|
|
1
|
+
name: CI Tests
|
2
|
+
on:
|
3
|
+
pull_request:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
schedule:
|
8
|
+
- cron: '0 7 * * SUN'
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
strategy:
|
12
|
+
fail-fast: false
|
13
|
+
matrix:
|
14
|
+
include:
|
15
|
+
- { os: ubuntu-20.04, ruby: '3.0', backend: epoll }
|
16
|
+
- { os: ubuntu-20.04, ruby: '3.0', backend: ruby, disable-epoll: 1 }
|
17
|
+
- { os: macos-11.0, ruby: '3.0', backend: kqueue }
|
18
|
+
- { os: macos-11.0, ruby: '3.0', backend: ruby, disable-kqueue: 1 }
|
19
|
+
- { os: windows-2019, ruby: mingw, backend: ruby }
|
20
|
+
- { os: windows-2019, ruby: mswin, backend: ruby }
|
21
|
+
name: test ${{ matrix.os }} ${{ matrix.ruby }} ${{ matrix.backend }}
|
22
|
+
runs-on: ${{ matrix.os }}
|
23
|
+
timeout-minutes: 5
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v2
|
26
|
+
- uses: ruby/setup-ruby@master
|
27
|
+
with:
|
28
|
+
ruby-version: ${{ matrix.ruby }}
|
29
|
+
bundler-cache: false
|
30
|
+
- name: Install Dependencies
|
31
|
+
run: |
|
32
|
+
gem install bundler
|
33
|
+
bundle install --jobs 4 --retry 3
|
34
|
+
- name: Compile
|
35
|
+
env:
|
36
|
+
DISABLE_EPOLL: ${{ matrix.disable-epoll }}
|
37
|
+
DISABLE_KQUEUE: ${{ matrix.disable-kqueue }}
|
38
|
+
run: rake compile
|
39
|
+
- name: Test
|
40
|
+
run: rake
|
41
|
+
build:
|
42
|
+
runs-on: ubuntu-20.04
|
43
|
+
steps:
|
44
|
+
- uses: actions/checkout@v2
|
45
|
+
- uses: ruby/setup-ruby@master
|
46
|
+
with:
|
47
|
+
ruby-version: '3.0'
|
48
|
+
bundler-cache: false
|
49
|
+
- name: Install Dependencies
|
50
|
+
run: |
|
51
|
+
gem install bundler
|
52
|
+
bundle install --jobs 4 --retry 3
|
53
|
+
- name: Build
|
54
|
+
run: gem build evt.gemspec
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,46 @@
|
|
1
|
-
#
|
1
|
+
# Evt
|
2
2
|
|
3
|
-
|
3
|
+
The Event Library that designed for Ruby 3.0 Fiber Scheduler.
|
4
4
|
|
5
|
-
|
5
|
+
**This gem is still under development, APIs and features are not stable. Advices and PRs are highly welcome.**
|
6
6
|
|
7
|
-
|
7
|
+
[![CI Tests](https://github.com/dsh0416/evt/workflows/CI%20Tests/badge.svg)](https://github.com/dsh0416/evt/actions?query=workflow%3A%22CI+Tests%22)
|
8
|
+
[![Gem Version](https://badge.fury.io/rb/evt.svg)](https://rubygems.org/gems/evt)
|
9
|
+
[![Downloads](https://ruby-gem-downloads-badge.herokuapp.com/evt?type=total)](https://rubygems.org/gems/evt)
|
10
|
+
|
11
|
+
## Features
|
12
|
+
|
13
|
+
### IO Backend Support
|
14
|
+
|
15
|
+
| | Linux | Windows | macOS | FreeBSD |
|
16
|
+
| --------------- | ----------- | ------------| ----------- | ----------- |
|
17
|
+
| io_uring | ✅ (See 1) | ❌ | ❌ | ❌ |
|
18
|
+
| epoll | ✅ (See 2) | ❌ | ❌ | ❌ |
|
19
|
+
| kqueue | ❌ | ❌ | ✅ (⚠️ See 5) | ✅ |
|
20
|
+
| IOCP | ❌ | ❌ (⚠️See 3) | ❌ | ❌ |
|
21
|
+
| Ruby (`IO.select`) | ✅ Fallback | ✅ (⚠️See 4) | ✅ Fallback | ✅ Fallback |
|
22
|
+
|
23
|
+
1. when liburing is installed
|
24
|
+
2. when kernel version >= 2.6.8
|
25
|
+
3. WOULD NOT WORK until `FILE_FLAG_OVERLAPPED` is included in I/O initialization process.
|
26
|
+
4. Some I/Os are not able to be nonblock under Windows. See [Scheduler Docs](https://docs.ruby-lang.org/en/master/doc/scheduler_md.html#label-IO).
|
27
|
+
5. `kqueue` performance in Darwin is very poor. **MAY BE DISABLED IN THE FUTURE.**
|
28
|
+
|
29
|
+
### Benchmark
|
30
|
+
|
31
|
+
The benchmark is running under `v0.2.2` version. See [evt-server-benchmark](https://github.com/dsh0416/evt-server-benchmark) for test code, the test is running under a single-thread server.
|
32
|
+
|
33
|
+
The test command is `wrk -t4 -c8192 -d30s http://localhost:3001`.
|
34
|
+
|
35
|
+
All of the systems have set their file descriptor limit to maximum.
|
36
|
+
|
37
|
+
| OS | CPU | Memory | Backend | req/s |
|
38
|
+
| ----- | ----------- | ------ | ---------------------- | -------- |
|
39
|
+
| Linux | Ryzen 2700x | 64GB | epoll | 54680.08 |
|
40
|
+
| Linux | Ryzen 2700x | 64GB | io_uring | 50245.53 |
|
41
|
+
| Linux | Ryzen 2700x | 64GB | IO.select (using poll) | 44159.23 |
|
42
|
+
| macOS | i7-6820HQ | 16GB | kqueue | 37855.53 |
|
43
|
+
| macOS | i7-6820HQ | 16GB | IO.select (using poll) | 28293.36 |
|
8
44
|
|
9
45
|
## Install
|
10
46
|
|
@@ -18,17 +54,35 @@ gem install evt
|
|
18
54
|
require 'evt'
|
19
55
|
|
20
56
|
rd, wr = IO.pipe
|
21
|
-
|
57
|
+
scheduler = Evt::Scheduler.new
|
22
58
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
59
|
+
Fiber.set_scheduler scheduler
|
60
|
+
|
61
|
+
Fiber.schedule do
|
62
|
+
message = rd.read(20)
|
63
|
+
puts message
|
64
|
+
rd.close
|
27
65
|
end
|
28
66
|
|
29
|
-
|
30
|
-
|
31
|
-
|
67
|
+
Fiber.schedule do
|
68
|
+
wr.write("Hello World")
|
69
|
+
wr.close
|
70
|
+
end
|
32
71
|
|
33
|
-
|
72
|
+
scheduler.run
|
73
|
+
|
74
|
+
# "Hello World"
|
34
75
|
```
|
76
|
+
|
77
|
+
## Roadmap
|
78
|
+
|
79
|
+
- [x] Support epoll/kqueue/select
|
80
|
+
- [x] Upgrade to the latest Scheduler API
|
81
|
+
- [x] Support io_uring
|
82
|
+
- [x] Support iov features of io_uring
|
83
|
+
- [x] Support IOCP (**NOT ENABLED YET**)
|
84
|
+
- [x] Setup tests with Ruby 3
|
85
|
+
- [x] Selectable backend compilation by environment variable
|
86
|
+
- [ ] Support IOCP with iov features
|
87
|
+
- [ ] Setup more tests for production purpose
|
88
|
+
- [ ] Documentation for usages
|
data/evt.gemspec
CHANGED
@@ -6,11 +6,11 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.authors = ["Delton Ding"]
|
7
7
|
spec.email = ["dsh0416@gmail.com"]
|
8
8
|
|
9
|
-
spec.summary = "
|
9
|
+
spec.summary = "The Event Library that designed for Ruby 3.0 Fiber Scheluer."
|
10
10
|
spec.description = "A low-level Event Handler designed for Ruby 3 Scheduler for better performance"
|
11
11
|
spec.homepage = "https://github.com/dsh0416/evt"
|
12
12
|
spec.license = 'BSD-3-Clause'
|
13
|
-
spec.required_ruby_version = '>=
|
13
|
+
spec.required_ruby_version = '>= 3.0.0.rc1'
|
14
14
|
|
15
15
|
spec.metadata["homepage_uri"] = spec.homepage
|
16
16
|
spec.metadata["source_code_uri"] = "https://github.com/dsh0416/evt"
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
# Specify which files should be added to the gem when it is released.
|
19
19
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
20
|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
21
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
21
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|.vscode)/}) }
|
22
22
|
end
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
spec.extensions = ['ext/evt/extconf.rb']
|
data/ext/evt/epoll.h
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
#ifndef EPOLL_H
|
2
|
+
#define EPOLL_G
|
3
|
+
#include "evt.h"
|
4
|
+
|
5
|
+
#if HAVE_SYS_EPOLL_H
|
6
|
+
VALUE method_scheduler_init(VALUE self) {
|
7
|
+
rb_iv_set(self, "@epfd", INT2NUM(epoll_create(1))); // Size of epoll is ignored after Linux 2.6.8.
|
8
|
+
return Qnil;
|
9
|
+
}
|
10
|
+
|
11
|
+
VALUE method_scheduler_register(VALUE self, VALUE io, VALUE interest) {
|
12
|
+
struct epoll_event event;
|
13
|
+
ID id_fileno = rb_intern("fileno");
|
14
|
+
int epfd = NUM2INT(rb_iv_get(self, "@epfd"));
|
15
|
+
int fd = NUM2INT(rb_funcall(io, id_fileno, 0));
|
16
|
+
int ruby_interest = NUM2INT(interest);
|
17
|
+
int readable = NUM2INT(rb_const_get(rb_cIO, rb_intern("READABLE")));
|
18
|
+
int writable = NUM2INT(rb_const_get(rb_cIO, rb_intern("WRITABLE")));
|
19
|
+
|
20
|
+
if (ruby_interest & readable) {
|
21
|
+
event.events |= EPOLLIN;
|
22
|
+
}
|
23
|
+
|
24
|
+
if (ruby_interest & writable) {
|
25
|
+
event.events |= EPOLLOUT;
|
26
|
+
}
|
27
|
+
|
28
|
+
event.data.ptr = (void*) io;
|
29
|
+
|
30
|
+
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
|
31
|
+
return Qnil;
|
32
|
+
}
|
33
|
+
|
34
|
+
VALUE method_scheduler_deregister(VALUE self, VALUE io) {
|
35
|
+
ID id_fileno = rb_intern("fileno");
|
36
|
+
int epfd = NUM2INT(rb_iv_get(self, "@epfd"));
|
37
|
+
int fd = NUM2INT(rb_funcall(io, id_fileno, 0));
|
38
|
+
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); // Require Linux 2.6.9 for NULL event.
|
39
|
+
return Qnil;
|
40
|
+
}
|
41
|
+
|
42
|
+
VALUE method_scheduler_wait(VALUE self) {
|
43
|
+
int n, epfd, i, event_flag, timeout;
|
44
|
+
VALUE next_timeout, obj_io, readables, writables, result;
|
45
|
+
ID id_next_timeout = rb_intern("next_timeout");
|
46
|
+
ID id_push = rb_intern("push");
|
47
|
+
|
48
|
+
epfd = NUM2INT(rb_iv_get(self, "@epfd"));
|
49
|
+
next_timeout = rb_funcall(self, id_next_timeout, 0);
|
50
|
+
readables = rb_ary_new();
|
51
|
+
writables = rb_ary_new();
|
52
|
+
|
53
|
+
if (next_timeout == Qnil) {
|
54
|
+
timeout = -1;
|
55
|
+
} else {
|
56
|
+
timeout = NUM2INT(next_timeout);
|
57
|
+
}
|
58
|
+
|
59
|
+
struct epoll_event events[EPOLL_MAX_EVENTS];
|
60
|
+
|
61
|
+
n = epoll_wait(epfd, events, EPOLL_MAX_EVENTS, timeout);
|
62
|
+
if (n < 0) {
|
63
|
+
rb_raise(rb_eIOError, "unable to call epoll_wait");
|
64
|
+
}
|
65
|
+
|
66
|
+
for (i = 0; i < n; i++) {
|
67
|
+
event_flag = events[i].events;
|
68
|
+
if (event_flag & EPOLLIN) {
|
69
|
+
obj_io = (VALUE) events[i].data.ptr;
|
70
|
+
rb_funcall(readables, id_push, 1, obj_io);
|
71
|
+
}
|
72
|
+
|
73
|
+
if (event_flag & EPOLLOUT) {
|
74
|
+
obj_io = (VALUE) events[i].data.ptr;
|
75
|
+
rb_funcall(writables, id_push, 1, obj_io);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
result = rb_ary_new2(2);
|
80
|
+
rb_ary_store(result, 0, readables);
|
81
|
+
rb_ary_store(result, 1, writables);
|
82
|
+
return result;
|
83
|
+
}
|
84
|
+
|
85
|
+
VALUE method_scheduler_backend(VALUE klass) {
|
86
|
+
return rb_str_new_cstr("epoll");
|
87
|
+
}
|
88
|
+
#endif
|
89
|
+
#endif
|
data/ext/evt/evt.c
CHANGED
@@ -1,218 +1,39 @@
|
|
1
|
+
#ifndef EVT_C
|
2
|
+
#define EVT_C
|
3
|
+
|
1
4
|
#include "evt.h"
|
2
5
|
|
3
6
|
void Init_evt_ext()
|
4
7
|
{
|
8
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
9
|
+
rb_ext_ractor_safe(true);
|
10
|
+
#endif
|
5
11
|
Evt = rb_define_module("Evt");
|
6
12
|
Scheduler = rb_define_class_under(Evt, "Scheduler", rb_cObject);
|
13
|
+
Payload = rb_define_class_under(Scheduler, "Payload", rb_cObject);
|
14
|
+
Fiber = rb_define_class("Fiber", rb_cObject);
|
7
15
|
rb_define_singleton_method(Scheduler, "backend", method_scheduler_backend, 0);
|
8
16
|
rb_define_method(Scheduler, "init_selector", method_scheduler_init, 0);
|
9
17
|
rb_define_method(Scheduler, "register", method_scheduler_register, 2);
|
10
18
|
rb_define_method(Scheduler, "deregister", method_scheduler_deregister, 1);
|
11
19
|
rb_define_method(Scheduler, "wait", method_scheduler_wait, 0);
|
12
|
-
}
|
13
|
-
|
14
|
-
|
15
|
-
#if defined(__linux__) // TODO: Do more checks for using epoll
|
16
|
-
#include <sys/epoll.h>
|
17
|
-
#define EPOLL_MAX_EVENTS 64
|
18
|
-
|
19
|
-
VALUE method_scheduler_init(VALUE self) {
|
20
|
-
rb_iv_set(self, "@epfd", INT2NUM(epoll_create(1))); // Size of epoll is ignored after Linux 2.6.8.
|
21
|
-
return Qnil;
|
22
|
-
}
|
23
|
-
|
24
|
-
VALUE method_scheduler_register(VALUE self, VALUE io, VALUE interest) {
|
25
|
-
struct epoll_event event;
|
26
|
-
ID id_fileno = rb_intern("fileno");
|
27
|
-
int epfd = NUM2INT(rb_iv_get(self, "@epfd"));
|
28
|
-
int fd = NUM2INT(rb_funcall(io, id_fileno, 0));
|
29
|
-
int ruby_interest = NUM2INT(interest);
|
30
|
-
int readable = NUM2INT(rb_const_get(rb_cIO, rb_intern("WAIT_READABLE")));
|
31
|
-
int writable = NUM2INT(rb_const_get(rb_cIO, rb_intern("WAIT_WRITABLE")));
|
32
|
-
|
33
|
-
if (ruby_interest & readable) {
|
34
|
-
event.events |= EPOLLIN;
|
35
|
-
} else if (ruby_interest & writable) {
|
36
|
-
event.events |= EPOLLOUT;
|
37
|
-
}
|
38
|
-
event.data.ptr = (void*) io;
|
39
|
-
|
40
|
-
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
|
41
|
-
return Qnil;
|
42
|
-
}
|
43
|
-
|
44
|
-
VALUE method_scheduler_deregister(VALUE self, VALUE io) {
|
45
|
-
ID id_fileno = rb_intern("fileno");
|
46
|
-
int epfd = NUM2INT(rb_iv_get(self, "@epfd"));
|
47
|
-
int fd = NUM2INT(rb_funcall(io, id_fileno, 0));
|
48
|
-
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); // Require Linux 2.6.9 for NULL event.
|
49
|
-
return Qnil;
|
50
|
-
}
|
51
|
-
|
52
|
-
VALUE method_scheduler_wait(VALUE self) {
|
53
|
-
int n, epfd, i, event_flag, timeout;
|
54
|
-
VALUE next_timeout, obj_io, readables, writables, result;
|
55
|
-
ID id_next_timeout = rb_intern("next_timeout");
|
56
|
-
ID id_push = rb_intern("push");
|
57
|
-
|
58
|
-
epfd = NUM2INT(rb_iv_get(self, "@epfd"));
|
59
|
-
next_timeout = rb_funcall(self, id_next_timeout, 0);
|
60
|
-
readables = rb_ary_new();
|
61
|
-
writables = rb_ary_new();
|
62
|
-
|
63
|
-
if (next_timeout == Qnil) {
|
64
|
-
timeout = -1;
|
65
|
-
} else {
|
66
|
-
timeout = NUM2INT(next_timeout);
|
67
|
-
}
|
68
|
-
|
69
|
-
struct epoll_event* events = (struct epoll_event*) xmalloc(sizeof(struct epoll_event) * EPOLL_MAX_EVENTS);
|
70
|
-
|
71
|
-
n = epoll_wait(epfd, events, EPOLL_MAX_EVENTS, timeout);
|
72
|
-
// TODO: Check if n >= 0
|
73
|
-
|
74
|
-
for (i = 0; i < n; i++) {
|
75
|
-
event_flag = events[i].events;
|
76
|
-
if (event_flag & EPOLLIN) {
|
77
|
-
obj_io = (VALUE) events[i].data.ptr;
|
78
|
-
rb_funcall(readables, id_push, 1, obj_io);
|
79
|
-
} else if (event_flag & EPOLLOUT) {
|
80
|
-
obj_io = (VALUE) events[i].data.ptr;
|
81
|
-
rb_funcall(writables, id_push, 1, obj_io);
|
82
|
-
}
|
83
|
-
}
|
84
|
-
|
85
|
-
result = rb_ary_new2(2);
|
86
|
-
rb_ary_store(result, 0, readables);
|
87
|
-
rb_ary_store(result, 1, writables);
|
88
|
-
|
89
|
-
xfree(events);
|
90
|
-
return result;
|
91
|
-
}
|
92
|
-
|
93
|
-
VALUE method_scheduler_backend() {
|
94
|
-
return rb_str_new_cstr("epoll");
|
95
|
-
}
|
96
|
-
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
97
|
-
#include <sys/event.h>
|
98
|
-
#define KQUEUE_MAX_EVENTS 64
|
99
|
-
|
100
|
-
VALUE method_scheduler_init(VALUE self) {
|
101
|
-
rb_iv_set(self, "@kq", INT2NUM(kqueue()));
|
102
|
-
return Qnil;
|
103
|
-
}
|
104
|
-
|
105
|
-
VALUE method_scheduler_register(VALUE self, VALUE io, VALUE interest) {
|
106
|
-
struct kevent event;
|
107
|
-
u_short event_flags = 0;
|
108
|
-
ID id_fileno = rb_intern("fileno");
|
109
|
-
int kq = NUM2INT(rb_iv_get(self, "@kq"));
|
110
|
-
int fd = NUM2INT(rb_funcall(io, id_fileno, 0));
|
111
|
-
int ruby_interest = NUM2INT(interest);
|
112
|
-
int readable = NUM2INT(rb_const_get(rb_cIO, rb_intern("WAIT_READABLE")));
|
113
|
-
int writable = NUM2INT(rb_const_get(rb_cIO, rb_intern("WAIT_WRITABLE")));
|
114
|
-
|
115
|
-
if (ruby_interest & readable) {
|
116
|
-
event_flags |= EVFILT_READ;
|
117
|
-
} else if (ruby_interest & writable) {
|
118
|
-
event_flags |= EVFILT_WRITE;
|
119
|
-
}
|
120
|
-
|
121
|
-
EV_SET(&event, fd, event_flags, EV_ADD|EV_ENABLE, 0, 0, (void*) io);
|
122
|
-
kevent(kq, &event, 1, NULL, 0, NULL); // TODO: Check the return value
|
123
|
-
return Qnil;
|
124
|
-
}
|
125
20
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
struct timespec timeout;
|
142
|
-
VALUE next_timeout, obj_io, readables, writables, result;
|
143
|
-
ID id_next_timeout = rb_intern("next_timeout");
|
144
|
-
ID id_push = rb_intern("push");
|
145
|
-
|
146
|
-
kq = NUM2INT(rb_iv_get(self, "@kq"));
|
147
|
-
next_timeout = rb_funcall(self, id_next_timeout, 0);
|
148
|
-
readables = rb_ary_new();
|
149
|
-
writables = rb_ary_new();
|
150
|
-
|
151
|
-
events = (struct kevent*) xmalloc(sizeof(struct kevent) * KQUEUE_MAX_EVENTS);
|
152
|
-
|
153
|
-
if (next_timeout == Qnil || NUM2INT(next_timeout) == -1) {
|
154
|
-
n = kevent(kq, NULL, 0, events, KQUEUE_MAX_EVENTS, NULL);
|
155
|
-
} else {
|
156
|
-
timeout.tv_sec = next_timeout / 1000;
|
157
|
-
timeout.tv_nsec = next_timeout % 1000 * 1000 * 1000;
|
158
|
-
n = kevent(kq, NULL, 0, events, KQUEUE_MAX_EVENTS, &timeout);
|
159
|
-
}
|
160
|
-
|
161
|
-
// TODO: Check if n >= 0
|
162
|
-
for (i = 0; i < n; i++) {
|
163
|
-
event_flags = events[i].filter;
|
164
|
-
if (event_flags & EVFILT_READ) {
|
165
|
-
obj_io = (VALUE) events[i].udata;
|
166
|
-
rb_funcall(readables, id_push, 1, obj_io);
|
167
|
-
} else if (event_flags & EVFILT_WRITE) {
|
168
|
-
obj_io = (VALUE) events[i].udata;
|
169
|
-
rb_funcall(writables, id_push, 1, obj_io);
|
170
|
-
}
|
171
|
-
}
|
172
|
-
|
173
|
-
result = rb_ary_new2(2);
|
174
|
-
rb_ary_store(result, 0, readables);
|
175
|
-
rb_ary_store(result, 1, writables);
|
176
|
-
|
177
|
-
xfree(events);
|
178
|
-
return result;
|
179
|
-
}
|
180
|
-
|
181
|
-
VALUE method_scheduler_backend() {
|
182
|
-
return rb_str_new_cstr("kqueue");
|
183
|
-
}
|
21
|
+
#if HAVELIBURING_H
|
22
|
+
rb_define_method(Scheduler, "io_read", method_scheduler_io_read, 4);
|
23
|
+
rb_define_method(Scheduler, "io_write", method_scheduler_io_write, 4);
|
24
|
+
#endif
|
25
|
+
}
|
26
|
+
|
27
|
+
#if HAVE_LIBURING_H
|
28
|
+
#include "uring.h"
|
29
|
+
#elif HAVE_SYS_EPOLL_H
|
30
|
+
#include "epoll.h"
|
31
|
+
#elif HAVE_SYS_EVENT_H
|
32
|
+
#include "kqueue.h"
|
33
|
+
#elif HAVE_WINDOWS_H
|
34
|
+
#include "select.h"
|
35
|
+
// #include "iocp.h"
|
184
36
|
#else
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
}
|
189
|
-
|
190
|
-
VALUE method_scheduler_register(VALUE self, VALUE io, VALUE interest) {
|
191
|
-
return Qnil;
|
192
|
-
}
|
193
|
-
|
194
|
-
VALUE method_scheduler_deregister(VALUE self, VALUE io) {
|
195
|
-
return Qnil;
|
196
|
-
}
|
197
|
-
|
198
|
-
VALUE method_scheduler_wait(VALUE self) {
|
199
|
-
// return IO.select(@readable.keys, @writable.keys, [], next_timeout)
|
200
|
-
VALUE readable, writable, readable_keys, writable_keys, next_timeout;
|
201
|
-
ID id_select = rb_intern("select");
|
202
|
-
ID id_keys = rb_intern("keys");
|
203
|
-
ID id_next_timeout = rb_intern("next_timeout");
|
204
|
-
|
205
|
-
readable = rb_iv_get(self, "@readable");
|
206
|
-
writable = rb_iv_get(self, "@writable");
|
207
|
-
|
208
|
-
readable_keys = rb_funcall(readable, id_keys, 0);
|
209
|
-
writable_keys = rb_funcall(writable, id_keys, 0);
|
210
|
-
next_timeout = rb_funcall(self, id_next_timeout, 0);
|
211
|
-
|
212
|
-
return rb_funcall(rb_cIO, id_select, 4, readable_keys, writable_keys, rb_ary_new(), next_timeout);
|
213
|
-
}
|
214
|
-
|
215
|
-
VALUE method_scheduler_backend() {
|
216
|
-
return rb_str_new_cstr("ruby");
|
217
|
-
}
|
218
|
-
#endif
|
37
|
+
#include "select.h"
|
38
|
+
#endif
|
39
|
+
#endif
|