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