blob: e2218bfa2a61b9c9af3897bb58d3013c27b9f7aa [file] [log] [blame]
Mike Klein154e6da2017-07-26 15:13:47 -04001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "ok.h"
9
10struct SerialEngine : Engine {
11 static std::unique_ptr<Engine> Factory(Options) {
12 SerialEngine engine;
13 return move_unique(engine);
14 }
15
16 bool crashproof() override { return false; }
17
18 std::future<Status> spawn(std::function<Status(void)> fn) override {
19 return std::async(std::launch::deferred, fn);
20 }
21};
22static Register serial("serial",
23 "Run tasks serially on the main thread of a single process.",
24 SerialEngine::Factory);
25
26struct ThreadEngine : Engine {
27 static std::unique_ptr<Engine> Factory(Options) {
28 ThreadEngine engine;
29 return move_unique(engine);
30 }
31
32 bool crashproof() override { return false; }
33
34 std::future<Status> spawn(std::function<Status(void)> fn) override {
35 return std::async(std::launch::async, fn);
36 }
37};
38static Register thread("thread",
39 "Run each task on its own thread of a single process.",
40 ThreadEngine::Factory);
41
42#if !defined(_MSC_VER)
43 #include <sys/wait.h>
44 #include <unistd.h>
45
46 struct ForkEngine : Engine {
47 static std::unique_ptr<Engine> Factory(Options) {
48 ForkEngine engine;
49 return move_unique(engine);
50 }
51
52 bool crashproof() override { return true; }
53
54 std::future<Status> spawn(std::function<Status(void)> fn) override {
55 switch (fork()) {
56 case 0:
57 // We are the spawned child process.
58 // Run fn() and exit() with its Status as our return code.
59 _exit((int)fn());
60
61 case -1:
62 // The OS won't let us fork() another process right now.
63 // We'll need to wait for at least one live task to finish and try again.
64 return std::future<Status>();
65
66 default:
67 // We succesfully spawned a child process!
68 // This will wait for any spawned process to finish and return its Status.
69 return std::async(std::launch::deferred, [] {
70 do {
71 int status;
72 if (wait(&status) > 0) {
73 return WIFEXITED(status) ? (Status)WEXITSTATUS(status)
74 : Status::Crashed;
75 }
76 } while (errno == EINTR);
77 return Status::None;
78 });
79 }
80 }
81 };
82 static Register _fork("fork",
83 "Run each task in an independent process with fork().",
84 ForkEngine::Factory);
85#endif