Skip to content

Commit b7e2443

Browse files
committed
chore: ThreadPool returns errors
1 parent a09e7af commit b7e2443

File tree

7 files changed

+91
-25
lines changed

7 files changed

+91
-25
lines changed

include/mrdox/Support/Error.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace mrdox {
2626
/** Holds the description of an error, or success.
2727
*/
2828
class [[nodiscard]] MRDOX_DECL
29-
Error : public std::exception
29+
Error final : public std::exception
3030
{
3131
std::string text_;
3232

include/mrdox/Support/Report.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,19 @@ reportError(
8181
}
8282

8383
template<class Range>
84-
void
84+
Error
8585
reportErrors(Range const& errors)
8686
{
87+
MRDOX_ASSERT(std::begin(errors) != std::end(errors));
88+
std::size_t n = 0;
8789
for(auto const& err : errors)
90+
{
91+
++n;
8892
reportError(err.message());
93+
}
94+
if(n > 1)
95+
return Error("{} errors occurred", n);
96+
return Error("an error occurred");
8997
}
9098

9199
/** Report a warning to the console.

include/mrdox/Support/ThreadPool.hpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
#define MRDOX_SUPPORT_THREAD_HPP
1414

1515
#include <mrdox/Platform.hpp>
16-
#include <mrdox/Support/Error.hpp>
1716
#include <mrdox/Support/any_callable.hpp>
17+
#include <mrdox/Support/Error.hpp>
1818
#include <memory>
1919
#include <type_traits>
2020
#include <utility>
21+
#include <vector>
2122

2223
namespace llvm {
2324
class ThreadPool;
@@ -41,10 +42,10 @@ class MRDOX_VISIBLE
4142
friend class TaskGroup;
4243

4344
public:
44-
template<class Agent> struct arg_ty { using type = Agent; };
45-
template<class Agent> struct arg_ty<Agent&> { using type =
46-
std::conditional_t< std::is_const_v<Agent>, Agent, Agent&>; };
47-
template<class Agent> using arg_t = typename arg_ty<Agent>::type;
45+
template<class T> struct arg_ty { using type = T; };
46+
template<class T> struct arg_ty<T&> { using type =
47+
std::conditional_t< std::is_const_v<T>, T, T&>; };
48+
template<class T> using arg_t = typename arg_ty<T>::type;
4849

4950
/** Destructor.
5051
*/
@@ -93,9 +94,14 @@ class MRDOX_VISIBLE
9394
}
9495

9596
/** Invoke a function object for each element of a range.
97+
98+
@return Zero or more errors which were
99+
thrown from submitted work.
96100
*/
97101
template<class Range, class F>
98-
void forEach(Range&& range, F const& f);
102+
[[nodiscard]]
103+
std::vector<Error>
104+
forEach(Range&& range, F const& f);
99105

100106
/** Block until all work has completed.
101107
*/
@@ -114,7 +120,9 @@ class MRDOX_VISIBLE
114120
class MRDOX_VISIBLE
115121
TaskGroup
116122
{
117-
std::unique_ptr<llvm::ThreadPoolTaskGroup> impl_;
123+
struct Impl;
124+
125+
std::unique_ptr<Impl> impl_;
118126

119127
public:
120128
/** Destructor.
@@ -142,9 +150,13 @@ class MRDOX_VISIBLE
142150
}
143151

144152
/** Block until all work has completed.
153+
154+
@return Zero or more errors which were
155+
thrown from submitted work.
145156
*/
146157
MRDOX_DECL
147-
void
158+
[[nodiscard]]
159+
std::vector<Error>
148160
wait();
149161

150162
private:
@@ -154,7 +166,7 @@ class MRDOX_VISIBLE
154166
//------------------------------------------------
155167

156168
template<class Range, class F>
157-
void
169+
std::vector<Error>
158170
ThreadPool::
159171
forEach(
160172
Range&& range,
@@ -167,7 +179,7 @@ forEach(
167179
{
168180
f(value);
169181
});
170-
taskGroup.wait();
182+
return taskGroup.wait();
171183
}
172184

173185
} // mrdox

source/-adoc/AdocGenerator.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,7 @@ buildOne(
8383
visitor(corpus.globalNamespace());
8484
auto errors = ex->wait();
8585
if(! errors.empty())
86-
{
87-
reportErrors(errors);
88-
return Error("one or more errors occurred");
89-
}
86+
return reportErrors(errors);
9087
return Error::success();
9188
}
9289

source/-bitcode/BitcodeGenerator.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ class MultiFileBuilder : public Corpus::Visitor
4343
build()
4444
{
4545
corpus_.traverse(*this, SymbolID::zero);
46-
taskGroup_.wait();
47-
return Error();
46+
auto errors = taskGroup_.wait();
47+
if(! errors.empty())
48+
return reportErrors(errors);
49+
return Error::success();
4850
}
4951

5052
template<class T>

source/Support/Thread.cpp renamed to source/Support/ThreadPool.cpp

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include "Support/Debug.hpp"
1212
#include <mrdox/Support/ThreadPool.hpp>
1313
#include <llvm/Support/ThreadPool.h>
14+
#include <mutex>
15+
#include <unordered_set>
1416
#include <utility>
1517

1618
namespace clang {
@@ -82,6 +84,22 @@ post(
8284
//
8385
//------------------------------------------------
8486

87+
struct TaskGroup::
88+
Impl
89+
{
90+
std::mutex mutex;
91+
std::unordered_set<Error> errors;
92+
llvm::ThreadPoolTaskGroup taskGroup;
93+
94+
explicit
95+
Impl(
96+
llvm::ThreadPool& threadPool)
97+
: taskGroup(threadPool)
98+
{
99+
}
100+
};
101+
102+
85103
TaskGroup::
86104
~TaskGroup()
87105
{
@@ -90,15 +108,30 @@ TaskGroup::
90108
TaskGroup::
91109
TaskGroup(
92110
ThreadPool& threadPool)
93-
: impl_(std::make_unique<llvm::ThreadPoolTaskGroup>(*threadPool.impl_))
111+
: impl_(std::make_unique<Impl>(*threadPool.impl_))
94112
{
95113
}
96114

97-
void
115+
std::vector<Error>
98116
TaskGroup::
99117
wait()
100118
{
101-
impl_->wait();
119+
impl_->taskGroup.wait();
120+
121+
// VFALCO We could have a small data race here
122+
// where another thread posts work after the
123+
// wait is satisfied, but that could be
124+
// considered user error.
125+
//
126+
// In theory the lock should not be needed.
127+
//
128+
std::lock_guard<std::mutex> lock(impl_->mutex);
129+
std::vector<Error> errors;
130+
errors.reserve(impl_->errors.size());
131+
for(auto& err : impl_->errors)
132+
errors.emplace_back(std::move(err));
133+
impl_->errors.clear();
134+
return errors;
102135
}
103136

104137
void
@@ -108,10 +141,22 @@ post(
108141
{
109142
auto sp = std::make_shared<
110143
any_callable<void(void)>>(std::move(f));
111-
impl_->async(
112-
[sp]
144+
impl_->taskGroup.async(
145+
[&, sp]
113146
{
114-
(*sp)();
147+
try
148+
{
149+
(*sp)();
150+
}
151+
catch(Error const& err)
152+
{
153+
std::lock_guard<std::mutex> lock(impl_->mutex);
154+
impl_->errors.emplace(std::move(err));
155+
}
156+
// Any exception which is not
157+
// derived from Error should
158+
// be reported and terminate
159+
// the process immediately.
115160
});
116161
}
117162

source/Tool/CorpusImpl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ build(
144144
reportInfo("Reducing {} declarations", bitcodes.size());
145145
std::atomic<bool> GotFailure;
146146
GotFailure = false;
147-
corpus->config.threadPool().forEach(
147+
auto errors = corpus->config.threadPool().forEach(
148148
bitcodes,
149149
[&](auto& Group)
150150
{
@@ -179,6 +179,8 @@ build(
179179
MRDOX_ASSERT(Group.getKey() == StringRef(I->id));
180180
corpus->insert(std::move(I));
181181
});
182+
if(! errors.empty())
183+
return reportErrors(errors);
182184

183185
if(corpus->config.verboseOutput)
184186
llvm::outs() << "Collected " << corpus->InfoMap.size() << " symbols.\n";

0 commit comments

Comments
 (0)