Commit 2dbf31da authored by Kenton Varda's avatar Kenton Varda

Re-arrange async headers a bit to improve organization.

parent 4158ca9f
......@@ -136,7 +136,9 @@ includekj_HEADERS = \
src/kj/mutex.h \
src/kj/thread.h \
src/kj/work-queue.h \
src/kj/async-prelude.h \
src/kj/async.h \
src/kj/async-impl.h \
src/kj/async-unix.h \
src/kj/async-io.h \
src/kj/main.h
......
......@@ -207,7 +207,7 @@ public:
daemonPromise.attach(kj::addRef(*context));
daemonPromise.exclusiveJoin(kj::mv(cancelPaf.promise));
// Daemonize, ignoring exceptions.
kj::daemonize(kj::mv(daemonPromise), [](kj::Exception&&) {});
daemonPromise.daemonize([](kj::Exception&&) {});
// Now the other branch returns the response from the context.
auto contextPtr = context.get();
......
......@@ -807,7 +807,7 @@ void doTest() {
uint nextOrdinal = 0;
for (uint i = 0; i < 128; i++) {
for (uint i = 0; i < 96; i++) {
uint oldOrdinalCount = nextOrdinal;
auto newBuilder = kj::heap<MallocMessageBuilder>();
......
......@@ -2360,7 +2360,7 @@ private:
auto promise = kj::mv(cancelPaf.promise);
promise.exclusiveJoin(forked.addBranch().then([](kj::Own<RpcResponse>&&){}));
daemonize(kj::mv(promise), [](kj::Exception&&) {});
promise.daemonize([](kj::Exception&&) {});
} else {
// Hack: Both the success and error continuations need to use the context. We could
// refcount, but both will be destroyed at the same time anyway.
......@@ -2377,7 +2377,7 @@ private:
});
promise.attach(kj::mv(context));
promise.exclusiveJoin(kj::mv(cancelPaf.promise));
daemonize(kj::mv(promise), [](kj::Exception&&) {});
promise.daemonize([](kj::Exception&&) {});
}
}
}
......
This diff is collapsed.
......@@ -41,14 +41,14 @@ TEST(AsyncIo, SimpleNetwork) {
auto port = newPromiseAndFulfiller<uint>();
daemonize(port.promise.then([&](uint portnum) {
port.promise.then([&](uint portnum) {
return network->parseRemoteAddress("127.0.0.1", portnum);
}).then([&](Own<RemoteAddress>&& result) {
return result->connect();
}).then([&](Own<AsyncIoStream>&& result) {
client = kj::mv(result);
return client->write("foo", 3);
}), [](kj::Exception&& exception) {
}).daemonize([](kj::Exception&& exception) {
ADD_FAILURE() << kj::str(exception).cStr();
});
......@@ -97,7 +97,7 @@ TEST(AsyncIo, OneWayPipe) {
auto pipe = newOneWayPipe();
char receiveBuffer[4];
daemonize(pipe.out->write("foo", 3), [](kj::Exception&& exception) {
pipe.out->write("foo", 3).daemonize([](kj::Exception&& exception) {
ADD_FAILURE() << kj::str(exception).cStr();
});
......
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file contains a bunch of internal declarations that must appear before async.h can start.
// We don't define these directly in async.h because it makes the file hard to read.
#ifndef KJ_ASYNC_PRELUDE_H_
#define KJ_ASYNC_PRELUDE_H_
#include "exception.h"
namespace kj {
class EventLoop;
template <typename T>
class Promise;
namespace _ { // private
template <typename T> struct JoinPromises_ { typedef T Type; };
template <typename T> struct JoinPromises_<Promise<T>> { typedef T Type; };
template <typename T>
using JoinPromises = typename JoinPromises_<T>::Type;
// If T is Promise<U>, resolves to U, otherwise resolves to T.
class PropagateException {
// A functor which accepts a kj::Exception as a parameter and returns a broken promise of
// arbitrary type which simply propagates the exception.
public:
class Bottom {
public:
Bottom(Exception&& exception): exception(kj::mv(exception)) {}
Exception asException() { return kj::mv(exception); }
private:
Exception exception;
};
Bottom operator()(Exception&& e) {
return Bottom(kj::mv(e));
}
Bottom operator()(const Exception& e) {
return Bottom(kj::cp(e));
}
};
template <typename Func, typename T>
struct ReturnType_ { typedef decltype(instance<Func>()(instance<T>())) Type; };
template <typename Func>
struct ReturnType_<Func, void> { typedef decltype(instance<Func>()()) Type; };
template <typename Func, typename T>
using ReturnType = typename ReturnType_<Func, T>::Type;
// The return type of functor Func given a parameter of type T, with the special exception that if
// T is void, this is the return type of Func called with no arguments.
struct Void {};
// Application code should NOT refer to this! See `kj::READY_NOW` instead.
template <typename T> struct FixVoid_ { typedef T Type; };
template <> struct FixVoid_<void> { typedef Void Type; };
template <typename T> using FixVoid = typename FixVoid_<T>::Type;
// FixVoid<T> is just T unless T is void in which case it is _::Void (an empty struct).
template <typename T> struct UnfixVoid_ { typedef T Type; };
template <> struct UnfixVoid_<Void> { typedef void Type; };
template <typename T> using UnfixVoid = typename UnfixVoid_<T>::Type;
// UnfixVoid is the opposite of FixVoid.
template <typename In, typename Out>
struct MaybeVoidCaller {
// Calls the function converting a Void input to an empty parameter list and a void return
// value to a Void output.
template <typename Func>
static inline Out apply(Func& func, In&& in) {
return func(kj::mv(in));
}
};
template <typename In, typename Out>
struct MaybeVoidCaller<In&, Out> {
template <typename Func>
static inline Out apply(Func& func, In& in) {
return func(in);
}
};
template <typename Out>
struct MaybeVoidCaller<Void, Out> {
template <typename Func>
static inline Out apply(Func& func, Void&& in) {
return func();
}
};
template <typename In>
struct MaybeVoidCaller<In, Void> {
template <typename Func>
static inline Void apply(Func& func, In&& in) {
func(kj::mv(in));
return Void();
}
};
template <typename In>
struct MaybeVoidCaller<In&, Void> {
template <typename Func>
static inline Void apply(Func& func, In& in) {
func(in);
return Void();
}
};
template <>
struct MaybeVoidCaller<Void, Void> {
template <typename Func>
static inline Void apply(Func& func, Void&& in) {
func();
return Void();
}
};
template <typename T>
inline T&& returnMaybeVoid(T&& t) {
return kj::fwd<T>(t);
}
inline void returnMaybeVoid(Void&& v) {}
class ExceptionOrValue;
class PromiseNode;
class ChainPromiseNode;
template <typename T>
class ForkHub;
class TaskSetImpl;
class Event;
class PromiseBase {
public:
kj::String trace();
// Dump debug info about this promise.
private:
Own<PromiseNode> node;
PromiseBase() = default;
PromiseBase(Own<PromiseNode>&& node): node(kj::mv(node)) {}
friend class kj::EventLoop;
friend class ChainPromiseNode;
template <typename>
friend class kj::Promise;
friend class TaskSetImpl;
};
} // namespace _ (private)
} // namespace kj
#endif // KJ_ASYNC_PRELUDE_H_
......@@ -194,7 +194,7 @@ TEST(Async, SeparateFulfillerCanceled) {
auto pair = newPromiseAndFulfiller<void>();
EXPECT_TRUE(pair.fulfiller->isWaiting());
pair.promise.absolve();
pair.promise = nullptr;
EXPECT_FALSE(pair.fulfiller->isWaiting());
}
......@@ -473,8 +473,8 @@ TEST(Async, Daemonize) {
bool ran3 = false;
evalLater([&]() { ran1 = true; });
daemonize(evalLater([&]() { ran2 = true; }), [](kj::Exception&&) { ADD_FAILURE(); });
daemonize(evalLater([]() { KJ_FAIL_ASSERT("foo"); }), [&](kj::Exception&& e) { ran3 = true; });
evalLater([&]() { ran2 = true; }).daemonize([](kj::Exception&&) { ADD_FAILURE(); });
evalLater([]() { KJ_FAIL_ASSERT("foo"); }).daemonize([&](kj::Exception&& e) { ran3 = true; });
EXPECT_FALSE(ran1);
EXPECT_FALSE(ran2);
......
......@@ -84,9 +84,9 @@ TEST_F(AsyncUnixTest, SignalWithValue) {
TEST_F(AsyncUnixTest, SignalsMultiListen) {
UnixEventLoop loop;
daemonize(loop.onSignal(SIGIO).then([](siginfo_t&&) {
loop.onSignal(SIGIO).then([](siginfo_t&&) {
ADD_FAILURE() << "Received wrong signal.";
}), [](kj::Exception&& exception) {
}).daemonize([](kj::Exception&& exception) {
ADD_FAILURE() << kj::str(exception).cStr();
});
......@@ -147,10 +147,10 @@ TEST_F(AsyncUnixTest, PollMultiListen) {
KJ_SYSCALL(pipe(bogusPipefds));
KJ_DEFER({ close(bogusPipefds[1]); close(bogusPipefds[0]); });
daemonize(loop.onFdEvent(bogusPipefds[0], POLLIN | POLLPRI).then([](short s) {
loop.onFdEvent(bogusPipefds[0], POLLIN | POLLPRI).then([](short s) {
KJ_DBG(s);
ADD_FAILURE() << "Received wrong poll.";
}), [](kj::Exception&& exception) {
}).daemonize([](kj::Exception&& exception) {
ADD_FAILURE() << kj::str(exception).cStr();
});
......
......@@ -67,6 +67,16 @@ public:
}
};
class NeverReadyPromiseNode final: public _::PromiseNode {
public:
bool onReady(_::Event& event) noexcept override {
return false;
}
void get(_::ExceptionOrValue& output) noexcept override {
KJ_FAIL_REQUIRE("Not ready.");
}
};
} // namespace
namespace _ { // private
......@@ -210,6 +220,12 @@ EventLoop::~EventLoop() noexcept(false) {
}
}
void EventLoop::runForever() {
_::ExceptionOr<_::Void> result;
waitImpl(kj::heap<NeverReadyPromiseNode>(), result);
KJ_UNREACHABLE;
}
void EventLoop::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result) {
KJ_REQUIRE(threadLocalEventLoop == this,
"Can only call wait() in the thread that created this EventLoop.");
......@@ -452,14 +468,6 @@ void SimpleEventLoop::wake() const {
// =======================================================================================
void PromiseBase::absolve() {
runCatchingExceptions([this]() { node = nullptr; });
}
kj::String PromiseBase::trace() {
return traceImpl(nullptr, node);
}
TaskSet::TaskSet(ErrorHandler& errorHandler)
: impl(heap<_::TaskSetImpl>(errorHandler)) {}
......@@ -475,6 +483,10 @@ kj::String TaskSet::trace() {
namespace _ { // private
kj::String PromiseBase::trace() {
return traceImpl(nullptr, node);
}
PromiseNode* PromiseNode::getInnerForTrace() { return nullptr; }
bool PromiseNode::OnReadyEvent::init(Event& newEvent) {
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment