+sub async_check ($$$$) {
+ my ($ibx, $oidish, $cb, $arg) = @_; # $ibx may be $ctx
+ my $git = $ibx->{git} // $ibx->git;
+ $git->check_async($oidish, $cb, $arg);
+ return watch_cat($git) if $git->{-bc}; # --batch-command
+ $git->{async_chk} //= do {
+ my $self = bless { git => $git }, 'PublicInbox::GitAsyncCheck';
+ $git->{in_c}->blocking(0);
+ $self->SUPER::new($git->{in_c}, EPOLLIN|EPOLLET);
+ awaitpid($git->{pid_c}, \&aclose, $self);
+ \undef; # this is a true ref()
+ };
+}
+
+# this is safe to call inside $cb, but not guaranteed to enqueue
+# returns true if successful, undef if not. For fairness, we only
+# prefetch if there's no in-flight requests.
+sub ibx_async_prefetch {
+ my ($ibx, $oid, $cb, $arg) = @_;
+ my $git = $ibx->git;
+ if (!defined($ibx->{topdir}) && $GCF2C) {
+ if (!@{$GCF2C->{inflight} // []}) {
+ $oid .= " $git->{git_dir}\n";
+ return $GCF2C->gcf2_async(\$oid, $cb, $arg); # true
+ }
+ } elsif ($git->{async_cat}) {
+ return $git->async_prefetch($oid, $cb, $arg);
+ }
+ undef;
+}
+
+1;
+package PublicInbox::GitAsyncCheck;
+use v5.12;
+our @ISA = qw(PublicInbox::GitAsyncCat);
+use POSIX qw(WNOHANG);
+use PublicInbox::Syscall qw(EPOLLIN EPOLLET);
+
+sub event_step {
+ my ($self) = @_;
+ my $git = $self->{git} or return;
+ return $self->close if ($git->{in_c} // 0) != ($self->{sock} // 1);
+ my $inflight = $git->{inflight_c};
+ if ($inflight && @$inflight) {
+ $git->check_async_step($inflight);
+
+ # child death?
+ if (($git->{in_c} // 0) != ($self->{sock} // 1)) {
+ $self->close;
+ } elsif (@$inflight || exists $git->{rbuf_c}) {
+ # ok, more to do, requeue for fairness
+ $self->requeue;
+ }
+ }