Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit db6b577

Browse files
committed
Revert "[ORC][RPC] Make the future type of an Orc RPC call Error/Expected rather than"
This reverts commit r280016, and the followups of r280017, r280027, r280051, r280058, and r280059. MSVC's implementation of std::promise does not get along with llvm::Error. It uses its promised value too much like a normal value type. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@280100 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 72187d4 commit db6b577

File tree

3 files changed

+76
-117
lines changed

3 files changed

+76
-117
lines changed

include/llvm/ExecutionEngine/Orc/RPCUtils.h

Lines changed: 69 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <map>
1818
#include <vector>
1919

20+
#include "llvm/ADT/Optional.h"
2021
#include "llvm/ADT/STLExtras.h"
2122
#include "llvm/ExecutionEngine/Orc/OrcError.h"
2223

@@ -60,7 +61,6 @@ template <typename T> class RPCFunctionIdTraits {
6061
// partially specialized.
6162
class RPCBase {
6263
protected:
63-
6464
// RPC Function description type.
6565
//
6666
// This class provides the information and operations needed to support the
@@ -69,9 +69,12 @@ class RPCBase {
6969
// betwen the two. Both specializations have the same interface:
7070
//
7171
// Id - The function's unique identifier.
72-
// ErrorReturn - The return type for blocking calls.
72+
// OptionalReturn - The return type for asyncronous calls.
73+
// ErrorReturn - The return type for synchronous calls.
74+
// optionalToErrorReturn - Conversion from a valid OptionalReturn to an
75+
// ErrorReturn.
7376
// readResult - Deserialize a result from a channel.
74-
// abandon - Abandon a promised result.
77+
// abandon - Abandon a promised (asynchronous) result.
7578
// respond - Retun a result on the channel.
7679
template <typename FunctionIdT, FunctionIdT FuncId, typename FnT>
7780
class FunctionHelper {};
@@ -88,29 +91,32 @@ class RPCBase {
8891

8992
static const FunctionIdT Id = FuncId;
9093

94+
typedef Optional<RetT> OptionalReturn;
95+
9196
typedef Expected<RetT> ErrorReturn;
9297

98+
static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) {
99+
assert(V && "Return value not available");
100+
return std::move(*V);
101+
}
102+
93103
template <typename ChannelT>
94-
static Error readResult(ChannelT &C, std::promise<ErrorReturn> &P) {
104+
static Error readResult(ChannelT &C, std::promise<OptionalReturn> &P) {
95105
RetT Val;
96106
auto Err = deserialize(C, Val);
97107
auto Err2 = endReceiveMessage(C);
98108
Err = joinErrors(std::move(Err), std::move(Err2));
99-
if (Err)
100-
return Err;
101109

110+
if (Err) {
111+
P.set_value(OptionalReturn());
112+
return Err;
113+
}
102114
P.set_value(std::move(Val));
103115
return Error::success();
104116
}
105117

106-
static void abandon(std::promise<ErrorReturn> &P) {
107-
P.set_value(
108-
make_error<StringError>("RPC function call failed to return",
109-
inconvertibleErrorCode()));
110-
}
111-
112-
static void consumeAbandoned(std::future<ErrorReturn> &P) {
113-
consumeError(P.get().takeError());
118+
static void abandon(std::promise<OptionalReturn> &P) {
119+
P.set_value(OptionalReturn());
114120
}
115121

116122
template <typename ChannelT, typename SequenceNumberT>
@@ -142,24 +148,22 @@ class RPCBase {
142148

143149
static const FunctionIdT Id = FuncId;
144150

151+
typedef bool OptionalReturn;
145152
typedef Error ErrorReturn;
146153

154+
static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) {
155+
assert(V && "Return value not available");
156+
return Error::success();
157+
}
158+
147159
template <typename ChannelT>
148-
static Error readResult(ChannelT &C, std::promise<ErrorReturn> &P) {
160+
static Error readResult(ChannelT &C, std::promise<OptionalReturn> &P) {
149161
// Void functions don't have anything to deserialize, so we're good.
150-
P.set_value(Error::success());
162+
P.set_value(true);
151163
return endReceiveMessage(C);
152164
}
153165

154-
static void abandon(std::promise<ErrorReturn> &P) {
155-
P.set_value(
156-
make_error<StringError>("RPC function call failed to return",
157-
inconvertibleErrorCode()));
158-
}
159-
160-
static void consumeAbandoned(std::future<ErrorReturn> &P) {
161-
consumeError(P.get());
162-
}
166+
static void abandon(std::promise<OptionalReturn> &P) { P.set_value(false); }
163167

164168
template <typename ChannelT, typename SequenceNumberT>
165169
static Error respond(ChannelT &C, SequenceNumberT SeqNo,
@@ -374,118 +378,94 @@ class RPC : public RPCBase {
374378
template <FunctionIdT FuncId, typename FnT>
375379
using Function = FunctionHelper<FunctionIdT, FuncId, FnT>;
376380

377-
/// Return type for non-blocking call primitives.
381+
/// Return type for asynchronous call primitives.
378382
template <typename Func>
379-
using NonBlockingCallResult = std::future<typename Func::ErrorReturn>;
383+
using AsyncCallResult = std::future<typename Func::OptionalReturn>;
380384

381-
/// Return type for non-blocking call-with-seq primitives.
385+
/// Return type for asynchronous call-with-seq primitives.
382386
template <typename Func>
383-
using NonBlockingCallWithSeqResult =
384-
std::pair<NonBlockingCallResult<Func>, SequenceNumberT>;
387+
using AsyncCallWithSeqResult =
388+
std::pair<std::future<typename Func::OptionalReturn>, SequenceNumberT>;
385389

386-
/// Call Func on Channel C. Does not block, does not call send. Returns a pair
387-
/// of a future result and the sequence number assigned to the result.
390+
/// Serialize Args... to channel C, but do not call C.send().
391+
///
392+
/// Returns an error (on serialization failure) or a pair of:
393+
/// (1) A future Optional<T> (or future<bool> for void functions), and
394+
/// (2) A sequence number.
388395
///
389396
/// This utility function is primarily used for single-threaded mode support,
390397
/// where the sequence number can be used to wait for the corresponding
391-
/// result. In multi-threaded mode the appendCallNB method, which does not
398+
/// result. In multi-threaded mode the appendCallAsync method, which does not
392399
/// return the sequence numeber, should be preferred.
393400
template <typename Func, typename... ArgTs>
394-
Expected<NonBlockingCallWithSeqResult<Func>>
395-
appendCallNBWithSeq(ChannelT &C, const ArgTs &... Args) {
401+
Expected<AsyncCallWithSeqResult<Func>>
402+
appendCallAsyncWithSeq(ChannelT &C, const ArgTs &... Args) {
396403
auto SeqNo = SequenceNumberMgr.getSequenceNumber();
397-
std::promise<typename Func::ErrorReturn> Promise;
404+
std::promise<typename Func::OptionalReturn> Promise;
398405
auto Result = Promise.get_future();
399406
OutstandingResults[SeqNo] =
400407
createOutstandingResult<Func>(std::move(Promise));
401408

402409
if (auto Err = CallHelper<ChannelT, SequenceNumberT, Func>::call(C, SeqNo,
403410
Args...)) {
404411
abandonOutstandingResults();
405-
Func::consumeAbandoned(Result);
406412
return std::move(Err);
407413
} else
408-
return NonBlockingCallWithSeqResult<Func>(std::move(Result), SeqNo);
414+
return AsyncCallWithSeqResult<Func>(std::move(Result), SeqNo);
409415
}
410416

411-
/// The same as appendCallNBWithSeq, except that it calls C.send() to
417+
/// The same as appendCallAsyncWithSeq, except that it calls C.send() to
412418
/// flush the channel after serializing the call.
413419
template <typename Func, typename... ArgTs>
414-
Expected<NonBlockingCallWithSeqResult<Func>>
415-
callNBWithSeq(ChannelT &C, const ArgTs &... Args) {
416-
auto Result = appendCallNBWithSeq<Func>(C, Args...);
420+
Expected<AsyncCallWithSeqResult<Func>>
421+
callAsyncWithSeq(ChannelT &C, const ArgTs &... Args) {
422+
auto Result = appendCallAsyncWithSeq<Func>(C, Args...);
417423
if (!Result)
418424
return Result;
419425
if (auto Err = C.send()) {
420426
abandonOutstandingResults();
421-
Func::consumeAbandoned(Result->first);
422427
return std::move(Err);
423428
}
424429
return Result;
425430
}
426431

427432
/// Serialize Args... to channel C, but do not call send.
428433
/// Returns an error if serialization fails, otherwise returns a
429-
/// std::future<Expected<T>> (or a future<Error> for void functions).
434+
/// std::future<Optional<T>> (or a future<bool> for void functions).
430435
template <typename Func, typename... ArgTs>
431-
Expected<NonBlockingCallResult<Func>> appendCallNB(ChannelT &C,
432-
const ArgTs &... Args) {
433-
auto FutureResAndSeqOrErr = appendCallNBWithSeq<Func>(C, Args...);
434-
if (FutureResAndSeqOrErr)
435-
return std::move(FutureResAndSeqOrErr->first);
436-
return FutureResAndSeqOrErr.getError();
436+
Expected<AsyncCallResult<Func>> appendCallAsync(ChannelT &C,
437+
const ArgTs &... Args) {
438+
auto ResAndSeqOrErr = appendCallAsyncWithSeq<Func>(C, Args...);
439+
if (ResAndSeqOrErr)
440+
return std::move(ResAndSeqOrErr->first);
441+
return ResAndSeqOrErr.getError();
437442
}
438443

439-
/// The same as appendCallNB, except that it calls C.send to flush the
444+
/// The same as appendCallAsync, except that it calls C.send to flush the
440445
/// channel after serializing the call.
441446
template <typename Func, typename... ArgTs>
442-
Expected<NonBlockingCallResult<Func>> callNB(ChannelT &C,
443-
const ArgTs &... Args) {
444-
auto FutureResAndSeqOrErr = callNBWithSeq<Func>(C, Args...);
445-
if (FutureResAndSeqOrErr)
446-
return std::move(FutureResAndSeqOrErr->first);
447-
return FutureResAndSeqOrErr.getError();
448-
}
449-
450-
/// Call Func on Channel C. Blocks waiting for a result. Returns an Error
451-
/// for void functions or an Expected<T> for functions returning a T.
452-
///
453-
/// This function is for use in threaded code where another thread is
454-
/// handling responses and incoming calls.
455-
template <typename Func, typename... ArgTs>
456-
typename Func::ErrorReturn callB(ChannelT &C, const ArgTs &... Args) {
457-
if (auto FutureResOrErr = callNBWithSeq(C, Args...)) {
458-
if (auto Err = C.send()) {
459-
abandonOutstandingResults();
460-
Func::consumeAbandoned(*FutureResOrErr);
461-
return std::move(Err);
462-
}
463-
return FutureResOrErr->get();
464-
} else
465-
return FutureResOrErr.takeError();
447+
Expected<AsyncCallResult<Func>> callAsync(ChannelT &C,
448+
const ArgTs &... Args) {
449+
auto ResAndSeqOrErr = callAsyncWithSeq<Func>(C, Args...);
450+
if (ResAndSeqOrErr)
451+
return std::move(ResAndSeqOrErr->first);
452+
return ResAndSeqOrErr.getError();
466453
}
467454

468-
/// Call Func on Channel C. Block waiting for a result. While blocked, run
469-
/// HandleOther to handle incoming calls (Response calls will be handled
470-
/// implicitly before calling HandleOther). Returns an Error for void
471-
/// functions or an Expected<T> for functions returning a T.
472-
///
473-
/// This function is for use in single threaded mode when the calling thread
474-
/// must act as both sender and receiver.
455+
/// This can be used in single-threaded mode.
475456
template <typename Func, typename HandleFtor, typename... ArgTs>
476457
typename Func::ErrorReturn
477458
callSTHandling(ChannelT &C, HandleFtor &HandleOther, const ArgTs &... Args) {
478-
if (auto ResultAndSeqNoOrErr = callNBWithSeq<Func>(C, Args...)) {
459+
if (auto ResultAndSeqNoOrErr = callAsyncWithSeq<Func>(C, Args...)) {
479460
auto &ResultAndSeqNo = *ResultAndSeqNoOrErr;
480461
if (auto Err = waitForResult(C, ResultAndSeqNo.second, HandleOther))
481462
return std::move(Err);
482-
return ResultAndSeqNo.first.get();
463+
return Func::optionalToErrorReturn(ResultAndSeqNo.first.get());
483464
} else
484465
return ResultAndSeqNoOrErr.takeError();
485466
}
486467

487-
/// Call Func on Channel C. Block waiting for a result. Returns an Error for
488-
/// void functions or an Expected<T> for functions returning a T.
468+
// This can be used in single-threaded mode.
489469
template <typename Func, typename... ArgTs>
490470
typename Func::ErrorReturn callST(ChannelT &C, const ArgTs &... Args) {
491471
return callSTHandling<Func>(C, handleNone, Args...);
@@ -676,21 +656,21 @@ class RPC : public RPCBase {
676656
class OutstandingResultImpl : public OutstandingResult {
677657
private:
678658
public:
679-
OutstandingResultImpl(std::promise<typename Func::ErrorReturn> &&P)
659+
OutstandingResultImpl(std::promise<typename Func::OptionalReturn> &&P)
680660
: P(std::move(P)) {}
681661

682662
Error readResult(ChannelT &C) override { return Func::readResult(C, P); }
683663

684664
void abandon() override { Func::abandon(P); }
685665

686666
private:
687-
std::promise<typename Func::ErrorReturn> P;
667+
std::promise<typename Func::OptionalReturn> P;
688668
};
689669

690670
// Create an outstanding result for the given function.
691671
template <typename Func>
692672
std::unique_ptr<OutstandingResult>
693-
createOutstandingResult(std::promise<typename Func::ErrorReturn> &&P) {
673+
createOutstandingResult(std::promise<typename Func::OptionalReturn> &&P) {
694674
return llvm::make_unique<OutstandingResultImpl<Func>>(std::move(P));
695675
}
696676

include/llvm/Support/Error.h

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -629,27 +629,6 @@ template <class T> class Expected {
629629
typedef const typename std::remove_reference<T>::type *const_pointer;
630630

631631
public:
632-
633-
#ifdef _MSC_VER
634-
// WARNING: This constructor should *never* be called in user code.
635-
// It is provided under MSVC only so that Expected can be used
636-
// with MSVC's <future> header, which requires types to be default
637-
// constructible.
638-
//
639-
// FIXME; Kill this as soon as MSVC's <future> implementation no longer
640-
// requires types to be default constructible.
641-
Expected()
642-
: HasError(true)
643-
#ifndef NDEBUG
644-
,
645-
Checked(true)
646-
#endif // NDEBUG
647-
{
648-
new (getErrorStorage()) Error();
649-
(void)!!*getErrorStorage();
650-
}
651-
#endif // _MSC_VER
652-
653632
/// Create an Expected<T> error value from the given Error.
654633
Expected(Error Err)
655634
: HasError(true)

unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ TEST_F(DummyRPC, TestAsyncVoidBool) {
8383
QueueChannel C2(Q2, Q1);
8484

8585
// Make an async call.
86-
auto ResOrErr = callNBWithSeq<VoidBool>(C1, true);
86+
auto ResOrErr = callAsyncWithSeq<VoidBool>(C1, true);
8787
EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
8888

8989
{
@@ -102,8 +102,8 @@ TEST_F(DummyRPC, TestAsyncVoidBool) {
102102
}
103103

104104
// Verify that the function returned ok.
105-
auto Err = ResOrErr->first.get();
106-
EXPECT_FALSE(!!Err) << "Remote void function failed to execute.";
105+
auto Val = ResOrErr->first.get();
106+
EXPECT_TRUE(Val) << "Remote void function failed to execute.";
107107
}
108108

109109
TEST_F(DummyRPC, TestAsyncIntInt) {
@@ -112,7 +112,7 @@ TEST_F(DummyRPC, TestAsyncIntInt) {
112112
QueueChannel C2(Q2, Q1);
113113

114114
// Make an async call.
115-
auto ResOrErr = callNBWithSeq<IntInt>(C1, 21);
115+
auto ResOrErr = callAsyncWithSeq<IntInt>(C1, 21);
116116
EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
117117

118118
{
@@ -143,7 +143,7 @@ TEST_F(DummyRPC, TestSerialization) {
143143

144144
// Make a call to Proc1.
145145
std::vector<int> v({42, 7});
146-
auto ResOrErr = callNBWithSeq<AllTheTypes>(
146+
auto ResOrErr = callAsyncWithSeq<AllTheTypes>(
147147
C1, -101, 250, -10000, 10000, -1000000000, 1000000000, -10000000000,
148148
10000000000, true, "foo", v);
149149
EXPECT_TRUE(!!ResOrErr) << "Big (serialization test) call over queue failed";
@@ -179,8 +179,8 @@ TEST_F(DummyRPC, TestSerialization) {
179179
}
180180

181181
// Verify that the function returned ok.
182-
auto Err = ResOrErr->first.get();
183-
EXPECT_FALSE(!!Err) << "Remote void function failed to execute.";
182+
auto Val = ResOrErr->first.get();
183+
EXPECT_TRUE(Val) << "Remote void function failed to execute.";
184184
}
185185

186186
// Test the synchronous call API.

0 commit comments

Comments
 (0)