Commit 6d580639 authored by Kenton Varda's avatar Kenton Varda

Add thisCap() method to capability servers which returns a capability to itself.…

Add thisCap() method to capability servers which returns a capability to itself. Remove CapabilityServerSet's weak pointers since this supersedes them.
parent 69850c1e
...@@ -854,9 +854,7 @@ TEST(Capability, CapabilityServerSet) { ...@@ -854,9 +854,7 @@ TEST(Capability, CapabilityServerSet) {
auto ownServer2 = kj::heap<TestInterfaceImpl>(callCount); auto ownServer2 = kj::heap<TestInterfaceImpl>(callCount);
auto& server2 = *ownServer2; auto& server2 = *ownServer2;
auto client2AndWeak = set2.addWeak(kj::mv(ownServer2)); test::TestInterface::Client client2 = set2.add(kj::mv(ownServer2));
test::TestInterface::Client client2 = kj::mv(client2AndWeak.client);
kj::Own<WeakCapability<test::TestInterface>> client2Weak = kj::mv(client2AndWeak.weak);
// Getting the local server using the correct set works. // Getting the local server using the correct set works.
EXPECT_EQ(&server1, &KJ_ASSERT_NONNULL(set1.getLocalServer(client1).wait(waitScope))); EXPECT_EQ(&server1, &KJ_ASSERT_NONNULL(set1.getLocalServer(client1).wait(waitScope)));
...@@ -913,16 +911,53 @@ TEST(Capability, CapabilityServerSet) { ...@@ -913,16 +911,53 @@ TEST(Capability, CapabilityServerSet) {
EXPECT_TRUE(resolved1); EXPECT_TRUE(resolved1);
EXPECT_TRUE(resolved2); EXPECT_TRUE(resolved2);
EXPECT_TRUE(resolved3); EXPECT_TRUE(resolved3);
}
// Check weak pointer. class TestThisCap final: public test::TestInterface::Server {
{ public:
auto restored = KJ_ASSERT_NONNULL(client2Weak->get()); TestThisCap(int& callCount): callCount(callCount) {}
EXPECT_EQ(&server2, &KJ_ASSERT_NONNULL(set2.getLocalServer(restored).wait(waitScope))); ~TestThisCap() noexcept(false) { callCount = -1; }
test::TestInterface::Client getSelf() {
return thisCap();
}
protected:
kj::Promise<void> bar(BarContext context) {
++callCount;
return kj::READY_NOW;
} }
private:
int& callCount;
};
TEST(Capability, ThisCap) {
int callCount = 0;
kj::EventLoop loop;
kj::WaitScope waitScope(loop);
auto server = kj::heap<TestThisCap>(callCount);
TestThisCap* serverPtr = server;
test::TestInterface::Client client = kj::mv(server);
client.barRequest().send().wait(waitScope);
EXPECT_EQ(1, callCount);
test::TestInterface::Client client2 = serverPtr->getSelf();
EXPECT_EQ(1, callCount);
client2.barRequest().send().wait(waitScope);
EXPECT_EQ(2, callCount);
client = nullptr;
EXPECT_EQ(2, callCount);
client2.barRequest().send().wait(waitScope);
EXPECT_EQ(3, callCount);
client2 = nullptr; client2 = nullptr;
EXPECT_TRUE(client2Weak->get() == nullptr); EXPECT_EQ(-1, callCount);
} }
} // namespace } // namespace
......
...@@ -463,21 +463,18 @@ private: ...@@ -463,21 +463,18 @@ private:
class LocalClient final: public ClientHook, public kj::Refcounted { class LocalClient final: public ClientHook, public kj::Refcounted {
public: public:
LocalClient(kj::Own<Capability::Server>&& server): server(kj::mv(server)) {} LocalClient(kj::Own<Capability::Server>&& serverParam)
LocalClient(kj::Own<Capability::Server>&& server, : server(kj::mv(serverParam)) {
server->thisHook = this;
}
LocalClient(kj::Own<Capability::Server>&& serverParam,
_::CapabilityServerSetBase& capServerSet, void* ptr) _::CapabilityServerSetBase& capServerSet, void* ptr)
: server(kj::mv(server)), capServerSet(&capServerSet), ptr(ptr) {} : server(kj::mv(serverParam)), capServerSet(&capServerSet), ptr(ptr) {
server->thisHook = this;
~LocalClient() noexcept(false) {
KJ_IF_MAYBE(w, weak) {
w->client = nullptr;
}
} }
void setWeak(_::WeakCapabilityBase& weak) { ~LocalClient() noexcept(false) {
KJ_REQUIRE(this->weak == nullptr && weak.client == nullptr); server->thisHook = nullptr;
weak.client = *this;
this->weak = weak;
} }
Request<AnyPointer, AnyPointer> newCall( Request<AnyPointer, AnyPointer> newCall(
...@@ -555,8 +552,6 @@ private: ...@@ -555,8 +552,6 @@ private:
kj::Own<Capability::Server> server; kj::Own<Capability::Server> server;
_::CapabilityServerSetBase* capServerSet = nullptr; _::CapabilityServerSetBase* capServerSet = nullptr;
void* ptr = nullptr; void* ptr = nullptr;
kj::Maybe<_::WeakCapabilityBase&> weak;
friend class _::WeakCapabilityBase;
}; };
kj::Own<ClientHook> Capability::Client::makeLocalClient(kj::Own<Capability::Server>&& server) { kj::Own<ClientHook> Capability::Client::makeLocalClient(kj::Own<Capability::Server>&& server) {
...@@ -680,30 +675,11 @@ Request<AnyPointer, AnyPointer> newBrokenRequest( ...@@ -680,30 +675,11 @@ Request<AnyPointer, AnyPointer> newBrokenRequest(
namespace _ { // private namespace _ { // private
WeakCapabilityBase::~WeakCapabilityBase() noexcept(false) {
KJ_IF_MAYBE(c, client) {
c->weak = nullptr;
}
}
kj::Maybe<Capability::Client> WeakCapabilityBase::getInternal() {
return client.map([](LocalClient& client) {
return Capability::Client(client.addRef());
});
}
Capability::Client CapabilityServerSetBase::addInternal( Capability::Client CapabilityServerSetBase::addInternal(
kj::Own<Capability::Server>&& server, void* ptr) { kj::Own<Capability::Server>&& server, void* ptr) {
return Capability::Client(kj::refcounted<LocalClient>(kj::mv(server), *this, ptr)); return Capability::Client(kj::refcounted<LocalClient>(kj::mv(server), *this, ptr));
} }
Capability::Client CapabilityServerSetBase::addWeakInternal(
kj::Own<Capability::Server>&& server, _::WeakCapabilityBase& weak, void* ptr) {
auto result = kj::refcounted<LocalClient>(kj::mv(server), *this, ptr);
result->setWeak(weak);
return Capability::Client(kj::mv(result));
}
kj::Promise<void*> CapabilityServerSetBase::getLocalServerInternal(Capability::Client& client) { kj::Promise<void*> CapabilityServerSetBase::getLocalServerInternal(Capability::Client& client) {
ClientHook* hook = client.hook.get(); ClientHook* hook = client.hook.get();
......
...@@ -332,6 +332,17 @@ public: ...@@ -332,6 +332,17 @@ public:
// a proxy. // a proxy.
protected: protected:
inline Capability::Client thisCap();
// Get a capability pointing to this object, much like the `this` keyword.
//
// The effect of this method is undefined if:
// - No capability client has been created pointing to this object. (This is always the case in
// the server's constructor.)
// - The capability client pointing at this object has been destoryed. (This is always the case
// in the server's destructor.)
// - Multiple capability clients have been created around the same server (possible if the server
// is refcounted, which is not recommended since the client itself provides refcounting).
template <typename Params, typename Results> template <typename Params, typename Results>
CallContext<Params, Results> internalGetTypedContext( CallContext<Params, Results> internalGetTypedContext(
CallContext<AnyPointer, AnyPointer> typeless); CallContext<AnyPointer, AnyPointer> typeless);
...@@ -341,52 +352,28 @@ protected: ...@@ -341,52 +352,28 @@ protected:
uint64_t typeId, uint16_t methodId); uint64_t typeId, uint16_t methodId);
kj::Promise<void> internalUnimplemented(const char* interfaceName, const char* methodName, kj::Promise<void> internalUnimplemented(const char* interfaceName, const char* methodName,
uint64_t typeId, uint16_t methodId); uint64_t typeId, uint16_t methodId);
private:
ClientHook* thisHook = nullptr;
friend class LocalClient;
}; };
// ======================================================================================= // =======================================================================================
namespace _ { // private namespace _ { // private
class WeakCapabilityBase {
public:
~WeakCapabilityBase() noexcept(false);
kj::Maybe<Capability::Client> getInternal();
private:
kj::Maybe<LocalClient&> client;
friend class capnp::LocalClient;
};
class CapabilityServerSetBase { class CapabilityServerSetBase {
public: public:
Capability::Client addInternal(kj::Own<Capability::Server>&& server, void* ptr); Capability::Client addInternal(kj::Own<Capability::Server>&& server, void* ptr);
Capability::Client addWeakInternal(kj::Own<Capability::Server>&& server,
_::WeakCapabilityBase& weak, void* ptr);
kj::Promise<void*> getLocalServerInternal(Capability::Client& client); kj::Promise<void*> getLocalServerInternal(Capability::Client& client);
}; };
} // namespace _ (private) } // namespace _ (private)
template <typename T>
class WeakCapability: private _::WeakCapabilityBase {
public:
kj::Maybe<typename T::Client> get();
// If the server is still alive, get a live client to it.
private:
template <typename>
friend class CapabilityServerSet;
};
template <typename T> template <typename T>
class CapabilityServerSet: private _::CapabilityServerSetBase { class CapabilityServerSet: private _::CapabilityServerSetBase {
// Allows a server to: // Allows a server to recognize its own capabilities when passed back to it, and obtain the
// 1) Recognize its own capabilities when passed back to it, and obtain the underlying Server // underlying Server objects associated with them.
// objects associated with them.
// 2) Obtain "weak" versions of these capabilities, which do not prevent the underlying Server
// from being destroyed but can be upgraded to normal Clients as long as the Server is still
// alive.
// //
// All objects in the set must have the same interface type T. The objects may implement various // All objects in the set must have the same interface type T. The objects may implement various
// interfaces derived from T (and in fact T can be `capnp::Capability` to accept all objects), // interfaces derived from T (and in fact T can be `capnp::Capability` to accept all objects),
...@@ -404,14 +391,6 @@ public: ...@@ -404,14 +391,6 @@ public:
typename T::Client add(kj::Own<typename T::Server>&& server); typename T::Client add(kj::Own<typename T::Server>&& server);
// Create a new capability Client for the given Server and also add this server to the set. // Create a new capability Client for the given Server and also add this server to the set.
struct ClientAndWeak {
typename T::Client client;
kj::Own<WeakCapability<T>> weak;
};
ClientAndWeak addWeak(kj::Own<typename T::Server>&& server);
// Like add() but also creates a weak reference.
kj::Promise<kj::Maybe<typename T::Server&>> getLocalServer(typename T::Client& client); kj::Promise<kj::Maybe<typename T::Server&>> getLocalServer(typename T::Client& client);
// Given a Client pointing to a server previously passed to add(), return the corresponding // Given a Client pointing to a server previously passed to add(), return the corresponding
// Server. This returns a promise because if the input client is itself a promise, this must // Server. This returns a promise because if the input client is itself a promise, this must
...@@ -782,11 +761,8 @@ CallContext<Params, Results> Capability::Server::internalGetTypedContext( ...@@ -782,11 +761,8 @@ CallContext<Params, Results> Capability::Server::internalGetTypedContext(
return CallContext<Params, Results>(*typeless.hook); return CallContext<Params, Results>(*typeless.hook);
} }
template <typename T> Capability::Client Capability::Server::thisCap() {
kj::Maybe<typename T::Client> WeakCapability<T>::get() { return Client(thisHook->addRef());
return getInternal().map([](Capability::Client&& client) {
return client.castAs<T>();
});
} }
template <typename T> template <typename T>
...@@ -797,17 +773,6 @@ typename T::Client CapabilityServerSet<T>::add(kj::Own<typename T::Server>&& ser ...@@ -797,17 +773,6 @@ typename T::Client CapabilityServerSet<T>::add(kj::Own<typename T::Server>&& ser
return addInternal(kj::mv(server), ptr).template castAs<T>(); return addInternal(kj::mv(server), ptr).template castAs<T>();
} }
template <typename T>
typename CapabilityServerSet<T>::ClientAndWeak CapabilityServerSet<T>::addWeak(
kj::Own<typename T::Server>&& server) {
void* ptr = reinterpret_cast<void*>(server.get());
auto weak = kj::heap<WeakCapability<T>>();
// Clang insists that `castAs` is a template-dependent member and therefore we need the
// `template` keyword here, but AFAICT this is wrong: addWeakImpl() is not a template.
auto client = addWeakInternal(kj::mv(server), *weak, ptr).template castAs<T>();
return { kj::mv(client), kj::mv(weak) };
}
template <typename T> template <typename T>
kj::Promise<kj::Maybe<typename T::Server&>> CapabilityServerSet<T>::getLocalServer( kj::Promise<kj::Maybe<typename T::Server&>> CapabilityServerSet<T>::getLocalServer(
typename T::Client& client) { typename T::Client& client) {
......
...@@ -250,6 +250,10 @@ public: ...@@ -250,6 +250,10 @@ public:
return hasInterfaces_; return hasInterfaces_;
} }
kj::StringTree strNoTypename() const & { return name.flatten(); }
kj::StringTree strNoTypename() && { return kj::mv(name); }
// Stringify but never prefix with `typename`. Use in contexts where `typename` is implicit.
private: private:
kj::StringTree name; kj::StringTree name;
...@@ -2164,7 +2168,9 @@ private: ...@@ -2164,7 +2168,9 @@ private:
}; };
} }
CppTypeName clientName = cppFullName(schema, nullptr); CppTypeName typeName = cppFullName(schema, nullptr);
CppTypeName clientName = typeName;
clientName.addMemberType("Client"); clientName.addMemberType("Client");
kj::String templates = kj::str(templateContext.allDecls()); // Ends with a newline kj::String templates = kj::str(templateContext.allDecls()); // Ends with a newline
...@@ -2227,7 +2233,7 @@ private: ...@@ -2227,7 +2233,7 @@ private:
"class ", fullName, "::Client\n" "class ", fullName, "::Client\n"
" : public virtual ::capnp::Capability::Client", " : public virtual ::capnp::Capability::Client",
KJ_MAP(s, superclasses) { KJ_MAP(s, superclasses) {
return kj::strTree(",\n public virtual ", s.typeName, "::Client"); return kj::strTree(",\n public virtual ", s.typeName.strNoTypename(), "::Client");
}, " {\n" }, " {\n"
"public:\n" "public:\n"
" typedef ", fullName, " Calls;\n" " typedef ", fullName, " Calls;\n"
...@@ -2261,7 +2267,7 @@ private: ...@@ -2261,7 +2267,7 @@ private:
"class ", fullName, "::Server\n" "class ", fullName, "::Server\n"
" : public virtual ::capnp::Capability::Server", " : public virtual ::capnp::Capability::Server",
KJ_MAP(s, superclasses) { KJ_MAP(s, superclasses) {
return kj::strTree(",\n public virtual ", s.typeName, "::Server"); return kj::strTree(",\n public virtual ", s.typeName.strNoTypename(), "::Server");
}, " {\n" }, " {\n"
"public:\n", "public:\n",
" typedef ", fullName, " Serves;\n" " typedef ", fullName, " Serves;\n"
...@@ -2273,6 +2279,11 @@ private: ...@@ -2273,6 +2279,11 @@ private:
"protected:\n", "protected:\n",
KJ_MAP(m, methods) { return kj::mv(m.serverDecls); }, KJ_MAP(m, methods) { return kj::mv(m.serverDecls); },
"\n" "\n"
" inline ", clientName, " thisCap() {\n"
" return ::capnp::Capability::Server::thisCap()\n"
" .template castAs<", typeName, ">();\n"
" }\n"
"\n"
" ::kj::Promise<void> dispatchCallInternal(uint16_t methodId,\n" " ::kj::Promise<void> dispatchCallInternal(uint16_t methodId,\n"
" ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context);\n" " ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context);\n"
"};\n" "};\n"
...@@ -2326,7 +2337,8 @@ private: ...@@ -2326,7 +2337,8 @@ private:
KJ_MAP(s, transitiveSuperclasses) { KJ_MAP(s, transitiveSuperclasses) {
return kj::strTree( return kj::strTree(
" case 0x", kj::hex(s.id), "ull:\n" " case 0x", kj::hex(s.id), "ull:\n"
" return ", s.typeName, "::Server::dispatchCallInternal(methodId, context);\n"); " return ", s.typeName.strNoTypename(),
"::Server::dispatchCallInternal(methodId, context);\n");
}, },
" default:\n" " default:\n"
" return internalUnimplemented(\"", proto.getDisplayName(), "\", interfaceId);\n" " return internalUnimplemented(\"", proto.getDisplayName(), "\", interfaceId);\n"
......
...@@ -204,6 +204,11 @@ protected: ...@@ -204,6 +204,11 @@ protected:
typedef ::capnp::CallContext<typename ::capnp::Persistent<SturdyRef, Owner>::SaveParams, typename ::capnp::Persistent<SturdyRef, Owner>::SaveResults> SaveContext; typedef ::capnp::CallContext<typename ::capnp::Persistent<SturdyRef, Owner>::SaveParams, typename ::capnp::Persistent<SturdyRef, Owner>::SaveResults> SaveContext;
virtual ::kj::Promise<void> save(SaveContext context); virtual ::kj::Promise<void> save(SaveContext context);
inline typename ::capnp::Persistent<SturdyRef, Owner>::Client thisCap() {
return ::capnp::Capability::Server::thisCap()
.template castAs< ::capnp::Persistent<SturdyRef, Owner>>();
}
::kj::Promise<void> dispatchCallInternal(uint16_t methodId, ::kj::Promise<void> dispatchCallInternal(uint16_t methodId,
::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context); ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context);
}; };
...@@ -449,6 +454,11 @@ protected: ...@@ -449,6 +454,11 @@ protected:
typedef ::capnp::CallContext<ExportParams, typename ::capnp::Persistent<ExternalRef, ExternalOwner>::SaveResults> ExportContext; typedef ::capnp::CallContext<ExportParams, typename ::capnp::Persistent<ExternalRef, ExternalOwner>::SaveResults> ExportContext;
virtual ::kj::Promise<void> export_(ExportContext context); virtual ::kj::Promise<void> export_(ExportContext context);
inline typename ::capnp::RealmGateway<InternalRef, ExternalRef, InternalOwner, ExternalOwner>::Client thisCap() {
return ::capnp::Capability::Server::thisCap()
.template castAs< ::capnp::RealmGateway<InternalRef, ExternalRef, InternalOwner, ExternalOwner>>();
}
::kj::Promise<void> dispatchCallInternal(uint16_t methodId, ::kj::Promise<void> dispatchCallInternal(uint16_t methodId,
::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context); ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context);
}; };
......
...@@ -50,6 +50,9 @@ public: ...@@ -50,6 +50,9 @@ public:
void detach(); void detach();
// Don't join the thread in ~Thread(). // Don't join the thread in ~Thread().
//
// TODO(soon): Currently broken: the thread uses the Thread objects during its execution; instead
// the Thread object and the thread itself will need to share a refcounted object.
private: private:
Function<void()> func; Function<void()> func;
......
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