1// Copyright 2015 The Kyua Authors.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9//   notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright
11//   notice, this list of conditions and the following disclaimer in the
12//   documentation and/or other materials provided with the distribution.
13// * Neither the name of Google Inc. nor the names of its contributors
14//   may be used to endorse or promote products derived from this software
15//   without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29#include "utils/process/executor.ipp"
30
31#if defined(HAVE_CONFIG_H)
32#include "config.h"
33#endif
34
35extern "C" {
36#include <sys/types.h>
37#include <sys/wait.h>
38
39#include <signal.h>
40}
41
42#include <forward_list>
43#include <fstream>
44#include <map>
45#include <memory>
46#include <stdexcept>
47#include <utility>
48
49#include "utils/datetime.hpp"
50#include "utils/format/macros.hpp"
51#include "utils/fs/auto_cleaners.hpp"
52#include "utils/fs/exceptions.hpp"
53#include "utils/fs/operations.hpp"
54#include "utils/fs/path.hpp"
55#include "utils/logging/macros.hpp"
56#include "utils/logging/operations.hpp"
57#include "utils/noncopyable.hpp"
58#include "utils/optional.ipp"
59#include "utils/passwd.hpp"
60#include "utils/process/child.ipp"
61#include "utils/process/deadline_killer.hpp"
62#include "utils/process/isolation.hpp"
63#include "utils/process/operations.hpp"
64#include "utils/process/status.hpp"
65#include "utils/sanity.hpp"
66#include "utils/signals/interrupts.hpp"
67#include "utils/signals/timer.hpp"
68
69namespace datetime = utils::datetime;
70namespace executor = utils::process::executor;
71namespace fs = utils::fs;
72namespace logging = utils::logging;
73namespace passwd = utils::passwd;
74namespace process = utils::process;
75namespace signals = utils::signals;
76
77using utils::none;
78using utils::optional;
79
80
81namespace {
82
83
84/// Template for temporary directories created by the executor.
85static const char* work_directory_template = PACKAGE_TARNAME ".XXXXXX";
86
87
88/// Mapping of active subprocess PIDs to their execution data.
89typedef std::map< int, executor::exec_handle > exec_handles_map;
90
91
92}  // anonymous namespace
93
94
95/// Basename of the file containing the stdout of the subprocess.
96const char* utils::process::executor::detail::stdout_name = "stdout.txt";
97
98
99/// Basename of the file containing the stderr of the subprocess.
100const char* utils::process::executor::detail::stderr_name = "stderr.txt";
101
102
103/// Basename of the subdirectory in which the subprocess is actually executed.
104///
105/// This is a subdirectory of the "unique work directory" generated for the
106/// subprocess so that our code can create control files on disk and not
107/// get them clobbered by the subprocess's activity.
108const char* utils::process::executor::detail::work_subdir = "work";
109
110
111/// Prepares a subprocess to run a user-provided hook in a controlled manner.
112///
113/// \param unprivileged_user User to switch to if not none.
114/// \param control_directory Path to the subprocess-specific control directory.
115/// \param work_directory Path to the subprocess-specific work directory.
116void
117utils::process::executor::detail::setup_child(
118    const optional< passwd::user > unprivileged_user,
119    const fs::path& control_directory,
120    const fs::path& work_directory)
121{
122    logging::set_inmemory();
123    process::isolate_path(unprivileged_user, control_directory);
124    process::isolate_child(unprivileged_user, work_directory);
125}
126
127
128/// Internal implementation for the exec_handle class.
129struct utils::process::executor::exec_handle::impl : utils::noncopyable {
130    /// PID of the process being run.
131    int pid;
132
133    /// Path to the subprocess-specific work directory.
134    fs::path control_directory;
135
136    /// Path to the subprocess's stdout file.
137    const fs::path stdout_file;
138
139    /// Path to the subprocess's stderr file.
140    const fs::path stderr_file;
141
142    /// Start time.
143    datetime::timestamp start_time;
144
145    /// User the subprocess is running as if different than the current one.
146    const optional< passwd::user > unprivileged_user;
147
148    /// Timer to kill the subprocess on activation.
149    process::deadline_killer timer;
150
151    /// Number of owners of the on-disk state.
152    executor::detail::refcnt_t state_owners;
153
154    /// Constructor.
155    ///
156    /// \param pid_ PID of the forked process.
157    /// \param control_directory_ Path to the subprocess-specific work
158    ///     directory.
159    /// \param stdout_file_ Path to the subprocess's stdout file.
160    /// \param stderr_file_ Path to the subprocess's stderr file.
161    /// \param start_time_ Timestamp of when this object was constructed.
162    /// \param timeout Maximum amount of time the subprocess can run for.
163    /// \param unprivileged_user_ User the subprocess is running as if
164    ///     different than the current one.
165    /// \param [in,out] state_owners_ Number of owners of the on-disk state.
166    ///     For first-time processes, this should be a new counter set to 0;
167    ///     for followup processes, this should point to the same counter used
168    ///     by the preceding process.
169    impl(const int pid_,
170         const fs::path& control_directory_,
171         const fs::path& stdout_file_,
172         const fs::path& stderr_file_,
173         const datetime::timestamp& start_time_,
174         const datetime::delta& timeout,
175         const optional< passwd::user > unprivileged_user_,
176         executor::detail::refcnt_t state_owners_) :
177        pid(pid_),
178        control_directory(control_directory_),
179        stdout_file(stdout_file_),
180        stderr_file(stderr_file_),
181        start_time(start_time_),
182        unprivileged_user(unprivileged_user_),
183        timer(timeout, pid_),
184        state_owners(state_owners_)
185    {
186        (*state_owners)++;
187        POST(*state_owners > 0);
188    }
189};
190
191
192/// Constructor.
193///
194/// \param pimpl Constructed internal implementation.
195executor::exec_handle::exec_handle(std::shared_ptr< impl > pimpl) :
196    _pimpl(pimpl)
197{
198}
199
200
201/// Destructor.
202executor::exec_handle::~exec_handle(void)
203{
204}
205
206
207/// Returns the PID of the process being run.
208///
209/// \return A PID.
210int
211executor::exec_handle::pid(void) const
212{
213    return _pimpl->pid;
214}
215
216
217/// Returns the path to the subprocess-specific control directory.
218///
219/// This is where the executor may store control files.
220///
221/// \return The path to a directory that exists until cleanup() is called.
222fs::path
223executor::exec_handle::control_directory(void) const
224{
225    return _pimpl->control_directory;
226}
227
228
229/// Returns the path to the subprocess-specific work directory.
230///
231/// This is guaranteed to be clear of files created by the executor.
232///
233/// \return The path to a directory that exists until cleanup() is called.
234fs::path
235executor::exec_handle::work_directory(void) const
236{
237    return _pimpl->control_directory / detail::work_subdir;
238}
239
240
241/// Returns the path to the subprocess's stdout file.
242///
243/// \return The path to a file that exists until cleanup() is called.
244const fs::path&
245executor::exec_handle::stdout_file(void) const
246{
247    return _pimpl->stdout_file;
248}
249
250
251/// Returns the path to the subprocess's stderr file.
252///
253/// \return The path to a file that exists until cleanup() is called.
254const fs::path&
255executor::exec_handle::stderr_file(void) const
256{
257    return _pimpl->stderr_file;
258}
259
260
261/// Internal implementation for the exit_handle class.
262struct utils::process::executor::exit_handle::impl : utils::noncopyable {
263    /// Original PID of the terminated subprocess.
264    ///
265    /// Note that this PID is no longer valid and cannot be used on system
266    /// tables!
267    const int original_pid;
268
269    /// Termination status of the subprocess, or none if it timed out.
270    const optional< process::status > status;
271
272    /// The user the process ran as, if different than the current one.
273    const optional< passwd::user > unprivileged_user;
274
275    /// Timestamp of when the subprocess was spawned.
276    const datetime::timestamp start_time;
277
278    /// Timestamp of when wait() or wait_any() returned this object.
279    const datetime::timestamp end_time;
280
281    /// Path to the subprocess-specific work directory.
282    const fs::path control_directory;
283
284    /// Path to the subprocess's stdout file.
285    const fs::path stdout_file;
286
287    /// Path to the subprocess's stderr file.
288    const fs::path stderr_file;
289
290    /// Number of owners of the on-disk state.
291    ///
292    /// This will be 1 if this exit_handle is the last holder of the on-disk
293    /// state, in which case cleanup() invocations will wipe the disk state.
294    /// For all other cases, this will hold a higher value.
295    detail::refcnt_t state_owners;
296
297    /// Mutable pointer to the corresponding executor state.
298    ///
299    /// This object references a member of the executor_handle that yielded this
300    /// exit_handle instance.  We need this direct access to clean up after
301    /// ourselves when the handle is destroyed.
302    exec_handles_map& all_exec_handles;
303
304    /// Whether the subprocess state has been cleaned yet or not.
305    ///
306    /// Used to keep track of explicit calls to the public cleanup().
307    bool cleaned;
308
309    /// Constructor.
310    ///
311    /// \param original_pid_ Original PID of the terminated subprocess.
312    /// \param status_ Termination status of the subprocess, or none if
313    ///     timed out.
314    /// \param unprivileged_user_ The user the process ran as, if different than
315    ///     the current one.
316    /// \param start_time_ Timestamp of when the subprocess was spawned.
317    /// \param end_time_ Timestamp of when wait() or wait_any() returned this
318    ///     object.
319    /// \param control_directory_ Path to the subprocess-specific work
320    ///     directory.
321    /// \param stdout_file_ Path to the subprocess's stdout file.
322    /// \param stderr_file_ Path to the subprocess's stderr file.
323    /// \param [in,out] state_owners_ Number of owners of the on-disk state.
324    /// \param [in,out] all_exec_handles_ Global object keeping track of all
325    ///     active executions for an executor.  This is a pointer to a member of
326    ///     the executor_handle object.
327    impl(const int original_pid_,
328         const optional< process::status > status_,
329         const optional< passwd::user > unprivileged_user_,
330         const datetime::timestamp& start_time_,
331         const datetime::timestamp& end_time_,
332         const fs::path& control_directory_,
333         const fs::path& stdout_file_,
334         const fs::path& stderr_file_,
335         detail::refcnt_t state_owners_,
336         exec_handles_map& all_exec_handles_) :
337        original_pid(original_pid_), status(status_),
338        unprivileged_user(unprivileged_user_),
339        start_time(start_time_), end_time(end_time_),
340        control_directory(control_directory_),
341        stdout_file(stdout_file_), stderr_file(stderr_file_),
342        state_owners(state_owners_),
343        all_exec_handles(all_exec_handles_), cleaned(false)
344    {
345    }
346
347    /// Destructor.
348    ~impl(void)
349    {
350        if (!cleaned) {
351            LW(F("Implicitly cleaning up exit_handle for exec_handle %s; "
352                 "ignoring errors!") % original_pid);
353            try {
354                cleanup();
355            } catch (const std::runtime_error& error) {
356                LE(F("Subprocess cleanup failed: %s") % error.what());
357            }
358        }
359    }
360
361    /// Cleans up the subprocess on-disk state.
362    ///
363    /// \throw engine::error If the cleanup fails, especially due to the
364    ///     inability to remove the work directory.
365    void
366    cleanup(void)
367    {
368        PRE(*state_owners > 0);
369        if (*state_owners == 1) {
370            LI(F("Cleaning up exit_handle for exec_handle %s") % original_pid);
371            fs::rm_r(control_directory);
372        } else {
373            LI(F("Not cleaning up exit_handle for exec_handle %s; "
374                 "%s owners left") % original_pid % (*state_owners - 1));
375        }
376        // We must decrease our reference only after we have successfully
377        // cleaned up the control directory.  Otherwise, the rm_r call would
378        // throw an exception, which would in turn invoke the implicit cleanup
379        // from the destructor, which would make us crash due to an invalid
380        // reference count.
381        (*state_owners)--;
382        // Marking this object as clean here, even if we did not do actually the
383        // cleaning above, is fine (albeit a bit confusing).  Note that "another
384        // owner" refers to a handle for a different PID, so that handle will be
385        // the one issuing the cleanup.
386        all_exec_handles.erase(original_pid);
387        cleaned = true;
388    }
389};
390
391
392/// Constructor.
393///
394/// \param pimpl Constructed internal implementation.
395executor::exit_handle::exit_handle(std::shared_ptr< impl > pimpl) :
396    _pimpl(pimpl)
397{
398}
399
400
401/// Destructor.
402executor::exit_handle::~exit_handle(void)
403{
404}
405
406
407/// Cleans up the subprocess status.
408///
409/// This function should be called explicitly as it provides the means to
410/// control any exceptions raised during cleanup.  Do not rely on the destructor
411/// to clean things up.
412///
413/// \throw engine::error If the cleanup fails, especially due to the inability
414///     to remove the work directory.
415void
416executor::exit_handle::cleanup(void)
417{
418    PRE(!_pimpl->cleaned);
419    _pimpl->cleanup();
420    POST(_pimpl->cleaned);
421}
422
423
424/// Gets the current number of owners of the on-disk data.
425///
426/// \return A shared reference counter.  Even though this function is marked as
427/// const, the return value is intentionally mutable because we need to update
428/// reference counts from different but related processes.  This is why this
429/// method is not public.
430std::shared_ptr< std::size_t >
431executor::exit_handle::state_owners(void) const
432{
433    return _pimpl->state_owners;
434}
435
436
437/// Returns the original PID corresponding to the terminated subprocess.
438///
439/// \return An exec_handle.
440int
441executor::exit_handle::original_pid(void) const
442{
443    return _pimpl->original_pid;
444}
445
446
447/// Returns the process termination status of the subprocess.
448///
449/// \return A process termination status, or none if the subprocess timed out.
450const optional< process::status >&
451executor::exit_handle::status(void) const
452{
453    return _pimpl->status;
454}
455
456
457/// Returns the user the process ran as if different than the current one.
458///
459/// \return None if the credentials of the process were the same as the current
460/// one, or else a user.
461const optional< passwd::user >&
462executor::exit_handle::unprivileged_user(void) const
463{
464    return _pimpl->unprivileged_user;
465}
466
467
468/// Returns the timestamp of when the subprocess was spawned.
469///
470/// \return A timestamp.
471const datetime::timestamp&
472executor::exit_handle::start_time(void) const
473{
474    return _pimpl->start_time;
475}
476
477
478/// Returns the timestamp of when wait() or wait_any() returned this object.
479///
480/// \return A timestamp.
481const datetime::timestamp&
482executor::exit_handle::end_time(void) const
483{
484    return _pimpl->end_time;
485}
486
487
488/// Returns the path to the subprocess-specific control directory.
489///
490/// This is where the executor may store control files.
491///
492/// \return The path to a directory that exists until cleanup() is called.
493fs::path
494executor::exit_handle::control_directory(void) const
495{
496    return _pimpl->control_directory;
497}
498
499
500/// Returns the path to the subprocess-specific work directory.
501///
502/// This is guaranteed to be clear of files created by the executor.
503///
504/// \return The path to a directory that exists until cleanup() is called.
505fs::path
506executor::exit_handle::work_directory(void) const
507{
508    return _pimpl->control_directory / detail::work_subdir;
509}
510
511
512/// Returns the path to the subprocess's stdout file.
513///
514/// \return The path to a file that exists until cleanup() is called.
515const fs::path&
516executor::exit_handle::stdout_file(void) const
517{
518    return _pimpl->stdout_file;
519}
520
521
522/// Returns the path to the subprocess's stderr file.
523///
524/// \return The path to a file that exists until cleanup() is called.
525const fs::path&
526executor::exit_handle::stderr_file(void) const
527{
528    return _pimpl->stderr_file;
529}
530
531
532/// Internal implementation for the executor_handle.
533///
534/// Because the executor is a singleton, these essentially is a container for
535/// global variables.
536struct utils::process::executor::executor_handle::impl : utils::noncopyable {
537    /// Numeric counter of executed subprocesses.
538    ///
539    /// This is used to generate a unique identifier for each subprocess as an
540    /// easy mechanism to discern their unique work directories.
541    size_t last_subprocess;
542
543    /// Interrupts handler.
544    std::auto_ptr< signals::interrupts_handler > interrupts_handler;
545
546    /// Root work directory for all executed subprocesses.
547    std::auto_ptr< fs::auto_directory > root_work_directory;
548
549    /// Mapping of PIDs to the data required at run time.
550    exec_handles_map all_exec_handles;
551
552    /// Former members of all_exec_handles removed due to PID reuse.
553    std::forward_list<exec_handle> stale_exec_handles;
554
555    /// Whether the executor state has been cleaned yet or not.
556    ///
557    /// Used to keep track of explicit calls to the public cleanup().
558    bool cleaned;
559
560    /// Constructor.
561    impl(void) :
562        last_subprocess(0),
563        interrupts_handler(new signals::interrupts_handler()),
564        root_work_directory(new fs::auto_directory(
565            fs::auto_directory::mkdtemp_public(work_directory_template))),
566        all_exec_handles(),
567        stale_exec_handles(),
568        cleaned(false)
569    {
570    }
571
572    /// Destructor.
573    ~impl(void)
574    {
575        if (!cleaned) {
576            LW("Implicitly cleaning up executor; ignoring errors!");
577            try {
578                cleanup();
579                cleaned = true;
580            } catch (const std::runtime_error& error) {
581                LE(F("Executor global cleanup failed: %s") % error.what());
582            }
583        }
584    }
585
586    /// Cleans up the executor state.
587    void
588    cleanup(void)
589    {
590        PRE(!cleaned);
591
592        for (exec_handles_map::const_iterator iter = all_exec_handles.begin();
593             iter != all_exec_handles.end(); ++iter) {
594            const int& pid = (*iter).first;
595            const exec_handle& data = (*iter).second;
596
597            process::terminate_group(pid);
598            int status;
599            if (::waitpid(pid, &status, 0) == -1) {
600                // Should not happen.
601                LW(F("Failed to wait for PID %s") % pid);
602            }
603
604            try {
605                fs::rm_r(data.control_directory());
606            } catch (const fs::error& e) {
607                LE(F("Failed to clean up subprocess work directory %s: %s") %
608                   data.control_directory() % e.what());
609            }
610        }
611        all_exec_handles.clear();
612
613        for (auto iter : stale_exec_handles) {
614            // The process already exited, so no need to kill and wait.
615            try {
616                fs::rm_r(iter.control_directory());
617            } catch (const fs::error& e) {
618                LE(F("Failed to clean up stale subprocess work directory "
619                    "%s: %s") % iter.control_directory() % e.what());
620            }
621        }
622        stale_exec_handles.clear();
623
624        try {
625            // The following only causes the work directory to be deleted, not
626            // any of its contents, so we expect this to always succeed.  This
627            // *should* be sufficient because, in the loop above, we have
628            // individually wiped the subdirectories of any still-unclean
629            // subprocesses.
630            root_work_directory->cleanup();
631        } catch (const fs::error& e) {
632            LE(F("Failed to clean up executor work directory %s: %s; "
633                "this could be an internal error or a buggy test") %
634                root_work_directory->directory() % e.what());
635        }
636        root_work_directory.reset(NULL);
637
638        interrupts_handler->unprogram();
639        interrupts_handler.reset(NULL);
640    }
641
642    /// Common code to run after any of the wait calls.
643    ///
644    /// \param original_pid The PID of the terminated subprocess.
645    /// \param status The exit status of the terminated subprocess.
646    ///
647    /// \return A pointer to an object describing the waited-for subprocess.
648    executor::exit_handle
649    post_wait(const int original_pid, const process::status& status)
650    {
651        PRE(original_pid == status.dead_pid());
652        LI(F("Waited for subprocess with exec_handle %s") % original_pid);
653
654        process::terminate_group(status.dead_pid());
655
656        const exec_handles_map::iterator iter = all_exec_handles.find(
657            original_pid);
658        exec_handle& data = (*iter).second;
659        data._pimpl->timer.unprogram();
660
661        // It is tempting to assert here (and old code did) that, if the timer
662        // has fired, the process has been forcibly killed by us.  This is not
663        // always the case though: for short-lived processes and with very short
664        // timeouts (think 1ms), it is possible for scheduling decisions to
665        // allow the subprocess to finish while at the same time cause the timer
666        // to fire.  So we do not assert this any longer and just rely on the
667        // timer expiration to check if the process timed out or not.  If the
668        // process did finish but the timer expired... oh well, we do not detect
669        // this correctly but we don't care because this should not really
670        // happen.
671
672        if (!fs::exists(data.stdout_file())) {
673            std::ofstream new_stdout(data.stdout_file().c_str());
674        }
675        if (!fs::exists(data.stderr_file())) {
676            std::ofstream new_stderr(data.stderr_file().c_str());
677        }
678
679        return exit_handle(std::shared_ptr< exit_handle::impl >(
680            new exit_handle::impl(
681                data.pid(),
682                data._pimpl->timer.fired() ?
683                    none : utils::make_optional(status),
684                data._pimpl->unprivileged_user,
685                data._pimpl->start_time, datetime::timestamp::now(),
686                data.control_directory(),
687                data.stdout_file(),
688                data.stderr_file(),
689                data._pimpl->state_owners,
690                all_exec_handles)));
691    }
692};
693
694
695/// Constructor.
696executor::executor_handle::executor_handle(void) throw() : _pimpl(new impl())
697{
698}
699
700
701/// Destructor.
702executor::executor_handle::~executor_handle(void)
703{
704}
705
706
707/// Queries the path to the root of the work directory for all subprocesses.
708///
709/// \return A path.
710const fs::path&
711executor::executor_handle::root_work_directory(void) const
712{
713    return _pimpl->root_work_directory->directory();
714}
715
716
717/// Cleans up the executor state.
718///
719/// This function should be called explicitly as it provides the means to
720/// control any exceptions raised during cleanup.  Do not rely on the destructor
721/// to clean things up.
722///
723/// \throw engine::error If there are problems cleaning up the executor.
724void
725executor::executor_handle::cleanup(void)
726{
727    PRE(!_pimpl->cleaned);
728    _pimpl->cleanup();
729    _pimpl->cleaned = true;
730}
731
732
733/// Initializes the executor.
734///
735/// \pre This function can only be called if there is no other executor_handle
736/// object alive.
737///
738/// \return A handle to the operations of the executor.
739executor::executor_handle
740executor::setup(void)
741{
742    return executor_handle();
743}
744
745
746/// Pre-helper for the spawn() method.
747///
748/// \return The created control directory for the subprocess.
749fs::path
750executor::executor_handle::spawn_pre(void)
751{
752    signals::check_interrupt();
753
754    ++_pimpl->last_subprocess;
755
756    const fs::path control_directory =
757        _pimpl->root_work_directory->directory() /
758        (F("%s") % _pimpl->last_subprocess);
759    fs::mkdir_p(control_directory / detail::work_subdir, 0755);
760
761    return control_directory;
762}
763
764
765/// Post-helper for the spawn() method.
766///
767/// \param control_directory Control directory as returned by spawn_pre().
768/// \param stdout_file Path to the subprocess' stdout.
769/// \param stderr_file Path to the subprocess' stderr.
770/// \param timeout Maximum amount of time the subprocess can run for.
771/// \param unprivileged_user If not none, user to switch to before execution.
772/// \param child The process created by spawn().
773///
774/// \return The execution handle of the started subprocess.
775executor::exec_handle
776executor::executor_handle::spawn_post(
777    const fs::path& control_directory,
778    const fs::path& stdout_file,
779    const fs::path& stderr_file,
780    const datetime::delta& timeout,
781    const optional< passwd::user > unprivileged_user,
782    std::auto_ptr< process::child > child)
783{
784    const exec_handle handle(std::shared_ptr< exec_handle::impl >(
785        new exec_handle::impl(
786            child->pid(),
787            control_directory,
788            stdout_file,
789            stderr_file,
790            datetime::timestamp::now(),
791            timeout,
792            unprivileged_user,
793            detail::refcnt_t(new detail::refcnt_t::element_type(0)))));
794    const auto value = exec_handles_map::value_type(handle.pid(), handle);
795    auto insert_pair = _pimpl->all_exec_handles.insert(value);
796    if (!insert_pair.second) {
797        LI(F("PID %s already in all_exec_handles") % handle.pid());
798        _pimpl->stale_exec_handles.push_front(insert_pair.first->second);
799        _pimpl->all_exec_handles.erase(insert_pair.first);
800        insert_pair = _pimpl->all_exec_handles.insert(value);
801        INV_MSG(insert_pair.second, F("PID %s still in all_exec_handles") %
802            handle.pid());
803    }
804    LI(F("Spawned subprocess with exec_handle %s") % handle.pid());
805    return handle;
806}
807
808
809/// Pre-helper for the spawn_followup() method.
810void
811executor::executor_handle::spawn_followup_pre(void)
812{
813    signals::check_interrupt();
814}
815
816
817/// Post-helper for the spawn_followup() method.
818///
819/// \param base Exit handle of the subprocess to use as context.
820/// \param timeout Maximum amount of time the subprocess can run for.
821/// \param child The process created by spawn_followup().
822///
823/// \return The execution handle of the started subprocess.
824executor::exec_handle
825executor::executor_handle::spawn_followup_post(
826    const exit_handle& base,
827    const datetime::delta& timeout,
828    std::auto_ptr< process::child > child)
829{
830    INV(*base.state_owners() > 0);
831    const exec_handle handle(std::shared_ptr< exec_handle::impl >(
832        new exec_handle::impl(
833            child->pid(),
834            base.control_directory(),
835            base.stdout_file(),
836            base.stderr_file(),
837            datetime::timestamp::now(),
838            timeout,
839            base.unprivileged_user(),
840            base.state_owners())));
841    const auto value = exec_handles_map::value_type(handle.pid(), handle);
842    auto insert_pair = _pimpl->all_exec_handles.insert(value);
843    if (!insert_pair.second) {
844        LI(F("PID %s already in all_exec_handles") % handle.pid());
845        _pimpl->stale_exec_handles.push_front(insert_pair.first->second);
846        _pimpl->all_exec_handles.erase(insert_pair.first);
847        insert_pair = _pimpl->all_exec_handles.insert(value);
848        INV_MSG(insert_pair.second, F("PID %s still in all_exec_handles") %
849            handle.pid());
850    }
851    LI(F("Spawned subprocess with exec_handle %s") % handle.pid());
852    return handle;
853}
854
855
856/// Waits for completion of any forked process.
857///
858/// \param exec_handle The handle of the process to wait for.
859///
860/// \return A pointer to an object describing the waited-for subprocess.
861executor::exit_handle
862executor::executor_handle::wait(const exec_handle exec_handle)
863{
864    signals::check_interrupt();
865    const process::status status = process::wait(exec_handle.pid());
866    return _pimpl->post_wait(exec_handle.pid(), status);
867}
868
869
870/// Waits for completion of any forked process.
871///
872/// \return A pointer to an object describing the waited-for subprocess.
873executor::exit_handle
874executor::executor_handle::wait_any(void)
875{
876    signals::check_interrupt();
877    const process::status status = process::wait_any();
878    return _pimpl->post_wait(status.dead_pid(), status);
879}
880
881
882/// Checks if an interrupt has fired.
883///
884/// Calls to this function should be sprinkled in strategic places through the
885/// code protected by an interrupts_handler object.
886///
887/// This is just a wrapper over signals::check_interrupt() to avoid leaking this
888/// dependency to the caller.
889///
890/// \throw signals::interrupted_error If there has been an interrupt.
891void
892executor::executor_handle::check_interrupt(void) const
893{
894    signals::check_interrupt();
895}
896