mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
* add join for ThreadPool without destroying the threads * Make the main Thread block waiting for the worker threads to finish instead of buzy looping and do proper initialization and freeing of all variables. * Updated test to use `atomic_store` and take into account the maximum queue size of the threadpool. * - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. - Return of Thread/Mutex/CondVar `destroy()` is now "@maydiscard" and should be ignored. It will return void in 0.8.0. - Return of Mutex `unlock()` and `lock()` is now "@maydiscard" and should be ignored. They will return void in 0.8.0. - Return of ConditionVariable `signal()` `broadcast()` and `wait()` are now "@maydiscard". They will return void in 0.8.0. - Return of Thread `detatch()` is now "@maydiscard". It will return void in 0.8.0. - Buffered/UnbufferedChannel, and both ThreadPools have `@maydiscard` on a set of functions. They will retunr void in 0.8.0. - Pthread bindings correctly return Errno instead of CInt. - Return of Thread `join()` is now "@maydiscard". --------- Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
241 lines
6.9 KiB
Plaintext
241 lines
6.9 KiB
Plaintext
module std::core::log;
|
|
import std::io, std::thread, std::time, std::math::random;
|
|
|
|
const FULL_LOG = env::COMPILER_SAFE_MODE || $feature(FULL_LOG);
|
|
|
|
typedef LogCategory = inline char;
|
|
typedef LogTag = char[12];
|
|
|
|
const LogCategory CATEGORY_APPLICATION = 0;
|
|
const LogCategory CATEGORY_SYSTEM = 1;
|
|
const LogCategory CATEGORY_KERNEL = 2;
|
|
const LogCategory CATEGORY_AUDIO = 3;
|
|
const LogCategory CATEGORY_VIDEO = 4;
|
|
const LogCategory CATEGORY_RENDER = 5;
|
|
const LogCategory CATEGORY_INPUT = 6;
|
|
const LogCategory CATEGORY_NETWORK = 7;
|
|
const LogCategory CATEGORY_SOCKET = 8;
|
|
const LogCategory CATEGORY_SECURITY = 9;
|
|
const LogCategory CATEGORY_TEST = 10;
|
|
const LogCategory CATEGORY_ERROR = 11;
|
|
const LogCategory CATEGORY_ASSERT = 12;
|
|
const LogCategory CATEGORY_CRASH = 13;
|
|
const LogCategory CATEGORY_STATS = 14;
|
|
const LogCategory CATEGORY_CUSTOM_START = 100;
|
|
|
|
tlocal LogCategory default_category = CATEGORY_APPLICATION;
|
|
tlocal LogTag current_tag;
|
|
|
|
|
|
enum LogPriority : int
|
|
{
|
|
VERBOSE,
|
|
DEBUG,
|
|
INFO,
|
|
WARN,
|
|
ERROR,
|
|
CRITICAL,
|
|
}
|
|
|
|
interface Logger
|
|
{
|
|
fn void log(LogPriority priority, LogCategory category, LogTag tag, String file, String function, int line, String fmt, any[] args);
|
|
}
|
|
|
|
macro void verbose(String fmt, ..., LogCategory category = default_category) => call_log(VERBOSE, category, fmt, $vasplat);
|
|
macro void debug(String fmt, ..., LogCategory category = default_category) => call_log(DEBUG, category, fmt, $vasplat);
|
|
macro void info(String fmt, ..., LogCategory category = default_category) => call_log(INFO, category, fmt, $vasplat);
|
|
macro void warn(String fmt, ..., LogCategory category = default_category) => call_log(WARN, category, fmt, $vasplat);
|
|
macro void error(String fmt, ..., LogCategory category = default_category) => call_log(ERROR, category, fmt, $vasplat);
|
|
macro void critical(String fmt, ..., LogCategory category = default_category) => call_log(CRITICAL, category, fmt, $vasplat);
|
|
|
|
macro void @category_scope(LogCategory new_category; @body)
|
|
{
|
|
LogCategory old = default_category;
|
|
default_category = new_category;
|
|
defer default_category = old;
|
|
@body();
|
|
}
|
|
|
|
<*
|
|
@require tag_prefix.len <= 3 : "The prefix may not exceed 3 bytes"
|
|
*>
|
|
macro void @tag_scope(String tag_prefix = ""; @body)
|
|
{
|
|
LogTag old = current_tag;
|
|
push_tag(tag_prefix);
|
|
defer current_tag = old;
|
|
@body();
|
|
}
|
|
|
|
<*
|
|
@require tag_prefix.len <= 3 : "The prefix may not exceed 3 bytes"
|
|
*>
|
|
macro void push_tag(String tag_prefix = "")
|
|
{
|
|
current_tag = create_tag(tag_prefix);
|
|
}
|
|
|
|
<*
|
|
@require tag_prefix.len <= 3 : "The prefix may not exceed 3 bytes"
|
|
*>
|
|
fn LogTag create_tag(String tag_prefix)
|
|
{
|
|
LogTag tag @noinit;
|
|
int start = 0;
|
|
foreach (int i, c : tag_prefix)
|
|
{
|
|
if (c == 0) break;
|
|
tag[start++] = c;
|
|
}
|
|
if (start > 0) tag[start++] = '_';
|
|
for (int i = start; i < tag.len; i++)
|
|
{
|
|
tag[i] = (char)rand_in_range('a', 'z');
|
|
}
|
|
return tag;
|
|
}
|
|
|
|
fn void set_priority_for_category(LogCategory category, LogPriority new_priority)
|
|
{
|
|
@atomic_store(config_priorities[category], new_priority, UNORDERED);
|
|
}
|
|
|
|
fn LogPriority get_priority_for_category(LogCategory category)
|
|
{
|
|
return @atomic_load(config_priorities[category], UNORDERED);
|
|
}
|
|
|
|
fn void set_priority_all(LogPriority new_priority)
|
|
{
|
|
for (int i = 0; i < config_priorities.len; i++)
|
|
{
|
|
@atomic_store(config_priorities[i], new_priority, UNORDERED);
|
|
}
|
|
}
|
|
fn void set_logger(Logger logger)
|
|
{
|
|
init();
|
|
if (!logger_mutex.is_initialized())
|
|
{
|
|
current_logger = logger;
|
|
current_logfn = &logger.log;
|
|
return;
|
|
}
|
|
logger_mutex.@in_lock()
|
|
{
|
|
current_logger = logger;
|
|
current_logfn = &logger.log;
|
|
};
|
|
}
|
|
|
|
macro void init()
|
|
{
|
|
log_init.call(fn () => (void)logger_mutex.init());
|
|
}
|
|
|
|
macro void call_log(LogPriority prio, LogCategory category, String fmt, args...)
|
|
{
|
|
$if FULL_LOG:
|
|
call_log_internal(prio, category, $$FILE, $$FUNC, $$LINE, fmt, args);
|
|
$else
|
|
call_log_internal(prio, category, "", "", 0, fmt, args);
|
|
$endif
|
|
}
|
|
|
|
fn void call_log_internal(LogPriority prio, LogCategory category, String file, String func, int line, String fmt, any[] args)
|
|
{
|
|
LogPriority priority = mem::@atomic_load(config_priorities[category], UNORDERED);
|
|
if (priority > prio) return;
|
|
init();
|
|
bool locked = logger_mutex.is_initialized();
|
|
if (locked) logger_mutex.lock();
|
|
Logger logger = current_logger;
|
|
LogFn logfn = current_logfn;
|
|
defer if (locked) logger_mutex.unlock();
|
|
logfn(logger.ptr, prio, category, current_tag, file, func, line, fmt, args);
|
|
}
|
|
|
|
fn String? get_category_name(LogCategory category)
|
|
{
|
|
String val = category_names[category];
|
|
return val ?: NOT_FOUND?;
|
|
}
|
|
|
|
fn void set_category_name(LogCategory category, String name)
|
|
{
|
|
category_names[category] = name;
|
|
}
|
|
|
|
struct NullLogger (Logger)
|
|
{
|
|
void* dummy;
|
|
}
|
|
|
|
fn void NullLogger.log(&self, LogPriority priority, LogCategory category, LogTag tag, String file, String function, int line, String fmt, any[] args) @dynamic
|
|
{}
|
|
|
|
struct MultiLogger (Logger)
|
|
{
|
|
Logger[] loggers;
|
|
}
|
|
|
|
fn void MultiLogger.log(&self, LogPriority priority, LogCategory category, LogTag tag, String file, String function, int line, String fmt, any[] args) @dynamic
|
|
{
|
|
foreach (logger : self.loggers)
|
|
{
|
|
logger.log(priority, category, tag, file, function, line, fmt, args);
|
|
}
|
|
}
|
|
|
|
|
|
module std::core::log @private;
|
|
import std::io, std::thread, std::time;
|
|
|
|
struct StderrLogger (Logger) @if(env::LIBC)
|
|
{
|
|
void* dummy;
|
|
}
|
|
|
|
fn void StderrLogger.log(&self, LogPriority priority, LogCategory category, LogTag tag, String file, String function, int line, String fmt, any[] args) @dynamic @if(env::LIBC)
|
|
{
|
|
@stack_mem(256 + 64; Allocator mem)
|
|
{
|
|
DString str;
|
|
str.init(mem, 256);
|
|
str.appendf(fmt, ...args);
|
|
TzDateTime time = datetime::now().to_local();
|
|
$if FULL_LOG:
|
|
io::eprintfn("[%02d:%02d:%02d:%04d] %s:%d [%s] %s", time.hour, time.min, time.sec, (time.usec / 1000), file, line, priority, str);
|
|
$else
|
|
io::eprintfn("[%02d:%02d:%02d:%04d] [%s] %s", time.hour, time.min, time.sec, (time.usec / 1000), priority, str);
|
|
$endif
|
|
};
|
|
}
|
|
|
|
alias LogFn = fn void(void*, LogPriority priority, LogCategory category, LogTag tag, String file, String function, int line, String fmt, any[] args);
|
|
LogFn current_logfn = env::LIBC ??? (LogFn)&StderrLogger.log : (LogFn)&NullLogger.log;
|
|
OnceFlag log_init;
|
|
Mutex logger_mutex;
|
|
Logger current_logger = env::LIBC ??? &stderr_logger : &null_logger;
|
|
StderrLogger stderr_logger @if (env::LIBC);
|
|
NullLogger null_logger;
|
|
LogPriority[256] config_priorities = { [0..255] = ERROR, [CATEGORY_APPLICATION] = INFO, [CATEGORY_TEST] = VERBOSE, [CATEGORY_ASSERT] = WARN};
|
|
String[256] category_names = {
|
|
[CATEGORY_APPLICATION] = "APP",
|
|
[CATEGORY_SYSTEM] = "SYSTEM",
|
|
[CATEGORY_KERNEL] = "KERNEL",
|
|
[CATEGORY_AUDIO] = "AUDIO",
|
|
[CATEGORY_VIDEO] = "VIDEO",
|
|
[CATEGORY_RENDER] = "RENDER",
|
|
[CATEGORY_INPUT] = "INPUT",
|
|
[CATEGORY_NETWORK] = "NETWORD",
|
|
[CATEGORY_SOCKET] = "SOCKET",
|
|
[CATEGORY_SECURITY] = "SECURITY",
|
|
[CATEGORY_TEST] = "TEST",
|
|
[CATEGORY_ERROR] = "ERROR",
|
|
[CATEGORY_ASSERT] = "ASSERT",
|
|
[CATEGORY_CRASH] = "CRASH",
|
|
[CATEGORY_STATS] = "STATS"
|
|
};
|