From 4825daa42f5667516fee65660ef1a6cccf8bb947 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 12 Feb 2017 13:08:15 +0100 Subject: Add managed_ptr for automatic real-time safe garbage collection --- test/maid_test.cpp | 108 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 96 insertions(+), 12 deletions(-) (limited to 'test/maid_test.cpp') diff --git a/test/maid_test.cpp b/test/maid_test.cpp index 73e8f71..dd615ec 100644 --- a/test/maid_test.cpp +++ b/test/maid_test.cpp @@ -1,6 +1,6 @@ /* This file is part of Raul. - Copyright 2007-2014 David Robillard + Copyright 2007-2017 David Robillard Raul is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -14,26 +14,110 @@ along with Raul. If not, see . */ +#include +#include +#include +#include + #include "raul/Maid.hpp" -class DisposableThing : public Raul::Maid::Disposable -{}; +using Raul::Maid; -class ManageableThing : public Raul::Maid::Manageable -{}; +static const size_t n_threads = 8; +static const size_t n_junk_per_thread = 1 << 18; -int -main(int argc, char** argv) +static std::atomic n_junk(0); +static std::atomic n_finished_threads(0); + +class Junk : public Maid::Disposable { +public: + explicit Junk(int v) : val(v) { ++n_junk; } + ~Junk() { --n_junk; } + + int val; +}; + +static void +litter(Maid* maid) { - Raul::Maid maid; + for (size_t i = 0; i < n_junk_per_thread; ++i) { + Maid::managed_ptr a = maid->make_managed(i); + } + + ++n_finished_threads; +} + +static void +test() +{ + Maid maid; + + // Check basic single-threaded correctness + { + assert(n_junk == 0); + Maid::managed_ptr a = maid.make_managed(1); + assert(n_junk == 1); + Maid::managed_ptr b = maid.make_managed(2); + assert(n_junk == 2); + } + + maid.dispose(nullptr); // Mustn't crash + + // All referenes dropped, but deletion deferred + assert(n_junk == 2); - DisposableThing* dis = new DisposableThing(); + // Trigger actual deletion + maid.cleanup(); + assert(n_junk == 0); + assert(maid.empty()); + + // Create some threads to produce garbage + std::vector litterers; + for (size_t i = 0; i < n_threads; ++i) { + litterers.push_back(std::thread(litter, &maid)); + } - std::shared_ptr man(new ManageableThing()); + // Wait for some garbage to show up if necessary (unlikely) + size_t initial_n_junk = n_junk; + while (maid.empty()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + initial_n_junk = n_junk; + } - maid.manage(man); - maid.dispose(dis); + printf("Starting with %zu initial bits of junk\n", initial_n_junk); + + // Ensure we're actually cleaning things up concurrently maid.cleanup(); + assert(n_junk != initial_n_junk); + + // Continue cleaning up as long as threads are running + size_t n_cleanup_calls = 1; + while (n_finished_threads < n_threads) { + maid.cleanup(); + ++n_cleanup_calls; + } + printf("Called cleanup %zu times\n", n_cleanup_calls); + + // Join litterer threads + for (auto& t : litterers) { + t.join(); + } + + // Clean up any leftover garbage (unlikely/impossible?) + maid.cleanup(); + assert(n_junk == 0); + + // Allocate a new object, then let it and the Maid go out of scope + Maid::managed_ptr c = maid.make_managed(5); + assert(n_junk == 1); +} + +int +main(int argc, char** argv) +{ + assert(n_junk == 0); + test(); + assert(n_junk == 0); return 0; } -- cgit v1.2.1