blob: 760eebb64734dc726020af6b610bac4be763a2d1 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <lib/unittest/unittest.h>
#include <fbl/alloc_checker.h>
#include <fbl/ref_ptr.h>
#include <ktl/move.h>
#include <object/dispatcher.h>
#include <object/event_pair_dispatcher.h>
#include "object/handle.h"
namespace {
// A Dispatcher-like class that tracks the number of calls to on_zero_handles()
// for testing purposes.
//
// This base class is available so that we can test that KernelHandle can
// properly upcast child->base RefPtrs.
class FakeDispatcherBase : public fbl::RefCounted<FakeDispatcherBase> {
public:
virtual ~FakeDispatcherBase() = default;
uint32_t current_handle_count() const { return 0; }
int on_zero_handles_calls() const { return on_zero_handles_calls_; }
void on_zero_handles() { on_zero_handles_calls_++; }
protected:
FakeDispatcherBase() = default;
private:
int on_zero_handles_calls_ = 0;
};
class FakeDispatcher : public FakeDispatcherBase {
public:
static fbl::RefPtr<FakeDispatcher> Create() {
fbl::AllocChecker ac;
auto dispatcher = fbl::AdoptRef(new (&ac) FakeDispatcher());
if (!ac.check()) {
unittest_printf("Failed to allocate FakeDispatcher\n");
return nullptr;
}
return dispatcher;
}
~FakeDispatcher() override = default;
private:
FakeDispatcher() = default;
};
bool KernelHandleCreate() {
BEGIN_TEST;
fbl::RefPtr<FakeDispatcher> dispatcher = FakeDispatcher::Create();
{
KernelHandle handle(dispatcher);
EXPECT_EQ(dispatcher.get(), handle.dispatcher().get());
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 0);
}
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 1);
END_TEST;
}
bool KernelHandleCreateUpcast() {
BEGIN_TEST;
fbl::RefPtr<FakeDispatcher> dispatcher = FakeDispatcher::Create();
{
KernelHandle<FakeDispatcherBase> handle(dispatcher);
EXPECT_EQ(dispatcher.get(), handle.dispatcher().get());
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 0);
}
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 1);
END_TEST;
}
bool KernelHandleReset() {
BEGIN_TEST;
fbl::RefPtr<FakeDispatcher> dispatcher = FakeDispatcher::Create();
fbl::RefPtr<FakeDispatcher> dispatcher2 = FakeDispatcher::Create();
{
KernelHandle handle(dispatcher);
handle.reset(dispatcher2);
EXPECT_EQ(dispatcher2.get(), handle.dispatcher().get());
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 1);
EXPECT_EQ(dispatcher2->on_zero_handles_calls(), 0);
}
EXPECT_EQ(dispatcher2->on_zero_handles_calls(), 1);
END_TEST;
}
bool KernelHandleResetUpcast() {
BEGIN_TEST;
fbl::RefPtr<FakeDispatcher> dispatcher = FakeDispatcher::Create();
fbl::RefPtr<FakeDispatcher> dispatcher2 = FakeDispatcher::Create();
{
KernelHandle<FakeDispatcherBase> handle(dispatcher);
handle.reset(dispatcher2);
EXPECT_EQ(dispatcher2.get(), handle.dispatcher().get());
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 1);
EXPECT_EQ(dispatcher2->on_zero_handles_calls(), 0);
}
EXPECT_EQ(dispatcher2->on_zero_handles_calls(), 1);
END_TEST;
}
bool KernelHandleResetToNull() {
BEGIN_TEST;
fbl::RefPtr<FakeDispatcher> dispatcher = FakeDispatcher::Create();
KernelHandle handle(dispatcher);
handle.reset();
EXPECT_NULL(handle.dispatcher());
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 1);
END_TEST;
}
bool KernelHandleRelease() {
BEGIN_TEST;
fbl::RefPtr<FakeDispatcher> dispatcher = FakeDispatcher::Create();
KernelHandle handle(dispatcher);
fbl::RefPtr<FakeDispatcher> dispatcher_copy = handle.release();
EXPECT_NULL(handle.dispatcher());
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 0);
EXPECT_EQ(dispatcher.get(), dispatcher_copy.get());
END_TEST;
}
bool KernelHandleMoveConstructor() {
BEGIN_TEST;
fbl::RefPtr<FakeDispatcher> dispatcher = FakeDispatcher::Create();
KernelHandle handle(dispatcher);
{
KernelHandle new_handle(ktl::move(handle));
EXPECT_NULL(handle.dispatcher());
EXPECT_NONNULL(new_handle.dispatcher());
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 0);
}
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 1);
END_TEST;
}
bool KernelHandleMoveConstructorUpcast() {
BEGIN_TEST;
fbl::RefPtr<FakeDispatcher> dispatcher = FakeDispatcher::Create();
KernelHandle handle(dispatcher);
{
KernelHandle<FakeDispatcherBase> new_handle(ktl::move(handle));
EXPECT_NULL(handle.dispatcher());
EXPECT_NONNULL(new_handle.dispatcher());
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 0);
}
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 1);
END_TEST;
}
bool KernelHandleMoveAssignment() {
BEGIN_TEST;
fbl::RefPtr<FakeDispatcher> dispatcher = FakeDispatcher::Create();
fbl::RefPtr<FakeDispatcher> dispatcher2 = FakeDispatcher::Create();
{
KernelHandle handle(dispatcher);
KernelHandle handle2(dispatcher2);
handle = ktl::move(handle2);
EXPECT_NONNULL(handle.dispatcher());
EXPECT_NULL(handle2.dispatcher());
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 1);
EXPECT_EQ(dispatcher2->on_zero_handles_calls(), 0);
}
EXPECT_EQ(dispatcher2->on_zero_handles_calls(), 1);
END_TEST;
}
bool KernelHandleMoveAssignmentUpcast() {
BEGIN_TEST;
fbl::RefPtr<FakeDispatcher> dispatcher = FakeDispatcher::Create();
fbl::RefPtr<FakeDispatcher> dispatcher2 = FakeDispatcher::Create();
{
KernelHandle<FakeDispatcherBase> handle(dispatcher);
KernelHandle handle2(dispatcher2);
handle = ktl::move(handle2);
EXPECT_NONNULL(handle.dispatcher());
EXPECT_NULL(handle2.dispatcher());
EXPECT_EQ(dispatcher->on_zero_handles_calls(), 1);
EXPECT_EQ(dispatcher2->on_zero_handles_calls(), 0);
}
EXPECT_EQ(dispatcher2->on_zero_handles_calls(), 1);
END_TEST;
}
bool KernelHandleUpgrade() {
BEGIN_TEST;
// HandleOwner requires a real Dispatcher so we can't use FakeDispatcher
// here. Use eventpair instead since we can signal the peer to check
// whether its on_zero_handles() has been called.
KernelHandle<EventPairDispatcher> eventpair[2];
zx_rights_t rights;
ASSERT_EQ(EventPairDispatcher::Create(&eventpair[0], &eventpair[1], &rights), ZX_OK);
{
HandleOwner handle_owner;
{
handle_owner = Handle::Make(ktl::move(eventpair[0]), rights);
EXPECT_NULL(eventpair[0].dispatcher());
EXPECT_TRUE(handle_owner);
EXPECT_EQ(handle_owner->rights(), rights);
}
EXPECT_EQ(eventpair[1].dispatcher()->user_signal_peer(0, ZX_USER_SIGNAL_0), ZX_OK);
}
EXPECT_EQ(eventpair[1].dispatcher()->user_signal_peer(0, ZX_USER_SIGNAL_0), ZX_ERR_PEER_CLOSED);
END_TEST;
}
} // namespace
UNITTEST_START_TESTCASE(handle_tests)
UNITTEST("KernelHandleCreate", KernelHandleCreate)
UNITTEST("KernelHandleCreateUpcast", KernelHandleCreateUpcast)
UNITTEST("KernelHandleReset", KernelHandleReset)
UNITTEST("KernelHandleResetUpcast", KernelHandleResetUpcast)
UNITTEST("KernelHandleResetToNull", KernelHandleResetToNull)
UNITTEST("KernelHandleRelease", KernelHandleRelease)
UNITTEST("KernelHandleMoveConstructor", KernelHandleMoveConstructor)
UNITTEST("KernelHandleMoveConstructorUpcast", KernelHandleMoveConstructorUpcast)
UNITTEST("KernelHandleMoveAssignment", KernelHandleMoveAssignment)
UNITTEST("KernelHandleMoveAssignmentUpcast", KernelHandleMoveAssignmentUpcast)
UNITTEST("KernelHandleUpgrade", KernelHandleUpgrade)
UNITTEST_END_TESTCASE(handle_tests, "handle", "Handle test")