Skip to content

Commit c86bea6

Browse files
committed
Implemented threaded version of pipe-draining
1 parent 4914405 commit c86bea6

File tree

1 file changed

+30
-15
lines changed

1 file changed

+30
-15
lines changed

git/cmd.py

+30-15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import sys
99
import select
1010
import logging
11+
import threading
1112
from subprocess import (
1213
call,
1314
Popen,
@@ -72,22 +73,31 @@ def read_line_slow(stream):
7273
return line
7374
# end
7475

75-
fdmap = { process.stdout.fileno() : (process.stdout, stdout_handler, read_line_fast),
76-
process.stderr.fileno() : (process.stderr, stderr_handler, read_line_slow) }
77-
78-
if hasattr(select, 'poll'):
79-
def dispatch_line(fd):
80-
stream, handler, readline = fdmap[fd]
76+
def dispatch_line(fno):
77+
stream, handler, readline = fdmap[fno]
8178
# this can possibly block for a while, but since we wake-up with at least one or more lines to handle,
8279
# we are good ...
8380
line = readline(stream).decode(defenc)
8481
if line and handler:
8582
handler(line)
8683
return line
8784
# end dispatch helper
85+
# end
86+
87+
def deplete_buffer(fno):
88+
while True:
89+
line = dispatch_line(fno)
90+
if not line:
91+
break
92+
# end deplete buffer
93+
# end
94+
95+
fdmap = { process.stdout.fileno() : (process.stdout, stdout_handler, read_line_fast),
96+
process.stderr.fileno() : (process.stderr, stderr_handler, read_line_slow) }
8897

89-
# poll is preferred, as select is limited to file handles up to 1024 ... . Not an issue for us though,
90-
# as we deal with relatively blank processes
98+
if hasattr(select, 'poll'):
99+
# poll is preferred, as select is limited to file handles up to 1024 ... . This could otherwise be
100+
# an issue for us, as it matters how many handles or own process has
91101
poll = select.poll()
92102
READ_ONLY = select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR
93103
CLOSED = select.POLLHUP | select.POLLERR
@@ -113,18 +123,23 @@ def dispatch_line(fd):
113123
# end endless loop
114124

115125
# Depelete all remaining buffers
116-
for fno, _ in fdmap.items():
117-
while True:
118-
line = dispatch_line(fno)
119-
if not line:
120-
break
121-
# end deplete buffer
126+
for fno in fdmap.keys():
127+
deplete_buffer(fno)
122128
# end for each file handle
123129
else:
124130
# Oh ... probably we are on windows. select.select() can only handle sockets, we have files
125131
# The only reliable way to do this now is to use threads and wait for both to finish
126132
# Since the finalizer is expected to wait, we don't have to introduce our own wait primitive
127-
raise NotImplementedError()
133+
# NO: It's not enough unfortunately, and we will have to sync the threads
134+
threads = list()
135+
for fno in fdmap.keys():
136+
t = threading.Thread(target = lambda: deplete_buffer(fno))
137+
threads.append(t)
138+
t.start()
139+
# end
140+
for t in threads:
141+
t.join()
142+
# end
128143
# end
129144

130145
return finalizer(process)

0 commit comments

Comments
 (0)