xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/multiprocessing/forkserver.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Workerimport errno
2*cda5da8dSAndroid Build Coastguard Workerimport os
3*cda5da8dSAndroid Build Coastguard Workerimport selectors
4*cda5da8dSAndroid Build Coastguard Workerimport signal
5*cda5da8dSAndroid Build Coastguard Workerimport socket
6*cda5da8dSAndroid Build Coastguard Workerimport struct
7*cda5da8dSAndroid Build Coastguard Workerimport sys
8*cda5da8dSAndroid Build Coastguard Workerimport threading
9*cda5da8dSAndroid Build Coastguard Workerimport warnings
10*cda5da8dSAndroid Build Coastguard Worker
11*cda5da8dSAndroid Build Coastguard Workerfrom . import connection
12*cda5da8dSAndroid Build Coastguard Workerfrom . import process
13*cda5da8dSAndroid Build Coastguard Workerfrom .context import reduction
14*cda5da8dSAndroid Build Coastguard Workerfrom . import resource_tracker
15*cda5da8dSAndroid Build Coastguard Workerfrom . import spawn
16*cda5da8dSAndroid Build Coastguard Workerfrom . import util
17*cda5da8dSAndroid Build Coastguard Worker
18*cda5da8dSAndroid Build Coastguard Worker__all__ = ['ensure_running', 'get_inherited_fds', 'connect_to_new_process',
19*cda5da8dSAndroid Build Coastguard Worker           'set_forkserver_preload']
20*cda5da8dSAndroid Build Coastguard Worker
21*cda5da8dSAndroid Build Coastguard Worker#
22*cda5da8dSAndroid Build Coastguard Worker#
23*cda5da8dSAndroid Build Coastguard Worker#
24*cda5da8dSAndroid Build Coastguard Worker
25*cda5da8dSAndroid Build Coastguard WorkerMAXFDS_TO_SEND = 256
26*cda5da8dSAndroid Build Coastguard WorkerSIGNED_STRUCT = struct.Struct('q')     # large enough for pid_t
27*cda5da8dSAndroid Build Coastguard Worker
28*cda5da8dSAndroid Build Coastguard Worker#
29*cda5da8dSAndroid Build Coastguard Worker# Forkserver class
30*cda5da8dSAndroid Build Coastguard Worker#
31*cda5da8dSAndroid Build Coastguard Worker
32*cda5da8dSAndroid Build Coastguard Workerclass ForkServer(object):
33*cda5da8dSAndroid Build Coastguard Worker
34*cda5da8dSAndroid Build Coastguard Worker    def __init__(self):
35*cda5da8dSAndroid Build Coastguard Worker        self._forkserver_address = None
36*cda5da8dSAndroid Build Coastguard Worker        self._forkserver_alive_fd = None
37*cda5da8dSAndroid Build Coastguard Worker        self._forkserver_pid = None
38*cda5da8dSAndroid Build Coastguard Worker        self._inherited_fds = None
39*cda5da8dSAndroid Build Coastguard Worker        self._lock = threading.Lock()
40*cda5da8dSAndroid Build Coastguard Worker        self._preload_modules = ['__main__']
41*cda5da8dSAndroid Build Coastguard Worker
42*cda5da8dSAndroid Build Coastguard Worker    def _stop(self):
43*cda5da8dSAndroid Build Coastguard Worker        # Method used by unit tests to stop the server
44*cda5da8dSAndroid Build Coastguard Worker        with self._lock:
45*cda5da8dSAndroid Build Coastguard Worker            self._stop_unlocked()
46*cda5da8dSAndroid Build Coastguard Worker
47*cda5da8dSAndroid Build Coastguard Worker    def _stop_unlocked(self):
48*cda5da8dSAndroid Build Coastguard Worker        if self._forkserver_pid is None:
49*cda5da8dSAndroid Build Coastguard Worker            return
50*cda5da8dSAndroid Build Coastguard Worker
51*cda5da8dSAndroid Build Coastguard Worker        # close the "alive" file descriptor asks the server to stop
52*cda5da8dSAndroid Build Coastguard Worker        os.close(self._forkserver_alive_fd)
53*cda5da8dSAndroid Build Coastguard Worker        self._forkserver_alive_fd = None
54*cda5da8dSAndroid Build Coastguard Worker
55*cda5da8dSAndroid Build Coastguard Worker        os.waitpid(self._forkserver_pid, 0)
56*cda5da8dSAndroid Build Coastguard Worker        self._forkserver_pid = None
57*cda5da8dSAndroid Build Coastguard Worker
58*cda5da8dSAndroid Build Coastguard Worker        if not util.is_abstract_socket_namespace(self._forkserver_address):
59*cda5da8dSAndroid Build Coastguard Worker            os.unlink(self._forkserver_address)
60*cda5da8dSAndroid Build Coastguard Worker        self._forkserver_address = None
61*cda5da8dSAndroid Build Coastguard Worker
62*cda5da8dSAndroid Build Coastguard Worker    def set_forkserver_preload(self, modules_names):
63*cda5da8dSAndroid Build Coastguard Worker        '''Set list of module names to try to load in forkserver process.'''
64*cda5da8dSAndroid Build Coastguard Worker        if not all(type(mod) is str for mod in self._preload_modules):
65*cda5da8dSAndroid Build Coastguard Worker            raise TypeError('module_names must be a list of strings')
66*cda5da8dSAndroid Build Coastguard Worker        self._preload_modules = modules_names
67*cda5da8dSAndroid Build Coastguard Worker
68*cda5da8dSAndroid Build Coastguard Worker    def get_inherited_fds(self):
69*cda5da8dSAndroid Build Coastguard Worker        '''Return list of fds inherited from parent process.
70*cda5da8dSAndroid Build Coastguard Worker
71*cda5da8dSAndroid Build Coastguard Worker        This returns None if the current process was not started by fork
72*cda5da8dSAndroid Build Coastguard Worker        server.
73*cda5da8dSAndroid Build Coastguard Worker        '''
74*cda5da8dSAndroid Build Coastguard Worker        return self._inherited_fds
75*cda5da8dSAndroid Build Coastguard Worker
76*cda5da8dSAndroid Build Coastguard Worker    def connect_to_new_process(self, fds):
77*cda5da8dSAndroid Build Coastguard Worker        '''Request forkserver to create a child process.
78*cda5da8dSAndroid Build Coastguard Worker
79*cda5da8dSAndroid Build Coastguard Worker        Returns a pair of fds (status_r, data_w).  The calling process can read
80*cda5da8dSAndroid Build Coastguard Worker        the child process's pid and (eventually) its returncode from status_r.
81*cda5da8dSAndroid Build Coastguard Worker        The calling process should write to data_w the pickled preparation and
82*cda5da8dSAndroid Build Coastguard Worker        process data.
83*cda5da8dSAndroid Build Coastguard Worker        '''
84*cda5da8dSAndroid Build Coastguard Worker        self.ensure_running()
85*cda5da8dSAndroid Build Coastguard Worker        if len(fds) + 4 >= MAXFDS_TO_SEND:
86*cda5da8dSAndroid Build Coastguard Worker            raise ValueError('too many fds')
87*cda5da8dSAndroid Build Coastguard Worker        with socket.socket(socket.AF_UNIX) as client:
88*cda5da8dSAndroid Build Coastguard Worker            client.connect(self._forkserver_address)
89*cda5da8dSAndroid Build Coastguard Worker            parent_r, child_w = os.pipe()
90*cda5da8dSAndroid Build Coastguard Worker            child_r, parent_w = os.pipe()
91*cda5da8dSAndroid Build Coastguard Worker            allfds = [child_r, child_w, self._forkserver_alive_fd,
92*cda5da8dSAndroid Build Coastguard Worker                      resource_tracker.getfd()]
93*cda5da8dSAndroid Build Coastguard Worker            allfds += fds
94*cda5da8dSAndroid Build Coastguard Worker            try:
95*cda5da8dSAndroid Build Coastguard Worker                reduction.sendfds(client, allfds)
96*cda5da8dSAndroid Build Coastguard Worker                return parent_r, parent_w
97*cda5da8dSAndroid Build Coastguard Worker            except:
98*cda5da8dSAndroid Build Coastguard Worker                os.close(parent_r)
99*cda5da8dSAndroid Build Coastguard Worker                os.close(parent_w)
100*cda5da8dSAndroid Build Coastguard Worker                raise
101*cda5da8dSAndroid Build Coastguard Worker            finally:
102*cda5da8dSAndroid Build Coastguard Worker                os.close(child_r)
103*cda5da8dSAndroid Build Coastguard Worker                os.close(child_w)
104*cda5da8dSAndroid Build Coastguard Worker
105*cda5da8dSAndroid Build Coastguard Worker    def ensure_running(self):
106*cda5da8dSAndroid Build Coastguard Worker        '''Make sure that a fork server is running.
107*cda5da8dSAndroid Build Coastguard Worker
108*cda5da8dSAndroid Build Coastguard Worker        This can be called from any process.  Note that usually a child
109*cda5da8dSAndroid Build Coastguard Worker        process will just reuse the forkserver started by its parent, so
110*cda5da8dSAndroid Build Coastguard Worker        ensure_running() will do nothing.
111*cda5da8dSAndroid Build Coastguard Worker        '''
112*cda5da8dSAndroid Build Coastguard Worker        with self._lock:
113*cda5da8dSAndroid Build Coastguard Worker            resource_tracker.ensure_running()
114*cda5da8dSAndroid Build Coastguard Worker            if self._forkserver_pid is not None:
115*cda5da8dSAndroid Build Coastguard Worker                # forkserver was launched before, is it still running?
116*cda5da8dSAndroid Build Coastguard Worker                pid, status = os.waitpid(self._forkserver_pid, os.WNOHANG)
117*cda5da8dSAndroid Build Coastguard Worker                if not pid:
118*cda5da8dSAndroid Build Coastguard Worker                    # still alive
119*cda5da8dSAndroid Build Coastguard Worker                    return
120*cda5da8dSAndroid Build Coastguard Worker                # dead, launch it again
121*cda5da8dSAndroid Build Coastguard Worker                os.close(self._forkserver_alive_fd)
122*cda5da8dSAndroid Build Coastguard Worker                self._forkserver_address = None
123*cda5da8dSAndroid Build Coastguard Worker                self._forkserver_alive_fd = None
124*cda5da8dSAndroid Build Coastguard Worker                self._forkserver_pid = None
125*cda5da8dSAndroid Build Coastguard Worker
126*cda5da8dSAndroid Build Coastguard Worker            cmd = ('from multiprocessing.forkserver import main; ' +
127*cda5da8dSAndroid Build Coastguard Worker                   'main(%d, %d, %r, **%r)')
128*cda5da8dSAndroid Build Coastguard Worker
129*cda5da8dSAndroid Build Coastguard Worker            if self._preload_modules:
130*cda5da8dSAndroid Build Coastguard Worker                desired_keys = {'main_path', 'sys_path'}
131*cda5da8dSAndroid Build Coastguard Worker                data = spawn.get_preparation_data('ignore')
132*cda5da8dSAndroid Build Coastguard Worker                data = {x: y for x, y in data.items() if x in desired_keys}
133*cda5da8dSAndroid Build Coastguard Worker            else:
134*cda5da8dSAndroid Build Coastguard Worker                data = {}
135*cda5da8dSAndroid Build Coastguard Worker
136*cda5da8dSAndroid Build Coastguard Worker            with socket.socket(socket.AF_UNIX) as listener:
137*cda5da8dSAndroid Build Coastguard Worker                address = connection.arbitrary_address('AF_UNIX')
138*cda5da8dSAndroid Build Coastguard Worker                listener.bind(address)
139*cda5da8dSAndroid Build Coastguard Worker                if not util.is_abstract_socket_namespace(address):
140*cda5da8dSAndroid Build Coastguard Worker                    os.chmod(address, 0o600)
141*cda5da8dSAndroid Build Coastguard Worker                listener.listen()
142*cda5da8dSAndroid Build Coastguard Worker
143*cda5da8dSAndroid Build Coastguard Worker                # all client processes own the write end of the "alive" pipe;
144*cda5da8dSAndroid Build Coastguard Worker                # when they all terminate the read end becomes ready.
145*cda5da8dSAndroid Build Coastguard Worker                alive_r, alive_w = os.pipe()
146*cda5da8dSAndroid Build Coastguard Worker                try:
147*cda5da8dSAndroid Build Coastguard Worker                    fds_to_pass = [listener.fileno(), alive_r]
148*cda5da8dSAndroid Build Coastguard Worker                    cmd %= (listener.fileno(), alive_r, self._preload_modules,
149*cda5da8dSAndroid Build Coastguard Worker                            data)
150*cda5da8dSAndroid Build Coastguard Worker                    exe = spawn.get_executable()
151*cda5da8dSAndroid Build Coastguard Worker                    args = [exe] + util._args_from_interpreter_flags()
152*cda5da8dSAndroid Build Coastguard Worker                    args += ['-c', cmd]
153*cda5da8dSAndroid Build Coastguard Worker                    pid = util.spawnv_passfds(exe, args, fds_to_pass)
154*cda5da8dSAndroid Build Coastguard Worker                except:
155*cda5da8dSAndroid Build Coastguard Worker                    os.close(alive_w)
156*cda5da8dSAndroid Build Coastguard Worker                    raise
157*cda5da8dSAndroid Build Coastguard Worker                finally:
158*cda5da8dSAndroid Build Coastguard Worker                    os.close(alive_r)
159*cda5da8dSAndroid Build Coastguard Worker                self._forkserver_address = address
160*cda5da8dSAndroid Build Coastguard Worker                self._forkserver_alive_fd = alive_w
161*cda5da8dSAndroid Build Coastguard Worker                self._forkserver_pid = pid
162*cda5da8dSAndroid Build Coastguard Worker
163*cda5da8dSAndroid Build Coastguard Worker#
164*cda5da8dSAndroid Build Coastguard Worker#
165*cda5da8dSAndroid Build Coastguard Worker#
166*cda5da8dSAndroid Build Coastguard Worker
167*cda5da8dSAndroid Build Coastguard Workerdef main(listener_fd, alive_r, preload, main_path=None, sys_path=None):
168*cda5da8dSAndroid Build Coastguard Worker    '''Run forkserver.'''
169*cda5da8dSAndroid Build Coastguard Worker    if preload:
170*cda5da8dSAndroid Build Coastguard Worker        if '__main__' in preload and main_path is not None:
171*cda5da8dSAndroid Build Coastguard Worker            process.current_process()._inheriting = True
172*cda5da8dSAndroid Build Coastguard Worker            try:
173*cda5da8dSAndroid Build Coastguard Worker                spawn.import_main_path(main_path)
174*cda5da8dSAndroid Build Coastguard Worker            finally:
175*cda5da8dSAndroid Build Coastguard Worker                del process.current_process()._inheriting
176*cda5da8dSAndroid Build Coastguard Worker        for modname in preload:
177*cda5da8dSAndroid Build Coastguard Worker            try:
178*cda5da8dSAndroid Build Coastguard Worker                __import__(modname)
179*cda5da8dSAndroid Build Coastguard Worker            except ImportError:
180*cda5da8dSAndroid Build Coastguard Worker                pass
181*cda5da8dSAndroid Build Coastguard Worker
182*cda5da8dSAndroid Build Coastguard Worker    util._close_stdin()
183*cda5da8dSAndroid Build Coastguard Worker
184*cda5da8dSAndroid Build Coastguard Worker    sig_r, sig_w = os.pipe()
185*cda5da8dSAndroid Build Coastguard Worker    os.set_blocking(sig_r, False)
186*cda5da8dSAndroid Build Coastguard Worker    os.set_blocking(sig_w, False)
187*cda5da8dSAndroid Build Coastguard Worker
188*cda5da8dSAndroid Build Coastguard Worker    def sigchld_handler(*_unused):
189*cda5da8dSAndroid Build Coastguard Worker        # Dummy signal handler, doesn't do anything
190*cda5da8dSAndroid Build Coastguard Worker        pass
191*cda5da8dSAndroid Build Coastguard Worker
192*cda5da8dSAndroid Build Coastguard Worker    handlers = {
193*cda5da8dSAndroid Build Coastguard Worker        # unblocking SIGCHLD allows the wakeup fd to notify our event loop
194*cda5da8dSAndroid Build Coastguard Worker        signal.SIGCHLD: sigchld_handler,
195*cda5da8dSAndroid Build Coastguard Worker        # protect the process from ^C
196*cda5da8dSAndroid Build Coastguard Worker        signal.SIGINT: signal.SIG_IGN,
197*cda5da8dSAndroid Build Coastguard Worker        }
198*cda5da8dSAndroid Build Coastguard Worker    old_handlers = {sig: signal.signal(sig, val)
199*cda5da8dSAndroid Build Coastguard Worker                    for (sig, val) in handlers.items()}
200*cda5da8dSAndroid Build Coastguard Worker
201*cda5da8dSAndroid Build Coastguard Worker    # calling os.write() in the Python signal handler is racy
202*cda5da8dSAndroid Build Coastguard Worker    signal.set_wakeup_fd(sig_w)
203*cda5da8dSAndroid Build Coastguard Worker
204*cda5da8dSAndroid Build Coastguard Worker    # map child pids to client fds
205*cda5da8dSAndroid Build Coastguard Worker    pid_to_fd = {}
206*cda5da8dSAndroid Build Coastguard Worker
207*cda5da8dSAndroid Build Coastguard Worker    with socket.socket(socket.AF_UNIX, fileno=listener_fd) as listener, \
208*cda5da8dSAndroid Build Coastguard Worker         selectors.DefaultSelector() as selector:
209*cda5da8dSAndroid Build Coastguard Worker        _forkserver._forkserver_address = listener.getsockname()
210*cda5da8dSAndroid Build Coastguard Worker
211*cda5da8dSAndroid Build Coastguard Worker        selector.register(listener, selectors.EVENT_READ)
212*cda5da8dSAndroid Build Coastguard Worker        selector.register(alive_r, selectors.EVENT_READ)
213*cda5da8dSAndroid Build Coastguard Worker        selector.register(sig_r, selectors.EVENT_READ)
214*cda5da8dSAndroid Build Coastguard Worker
215*cda5da8dSAndroid Build Coastguard Worker        while True:
216*cda5da8dSAndroid Build Coastguard Worker            try:
217*cda5da8dSAndroid Build Coastguard Worker                while True:
218*cda5da8dSAndroid Build Coastguard Worker                    rfds = [key.fileobj for (key, events) in selector.select()]
219*cda5da8dSAndroid Build Coastguard Worker                    if rfds:
220*cda5da8dSAndroid Build Coastguard Worker                        break
221*cda5da8dSAndroid Build Coastguard Worker
222*cda5da8dSAndroid Build Coastguard Worker                if alive_r in rfds:
223*cda5da8dSAndroid Build Coastguard Worker                    # EOF because no more client processes left
224*cda5da8dSAndroid Build Coastguard Worker                    assert os.read(alive_r, 1) == b'', "Not at EOF?"
225*cda5da8dSAndroid Build Coastguard Worker                    raise SystemExit
226*cda5da8dSAndroid Build Coastguard Worker
227*cda5da8dSAndroid Build Coastguard Worker                if sig_r in rfds:
228*cda5da8dSAndroid Build Coastguard Worker                    # Got SIGCHLD
229*cda5da8dSAndroid Build Coastguard Worker                    os.read(sig_r, 65536)  # exhaust
230*cda5da8dSAndroid Build Coastguard Worker                    while True:
231*cda5da8dSAndroid Build Coastguard Worker                        # Scan for child processes
232*cda5da8dSAndroid Build Coastguard Worker                        try:
233*cda5da8dSAndroid Build Coastguard Worker                            pid, sts = os.waitpid(-1, os.WNOHANG)
234*cda5da8dSAndroid Build Coastguard Worker                        except ChildProcessError:
235*cda5da8dSAndroid Build Coastguard Worker                            break
236*cda5da8dSAndroid Build Coastguard Worker                        if pid == 0:
237*cda5da8dSAndroid Build Coastguard Worker                            break
238*cda5da8dSAndroid Build Coastguard Worker                        child_w = pid_to_fd.pop(pid, None)
239*cda5da8dSAndroid Build Coastguard Worker                        if child_w is not None:
240*cda5da8dSAndroid Build Coastguard Worker                            returncode = os.waitstatus_to_exitcode(sts)
241*cda5da8dSAndroid Build Coastguard Worker
242*cda5da8dSAndroid Build Coastguard Worker                            # Send exit code to client process
243*cda5da8dSAndroid Build Coastguard Worker                            try:
244*cda5da8dSAndroid Build Coastguard Worker                                write_signed(child_w, returncode)
245*cda5da8dSAndroid Build Coastguard Worker                            except BrokenPipeError:
246*cda5da8dSAndroid Build Coastguard Worker                                # client vanished
247*cda5da8dSAndroid Build Coastguard Worker                                pass
248*cda5da8dSAndroid Build Coastguard Worker                            os.close(child_w)
249*cda5da8dSAndroid Build Coastguard Worker                        else:
250*cda5da8dSAndroid Build Coastguard Worker                            # This shouldn't happen really
251*cda5da8dSAndroid Build Coastguard Worker                            warnings.warn('forkserver: waitpid returned '
252*cda5da8dSAndroid Build Coastguard Worker                                          'unexpected pid %d' % pid)
253*cda5da8dSAndroid Build Coastguard Worker
254*cda5da8dSAndroid Build Coastguard Worker                if listener in rfds:
255*cda5da8dSAndroid Build Coastguard Worker                    # Incoming fork request
256*cda5da8dSAndroid Build Coastguard Worker                    with listener.accept()[0] as s:
257*cda5da8dSAndroid Build Coastguard Worker                        # Receive fds from client
258*cda5da8dSAndroid Build Coastguard Worker                        fds = reduction.recvfds(s, MAXFDS_TO_SEND + 1)
259*cda5da8dSAndroid Build Coastguard Worker                        if len(fds) > MAXFDS_TO_SEND:
260*cda5da8dSAndroid Build Coastguard Worker                            raise RuntimeError(
261*cda5da8dSAndroid Build Coastguard Worker                                "Too many ({0:n}) fds to send".format(
262*cda5da8dSAndroid Build Coastguard Worker                                    len(fds)))
263*cda5da8dSAndroid Build Coastguard Worker                        child_r, child_w, *fds = fds
264*cda5da8dSAndroid Build Coastguard Worker                        s.close()
265*cda5da8dSAndroid Build Coastguard Worker                        pid = os.fork()
266*cda5da8dSAndroid Build Coastguard Worker                        if pid == 0:
267*cda5da8dSAndroid Build Coastguard Worker                            # Child
268*cda5da8dSAndroid Build Coastguard Worker                            code = 1
269*cda5da8dSAndroid Build Coastguard Worker                            try:
270*cda5da8dSAndroid Build Coastguard Worker                                listener.close()
271*cda5da8dSAndroid Build Coastguard Worker                                selector.close()
272*cda5da8dSAndroid Build Coastguard Worker                                unused_fds = [alive_r, child_w, sig_r, sig_w]
273*cda5da8dSAndroid Build Coastguard Worker                                unused_fds.extend(pid_to_fd.values())
274*cda5da8dSAndroid Build Coastguard Worker                                code = _serve_one(child_r, fds,
275*cda5da8dSAndroid Build Coastguard Worker                                                  unused_fds,
276*cda5da8dSAndroid Build Coastguard Worker                                                  old_handlers)
277*cda5da8dSAndroid Build Coastguard Worker                            except Exception:
278*cda5da8dSAndroid Build Coastguard Worker                                sys.excepthook(*sys.exc_info())
279*cda5da8dSAndroid Build Coastguard Worker                                sys.stderr.flush()
280*cda5da8dSAndroid Build Coastguard Worker                            finally:
281*cda5da8dSAndroid Build Coastguard Worker                                os._exit(code)
282*cda5da8dSAndroid Build Coastguard Worker                        else:
283*cda5da8dSAndroid Build Coastguard Worker                            # Send pid to client process
284*cda5da8dSAndroid Build Coastguard Worker                            try:
285*cda5da8dSAndroid Build Coastguard Worker                                write_signed(child_w, pid)
286*cda5da8dSAndroid Build Coastguard Worker                            except BrokenPipeError:
287*cda5da8dSAndroid Build Coastguard Worker                                # client vanished
288*cda5da8dSAndroid Build Coastguard Worker                                pass
289*cda5da8dSAndroid Build Coastguard Worker                            pid_to_fd[pid] = child_w
290*cda5da8dSAndroid Build Coastguard Worker                            os.close(child_r)
291*cda5da8dSAndroid Build Coastguard Worker                            for fd in fds:
292*cda5da8dSAndroid Build Coastguard Worker                                os.close(fd)
293*cda5da8dSAndroid Build Coastguard Worker
294*cda5da8dSAndroid Build Coastguard Worker            except OSError as e:
295*cda5da8dSAndroid Build Coastguard Worker                if e.errno != errno.ECONNABORTED:
296*cda5da8dSAndroid Build Coastguard Worker                    raise
297*cda5da8dSAndroid Build Coastguard Worker
298*cda5da8dSAndroid Build Coastguard Worker
299*cda5da8dSAndroid Build Coastguard Workerdef _serve_one(child_r, fds, unused_fds, handlers):
300*cda5da8dSAndroid Build Coastguard Worker    # close unnecessary stuff and reset signal handlers
301*cda5da8dSAndroid Build Coastguard Worker    signal.set_wakeup_fd(-1)
302*cda5da8dSAndroid Build Coastguard Worker    for sig, val in handlers.items():
303*cda5da8dSAndroid Build Coastguard Worker        signal.signal(sig, val)
304*cda5da8dSAndroid Build Coastguard Worker    for fd in unused_fds:
305*cda5da8dSAndroid Build Coastguard Worker        os.close(fd)
306*cda5da8dSAndroid Build Coastguard Worker
307*cda5da8dSAndroid Build Coastguard Worker    (_forkserver._forkserver_alive_fd,
308*cda5da8dSAndroid Build Coastguard Worker     resource_tracker._resource_tracker._fd,
309*cda5da8dSAndroid Build Coastguard Worker     *_forkserver._inherited_fds) = fds
310*cda5da8dSAndroid Build Coastguard Worker
311*cda5da8dSAndroid Build Coastguard Worker    # Run process object received over pipe
312*cda5da8dSAndroid Build Coastguard Worker    parent_sentinel = os.dup(child_r)
313*cda5da8dSAndroid Build Coastguard Worker    code = spawn._main(child_r, parent_sentinel)
314*cda5da8dSAndroid Build Coastguard Worker
315*cda5da8dSAndroid Build Coastguard Worker    return code
316*cda5da8dSAndroid Build Coastguard Worker
317*cda5da8dSAndroid Build Coastguard Worker
318*cda5da8dSAndroid Build Coastguard Worker#
319*cda5da8dSAndroid Build Coastguard Worker# Read and write signed numbers
320*cda5da8dSAndroid Build Coastguard Worker#
321*cda5da8dSAndroid Build Coastguard Worker
322*cda5da8dSAndroid Build Coastguard Workerdef read_signed(fd):
323*cda5da8dSAndroid Build Coastguard Worker    data = b''
324*cda5da8dSAndroid Build Coastguard Worker    length = SIGNED_STRUCT.size
325*cda5da8dSAndroid Build Coastguard Worker    while len(data) < length:
326*cda5da8dSAndroid Build Coastguard Worker        s = os.read(fd, length - len(data))
327*cda5da8dSAndroid Build Coastguard Worker        if not s:
328*cda5da8dSAndroid Build Coastguard Worker            raise EOFError('unexpected EOF')
329*cda5da8dSAndroid Build Coastguard Worker        data += s
330*cda5da8dSAndroid Build Coastguard Worker    return SIGNED_STRUCT.unpack(data)[0]
331*cda5da8dSAndroid Build Coastguard Worker
332*cda5da8dSAndroid Build Coastguard Workerdef write_signed(fd, n):
333*cda5da8dSAndroid Build Coastguard Worker    msg = SIGNED_STRUCT.pack(n)
334*cda5da8dSAndroid Build Coastguard Worker    while msg:
335*cda5da8dSAndroid Build Coastguard Worker        nbytes = os.write(fd, msg)
336*cda5da8dSAndroid Build Coastguard Worker        if nbytes == 0:
337*cda5da8dSAndroid Build Coastguard Worker            raise RuntimeError('should not get here')
338*cda5da8dSAndroid Build Coastguard Worker        msg = msg[nbytes:]
339*cda5da8dSAndroid Build Coastguard Worker
340*cda5da8dSAndroid Build Coastguard Worker#
341*cda5da8dSAndroid Build Coastguard Worker#
342*cda5da8dSAndroid Build Coastguard Worker#
343*cda5da8dSAndroid Build Coastguard Worker
344*cda5da8dSAndroid Build Coastguard Worker_forkserver = ForkServer()
345*cda5da8dSAndroid Build Coastguard Workerensure_running = _forkserver.ensure_running
346*cda5da8dSAndroid Build Coastguard Workerget_inherited_fds = _forkserver.get_inherited_fds
347*cda5da8dSAndroid Build Coastguard Workerconnect_to_new_process = _forkserver.connect_to_new_process
348*cda5da8dSAndroid Build Coastguard Workerset_forkserver_preload = _forkserver.set_forkserver_preload
349