279 lines
5.9 KiB
C++
279 lines
5.9 KiB
C++
/*
|
|
* \brief Test for lifetime-management utilities
|
|
* \author Norman Feske
|
|
* \date 2013-03-12
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2013 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU General Public License version 2.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <base/printf.h>
|
|
#include <base/env.h>
|
|
#include <base/thread.h>
|
|
#include <timer_session/connection.h>
|
|
|
|
/* core includes */
|
|
#include <lifetime.h>
|
|
|
|
|
|
/********************************************************************
|
|
** Hooks for obtaining internal information of the tested classes **
|
|
********************************************************************/
|
|
|
|
static int weak_ptr_cnt;
|
|
|
|
|
|
void Genode::Volatile_object_base::debug_info() const
|
|
{
|
|
/* count number of weak pointers pointing to the object */
|
|
weak_ptr_cnt = 0;
|
|
for (Weak_ptr_base *curr = _list.first(); curr; curr = curr->next())
|
|
weak_ptr_cnt++;
|
|
}
|
|
|
|
|
|
static int weak_ptr_is_valid;
|
|
|
|
|
|
void Genode::Weak_ptr_base::debug_info() const
|
|
{
|
|
weak_ptr_is_valid = _valid;
|
|
}
|
|
|
|
|
|
struct Fatal_error { };
|
|
|
|
|
|
static void assert_weak_ptr_cnt(Genode::Volatile_object_base const *obj,
|
|
int expected_cnt)
|
|
{
|
|
obj->debug_info();
|
|
|
|
if (expected_cnt != weak_ptr_cnt) {
|
|
PERR("unexpected count, expected %d, got %d",
|
|
expected_cnt, weak_ptr_cnt);
|
|
throw Fatal_error();
|
|
}
|
|
}
|
|
|
|
|
|
static void assert_weak_ptr_valid(Genode::Weak_ptr_base const &ptr, bool valid)
|
|
{
|
|
ptr.debug_info();
|
|
|
|
if (weak_ptr_is_valid == valid)
|
|
return;
|
|
|
|
PERR("weak pointer unexpectedly %s", valid ? "valid" : "invalid");
|
|
throw Fatal_error();
|
|
}
|
|
|
|
|
|
/********************************************
|
|
** Test for the tracking of weak pointers **
|
|
********************************************/
|
|
|
|
static bool object_is_constructed;
|
|
|
|
|
|
struct Object : Genode::Volatile_object<Object>
|
|
{
|
|
Object() { object_is_constructed = true; }
|
|
|
|
~Object()
|
|
{
|
|
Volatile_object<Object>::lock_for_destruction();
|
|
object_is_constructed = false;
|
|
}
|
|
};
|
|
|
|
|
|
static void test_weak_pointer_tracking()
|
|
{
|
|
using namespace Genode;
|
|
|
|
PLOG("construct invalid weak pointer");
|
|
{
|
|
Weak_ptr<Object> ptr;
|
|
assert_weak_ptr_valid(ptr, false);
|
|
}
|
|
|
|
Object *obj = new (env()->heap()) Object;
|
|
|
|
Weak_ptr<Object> ptr_1 = obj->weak_ptr();
|
|
assert_weak_ptr_valid(ptr_1, true);
|
|
|
|
Weak_ptr<Object> ptr_2 = obj->weak_ptr();
|
|
assert_weak_ptr_valid(ptr_2, true);
|
|
|
|
assert_weak_ptr_cnt(obj, 2);
|
|
|
|
PLOG("test: assign weak pointer to itself");
|
|
ptr_2 = ptr_2;
|
|
assert_weak_ptr_cnt(obj, 2);
|
|
assert_weak_ptr_valid(ptr_2, true);
|
|
|
|
{
|
|
PLOG("test: assign weak pointer to another");
|
|
Weak_ptr<Object> ptr_3 = ptr_2;
|
|
assert_weak_ptr_cnt(obj, 3);
|
|
|
|
PLOG("test: destruct weak pointer");
|
|
/* 'ptr_3' gets destructed when leaving the scope */
|
|
}
|
|
assert_weak_ptr_cnt(obj, 2);
|
|
|
|
PLOG("destruct object");
|
|
destroy(env()->heap(), obj);
|
|
|
|
/*
|
|
* The destruction of the object should have invalidated all weak pointers
|
|
* pointing to the object.
|
|
*/
|
|
assert_weak_ptr_valid(ptr_1, false);
|
|
assert_weak_ptr_valid(ptr_2, false);
|
|
}
|
|
|
|
|
|
/*******************************************
|
|
** Test for deferring object destruction **
|
|
*******************************************/
|
|
|
|
struct Destruct_thread : Genode::Thread<4096>
|
|
{
|
|
Object *obj;
|
|
|
|
void entry()
|
|
{
|
|
using namespace Genode;
|
|
PLOG("thread: going to destroy object");
|
|
destroy(env()->heap(), obj);
|
|
PLOG("thread: destruction completed, job done");
|
|
}
|
|
|
|
Destruct_thread(Object *obj) : obj(obj) { }
|
|
};
|
|
|
|
|
|
static void assert_constructed(bool expect_constructed)
|
|
{
|
|
if (object_is_constructed == expect_constructed)
|
|
return;
|
|
|
|
PERR("object unexpectedly %sconstructed",
|
|
!object_is_constructed ? "not" : "");
|
|
throw Fatal_error();
|
|
}
|
|
|
|
|
|
static void test_deferred_destruction()
|
|
{
|
|
using namespace Genode;
|
|
|
|
static Timer::Connection timer;
|
|
|
|
Object *obj = new (env()->heap()) Object;
|
|
|
|
Weak_ptr<Object> ptr = obj->weak_ptr();
|
|
assert_weak_ptr_cnt(obj, 1);
|
|
assert_weak_ptr_valid(ptr, true);
|
|
assert_constructed(true);
|
|
|
|
/* create thread that will be used to destruct the object */
|
|
Destruct_thread destruct_thread(obj);
|
|
|
|
{
|
|
/* acquire possession over the object */
|
|
Locked_ptr<Object> locked_ptr(ptr);
|
|
|
|
/* start destruction using dedicated thread */
|
|
destruct_thread.start();
|
|
|
|
/* yield some time to the other thread */
|
|
timer.msleep(500);
|
|
|
|
/* even after the time period, the object should still be alive */
|
|
assert_constructed(true);
|
|
|
|
/* now, we release the locked pointer, the destruction can begin */
|
|
}
|
|
|
|
/*
|
|
* Now that the thread is expected to be unblocked, yield some time
|
|
* to actually do the destruction.
|
|
*/
|
|
timer.msleep(100);
|
|
|
|
assert_constructed(false);
|
|
|
|
destruct_thread.join();
|
|
}
|
|
|
|
|
|
/*******************************************************
|
|
** Test the failed aquisition of a destructed object **
|
|
*******************************************************/
|
|
|
|
static void test_acquisition_failure()
|
|
{
|
|
using namespace Genode;
|
|
|
|
PLOG("create object and weak pointer");
|
|
Object *obj = new (env()->heap()) Object;
|
|
Weak_ptr<Object> ptr = obj->weak_ptr();
|
|
|
|
PLOG("try to acquire possession over the object");
|
|
{
|
|
Locked_ptr<Object> locked_ptr(ptr);
|
|
|
|
if (!locked_ptr.is_valid()) {
|
|
PERR("locked pointer unexpectedly invalid");
|
|
throw Fatal_error();
|
|
}
|
|
|
|
/* release lock */
|
|
}
|
|
|
|
PLOG("destroy object");
|
|
destroy(env()->heap(), obj);
|
|
|
|
PLOG("try again, this time we should get an invalid pointer");
|
|
{
|
|
Locked_ptr<Object> locked_ptr(ptr);
|
|
|
|
if (locked_ptr.is_valid()) {
|
|
PERR("locked pointer unexpectedly valid");
|
|
throw Fatal_error();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/******************
|
|
** Main program **
|
|
******************/
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
using namespace Genode;
|
|
|
|
printf("--- test-lifetime started ---\n");
|
|
|
|
printf("\n-- test tracking of weak pointers --\n");
|
|
test_weak_pointer_tracking();
|
|
|
|
printf("\n-- test deferred destruction --\n");
|
|
test_deferred_destruction();
|
|
|
|
printf("\n-- test acquisition failure --\n");
|
|
test_acquisition_failure();
|
|
|
|
printf("\n--- finished test-lifetime ---\n");
|
|
return 0;
|
|
}
|