Merge branch 'jk/push-client-deadlock-fix'

"git push" from a corrupt repository that attempts to push a large
number of refs deadlocked; the thread to relay rejection notices
for these ref updates blocked on writing them to the main thread,
after the main thread at the receiving end notices that the push
failed and decides not to read these notices and return a failure.

* jk/push-client-deadlock-fix:
  t5504: drop sigpipe=ok from push tests
  fetch-pack: isolate sigpipe in demuxer thread
  send-pack: isolate sigpipe in demuxer thread
  run-command: teach async threads to ignore SIGPIPE
  send-pack: close demux pipe before finishing async process
This commit is contained in:
Junio C Hamano 2016-04-29 12:59:08 -07:00
Родитель 60b3e9b959 c4b27511ab
Коммит d689301043
5 изменённых файлов: 21 добавлений и 11 удалений

Просмотреть файл

@ -15,7 +15,6 @@
#include "version.h" #include "version.h"
#include "prio-queue.h" #include "prio-queue.h"
#include "sha1-array.h" #include "sha1-array.h"
#include "sigchain.h"
static int transfer_unpack_limit = -1; static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1; static int fetch_unpack_limit = -1;
@ -674,10 +673,8 @@ static int sideband_demux(int in, int out, void *data)
int *xd = data; int *xd = data;
int ret; int ret;
sigchain_push(SIGPIPE, SIG_IGN);
ret = recv_sideband("fetch-pack", xd[0], out); ret = recv_sideband("fetch-pack", xd[0], out);
close(out); close(out);
sigchain_pop(SIGPIPE);
return ret; return ret;
} }
@ -701,6 +698,7 @@ static int get_pack(struct fetch_pack_args *args,
demux.proc = sideband_demux; demux.proc = sideband_demux;
demux.data = xd; demux.data = xd;
demux.out = -1; demux.out = -1;
demux.isolate_sigpipe = 1;
if (start_async(&demux)) if (start_async(&demux))
die("fetch-pack: unable to fork off sideband" die("fetch-pack: unable to fork off sideband"
" demultiplexer"); " demultiplexer");

Просмотреть файл

@ -590,6 +590,16 @@ static void *run_thread(void *data)
struct async *async = data; struct async *async = data;
intptr_t ret; intptr_t ret;
if (async->isolate_sigpipe) {
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGPIPE);
if (pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) {
ret = error("unable to block SIGPIPE in async thread");
return (void *)ret;
}
}
pthread_setspecific(async_key, async); pthread_setspecific(async_key, async);
ret = async->proc(async->proc_in, async->proc_out, async->data); ret = async->proc(async->proc_in, async->proc_out, async->data);
return (void *)ret; return (void *)ret;

Просмотреть файл

@ -116,6 +116,7 @@ struct async {
int proc_in; int proc_in;
int proc_out; int proc_out;
#endif #endif
int isolate_sigpipe;
}; };
int start_async(struct async *async); int start_async(struct async *async);

Просмотреть файл

@ -518,6 +518,7 @@ int send_pack(struct send_pack_args *args,
demux.proc = sideband_demux; demux.proc = sideband_demux;
demux.data = fd; demux.data = fd;
demux.out = -1; demux.out = -1;
demux.isolate_sigpipe = 1;
if (start_async(&demux)) if (start_async(&demux))
die("send-pack: unable to fork off sideband demultiplexer"); die("send-pack: unable to fork off sideband demultiplexer");
in = demux.out; in = demux.out;
@ -531,8 +532,10 @@ int send_pack(struct send_pack_args *args,
close(out); close(out);
if (git_connection_is_socket(conn)) if (git_connection_is_socket(conn))
shutdown(fd[0], SHUT_WR); shutdown(fd[0], SHUT_WR);
if (use_sideband) if (use_sideband) {
close(demux.out);
finish_async(&demux); finish_async(&demux);
}
fd[1] = -1; fd[1] = -1;
return -1; return -1;
} }
@ -551,11 +554,11 @@ int send_pack(struct send_pack_args *args,
packet_flush(out); packet_flush(out);
if (use_sideband && cmds_sent) { if (use_sideband && cmds_sent) {
close(demux.out);
if (finish_async(&demux)) { if (finish_async(&demux)) {
error("error in sideband demultiplexer"); error("error in sideband demultiplexer");
ret = -1; ret = -1;
} }
close(demux.out);
} }
if (ret < 0) if (ret < 0)

Просмотреть файл

@ -100,11 +100,8 @@ test_expect_success 'push with receive.fsckobjects' '
git config receive.fsckobjects true && git config receive.fsckobjects true &&
git config transfer.fsckobjects false git config transfer.fsckobjects false
) && ) &&
test_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act && test_must_fail git push --porcelain dst master:refs/heads/test >act &&
{ test_cmp exp act
test_cmp exp act ||
! test -s act
}
' '
test_expect_success 'push with transfer.fsckobjects' ' test_expect_success 'push with transfer.fsckobjects' '
@ -114,7 +111,8 @@ test_expect_success 'push with transfer.fsckobjects' '
cd dst && cd dst &&
git config transfer.fsckobjects true git config transfer.fsckobjects true
) && ) &&
test_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act test_must_fail git push --porcelain dst master:refs/heads/test >act &&
test_cmp exp act
' '
cat >bogus-commit <<\EOF cat >bogus-commit <<\EOF