v / vlib / picoev / loop_default.c.v
95 lines · 84 sloc · 2.13 KB · 6cbffd53ba3e36764de579e5e758bc7b962d0632
Raw
1module picoev
2
3$if windows {
4 #include <winsock2.h>
5 #include <ws2tcpip.h>
6} $else {
7 #include <sys/select.h>
8}
9
10pub struct SelectLoop {
11mut:
12 id int
13 now i64
14}
15
16type LoopType = SelectLoop
17
18// create_select_loop creates a new `SelectLoop` struct with the given `id`.
19pub fn create_select_loop(id int) !&SelectLoop {
20 return &SelectLoop{
21 id: id
22 }
23}
24
25// updates the events associated with a file descriptor in the event loop.
26@[direct_array_access]
27fn (mut pv Picoev) update_events(fd int, events int) int {
28 // check if fd is in range
29 assert fd < max_fds
30
31 pv.file_descriptors[fd].events = u32(events & picoev_readwrite)
32 return 0
33}
34
35// performs a single iteration of the select-based event loop.
36@[direct_array_access]
37fn (mut pv Picoev) poll_once(max_wait_in_sec int) int {
38 // Initializes sets for read, write, and error events
39 readfds, writefds, errorfds := C.fd_set{}, C.fd_set{}, C.fd_set{}
40
41 // setup
42 C.FD_ZERO(&readfds)
43 C.FD_ZERO(&writefds)
44 C.FD_ZERO(&errorfds)
45
46 mut maxfd := 0
47
48 // finds the maximum file descriptor and adds sockets to the sets `fd_sets`.
49 for target in pv.file_descriptors {
50 if target.loop_id == pv.loop.id {
51 if target.events & picoev_read != 0 {
52 C.FD_SET(target.fd, &readfds)
53 if maxfd < target.fd {
54 maxfd = target.fd
55 }
56 }
57 if target.events & picoev_write != 0 {
58 C.FD_SET(target.fd, &writefds)
59 if maxfd < target.fd {
60 maxfd = target.fd
61 }
62 }
63 }
64 }
65
66 // select and handle sockets if any
67 tv := C.timeval{
68 tv_sec: u64(max_wait_in_sec)
69 tv_usec: 0
70 }
71 r := C.select(maxfd + 1, &readfds, &writefds, &errorfds, &tv)
72 if r == -1 {
73 // timeout
74 return -1
75 } else if r > 0 {
76 // Iterates through file descriptors and calls their callbacks for triggered events
77 for target in pv.file_descriptors {
78 if target.loop_id == pv.loop.id {
79 mut read_events := 0
80 if C.FD_ISSET(target.fd, &readfds) != 0 {
81 read_events |= picoev_read
82 }
83 if C.FD_ISSET(target.fd, &writefds) != 0 {
84 read_events |= picoev_write
85 }
86 if read_events != 0 {
87 trace_fd('do callback ${target.fd}')
88 // do callback!
89 unsafe { target.cb(target.fd, read_events, &pv) }
90 }
91 }
92 }
93 }
94 return 0
95}
96