File Coverage

blib/lib/Hypersonic/Event/EventPorts.pm
Criterion Covered Total %
statement 12 33 36.3
branch 1 2 50.0
condition n/a
subroutine 5 18 27.7
pod 12 14 85.7
total 30 67 44.7


line stmt bran cond sub pod time code
1             package Hypersonic::Event::EventPorts;
2              
3 2     2   206084 use strict;
  2         2  
  2         60  
4 2     2   6 use warnings;
  2         2  
  2         72  
5 2     2   23 use 5.010;
  2         6  
6              
7 2     2   7 use parent 'Hypersonic::Event::Role';
  2         3  
  2         23  
8              
9             our $VERSION = '0.15';
10              
11 0     0 1 0 sub name { 'event_ports' }
12              
13             sub available {
14             # Event ports are available on Solaris 10+ and illumos
15 3 50   3 1 21 return 0 unless $^O eq 'solaris';
16              
17             # Check for port_create in libc
18 0           return -f '/usr/include/port.h';
19             }
20              
21             sub includes {
22 0     0 1   return <<'C';
23             #include
24             #include
25             #include
26             C
27             }
28              
29             sub defines {
30 0     0 1   return <<'C';
31             #define EV_BACKEND_EVENT_PORTS 1
32             #ifndef MAX_EVENTS
33             #define MAX_EVENTS 1024
34             #endif
35             C
36             }
37              
38 0     0 1   sub event_struct { 'port_event_t' }
39              
40 0     0 1   sub extra_cflags { '' }
41 0     0 1   sub extra_ldflags { '' } # Event ports are in libc on Solaris
42              
43             # Create event port and associate listen socket
44             sub gen_create {
45 0     0 1   my ($class, $builder, $listen_fd_var) = @_;
46              
47 0           $builder->comment('Event Ports backend - Solaris/illumos high-performance I/O')
48             ->blank
49             ->line('int ev_fd = port_create();')
50             ->if('ev_fd < 0')
51             ->line('croak("port_create() failed");')
52             ->endif
53             ->blank
54             ->comment('Associate listen socket with port')
55             ->if("port_associate(ev_fd, PORT_SOURCE_FD, $listen_fd_var, POLLIN, NULL) < 0")
56             ->line('close(ev_fd);')
57             ->line('croak("port_associate() failed for listen socket");')
58             ->endif
59             ->blank;
60             }
61              
62             # Associate fd with event port
63             sub gen_add {
64 0     0 1   my ($class, $builder, $loop_var, $fd_var) = @_;
65              
66             # Event ports require re-association after each event (one-shot)
67 0           $builder->if("port_associate($loop_var, PORT_SOURCE_FD, $fd_var, POLLIN, (void*)(intptr_t)$fd_var) < 0")
68             ->line('perror("port_associate");')
69             ->endif;
70             }
71              
72             # Dissociate fd from event port
73             sub gen_del {
74 0     0 1   my ($class, $builder, $loop_var, $fd_var) = @_;
75              
76 0           $builder->line("port_dissociate($loop_var, PORT_SOURCE_FD, $fd_var);");
77             }
78              
79             # Wait for events using port_getn
80             sub gen_wait {
81 0     0 1   my ($class, $builder, $loop_var, $events_var, $count_var, $timeout_var) = @_;
82              
83 0           $builder->line("static port_event_t $events_var" . "[MAX_EVENTS];")
84             ->line('uint_t nget = 1;') # Minimum events to wait for
85             ->line('uint_t max_events = MAX_EVENTS;')
86             ->blank
87             ->line('struct timespec ts;')
88             ->line("ts.tv_sec = $timeout_var / 1000;")
89             ->line("ts.tv_nsec = ($timeout_var % 1000) * 1000000;")
90             ->blank
91             ->line("int result = port_getn($loop_var, $events_var, max_events, &nget, &ts);")
92             ->if('result < 0')
93             ->if('errno == EINTR || errno == ETIME')
94             ->line('continue;') # Timeout or interrupted - normal
95             ->endif
96             ->line('perror("port_getn");')
97             ->line('break;')
98             ->endif
99             ->line("int $count_var = (int)nget;");
100             }
101              
102             # Extract fd from event - note: must re-associate after each event
103             sub gen_get_fd {
104 0     0 1   my ($class, $builder, $events_var, $index_var, $fd_var) = @_;
105              
106 0           $builder->line("port_event_t* pe = &${events_var}[$index_var];")
107             ->line("int $fd_var = (int)pe->portev_object;")
108             ->blank
109             ->comment('Event ports are one-shot - must re-associate for more events')
110             ->if("$fd_var != listen_fd")
111             ->line("port_associate(ev_fd, PORT_SOURCE_FD, $fd_var, POLLIN, (void*)(intptr_t)$fd_var);")
112             ->endif;
113             }
114              
115             # Re-associate listen socket after accept
116             sub gen_rearm_listen {
117 0     0 0   my ($class, $builder, $loop_var, $listen_fd_var) = @_;
118              
119 0           $builder->comment('Re-associate listen socket (event ports are one-shot)')
120             ->line("port_associate($loop_var, PORT_SOURCE_FD, $listen_fd_var, POLLIN, NULL);");
121             }
122              
123             # Future/Pool integration - add pool notify fd to event port
124             sub gen_add_pool_notify {
125 0     0 0   my ($class, $builder, $loop_var, $notify_fd_var) = @_;
126              
127 0           $builder->line("/* Add pool notify fd to event port */")
128             ->if("port_associate($loop_var, PORT_SOURCE_FD, $notify_fd_var, POLLIN, (void*)(intptr_t)$notify_fd_var) < 0")
129             ->line('perror("port_associate pool notify");')
130             ->endif;
131             }
132              
133             1;
134              
135             __END__