+sub write_all {
+ my ($self, $out, $buf, $read_step, $inflight) = @_;
+ $read_step->($self, $inflight) while @$inflight >= MAX_INFLIGHT;
+ do {
+ my $w = syswrite($out, $buf);
+ if (defined $w) {
+ return if $w == length($buf);
+ substr($buf, 0, $w, ''); # sv_chop
+ } elsif ($! != EAGAIN) {
+ $self->fail("write: $!");
+ }
+ $read_step->($self, $inflight);
+ } while (1);
+}
+
+sub check_async ($$$$) {
+ my ($self, $oid, $cb, $arg) = @_;
+ my $inflight = $self->{-bc} ?
+ ($self->{inflight} // cat_async_begin($self)) :
+ ($self->{inflight_c} // check_async_begin($self));
+ if ($self->{-bc}) {
+ substr($oid, 0, 0) = 'info ';
+ write_all($self, $self->{out}, "$oid\n",
+ \&cat_async_step, $inflight);
+ } else {
+ write_all($self, $self->{out_c}, "$oid\n",
+ \&check_async_step, $inflight);
+ }
+ push(@$inflight, $oid, $cb, $arg);
+}
+
+sub _check_cb { # check_async callback
+ my ($hex, $type, $size, $result) = @_;
+ @$result = ($hex, $type, $size);
+}
+
+sub check {
+ my ($self, $oid) = @_;
+ my $result = [];
+ check_async($self, $oid, \&_check_cb, $result);
+ check_async_wait($self);
+ my ($hex, $type, $size) = @$result;
+
+ # git <2.21 would show `dangling' (2.21+ shows `ambiguous')
+ # https://public-inbox.org/git/20190118033845.s2vlrb3wd3m2jfzu@dcvr/T/
+ return if $type =~ /\A(?:missing|ambiguous)\z/ || $hex eq 'dangling';