aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/fmsg/defer.go
blob: deef58f0621ae388882d0090fe421b6a1bc91895 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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() {
	dequeueOnce.Do(dequeue)
	if wstate.CompareAndSwap(false, true) {
		withhold <- struct{}{}
	}
}

func Resume() {
	dequeueOnce.Do(dequeue)
	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...)
}