mirror of
https://github.com/daeuniverse/dae.git
synced 2025-01-13 00:04:47 +07:00
93 lines
1.5 KiB
Go
93 lines
1.5 KiB
Go
package control
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const UdpTaskQueueLength = 128
|
|
|
|
type UdpTask = func()
|
|
|
|
type UdpTaskQueue struct {
|
|
ch chan UdpTask
|
|
timer *time.Timer
|
|
agingTime time.Duration
|
|
closed chan struct{}
|
|
freed chan struct{}
|
|
}
|
|
|
|
func (q *UdpTaskQueue) Push(task UdpTask) {
|
|
q.timer.Reset(q.agingTime)
|
|
q.ch <- task
|
|
}
|
|
|
|
type UdpTaskPool struct {
|
|
queueChPool sync.Pool
|
|
// mu protects m
|
|
mu sync.Mutex
|
|
m map[string]*UdpTaskQueue
|
|
}
|
|
|
|
func NewUdpTaskPool() *UdpTaskPool {
|
|
p := &UdpTaskPool{
|
|
queueChPool: sync.Pool{New: func() any {
|
|
return make(chan UdpTask, UdpTaskQueueLength)
|
|
}},
|
|
mu: sync.Mutex{},
|
|
m: map[string]*UdpTaskQueue{},
|
|
}
|
|
return p
|
|
}
|
|
|
|
func (p *UdpTaskPool) convoy(q *UdpTaskQueue) {
|
|
for {
|
|
select {
|
|
case <-q.closed:
|
|
clearloop:
|
|
for {
|
|
select {
|
|
case <-q.ch:
|
|
default:
|
|
break clearloop
|
|
}
|
|
}
|
|
close(q.freed)
|
|
return
|
|
case t := <-q.ch:
|
|
t()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (p *UdpTaskPool) EmitTask(key string, task UdpTask) {
|
|
p.mu.Lock()
|
|
q, ok := p.m[key]
|
|
if !ok {
|
|
ch := p.queueChPool.Get().(chan UdpTask)
|
|
q = &UdpTaskQueue{
|
|
ch: ch,
|
|
timer: nil,
|
|
agingTime: DefaultNatTimeout,
|
|
closed: make(chan struct{}),
|
|
freed: make(chan struct{}),
|
|
}
|
|
q.timer = time.AfterFunc(q.agingTime, func() {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if p.m[key] == q {
|
|
delete(p.m, key)
|
|
}
|
|
close(q.closed)
|
|
<-q.freed
|
|
p.queueChPool.Put(ch)
|
|
})
|
|
p.m[key] = q
|
|
go p.convoy(q)
|
|
}
|
|
p.mu.Unlock()
|
|
q.Push(task)
|
|
}
|
|
|
|
var DefaultUdpTaskPool = NewUdpTaskPool()
|