aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/fmsg/defer.go
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-10-26 23:09:32 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-10-26 23:09:32 +0900
commitae1a102882103221ef842176dfd8cb1090d5f591 (patch)
tree16f34686bac5564998a9a0e84be96d83ed3e59bd /internal/fmsg/defer.go
parent093e99d062f873dc9d83b1f76a156c1ee4275c57 (diff)
fmsg: support temporarily withholding output
Trying to print to a shared stdout is a terrible idea. This change makes it possible to withhold output for the lifetime of the sandbox. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'internal/fmsg/defer.go')
-rw-r--r--internal/fmsg/defer.go70
1 files changed, 70 insertions, 0 deletions
diff --git a/internal/fmsg/defer.go b/internal/fmsg/defer.go
new file mode 100644
index 00000000..cee3c737
--- /dev/null
+++ b/internal/fmsg/defer.go
@@ -0,0 +1,70 @@
+package fmsg
+
+import (
+ "os"
+ "sync"
+ "sync/atomic"
+)
+
+var (
+ wstate atomic.Bool
+ withhold = make(chan struct{}, 1)
+ msgbuf = make(chan dOp, 64) // these ops are tiny so a large buffer is allocated for withholding output
+
+ dequeueOnce sync.Once
+ queueSync sync.WaitGroup
+)
+
+func dequeue() {
+ go func() {
+ for {
+ select {
+ case op := <-msgbuf:
+ op.Do()
+ queueSync.Done()
+ case <-withhold:
+ <-withhold
+ }
+ }
+ }()
+}
+
+type dOp interface{ Do() }
+
+func Exit(code int) {
+ queueSync.Wait()
+ os.Exit(code)
+}
+
+func Withhold() {
+ if wstate.CompareAndSwap(false, true) {
+ withhold <- struct{}{}
+ }
+}
+
+func Resume() {
+ if wstate.CompareAndSwap(true, false) {
+ withhold <- struct{}{}
+ }
+}
+
+type dPrint []any
+
+func (v dPrint) Do() {
+ std.Print(v...)
+}
+
+type dPrintf struct {
+ format string
+ v []any
+}
+
+func (d *dPrintf) Do() {
+ std.Printf(d.format, d.v...)
+}
+
+type dPrintln []any
+
+func (v dPrintln) Do() {
+ std.Println(v...)
+}