File Coverage

blib/lib/Hypersonic/Event/Role.pm
Criterion Covered Total %
statement 19 65 29.2
branch 0 4 0.0
condition 0 6 0.0
subroutine 9 30 30.0
pod 14 24 58.3
total 42 129 32.5


line stmt bran cond sub pod time code
1             package Hypersonic::Event::Role;
2              
3 33     33   263326 use strict;
  33         94  
  33         1038  
4 33     33   129 use warnings;
  33         52  
  33         1207  
5 33     33   503 use 5.010;
  33         119  
6              
7             our $VERSION = '0.15';
8              
9             # Hypersonic::Event::Role - Base class for event backends
10             #
11             # This module defines the interface that all event backends must implement.
12             # Backends should inherit from this class to get default implementations
13             # of optional methods and clear error messages for missing required methods.
14              
15             # ============================================================
16             # Required Methods - backends MUST override these
17             # ============================================================
18              
19             sub name {
20 1     1 1 2538 my $class = shift;
21 1         8 die "$class must implement name()";
22             }
23              
24             sub available {
25 1     1 1 313 my $class = shift;
26 1         6 die "$class must implement available()";
27             }
28              
29             sub includes {
30 0     0 1 0 my $class = shift;
31 0         0 die "$class must implement includes()";
32             }
33              
34             sub defines {
35 0     0 1 0 my $class = shift;
36 0         0 die "$class must implement defines()";
37             }
38              
39             sub event_struct {
40 0     0 1 0 my $class = shift;
41 0         0 die "$class must implement event_struct()";
42             }
43              
44             # Event struct used by the UA::Async *slot tracking* helpers
45             # (gen_create_loop / gen_add_with_slot / gen_wait_once / gen_get_slot).
46             #
47             # For most backends this is the same as event_struct, but io_uring
48             # uses io_uring_cqe for its main server loop (correct for the ring
49             # API) while its slot-tracking helpers are implemented on top of a
50             # private epoll instance and therefore need struct epoll_event here.
51             # Override in those backends; default delegates to event_struct.
52             sub slot_event_struct {
53 12     12 0 40 my $class = shift;
54 12         42 return $class->event_struct;
55             }
56              
57             sub gen_create {
58 0     0 1 0 my ($class, $builder, $listen_fd_var) = @_;
59 0         0 die "$class must implement gen_create(\$builder, \$listen_fd_var)";
60             }
61              
62             sub gen_add {
63 0     0 1 0 my ($class, $builder, $loop_var, $fd_var) = @_;
64 0         0 die "$class must implement gen_add(\$builder, \$loop_var, \$fd_var)";
65             }
66              
67             sub gen_del {
68 0     0 1 0 my ($class, $builder, $loop_var, $fd_var) = @_;
69 0         0 die "$class must implement gen_del(\$builder, \$loop_var, \$fd_var)";
70             }
71              
72             sub gen_wait {
73 0     0 1 0 my ($class, $builder, $loop_var, $events_var, $count_var, $timeout_var) = @_;
74 0         0 die "$class must implement gen_wait(\$builder, \$loop_var, \$events_var, \$count_var, \$timeout_var)";
75             }
76              
77             sub gen_get_fd {
78 0     0 1 0 my ($class, $builder, $events_var, $index_var, $fd_var) = @_;
79 0         0 die "$class must implement gen_get_fd(\$builder, \$events_var, \$index_var, \$fd_var)";
80             }
81              
82             # ============================================================
83             # Optional Methods - backends MAY override these
84             # ============================================================
85              
86             # Additional compiler flags (e.g., -I/path/to/headers)
87 1     1 1 7782 sub extra_cflags { '' }
88              
89             # Additional linker flags (e.g., -luring)
90 1     1 1 3 sub extra_ldflags { '' }
91              
92             # One-time initialization code (called once at start)
93             sub gen_init {
94 0     0 1 0 my ($class, $builder) = @_;
95             # Default: no-op
96             }
97              
98             # Cleanup code (called on shutdown)
99             sub gen_cleanup {
100 0     0 1 0 my ($class, $builder) = @_;
101             # Default: no-op
102             }
103              
104             # ============================================================
105             # Async Slot Integration Methods (UA Async)
106             # ============================================================
107              
108             # Generate: add fd with slot as user data
109             # slot_var is an integer slot ID that will be stored with the fd
110             # events: 'read', 'write', or 'both'
111             sub gen_add_with_slot {
112 0     0 0 0 my ($class, $builder, $loop_var, $fd_var, $slot_var, $events) = @_;
113             # Default implementation - subclasses should override
114 0         0 die "$class must implement gen_add_with_slot(\$builder, \$loop_var, \$fd_var, \$slot_var, \$events)";
115             }
116              
117             # Generate: extract slot from event (returns the user data)
118             sub gen_get_slot {
119 0     0 0 0 my ($class, $builder, $events_var, $index_var, $slot_var) = @_;
120 0         0 die "$class must implement gen_get_slot(\$builder, \$events_var, \$index_var, \$slot_var)";
121             }
122              
123             # Generate: create event loop (without listen socket)
124             sub gen_create_loop {
125 0     0 0 0 my ($class, $builder, $loop_var) = @_;
126             # Default - call gen_create with dummy fd
127 0         0 die "$class must implement gen_create_loop(\$builder, \$loop_var)";
128             }
129              
130             # ============================================================
131             # Future/Pool Integration Methods (Single Pool - Legacy)
132             # ============================================================
133              
134             # Generate code to add the Future pool notify fd to the event loop
135             # Called during event loop setup when pool is available
136             sub gen_add_pool_notify {
137 0     0 0 0 my ($class, $builder, $loop_var, $notify_fd_var) = @_;
138             # Default: use gen_add
139 0         0 $class->gen_add($builder, $loop_var, $notify_fd_var);
140             }
141              
142             # Generate code to check if the current fd is the pool notify fd
143             # Should set a variable indicating this is a pool notification
144             sub gen_check_pool_notify {
145 0     0 0 0 my ($class, $builder, $fd_var, $notify_fd_var, $is_pool_var) = @_;
146 0         0 $builder->line("int $is_pool_var = ($fd_var == $notify_fd_var);");
147             }
148              
149             # Generate code to process pool notifications (call pool_process_ready)
150             sub gen_process_pool_ready {
151 0     0 0 0 my ($class, $builder) = @_;
152 0         0 $builder->line('/* Process completed async operations */')
153             ->line('extern int xs_pool_process_ready(pTHX_ CV *cv);')
154             ->line('xs_pool_process_ready(aTHX_ NULL);');
155             }
156              
157             # ============================================================
158             # Multi-Pool Integration Methods (OO API)
159             # ============================================================
160              
161             # Generate code to add multiple pool notify fds to the event loop
162             # pool_slots is an array variable, pool_count is the count
163             sub gen_add_multi_pool_notify {
164 0     0 0 0 my ($class, $builder, $loop_var, $pool_slots_var, $pool_count_var) = @_;
165              
166 0         0 $builder->line("/* Add all pool notify fds to event loop */")
167             ->line("{ int _pi; int _pool_notify_fd;")
168             ->line("for (_pi = 0; _pi < $pool_count_var; _pi++) {")
169             ->line(" _pool_notify_fd = pool_get_notify_fd_slot($pool_slots_var\[_pi]);")
170             ->line(" if (_pool_notify_fd >= 0) {");
171              
172             # Use the backend's gen_add method - inline the generated code
173 0         0 $class->gen_add($builder, $loop_var, '_pool_notify_fd');
174              
175 0         0 $builder->line(" }")
176             ->line("} }");
177             }
178              
179             # Generate code to check if fd matches any pool's notify_fd
180             # Sets matched_slot_var to the pool slot if matched, -1 otherwise
181             sub gen_check_multi_pool_notify {
182 0     0 0 0 my ($class, $builder, $fd_var, $pool_slots_var, $pool_count_var, $matched_slot_var) = @_;
183              
184 0         0 $builder->line("int $matched_slot_var = -1;")
185             ->line("{ int _pi; int _pslot;")
186             ->line("for (_pi = 0; _pi < $pool_count_var; _pi++) {")
187             ->line(" _pslot = $pool_slots_var\[_pi];")
188             ->line(" if ($fd_var == pool_get_notify_fd_slot(_pslot)) {")
189             ->line(" $matched_slot_var = _pslot;")
190             ->line(" break;")
191             ->line(" }")
192             ->line("} }");
193             }
194              
195             # Generate code to process a specific pool's completed operations
196             sub gen_process_pool_slot {
197 0     0 0 0 my ($class, $builder, $slot_var) = @_;
198 0         0 $builder->line("/* Process completed async operations for pool slot */")
199             ->line("pool_process_ready_slot($slot_var);");
200             }
201              
202             # ============================================================
203             # Utility Methods for Backends
204             # ============================================================
205              
206             # Check if a header file exists
207             sub _has_header {
208 0     0   0 my ($class, @paths) = @_;
209 0         0 for my $path (@paths) {
210 0 0       0 return 1 if -f $path;
211             }
212 0         0 return 0;
213             }
214              
215             # Check if a library exists (file check only - use _can_link for full verification)
216             sub _has_library {
217 0     0   0 my ($class, $lib) = @_;
218             # Check common library paths
219 0         0 for my $dir (qw(/usr/lib /usr/local/lib /lib /lib64 /usr/lib64)) {
220 0 0 0     0 return 1 if -f "$dir/lib$lib.so" || -f "$dir/lib$lib.a" || -f "$dir/lib$lib.dylib";
      0        
221             }
222 0         0 return 0;
223             }
224              
225             # Check if a library can actually be linked (compile+link test)
226             # Delegates to centralized Hypersonic::JIT::Util
227             sub _can_link {
228 3     3   93971 my ($class, $lib_flag, $test_symbol, $extra_includes) = @_;
229 3         748 require Hypersonic::JIT::Util;
230 3         34 return Hypersonic::JIT::Util->can_link('', $lib_flag, $test_symbol, $extra_includes);
231             }
232              
233             1;
234              
235             __END__