summaryrefslogtreecommitdiffhomepage
path: root/ProcessRunner.cpp
blob: bdde0542105c1469958525ac2aa906db95ab3101 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include "ProcessRunner.h"

#include <stdexcept>
#include <thread>

#include <boost/process.hpp>

#include <sys/wait.h>

namespace bp = boost::process;

ProcessRunner::ProcessRunner():
 _max_number_of_processes{static_cast<int>(std::thread::hardware_concurrency())}
{}

void ProcessRunner::spawn(const std::string& key, const std::string& command)
{
 _processes.emplace_back(process{key, command});
}

bool ProcessRunner::empty()
{
 return running() == 0;
}

bool ProcessRunner::full()
{
 return running() == _max_number_of_processes;
}

int ProcessRunner::wait_one(std::string& key)
{
 if (running() > 0 && finished() == 0) {
  waitpid(-1, NULL, 0);
 }

 // Actually, several childs may have finished. Therefore, end and
 // remove all finished childs.
 if (finished() > 0) {
  for (auto it = _processes.begin(); it != _processes.end(); ++it) {
   bp::child &child{it->child};
   if (!child.running()) {
    child.wait();
    int result{child.exit_code()};

    key = it->key;

    _processes.erase(it, it+1);
    return result;
   }
  }
 };

 if (_processes.empty()) {
  throw std::runtime_error("No process to wait for");
 }

 throw std::runtime_error("No process finished");
}

int ProcessRunner::wait_all()
{
 int ret{};
 for (auto &i: _processes) {
  i.child.wait();
  int result{i.child.exit_code()};
  if (result != 0 && ret == 0) {
   ret = result;
  }
 }

 _processes.clear();

 return ret;
}

size_t ProcessRunner::running()
{
 size_t result{};
 for (auto &i: _processes) {
  if (i.child.running()) {
   ++result;
  }
 }
 return result;
}

size_t ProcessRunner::finished()
{
 return _processes.size() - running();
}