Skip to content

Commit a44ff78

Browse files
committed
picoev: enable running veb services on Termux
1 parent 772d210 commit a44ff78

3 files changed

Lines changed: 145 additions & 2 deletions

File tree

‎vlib/picoev/loop_termux.c.v‎

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
module picoev
2+
3+
#include <sys/epoll.h>
4+
5+
$if !musl ? {
6+
#include <sys/cdefs.h> // needed for cross compiling to linux
7+
}
8+
9+
fn C.epoll_create(__flags int) int
10+
fn C.epoll_wait(__epfd int, __events &C.epoll_event, __maxevents int, __timeout int) int
11+
fn C.epoll_ctl(__epfd int, __op int, __fd int, __event &C.epoll_event) int
12+
13+
@[typedef]
14+
union C.epoll_data {
15+
mut:
16+
ptr voidptr
17+
fd int
18+
u32 u32
19+
u64 u64
20+
}
21+
22+
@[packed]
23+
pub struct C.epoll_event {
24+
events u32
25+
data C.epoll_data
26+
}
27+
28+
@[heap]
29+
pub struct EpollLoop {
30+
mut:
31+
id int
32+
epoll_fd int
33+
events [1024]C.epoll_event
34+
now i64
35+
}
36+
37+
type LoopType = EpollLoop
38+
39+
// create_epoll_loop creates a new epoll instance for and returns an
40+
// `EpollLoop` struct with `id`
41+
pub fn create_epoll_loop(id int) !&EpollLoop {
42+
mut loop := &EpollLoop{
43+
id: id
44+
}
45+
46+
loop.epoll_fd = C.epoll_create(max_fds)
47+
if loop.epoll_fd == -1 {
48+
return error('could not create epoll loop!')
49+
}
50+
51+
return loop
52+
}
53+
54+
@[direct_array_access]
55+
fn (mut pv Picoev) update_events(fd int, events int) int {
56+
// check if fd is in range
57+
assert fd < max_fds
58+
59+
mut target := pv.file_descriptors[fd]
60+
mut ev := C.epoll_event{}
61+
62+
// fd belongs to loop
63+
if events & picoev_del != target.events && target.loop_id != pv.loop.id {
64+
return -1
65+
}
66+
67+
if events & picoev_readwrite == target.events {
68+
return 0
69+
}
70+
71+
// vfmt off
72+
ev.events = u32(
73+
(if events & picoev_read != 0 { C.EPOLLIN } else { 0 })
74+
|
75+
(if events & picoev_write != 0 { C.EPOLLOUT } else { 0 })
76+
)
77+
// vfmt on
78+
ev.data.fd = fd
79+
80+
if events & picoev_del != 0 {
81+
// nothing to do
82+
} else if events & picoev_readwrite == 0 {
83+
// delete the file if it exists
84+
epoll_ret := C.epoll_ctl(pv.loop.epoll_fd, C.EPOLL_CTL_DEL, fd, &ev)
85+
86+
// check error
87+
assert epoll_ret == 0
88+
} else {
89+
// change settings to 0
90+
mut epoll_ret := C.epoll_ctl(pv.loop.epoll_fd, C.EPOLL_CTL_MOD, fd, &ev)
91+
if epoll_ret != 0 {
92+
// if the file is not present we want to add it
93+
assert C.errno == C.ENOENT
94+
epoll_ret = C.epoll_ctl(pv.loop.epoll_fd, C.EPOLL_CTL_ADD, fd, &ev)
95+
96+
// check error
97+
assert epoll_ret == 0
98+
}
99+
}
100+
101+
// convert to u32?
102+
target.events = u32(events)
103+
return 0
104+
}
105+
106+
@[direct_array_access]
107+
fn (mut pv Picoev) poll_once(max_wait_in_sec int) int {
108+
nevents := C.epoll_wait(pv.loop.epoll_fd, &pv.loop.events[0], max_fds, max_wait_in_sec * 1000)
109+
110+
if nevents == -1 {
111+
// timeout has occurred
112+
return -1
113+
}
114+
115+
for i := 0; i < nevents; i++ {
116+
mut event := pv.loop.events[i]
117+
target := unsafe { pv.file_descriptors[event.data.fd] }
118+
unsafe {
119+
assert event.data.fd < max_fds
120+
}
121+
if pv.loop.id == target.loop_id && target.events & picoev_readwrite != 0 {
122+
mut read_events := 0
123+
if event.events & u32(C.EPOLLIN) != 0 {
124+
read_events |= picoev_read
125+
}
126+
if event.events & u32(C.EPOLLOUT) != 0 {
127+
read_events |= picoev_write
128+
}
129+
130+
if read_events != 0 {
131+
// do callback!
132+
unsafe { target.cb(event.data.fd, read_events, &pv) }
133+
}
134+
} else {
135+
// defer epoll delete
136+
event.events = 0
137+
unsafe {
138+
C.epoll_ctl(pv.loop.epoll_fd, C.EPOLL_CTL_DEL, event.data.fd, &event)
139+
}
140+
}
141+
}
142+
return 0
143+
}

‎vlib/picoev/picoev.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ pub fn new(config Config) !&Picoev {
323323
// epoll on linux
324324
// kqueue on macos and bsd
325325
// select on windows and others
326-
$if linux {
326+
$if linux || termux {
327327
pv.loop = create_epoll_loop(0) or { panic(err) }
328328
} $else $if freebsd || macos {
329329
pv.loop = create_kqueue_loop(0) or { panic(err) }

‎vlib/picoev/socket_util.c.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ fn listen(config Config) !int {
104104
// can be accepted
105105
net.socket_error(C.setsockopt(fd, C.IPPROTO_IPV6, C.IPV6_V6ONLY, &flag_zero, sizeof(int)))!
106106
}
107-
$if linux {
107+
$if linux || termux {
108108
// epoll socket options
109109
net.socket_error(C.setsockopt(fd, C.SOL_SOCKET, C.SO_REUSEPORT, &flag, sizeof(int)))!
110110
net.socket_error(C.setsockopt(fd, C.IPPROTO_TCP, C.TCP_QUICKACK, &flag, sizeof(int)))!

0 commit comments

Comments
 (0)