diff --git a/rpp/impl/log.cpp b/rpp/impl/log.cpp index 11dc892..a4c9d4f 100644 --- a/rpp/impl/log.cpp +++ b/rpp/impl/log.cpp @@ -40,9 +40,21 @@ struct Static_Data { } }; -static Static_Data g_log_data; +static Storage g_log_data; static thread_local u64 g_log_indent = 0; +namespace detail { + +Static_Init::Static_Init() noexcept { + g_log_data.construct(); +} + +Static_Init::~Static_Init() noexcept { + g_log_data.destruct(); +} + +} // namespace detail + #ifdef RPP_OS_WINDOWS [[nodiscard]] String_View sys_error() noexcept { @@ -147,23 +159,25 @@ void output(Level level, const Location& loc, String_View msg) noexcept { Thread::Id thread = Thread::this_id(); ::time_t timer = ::time(null); - Thread::Lock lock(g_log_data.lock); + { + Thread::Lock lock(g_log_data->lock); - String_View time = sys_time_string(timer); + String_View time = sys_time_string(timer); - printf(format_str, time.length(), time.data(), level_str, thread, loc.file.length(), - loc.file.data(), loc.line, g_log_indent * INDENT_SIZE, "", msg.length(), msg.data()); - fflush(stdout); + printf(format_str, time.length(), time.data(), level_str, thread, loc.file.length(), + loc.file.data(), loc.line, g_log_indent * INDENT_SIZE, "", msg.length(), msg.data()); + fflush(stdout); - for(auto& [_, callback] : g_log_data.callbacks) { - callback(level, thread, timer, loc, msg); + if(g_log_data->file) { + fprintf(g_log_data->file, format_str, time.length(), time.data(), level_str, thread, + loc.file.length(), loc.file.data(), loc.line, g_log_indent * INDENT_SIZE, "", + msg.length(), msg.data()); + fflush(g_log_data->file); + } } - if(g_log_data.file) { - fprintf(g_log_data.file, format_str, time.length(), time.data(), level_str, thread, - loc.file.length(), loc.file.data(), loc.line, g_log_indent * INDENT_SIZE, "", - msg.length(), msg.data()); - fflush(g_log_data.file); + for(auto& [_, callback] : g_log_data->callbacks) { + callback(level, thread, timer, loc, msg); } } @@ -178,17 +192,17 @@ Scope::~Scope() noexcept { [[nodiscard]] Token subscribe(Function f) noexcept { - Thread::Lock lock(g_log_data.lock); - Token t = g_log_data.next++; - g_log_data.callbacks.insert(t, rpp::move(f)); + Thread::Lock lock(g_log_data->lock); + Token t = g_log_data->next++; + g_log_data->callbacks.insert(t, rpp::move(f)); return t; } void unsubscribe(Token token) noexcept { - Thread::Lock lock(g_log_data.lock); - g_log_data.callbacks.erase(token); - if(g_log_data.callbacks.empty()) { - g_log_data.callbacks.~Map(); + Thread::Lock lock(g_log_data->lock); + g_log_data->callbacks.erase(token); + if(g_log_data->callbacks.empty()) { + g_log_data->callbacks.~Map(); } } diff --git a/rpp/impl/profile.cpp b/rpp/impl/profile.cpp index f1b40a3..38acbee 100644 --- a/rpp/impl/profile.cpp +++ b/rpp/impl/profile.cpp @@ -159,6 +159,8 @@ void Profile::Frame_Profile::exit() noexcept { void Profile::alloc(Alloc a) noexcept { if constexpr(DO_PROFILE) { + bool replaced = false; + bool no_entry = false; { Thread::Lock lock(allocs_lock); Alloc_Profile& prof = allocs.get_or_insert(a.name); @@ -166,7 +168,7 @@ void Profile::alloc(Alloc a) noexcept { if(a.size) { if(prof.current_set.contains(a.address)) { - warn("Profile: % reallocated %!", a.name, a.address); + replaced = true; } prof.current_set.insert(a.address, a.size); @@ -179,7 +181,7 @@ void Profile::alloc(Alloc a) noexcept { Opt> sz = prof.current_set.try_get(a.address); if(!sz.ok()) { - warn("Profile: % freed % with no entry!", a.name, a.address); + no_entry = true; } else { i64 size = **sz; prof.current_set.erase(a.address); @@ -189,10 +191,16 @@ void Profile::alloc(Alloc a) noexcept { } } } + + if(replaced) warn("Profile: % reallocated %!", a.name, a.address); + if(no_entry) warn("Profile: % freed % with no entry!", a.name, a.address); + { - Thread::Lock lock(this_thread.frames_lock); - if(this_thread.during_frame) { - this_thread.frames.back().allocations.push(rpp::move(a)); + if(!this_thread_destroyed) { + Thread::Lock lock(this_thread.frames_lock); + if(this_thread.during_frame) { + this_thread.frames.back().allocations.push(rpp::move(a)); + } } } } @@ -248,10 +256,6 @@ void Profile::finalize() noexcept { } else { info("No regions leaked."); } - if(net != 0) { - warn("Memory leaked, shutting down now..."); - Libc::exit(1); - } } } // namespace rpp diff --git a/rpp/log.h b/rpp/log.h index 0eb6e52..d2d48a0 100644 --- a/rpp/log.h +++ b/rpp/log.h @@ -92,6 +92,18 @@ void log(Level level, const Location& loc, String_View fmt, const Ts&... args) n Region(R) output(level, loc, format>(fmt, args...).view()); } +namespace detail { + +struct Static_Init { + Static_Init() noexcept; + ~Static_Init() noexcept; +}; + +// Constructed before subsequent globals and destructed after them. +inline Static_Init g_initializer; + +}; // namespace detail + } // namespace Log RPP_NAMED_ENUM(Log::Level, "Level", info, RPP_CASE(info), RPP_CASE(warn), RPP_CASE(fatal)); diff --git a/rpp/profile.h b/rpp/profile.h index 62d2369..2f87822 100644 --- a/rpp/profile.h +++ b/rpp/profile.h @@ -138,6 +138,7 @@ struct Profile { } ~Thread_Profile() noexcept { finalize(); + this_thread_destroyed = true; } void finalize() noexcept { @@ -161,6 +162,7 @@ struct Profile { static inline Thread::Mutex allocs_lock; static inline Thread::Mutex finalizers_lock; static inline thread_local Thread_Profile this_thread; + static inline thread_local bool this_thread_destroyed = false; static inline Map, Mhidden> threads; static inline Map allocs; static inline Vec, Mhidden> finalizers; diff --git a/test/static.cpp b/test/static.cpp new file mode 100644 index 0000000..bf1610e --- /dev/null +++ b/test/static.cpp @@ -0,0 +1,48 @@ + +#include "test.h" + +#include +#include + +using Alloc = Mallocator<"Alloc">; + +struct Destroy { + ~Destroy() { + info("Log at static destruction."); + Profile::finalize(); + } +}; +Destroy at_exit; + +Test test{"static"_v}; + +Vec g_vec0; +Vec g_vec1{1, 2, 3}; + +i32 main() { + Profile::begin_frame(); + + static Vec vec{1, 2, 3}; + static Box box{5}; + + static thread_local Vec tls_vec{1, 2, 3}; + static thread_local Box tls_box{5}; + + info("g_vec0: %", g_vec0); + info("g_vec1: %", g_vec1); + info("vec: %", vec); + info("box: %", box); + info("tls_vec: %", tls_vec); + info("tls_box: %", tls_box); + + auto v = Thread::spawn([]() { + tls_vec = Vec{1, 2, 3, 4, 5}; + info("tls_vec in thread: %", tls_vec); + info("tls_box in thread: %", tls_box); + return move(tls_vec); + }); + info("Thread returned: %", v->block()); + + Profile::end_frame(); + return 0; +} diff --git a/test/static.expect b/test/static.expect new file mode 100644 index 0000000..cd21305 --- /dev/null +++ b/test/static.expect @@ -0,0 +1,9 @@ +[Level::info] g_vec0: Vec[] +[Level::info] g_vec1: Vec[1, 2, 3] +[Level::info] vec: Vec[1, 2, 3] +[Level::info] box: Box{5} +[Level::info] tls_vec: Vec[1, 2, 3] +[Level::info] tls_box: Box{5} +[Level::info] tls_vec in thread: Vec[1, 2, 3, 4, 5] +[Level::info] tls_box in thread: Box{null} +[Level::info] Thread returned: Vec[1, 2, 3, 4, 5] diff --git a/test/test.h b/test/test.h index 90bf09a..c0d8823 100644 --- a/test/test.h +++ b/test/test.h @@ -6,12 +6,10 @@ using namespace rpp; struct Test { - using Alloc = Mallocator<"Test">; - explicit Test(String_View name) : name(name) { token = Log::subscribe( [&](Log::Level lvl, Thread::Id, Log::Time, Log::Location, String_View msg) { - auto m = format("[%] %\n"_v, lvl, msg); + auto m = format("[%] %\n"_v, lvl, msg); for(u8 c : m) { result.push(c); } @@ -20,7 +18,7 @@ struct Test { ~Test() { Log::unsubscribe(token); - auto expect = name.append(".expect"_v); + auto expect = name.append(".expect"_v); expected = move(*Files::read(expect.view())); bool differs = false; @@ -36,14 +34,14 @@ struct Test { } if(differs) { - auto corrected = name.append(".corrected"_v); + auto corrected = name.append(".corrected"_v); static_cast(Files::write(corrected.view(), result.slice())); Libc::exit(1); } } String_View name; - Vec result; + Vec result; Vec expected; Log::Token token; };