Ignore:
Timestamp:
Dec 28, 2008, 1:21:33 AM (16 years ago)
Author:
andersk
Message:
Replace {svnproxy,gitproxy} select() loop with a poll() loop, to catch closed
output handles.  This should prevent the gitproxy deadlock on errors.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • server/common/oursrc/execsys/svnproxy.pl

    r835 r903  
    22#
    33# svnproxy: Wrapper around svnserve for Subversion virtual hosting.
    4 # version 1.0, released 2008-08-29
     4# version 1.1, released 2008-12-28
    55# Copyright © 2008 Anders Kaseorg <andersk@mit.edu>
    66#
     
    2323use IPC::Open2;
    2424use Errno qw(EINTR);
     25use IO::Poll qw(POLLIN POLLOUT POLLHUP);
    2526
    2627# Read the initial greeting from a dummy svnserve process.
     
    7172
    7273# Now start the real svnserve based on the URL.
    73 open2(\*IN, \*OUT, '/usr/local/sbin/ldapize.pl', $url) or die "$0: open: $!";
     74$pid = open2(\*IN, \*OUT, '/usr/local/sbin/ldapize.pl', $url) or die "$0: open: $!";
    7475
    7576# Read the greeting, expecting it to be identical to the dummy greeting.
     
    8586# (STDIN -> OUT, IN -> STDOUT), including the client's response to svnserve.
    8687my ($cbuf, $sbuf) = ($response, '');
    87 my ($rin, $win, $ein) = ('', '', '');
    88 my ($stdout, $out, $stdin, $in) = (fileno(STDOUT), fileno(OUT), fileno(STDIN), fileno(IN));
    89 vec($win, $stdout, 1) = 0;
    90 vec($win, $out, 1) = 1;
    91 vec($rin, $stdin, 1) = 0;
    92 vec($rin, $in, 1) = 1;
    93 while (vec($win, $stdout, 1) or vec($win, $out, 1) or
    94        vec($rin, $stdin, 1) or vec($rin, $in, 1)) {
    95     my $n = select(my $rout = $rin, my $wout = $win, my $eout = $ein, undef);
     88my $poll = new IO::Poll;
     89$poll->mask(\*STDOUT => POLLHUP);
     90$poll->mask(\*OUT => POLLOUT);
     91$poll->remove(\*STDIN);
     92$poll->mask(\*IN => POLLIN);
     93while ($poll->handles()) {
     94    my $n = $poll->poll();
    9695    next if $n < 0 and $! == EINTR;
    9796    $n >= 0 or die "select: $!";
    98     if (vec($rout, $stdin, 1)) {
     97    if ($poll->events(\*STDIN)) {
    9998        my $n = sysread(STDIN, $cbuf, 4096);
    10099        next if $n < 0 and $! == EINTR;
    101100        $n >= 0 or die "read: $!";
    102         vec($rin, $stdin, 1) = 0;
    103         vec($win, $out, 1) = 1;
    104     } elsif (vec($rout, $in, 1)) {
     101        $poll->remove(\*STDIN);
     102        $poll->mask(\*OUT => POLLOUT);
     103    } elsif ($poll->events(\*IN)) {
    105104        my $n = sysread(IN, $sbuf, 4096);
    106105        next if $n < 0 and $! == EINTR;
    107106        $n >= 0 or die "read: $!";
    108         vec($rin, $in, 1) = 0;
    109         vec($win, $stdout, 1) = 1;
    110     } elsif (vec($wout, $stdout, 1) && $sbuf ne '') {
     107        $poll->remove(\*IN);
     108        $poll->mask(\*STDOUT => POLLOUT);
     109    } elsif ($poll->events(\*STDOUT) & POLLOUT && $sbuf ne '') {
    111110        my $n = syswrite(STDOUT, $sbuf);
    112111        next if $n < 0 and $! == EINTR;
     
    114113        $sbuf = substr($sbuf, $n);
    115114        if ($sbuf eq '') {
    116             vec($win, $stdout, 1) = 0;
    117             vec($rin, $in, 1) = 1;
     115            $poll->mask(\*STDOUT => POLLHUP);
     116            $poll->mask(\*IN => POLLIN);
    118117        }
    119     } elsif (vec($wout, $stdout, 1)) {
    120         vec($win, $stdout, 1) = 0;
     118    } elsif ($poll->events(\*STDOUT)) {
     119        $poll->remove(\*STDOUT);
     120        $poll->remove(\*IN);
    121121        close(STDOUT) or die "close: $!";
    122122        close(IN) or die "close: $!";
    123     } elsif (vec($wout, $out, 1) && $cbuf ne '') {
     123    } elsif ($poll->events(\*OUT) & POLLOUT && $cbuf ne '') {
    124124        my $n = syswrite(OUT, $cbuf);
    125125        next if $n < 0 and $! == EINTR;
     
    127127        $cbuf = substr($cbuf, $n);
    128128        if ($cbuf eq '') {
    129             vec($win, $out, 1) = 0;
    130             vec($rin, $stdin, 1) = 1;
     129            $poll->mask(\*OUT => POLLHUP);
     130            $poll->mask(\*STDIN => POLLIN);
    131131        }
    132     } elsif (vec($wout, $out, 1)) {
    133         vec($win, $out, 1) = 0;
     132    } elsif ($poll->events(\*OUT)) {
     133        $poll->remove(\*OUT);
     134        $poll->remove(\*STDIN);
    134135        close(OUT) or die "close: $!";
    135136        close(STDIN) or die "close: $!";
    136137    }
    137138}
     139
     140while (waitpid($pid, 0) == -1 && $! == EINTR) { }
Note: See TracChangeset for help on using the changeset viewer.