[ORC] Use native Errors rather than converted std::error_codes for ORC RPC.

llvm-svn: 300155
This commit is contained in:
Lang Hames 2017-04-13 01:03:06 +00:00
parent b3f5742551
commit 22bc7b9648
6 changed files with 136 additions and 51 deletions

View File

@ -27,26 +27,15 @@ enum class OrcErrorCode : int {
RemoteMProtectAddrUnrecognized,
RemoteIndirectStubsOwnerDoesNotExist,
RemoteIndirectStubsOwnerIdAlreadyInUse,
RPCConnectionClosed,
RPCCouldNotNegotiateFunction,
RPCResponseAbandoned,
UnexpectedRPCCall,
UnexpectedRPCResponse,
UnknownRPCFunction
};
std::error_code orcError(OrcErrorCode ErrCode);
class RPCFunctionNotSupported : public ErrorInfo<RPCFunctionNotSupported> {
public:
static char ID;
RPCFunctionNotSupported(std::string RPCFunctionSignature);
std::error_code convertToErrorCode() const override;
void log(raw_ostream &OS) const override;
const std::string &getFunctionSignature() const;
private:
std::string RPCFunctionSignature;
};
} // End namespace orc.
} // End namespace llvm.

View File

@ -32,6 +32,109 @@ namespace llvm {
namespace orc {
namespace rpc {
/// Base class of all fatal RPC errors (those that necessarily result in the
/// termination of the RPC session).
class RPCFatalError : public ErrorInfo<RPCFatalError> {
public:
static char ID;
};
/// RPCConnectionClosed is returned from RPC operations if the RPC connection
/// has already been closed due to either an error or graceful disconnection.
class ConnectionClosed : public ErrorInfo<ConnectionClosed> {
public:
static char ID;
std::error_code convertToErrorCode() const override;
void log(raw_ostream &OS) const override;
};
/// BadFunctionCall is returned from handleOne when the remote makes a call with
/// an unrecognized function id.
///
/// This error is fatal because Orc RPC needs to know how to parse a function
/// call to know where the next call starts, and if it doesn't recognize the
/// function id it cannot parse the call.
template <typename FnIdT, typename SeqNoT>
class BadFunctionCall
: public ErrorInfo<BadFunctionCall<FnIdT, SeqNoT>, RPCFatalError> {
public:
static char ID;
BadFunctionCall(FnIdT FnId, SeqNoT SeqNo)
: FnId(std::move(FnId)), SeqNo(std::move(SeqNo)) {}
std::error_code convertToErrorCode() const override {
return orcError(OrcErrorCode::UnexpectedRPCCall);
}
void log(raw_ostream &OS) const override {
OS << "Call to invalid RPC function id '" << FnId << "' with "
"sequence number " << SeqNo;
}
private:
FnIdT FnId;
SeqNoT SeqNo;
};
template <typename FnIdT, typename SeqNoT>
char BadFunctionCall<FnIdT, SeqNoT>::ID = 0;
/// InvalidSequenceNumberForResponse is returned from handleOne when a response
/// call arrives with a sequence number that doesn't correspond to any in-flight
/// function call.
///
/// This error is fatal because Orc RPC needs to know how to parse the rest of
/// the response call to know where the next call starts, and if it doesn't have
/// a result parser for this sequence number it can't do that.
template <typename SeqNoT>
class InvalidSequenceNumberForResponse
: public ErrorInfo<InvalidSequenceNumberForResponse<SeqNoT>, RPCFatalError> {
public:
static char ID;
InvalidSequenceNumberForResponse(SeqNoT SeqNo)
: SeqNo(std::move(SeqNo)) {}
std::error_code convertToErrorCode() const override {
return orcError(OrcErrorCode::UnexpectedRPCCall);
};
void log(raw_ostream &OS) const override {
OS << "Response has unknown sequence number " << SeqNo;
}
private:
SeqNoT SeqNo;
};
template <typename SeqNoT>
char InvalidSequenceNumberForResponse<SeqNoT>::ID = 0;
/// This non-fatal error will be passed to asynchronous result handlers in place
/// of a result if the connection goes down before a result returns, or if the
/// function to be called cannot be negotiated with the remote.
class ResponseAbandoned : public ErrorInfo<ResponseAbandoned> {
public:
static char ID;
std::error_code convertToErrorCode() const override;
void log(raw_ostream &OS) const override;
};
/// This error is returned if the remote does not have a handler installed for
/// the given RPC function.
class CouldNotNegotiate : public ErrorInfo<CouldNotNegotiate> {
public:
static char ID;
CouldNotNegotiate(std::string Signature);
std::error_code convertToErrorCode() const override;
void log(raw_ostream &OS) const override;
const std::string &getSignature() const { return Signature; }
private:
std::string Signature;
};
template <typename DerivedFunc, typename FnT> class Function;
// RPC Function class.
@ -500,7 +603,7 @@ public:
// Create an error instance representing an abandoned response.
static Error createAbandonedResponseError() {
return errorCodeToError(orcError(OrcErrorCode::RPCResponseAbandoned));
return make_error<ResponseAbandoned>();
}
};
@ -814,12 +917,9 @@ public:
if (auto FnIdOrErr = getRemoteFunctionId<Func>(LazyAutoNegotiation, false))
FnId = *FnIdOrErr;
else {
// This isn't a channel error so we don't want to abandon other pending
// responses, but we still need to run the user handler with an error to
// let them know the call failed.
if (auto Err = Handler(errorCodeToError(
orcError(OrcErrorCode::UnknownRPCFunction))))
report_fatal_error(std::move(Err));
// Negotiation failed. Notify the handler then return the negotiate-failed
// error.
cantFail(Handler(make_error<ResponseAbandoned>()));
return FnIdOrErr.takeError();
}
@ -885,7 +985,8 @@ public:
return I->second(C, SeqNo);
// else: No handler found. Report error to client?
return errorCodeToError(orcError(OrcErrorCode::UnexpectedRPCCall));
return make_error<BadFunctionCall<FunctionIdT, SequenceNumberT>>(FnId,
SeqNo);
}
/// Helper for handling setter procedures - this method returns a functor that
@ -995,7 +1096,8 @@ protected:
// Unlock the pending results map to prevent recursive lock.
Lock.unlock();
abandonPendingResponses();
return errorCodeToError(orcError(OrcErrorCode::UnexpectedRPCResponse));
return make_error<
InvalidSequenceNumberForResponse<SequenceNumberT>>(SeqNo);
}
}
@ -1041,7 +1143,7 @@ protected:
Impl.template callB<OrcRPCNegotiate>(Func::getPrototype())) {
RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
if (*RemoteIdOrErr == getInvalidFunctionId())
return make_error<RPCFunctionNotSupported>(Func::getPrototype());
return make_error<CouldNotNegotiate>(Func::getPrototype());
return *RemoteIdOrErr;
} else
return RemoteIdOrErr.takeError();
@ -1049,7 +1151,7 @@ protected:
// No key was available in the map and we weren't allowed to try to
// negotiate one, so return an unknown function error.
return make_error<RPCFunctionNotSupported>(Func::getPrototype());
return make_error<CouldNotNegotiate>(Func::getPrototype());
}
using WrappedHandlerFn = std::function<Error(ChannelT &, SequenceNumberT)>;

View File

@ -64,6 +64,12 @@ public:
/// using std::error_code. It will be removed in the future.
virtual std::error_code convertToErrorCode() const = 0;
// Returns the class ID for this type.
static const void *classID() { return &ID; }
// Returns the class ID for the dynamic type of this ErrorInfoBase instance.
virtual const void *dynamicClassID() const = 0;
// Check whether this instance is a subclass of the class identified by
// ClassID.
virtual bool isA(const void *const ClassID) const {
@ -75,9 +81,6 @@ public:
return isA(ErrorInfoT::classID());
}
// Returns the class ID for this type.
static const void *classID() { return &ID; }
private:
virtual void anchor();
@ -316,11 +319,14 @@ template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) {
template <typename ThisErrT, typename ParentErrT = ErrorInfoBase>
class ErrorInfo : public ParentErrT {
public:
static const void *classID() { return &ThisErrT::ID; }
const void *dynamicClassID() const override { return &ThisErrT::ID; }
bool isA(const void *const ClassID) const override {
return ClassID == classID() || ParentErrT::isA(ClassID);
}
static const void *classID() { return &ThisErrT::ID; }
};
/// Special ErrorInfo subclass representing a list of ErrorInfos.
@ -926,6 +932,8 @@ public:
void log(raw_ostream &OS) const override;
std::error_code convertToErrorCode() const override;
const std::string &getMessage() const { return Msg; }
private:
std::string Msg;
std::error_code EC;

View File

@ -6,6 +6,7 @@ add_llvm_library(LLVMOrcJIT
OrcCBindings.cpp
OrcError.cpp
OrcMCJITReplacement.cpp
RPCUtils.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc

View File

@ -39,14 +39,16 @@ public:
return "Remote indirect stubs owner does not exist";
case OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse:
return "Remote indirect stubs owner Id already in use";
case OrcErrorCode::RPCConnectionClosed:
return "RPC connection closed";
case OrcErrorCode::RPCCouldNotNegotiateFunction:
return "Could not negotiate RPC function";
case OrcErrorCode::RPCResponseAbandoned:
return "RPC response abandoned";
case OrcErrorCode::UnexpectedRPCCall:
return "Unexpected RPC call";
case OrcErrorCode::UnexpectedRPCResponse:
return "Unexpected RPC response";
case OrcErrorCode::UnknownRPCFunction:
return "Unknown RPC function";
}
llvm_unreachable("Unhandled error code");
}
@ -58,27 +60,10 @@ static ManagedStatic<OrcErrorCategory> OrcErrCat;
namespace llvm {
namespace orc {
char RPCFunctionNotSupported::ID = 0;
std::error_code orcError(OrcErrorCode ErrCode) {
typedef std::underlying_type<OrcErrorCode>::type UT;
return std::error_code(static_cast<UT>(ErrCode), *OrcErrCat);
}
RPCFunctionNotSupported::RPCFunctionNotSupported(std::string RPCFunctionSignature)
: RPCFunctionSignature(std::move(RPCFunctionSignature)) {}
std::error_code RPCFunctionNotSupported::convertToErrorCode() const {
return orcError(OrcErrorCode::UnknownRPCFunction);
}
void RPCFunctionNotSupported::log(raw_ostream &OS) const {
OS << "Could not negotiate RPC function '" << RPCFunctionSignature << "'";
}
const std::string &RPCFunctionNotSupported::getFunctionSignature() const {
return RPCFunctionSignature;
}
}
}

View File

@ -604,10 +604,10 @@ TEST(DummyRPC, TestAPICalls) {
{
auto Err = DummyCallsAll::negotiate(Client);
EXPECT_EQ(errorToErrorCode(std::move(Err)).value(),
static_cast<int>(OrcErrorCode::UnknownRPCFunction))
<< "Expected 'UnknownRPCFunction' error for attempted negotiate of "
EXPECT_TRUE(Err.isA<CouldNotNegotiate>())
<< "Expected CouldNotNegotiate error for attempted negotiate of "
"unsupported function";
consumeError(std::move(Err));
}
ServerThread.join();