File Coverage

blib/lib/Hypersonic/Event/Epoll.pm
Criterion Covered Total %
statement 37 41 90.2
branch 3 4 75.0
condition n/a
subroutine 20 22 90.9
pod 12 18 66.6
total 72 85 84.7


line stmt bran cond sub pod time code
1             package Hypersonic::Event::Epoll;
2              
3 27     27   208576 use strict;
  27         110  
  27         1347  
4 27     27   163 use warnings;
  27         107  
  27         2476  
5 27     27   676 use 5.010;
  27         172  
6              
7 27     27   166 use parent 'Hypersonic::Event::Role';
  27         96  
  27         499  
8              
9             our $VERSION = '0.15';
10              
11 22     22 1 2071 sub name { 'epoll' }
12              
13             sub available {
14 110     110 1 3403 return $^O eq 'linux';
15             }
16              
17             sub includes {
18 49     49 1 2866 return '#include ';
19             }
20              
21             sub defines {
22 49     49 1 3586 return <<'C';
23             #define EV_BACKEND_EPOLL 1
24             #ifndef MAX_EVENTS
25             #define MAX_EVENTS 1024
26             #endif
27             C
28             }
29              
30 33     33 1 3584 sub event_struct { 'epoll_event' }
31              
32 21     21 1 2738 sub extra_cflags { '' }
33 21     21 1 81 sub extra_ldflags { '' }
34              
35             # Generate: create epoll instance and add listen socket
36             sub gen_create {
37 21     21 1 3465 my ($class, $builder, $listen_fd_var) = @_;
38              
39 21         671 $builder->line('int ev_fd;')
40             ->line('struct epoll_event ev;')
41             ->blank
42             ->line('ev_fd = epoll_create1(0);')
43             ->if('ev_fd < 0')
44             ->line('croak("epoll_create1() failed");')
45             ->endif
46             ->blank
47             ->line('ev.events = EPOLLIN | EPOLLET;')
48             ->line("ev.data.fd = $listen_fd_var;")
49             ->if("epoll_ctl(ev_fd, EPOLL_CTL_ADD, $listen_fd_var, &ev) < 0")
50             ->line('close(ev_fd);')
51             ->line('croak("epoll_ctl() failed to add listen socket");')
52             ->endif;
53             }
54              
55             # Generate: add fd to epoll
56             sub gen_add {
57 21     21 1 1405 my ($class, $builder, $loop_var, $fd_var) = @_;
58              
59 21         230 $builder->line('ev.events = EPOLLIN | EPOLLET;')
60             ->line("ev.data.fd = $fd_var;")
61             ->line("epoll_ctl($loop_var, EPOLL_CTL_ADD, $fd_var, &ev);");
62             }
63              
64             # Generate: remove fd from epoll
65             sub gen_del {
66 81     81 1 1559 my ($class, $builder, $loop_var, $fd_var) = @_;
67              
68 81         529 $builder->line("epoll_ctl($loop_var, EPOLL_CTL_DEL, $fd_var, NULL);");
69             }
70              
71             # Generate: wait for events (inside a loop - can use continue/break)
72             sub gen_wait {
73 21     21 1 1188 my ($class, $builder, $loop_var, $events_var, $count_var, $timeout_var) = @_;
74              
75 21         471 $builder->line("int $count_var;")
76             ->line("$count_var = epoll_wait($loop_var, $events_var, MAX_EVENTS, $timeout_var);")
77             ->if("$count_var < 0")
78             ->if('errno == EINTR')
79             ->line('continue;')
80             ->endif
81             ->line('perror("epoll_wait");')
82             ->line('break;')
83             ->endif;
84             }
85              
86             # Generate: wait for events - single call version (no loop control)
87             sub gen_wait_once {
88 12     12 0 25 my ($class, $builder, $loop_var, $events_var, $count_var, $timeout_ms) = @_;
89              
90 12         130 $builder->line("$count_var = epoll_wait($loop_var, $events_var, MAX_EVENTS, $timeout_ms);")
91             ->line("if ($count_var < 0 && errno == EINTR) $count_var = 0;");
92             }
93              
94             # Generate: extract fd from event
95             sub gen_get_fd {
96 21     21 1 649 my ($class, $builder, $events_var, $index_var, $fd_var) = @_;
97              
98 21         353 $builder->line("int $fd_var;")
99             ->line("$fd_var = ${events_var}[$index_var].data.fd;");
100             }
101              
102             # ============================================================
103             # Async Slot Integration Methods (UA Async)
104             # ============================================================
105              
106             # Generate: create epoll without adding any fds
107             # Note: loop_var must be already declared
108             sub gen_create_loop {
109 12     12 0 44 my ($class, $builder, $loop_var) = @_;
110              
111 12         154 $builder->line("$loop_var = epoll_create1(0);")
112             ->if("$loop_var < 0")
113             ->line('croak("epoll_create1() failed");')
114             ->endif;
115             }
116              
117             # Generate: add fd with slot as user data
118             # Note: epoll_event.data is a union - we use data.u32 for slot
119             sub gen_add_with_slot {
120 24     24 0 88 my ($class, $builder, $loop_var, $fd_var, $slot_var, $events) = @_;
121              
122 24 50       73 my $ev_flags = $events eq 'read' ? 'EPOLLIN | EPOLLET | EPOLLONESHOT'
    100          
123             : $events eq 'write' ? 'EPOLLOUT | EPOLLET | EPOLLONESHOT'
124             : 'EPOLLIN | EPOLLET | EPOLLONESHOT';
125              
126 24         197 $builder->line('{')
127             ->line(' struct epoll_event _ev;')
128             ->line(" _ev.events = $ev_flags;")
129             ->line(" _ev.data.u32 = (uint32_t)$slot_var;")
130             ->line(" epoll_ctl($loop_var, EPOLL_CTL_ADD, $fd_var, &_ev);")
131             ->line('}');
132             }
133              
134             # Generate: extract slot from event data
135             sub gen_get_slot {
136 12     12 0 65 my ($class, $builder, $events_var, $index_var, $slot_var) = @_;
137              
138 12         102 $builder->line("int $slot_var;")
139             ->line("$slot_var = (int)${events_var}[$index_var].data.u32;");
140             }
141              
142             # ============================================================
143             # Future/Pool Integration Methods
144             # ============================================================
145              
146             # Future/Pool integration - add pool notify fd to epoll
147             sub gen_add_pool_notify {
148 0     0 0   my ($class, $builder, $loop_var, $notify_fd_var) = @_;
149              
150 0           $builder->line("/* Add pool notify fd to epoll */")
151             ->line('ev.events = EPOLLIN;')
152             ->line("ev.data.fd = $notify_fd_var;")
153             ->line("epoll_ctl($loop_var, EPOLL_CTL_ADD, $notify_fd_var, &ev);");
154             }
155              
156             # Multi-pool integration - add all pool notify fds to epoll
157             sub gen_add_multi_pool_notify {
158 0     0 0   my ($class, $builder, $loop_var, $pool_slots_var, $pool_count_var) = @_;
159              
160 0           $builder->line("/* Add all pool notify fds to epoll */")
161             ->line("{ int _pi; int _pool_notify_fd;")
162             ->line("for (_pi = 0; _pi < $pool_count_var; _pi++) {")
163             ->line(" _pool_notify_fd = pool_get_notify_fd_slot($pool_slots_var\[_pi]);")
164             ->line(" if (_pool_notify_fd >= 0) {")
165             ->line(" ev.events = EPOLLIN;")
166             ->line(" ev.data.fd = _pool_notify_fd;")
167             ->line(" epoll_ctl($loop_var, EPOLL_CTL_ADD, _pool_notify_fd, &ev);")
168             ->line(" }")
169             ->line("} }");
170             }
171              
172             1;
173              
174             __END__