File Coverage

blib/lib/Hypersonic/Event.pm
Criterion Covered Total %
statement 31 51 60.7
branch 13 32 40.6
condition 2 14 14.2
subroutine 7 11 63.6
pod 6 7 85.7
total 59 115 51.3


line stmt bran cond sub pod time code
1             package Hypersonic::Event;
2              
3 25     25   216216 use strict;
  25         45  
  25         926  
4 25     25   100 use warnings;
  25         38  
  25         1371  
5 25     25   436 use 5.010;
  25         82  
6              
7             our $VERSION = '0.15';
8              
9             # Hypersonic::Event - Event backend registry and selection
10             #
11             # This module provides a central registry for event loop backends and
12             # automatic detection of the best available backend for the platform.
13             # All event loop implementations are JIT-compiled via XS::JIT::Builder.
14              
15             # Backend registry - maps name to module
16             my %BACKENDS = (
17             io_uring => 'Hypersonic::Event::IOUring', # Linux 5.1+ (fastest)
18             epoll => 'Hypersonic::Event::Epoll', # Linux (fast)
19             kqueue => 'Hypersonic::Event::Kqueue', # BSD/macOS (fast)
20             iocp => 'Hypersonic::Event::IOCP', # Windows (fast, completion-based)
21             event_ports => 'Hypersonic::Event::EventPorts', # Solaris/illumos (fast)
22             poll => 'Hypersonic::Event::Poll', # POSIX fallback
23             select => 'Hypersonic::Event::Select', # Universal (Windows support)
24             );
25              
26             # Priority order for auto-selection (first available wins)
27             my @PRIORITY = qw(io_uring epoll kqueue iocp event_ports poll select);
28              
29             # Check if io_uring is available (Linux 5.1+ with liburing)
30             sub _has_io_uring {
31 0 0   0   0 return 0 unless $^O eq 'linux';
32              
33             # Check kernel version >= 5.1
34 0   0     0 my $ver = `uname -r 2>/dev/null` || '';
35 0         0 my ($major, $minor) = $ver =~ /^(\d+)\.(\d+)/;
36 0 0 0     0 return 0 unless $major && ($major > 5 || ($major == 5 && $minor >= 1));
      0        
37              
38             # Check for liburing.h in common locations
39 0         0 for my $path (
40             '/usr/include/liburing.h',
41             '/usr/local/include/liburing.h',
42             '/usr/include/x86_64-linux-gnu/liburing.h',
43             ) {
44 0 0       0 return 1 if -f $path;
45             }
46              
47 0         0 return 0;
48             }
49              
50             # Select best available backend for this platform
51             sub best_backend {
52 53     53 1 12322 my $class = shift;
53              
54             # Windows prefers IOCP (falls back to select if unavailable)
55 53 50       311 if ($^O eq 'MSWin32') {
56 0         0 my $mod = $BACKENDS{iocp};
57 0         0 eval "require $mod";
58 0 0 0     0 return 'iocp' if !$@ && $mod->available;
59 0         0 return 'select';
60             }
61              
62 53         286 for my $name (@PRIORITY) {
63 106 50       744 my $mod = $BACKENDS{$name} or next;
64              
65             # Try to load the module
66 106         15200 eval "require $mod";
67 106 50       596 next if $@;
68              
69             # Check if it's available on this platform
70 106 100       863 next unless $mod->available;
71              
72 53         833 return $name;
73             }
74              
75 0         0 die "No event backend available for platform: $^O";
76             }
77              
78             # Get backend module by name (loads if needed)
79             sub backend {
80 55     55 1 13552 my ($class, $name) = @_;
81 55   66     210 $name //= $class->best_backend;
82              
83 55 100       298 my $mod = $BACKENDS{$name}
84             or die "Unknown event backend: $name (available: " . join(', ', sort keys %BACKENDS) . ")";
85              
86 54 50       3825 eval "require $mod" or die "Cannot load $mod: $@";
87              
88 54 50       424 die "$mod is not available on this platform"
89             unless $mod->available;
90              
91 54         246 return $mod;
92             }
93              
94             # List all backends that work on this system
95             sub available_backends {
96 2     2 1 2139 my $class = shift;
97 2         3 my @available;
98              
99 2         3 for my $name (@PRIORITY) {
100 14 50       53 my $mod = $BACKENDS{$name} or next;
101              
102 14         944 eval "require $mod";
103 14 50       54 next if $@;
104              
105 14 100       98 push @available, $name if $mod->available;
106             }
107              
108 2         16 return @available;
109             }
110              
111             # Return the backend priority order
112             sub backend_priority {
113 1     1 0 229758 return @PRIORITY;
114             }
115              
116             # List all registered backends (whether available or not)
117             sub all_backends {
118 0     0 1   return sort keys %BACKENDS;
119             }
120              
121             # Register a custom backend
122             sub register_backend {
123 0     0 1   my ($class, $name, $module) = @_;
124              
125 0 0         die "Backend name required" unless $name;
126 0 0         die "Module name required" unless $module;
127              
128 0           $BACKENDS{$name} = $module;
129              
130 0           return 1;
131             }
132              
133             # Unregister a backend
134             sub unregister_backend {
135 0     0 1   my ($class, $name) = @_;
136 0           delete $BACKENDS{$name};
137             }
138              
139             1;
140              
141             __END__