log: fix panic on mutex destroy, when exiting a program, while a thread is still logging

This commit is contained in:
Delyan Angelov 2025-02-24 18:28:27 +02:00
parent 1cb76c92f4
commit b9d057118c
No known key found for this signature in database
GPG key ID: 66886C0F12D595ED
2 changed files with 30 additions and 10 deletions

View file

@ -6,11 +6,6 @@ pub type FnExitCb = fn ()
fn C.atexit(f FnExitCb) int
fn C.strerror(int) &char
@[noreturn]
fn vhalt() {
for {}
}
@[markused]
fn v_segmentation_fault_handler(signal_number i32) {
$if freestanding {
@ -99,7 +94,7 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
C.exit(1)
}
}
vhalt()
C.exit(1)
}
// panic_option_not_set is called by V, when you use option error propagation in your main function.
@ -154,7 +149,7 @@ pub fn panic(s string) {
C.exit(1)
}
}
vhalt()
C.exit(1)
}
// return a C-API error message matching to `errnum`

View file

@ -23,15 +23,22 @@ pub fn new_thread_safe_log() &ThreadSafeLog {
@[unsafe]
pub fn (mut x ThreadSafeLog) free() {
unsafe {
// make sure other threads are not in the blocks protected by the mutex:
mut p := x.mu
p.try_lock()
x.mu = nil
p.unlock()
p.destroy()
free(p)
x.Log.free()
x.mu.destroy()
free(x.mu)
// C.printf(c'ThreadSafeLog free(x), x: %p\n', x)
}
}
// set_level changes the log level
pub fn (mut x ThreadSafeLog) set_level(level Level) {
if unsafe { x.mu == 0 } {
return
}
x.mu.lock()
x.Log.set_level(level)
x.mu.unlock()
@ -40,6 +47,9 @@ pub fn (mut x ThreadSafeLog) set_level(level Level) {
// set_always_flush called with true, will make the log flush after every single .fatal(), .error(), .warn(), .info(), .debug() call.
// That can be much slower, if you plan to do lots of frequent calls, but if your program exits early or crashes, your logs will be more complete.
pub fn (mut x ThreadSafeLog) set_always_flush(should_flush bool) {
if unsafe { x.mu == 0 } {
return
}
x.mu.lock()
x.Log.set_always_flush(should_flush)
x.mu.unlock()
@ -47,6 +57,9 @@ pub fn (mut x ThreadSafeLog) set_always_flush(should_flush bool) {
// debug logs a debug message
pub fn (mut x ThreadSafeLog) debug(s string) {
if unsafe { x.mu == 0 } {
return
}
x.mu.lock()
x.Log.debug(s)
x.mu.unlock()
@ -54,6 +67,9 @@ pub fn (mut x ThreadSafeLog) debug(s string) {
// info logs an info messagep
pub fn (mut x ThreadSafeLog) info(s string) {
if unsafe { x.mu == 0 } {
return
}
x.mu.lock()
x.Log.info(s)
x.mu.unlock()
@ -61,6 +77,9 @@ pub fn (mut x ThreadSafeLog) info(s string) {
// warn logs a warning message
pub fn (mut x ThreadSafeLog) warn(s string) {
if unsafe { x.mu == 0 } {
return
}
x.mu.lock()
x.Log.warn(s)
x.mu.unlock()
@ -68,6 +87,9 @@ pub fn (mut x ThreadSafeLog) warn(s string) {
// error logs an error message
pub fn (mut x ThreadSafeLog) error(s string) {
if unsafe { x.mu == 0 } {
return
}
x.mu.lock()
x.Log.error(s)
x.mu.unlock()
@ -76,6 +98,9 @@ pub fn (mut x ThreadSafeLog) error(s string) {
// fatal logs a fatal message, and panics
@[noreturn]
pub fn (mut x ThreadSafeLog) fatal(s string) {
if unsafe { x.mu == 0 } {
panic(s)
}
x.mu.lock()
defer {
// TODO: Log.fatal() is marked as noreturn, but this defer is allowed.