fmsg: drop messages when msgbuf is full during withhold
test / test (push) Successful in 20s Details

Logging functions are not expected to block. This change fixes multiple hangs where more than 64 messages are produced during withhold.

Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
This commit is contained in:
Ophestra Umiker 2024-11-04 12:56:19 +09:00
parent 88abcbe0b2
commit d7df24c999
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
2 changed files with 26 additions and 6 deletions

View File

@ -8,6 +8,7 @@ import (
var ( var (
wstate atomic.Bool wstate atomic.Bool
dropped atomic.Uint64
withhold = make(chan struct{}, 1) withhold = make(chan struct{}, 1)
msgbuf = make(chan dOp, 64) // these ops are tiny so a large buffer is allocated for withholding output msgbuf = make(chan dOp, 64) // these ops are tiny so a large buffer is allocated for withholding output
@ -29,6 +30,25 @@ func dequeue() {
}() }()
} }
// queue submits ops to msgbuf but drops messages
// when the buffer is full and dequeue is withholding
func queue(op dOp) {
select {
case msgbuf <- op:
queueSync.Add(1)
default:
// send the op anyway if not withholding
// as dequeue will get to it eventually
if !wstate.Load() {
queueSync.Add(1)
msgbuf <- op
} else {
// increment dropped message count
dropped.Add(1)
}
}
}
type dOp interface{ Do() } type dOp interface{ Do() }
func Exit(code int) { func Exit(code int) {
@ -47,6 +67,9 @@ func Resume() {
dequeueOnce.Do(dequeue) dequeueOnce.Do(dequeue)
if wstate.CompareAndSwap(true, false) { if wstate.CompareAndSwap(true, false) {
withhold <- struct{}{} withhold <- struct{}{}
if d := dropped.Swap(0); d != 0 {
Printf("dropped %d messages during withhold", d)
}
} }
} }

View File

@ -16,20 +16,17 @@ func SetPrefix(prefix string) {
func Print(v ...any) { func Print(v ...any) {
dequeueOnce.Do(dequeue) dequeueOnce.Do(dequeue)
queueSync.Add(1) queue(dPrint(v))
msgbuf <- dPrint(v)
} }
func Printf(format string, v ...any) { func Printf(format string, v ...any) {
dequeueOnce.Do(dequeue) dequeueOnce.Do(dequeue)
queueSync.Add(1) queue(&dPrintf{format, v})
msgbuf <- &dPrintf{format, v}
} }
func Println(v ...any) { func Println(v ...any) {
dequeueOnce.Do(dequeue) dequeueOnce.Do(dequeue)
queueSync.Add(1) queue(dPrintln(v))
msgbuf <- dPrintln(v)
} }
func Fatal(v ...any) { func Fatal(v ...any) {