3 # Thomas Nagy, 2015 (ita)
5 # prefer the waf 1.8 version
8 The full samba build can be faster by ~10%, but there are a few limitations:
9 * only one build process should be run at a time as the servers would use the same ports
10 * only one build command is going to be called ("waf build configure build" would not work)
14 mod = Utils.load_tool('prefork')
17 (build declarations after)
20 import os, re, socket, threading, sys, subprocess, time, atexit, traceback
24 import socketserver as SocketServer
26 from queue import Queue
28 from Queue import Queue
32 import pickle as cPickle
42 def make_header(params):
43 header = ','.join(params)
44 if sys.hexversion > 0x3000000:
45 header = header.encode('iso8859-1')
46 header = header.ljust(HEADER_SIZE)
47 assert(len(header) == HEADER_SIZE)
51 re_valid_query = re.compile('^[a-zA-Z0-9_, ]+$')
52 class req(SocketServer.StreamRequestHandler):
56 self.process_command()
57 except Exception as e:
61 def process_command(self):
62 query = self.rfile.read(HEADER_SIZE)
66 assert(len(query) == HEADER_SIZE)
67 if sys.hexversion > 0x3000000:
68 query = query.decode('iso8859-1')
70 if not re_valid_query.match(query):
71 raise ValueError('Invalid query %r' % query)
73 query = query.strip().split(',')
76 self.run_command(query[1:])
78 raise ValueError('Exit')
80 raise ValueError('Invalid query %r' % query)
82 def run_command(self, query):
85 data = self.rfile.read(size)
86 assert(len(data) == size)
87 kw = cPickle.loads(data)
90 ret = out = err = exc = None
96 if kw['stdout'] or kw['stderr']:
97 p = subprocess.Popen(cmd, **kw)
98 (out, err) = p.communicate()
101 ret = subprocess.Popen(cmd, **kw).wait()
102 except Exception as e:
104 exc = str(e) + traceback.format_exc()
107 if out or err or exc:
108 data = (out, err, exc)
109 data = cPickle.dumps(data, -1)
113 params = [RES, str(ret), str(len(data))]
115 self.wfile.write(make_header(params))
118 self.wfile.write(data)
120 def create_server(conn, cls):
121 #SocketServer.ThreadingTCPServer.allow_reuse_address = True
122 #server = SocketServer.ThreadingTCPServer(conn, req)
124 SocketServer.TCPServer.allow_reuse_address = True
125 server = SocketServer.TCPServer(conn, req)
126 #server.timeout = 6000 # seconds
127 server.serve_forever(poll_interval=0.001)
129 if __name__ == '__main__':
130 if len(sys.argv) > 1:
131 port = int(sys.argv[1])
134 #conn = (socket.gethostname(), port)
135 conn = ("127.0.0.1", port)
136 #print("listening - %r %r\n" % conn)
137 create_server(conn, req)
142 def init_task_pool(self):
143 # lazy creation, and set a common pool for all task consumers
144 pool = self.pool = []
145 for i in range(self.numjobs):
146 consumer = Runner.get_pool()
147 pool.append(consumer)
149 self.ready = Queue(0)
151 consumer.ready = self.ready
153 threading.current_thread().idx = consumer.idx
154 except Exception as e:
159 Runner.Parallel.init_task_pool = init_task_pool
163 def make_server(idx):
165 cmd = [sys.executable, os.path.abspath(__file__), str(port)]
166 proc = subprocess.Popen(cmd)
173 conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
174 conn.connect(('127.0.0.1', port))
192 atexit.register(close_all)
194 def put_data(conn, data):
197 def read_data(conn, siz):
200 print("closed connection?")
202 assert(len(ret) == siz)
205 def exec_command(cmd, **kw):
208 kw['stdout'] = kw['stderr'] = subprocess.PIPE
211 kw['stdout'] = kw['stderr'] = None
212 kw['shell'] = isinstance(cmd, str)
214 idx = threading.current_thread().idx
217 data = cPickle.dumps(kw, -1)
218 params = [REQ, str(len(data))]
219 header = make_header(params)
223 put_data(conn, header)
226 data = read_data(conn, HEADER_SIZE)
227 if sys.hexversion > 0x3000000:
228 data = data.decode('iso8859-1')
230 lst = data.split(',')
236 data = read_data(conn, dlen)
237 (out, err, exc) = cPickle.loads(data)
239 raise Utils.WafError('Execution failure: %s' % exc)
249 threading.Thread.__init__(self)
251 # identifier of the current thread
252 self.idx = len(SERVERS)
254 # create a server and wait for the connection
255 srv = make_server(self.idx)
261 conn = make_conn(srv)
266 raise ValueError('Could not start the server!')
271 Runner.TaskConsumer.__init__ = __init__
274 # dangerous, there is no other command hopefully
275 Utils.exec_command = exec_command