Hypersonic
view release on metacpan or search on metacpan
lib/Hypersonic/UA/Async.pm view on Meta::CPAN
->xs_function('xs_async_get_result')
->xs_preamble
->line('if (items < 1) croak("Usage: get_result($slot)");')
->blank
->line('int slot = SvIV(ST(0));')
->line('if (slot < 0 || slot >= MAX_ASYNC_CONTEXTS || !async_registry[slot].in_use) {')
->line(' ST(0) = &PL_sv_undef;')
->line(' XSRETURN(1);')
->line('}')
->blank
->line('AsyncContext *ctx = &async_registry[slot];')
->blank
->if('ctx->state == ASYNC_STATE_ERROR && ctx->error')
->comment('Return error as a list (0, error_msg)')
->line('ST(0) = sv_2mortal(newSViv(0));')
->line('ST(1) = sv_2mortal(newSVpv(ctx->error, 0));')
->line('XSRETURN(2);')
->elsif('ctx->state == ASYNC_STATE_DONE && ctx->recv_buffer')
->comment('Return success as a list (1, body)')
->line('ST(0) = sv_2mortal(newSViv(1));')
->line('ST(1) = sv_2mortal(newSVpvn(ctx->recv_buffer, ctx->recv_buffer_len));')
->line('XSRETURN(2);')
->else
->comment('Not ready yet')
->line('ST(0) = &PL_sv_undef;')
->line('XSRETURN(1);')
->endif
->xs_end
->blank;
}
sub gen_xs_tick {
my ($class, $builder, $opts) = @_;
my $event_backend = $opts->{event_backend};
my $backend_name = $opts->{event_backend_name} // 'kqueue';
$builder->comment("Process pending async events - AUTO-TICKING pure C path ($backend_name)")
->comment('Loops until all requests complete OR no progress for 1ms')
->xs_function('xs_ua_tick')
->xs_preamble
->line('int i;')
->line('int nev;')
->line('I32 j;')
->line('if (items < 1) croak("Usage: $ua->tick()");')
->blank
->line('SV *self_sv = ST(0);')
->line('HV *ua_hv = (HV *)SvRV(self_sv);')
->blank
->comment('Get the _async_pending array')
->line('SV **pending_svp = hv_fetch(ua_hv, "_async_pending", 14, 0);')
->if('!pending_svp || !SvROK(*pending_svp)')
->line('ST(0) = sv_2mortal(newSViv(0));')
->line('XSRETURN(1);')
->endif
->blank
->line('AV *pending_av = (AV *)SvRV(*pending_svp);')
->blank
->comment('Main tick loop - process until no pending or no progress')
->line('int total_completed = 0;')
->line('int iterations = 0;')
->line('int max_iterations = 1000; /* Safety cap */')
->blank
->line('tick_loop:')
->line('{')
->line(' I32 len = av_len(pending_av) + 1;')
->line(' if (len == 0 || iterations++ >= max_iterations) {')
->line(' ST(0) = sv_2mortal(newSViv(len));')
->line(' XSRETURN(1);')
->line(' }')
->blank
->comment(' Collect slots from pending array')
->line(' int slots[MAX_ASYNC_CONTEXTS];')
->line(' int slot_count = 0;')
->blank
->line(' for (j = 0; j < len; j++) {')
->line(' SV **slot_svp = av_fetch(pending_av, j, 0);')
->line(' if (!slot_svp) continue;')
->line(' int slot = SvIV(*slot_svp);')
->line(' if (slot >= 0 && slot < MAX_ASYNC_CONTEXTS) {')
->line(' AsyncContext *ctx = &async_registry[slot];')
->line(' if (ctx->in_use && ctx->fd >= 0) {')
->line(' slots[slot_count++] = slot;')
->line(' }')
->line(' }')
->line(' }')
->blank;
# Create event loop using the backend
$builder->comment('Create event loop if needed')
->line('if (async_ev_fd < 0) {');
$event_backend->gen_create_loop($builder, 'async_ev_fd');
$builder->line('}')
->blank;
# Register all fds - use backend's native slot-tracking struct.
# See note in gen_xs_poll_batch above: io_uring overrides this to
# epoll_event because its slot helpers run on a private epoll fd.
my $event_struct = $event_backend->slot_event_struct;
$builder->comment('Register all fds with event loop')
->line('int change_count = 0;')
->blank
->line('for (i = 0; i < slot_count; i++) {')
->line(' int slot = slots[i];')
->line(' AsyncContext *ctx = &async_registry[slot];')
->line(' int events = async_poll_one(slot);')
->line(' if (events == ASYNC_WAIT_NONE) continue;')
->blank
->line(' if (events == ASYNC_WAIT_READ) {');
$event_backend->gen_add_with_slot($builder, 'async_ev_fd', 'ctx->fd', 'slot', 'read');
$builder->line(' } else {');
$event_backend->gen_add_with_slot($builder, 'async_ev_fd', 'ctx->fd', 'slot', 'write');
$builder->line(' }')
->line(' change_count++;')
->line('}')
->blank;
# Wait for events
$builder->comment('Wait for events (1ms timeout)')
->line("struct $event_struct ready_events[MAX_EVENTS];");
$event_backend->gen_wait_once($builder, 'async_ev_fd', 'ready_events', 'nev', '1');
# Process ready events
$builder->blank
->comment('Process ready events in pure C')
->line('for (i = 0; i < nev; i++) {');
( run in 0.784 second using v1.01-cache-2.11-cpan-71847e10f99 )