File Coverage

blib/lib/Hypersonic/Event/Kqueue.pm
Criterion Covered Total %
statement 12 41 29.2
branch 0 4 0.0
condition n/a
subroutine 5 22 22.7
pod 12 18 66.6
total 29 85 34.1


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