Changeset 903 for server/common


Ignore:
Timestamp:
Dec 28, 2008, 1:21:33 AM (15 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.
Location:
server/common/oursrc/execsys
Files:
2 edited

Legend:

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

    r851 r903  
    22#
    33# gitproxy: Wrapper around git daemon for Git virtual hosting.
    4 # version 1.0, released 2008-10-08
     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# Receive the first message from the client, and parse out the URL.
     
    4647
    4748# Now start the real git daemon based on the URL.
    48 open2(\*IN, \*OUT, '/usr/local/sbin/ldapize.pl', "git://$host/") or die "$0: open: $!";
     49my $pid = open2(\*IN, \*OUT, '/usr/local/sbin/ldapize.pl', "git://$host/") or die "$0: open: $!";
    4950
    50 # Finally, go into a select loop to transfer the remaining data
     51# Finally, go into a poll loop to transfer the remaining data
    5152# (STDIN -> OUT, IN -> STDOUT), including the client's message to git daemon.
    5253my ($cbuf, $sbuf) = ($msg, '');
    53 my ($rin, $win, $ein) = ('', '', '');
    54 my ($stdout, $out, $stdin, $in) = (fileno(STDOUT), fileno(OUT), fileno(STDIN), fileno(IN));
    55 vec($win, $stdout, 1) = 0;
    56 vec($win, $out, 1) = 1;
    57 vec($rin, $stdin, 1) = 0;
    58 vec($rin, $in, 1) = 1;
    59 while (vec($win, $stdout, 1) or vec($win, $out, 1) or
    60        vec($rin, $stdin, 1) or vec($rin, $in, 1)) {
    61     my $n = select(my $rout = $rin, my $wout = $win, my $eout = $ein, undef);
     54my $poll = new IO::Poll;
     55$poll->mask(\*STDOUT => POLLHUP);
     56$poll->mask(\*OUT => POLLOUT);
     57$poll->remove(\*STDIN);
     58$poll->mask(\*IN => POLLIN);
     59while ($poll->handles()) {
     60    my $n = $poll->poll();
    6261    next if $n < 0 and $! == EINTR;
    6362    $n >= 0 or die "select: $!";
    64     if (vec($rout, $stdin, 1)) {
     63    if ($poll->events(\*STDIN)) {
    6564        my $n = sysread(STDIN, $cbuf, 4096);
    6665        next if $n < 0 and $! == EINTR;
    6766        $n >= 0 or die "read: $!";
    68         vec($rin, $stdin, 1) = 0;
    69         vec($win, $out, 1) = 1;
    70     } elsif (vec($rout, $in, 1)) {
     67        $poll->remove(\*STDIN);
     68        $poll->mask(\*OUT => POLLOUT);
     69    } elsif ($poll->events(\*IN)) {
    7170        my $n = sysread(IN, $sbuf, 4096);
    7271        next if $n < 0 and $! == EINTR;
    7372        $n >= 0 or die "read: $!";
    74         vec($rin, $in, 1) = 0;
    75         vec($win, $stdout, 1) = 1;
    76     } elsif (vec($wout, $stdout, 1) && $sbuf ne '') {
     73        $poll->remove(\*IN);
     74        $poll->mask(\*STDOUT => POLLOUT);
     75    } elsif ($poll->events(\*STDOUT) & POLLOUT && $sbuf ne '') {
    7776        my $n = syswrite(STDOUT, $sbuf);
    7877        next if $n < 0 and $! == EINTR;
     
    8079        $sbuf = substr($sbuf, $n);
    8180        if ($sbuf eq '') {
    82             vec($win, $stdout, 1) = 0;
    83             vec($rin, $in, 1) = 1;
     81            $poll->mask(\*STDOUT => POLLHUP);
     82            $poll->mask(\*IN => POLLIN);
    8483        }
    85     } elsif (vec($wout, $stdout, 1)) {
    86         vec($win, $stdout, 1) = 0;
     84    } elsif ($poll->events(\*STDOUT)) {
     85        $poll->remove(\*STDOUT);
     86        $poll->remove(\*IN);
    8787        close(STDOUT) or die "close: $!";
    8888        close(IN) or die "close: $!";
    89     } elsif (vec($wout, $out, 1) && $cbuf ne '') {
     89    } elsif ($poll->events(\*OUT) & POLLOUT && $cbuf ne '') {
    9090        my $n = syswrite(OUT, $cbuf);
    9191        next if $n < 0 and $! == EINTR;
     
    9393        $cbuf = substr($cbuf, $n);
    9494        if ($cbuf eq '') {
    95             vec($win, $out, 1) = 0;
    96             vec($rin, $stdin, 1) = 1;
     95            $poll->mask(\*OUT => POLLHUP);
     96            $poll->mask(\*STDIN => POLLIN);
    9797        }
    98     } elsif (vec($wout, $out, 1)) {
    99         vec($win, $out, 1) = 0;
     98    } elsif ($poll->events(\*OUT)) {
     99        $poll->remove(\*OUT);
     100        $poll->remove(\*STDIN);
    100101        close(OUT) or die "close: $!";
    101102        close(STDIN) or die "close: $!";
    102103    }
    103104}
     105
     106while (waitpid($pid, 0) == -1 && $! == EINTR) { }
  • 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.