mirror of
https://github.com/safing/portbase
synced 2025-09-10 15:34:26 +00:00
Add microtask queues and signaling
This commit is contained in:
parent
ce02b26ff5
commit
7fec4f5428
3 changed files with 331 additions and 114 deletions
|
@ -2,6 +2,7 @@ package modules
|
|||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
@ -41,7 +42,7 @@ func TestMicroTaskWaiting(t *testing.T) { //nolint:paralleltest // Too much inte
|
|||
go func() {
|
||||
defer mtwWaitGroup.Done()
|
||||
// exec at slot 1
|
||||
_ = mtModule.RunMicroTask(&mtTestName, func(ctx context.Context) error {
|
||||
_ = mtModule.RunHighPriorityMicroTask(mtTestName, func(ctx context.Context) error {
|
||||
mtwOutputChannel <- "1" // slot 1
|
||||
time.Sleep(mtwSleepDuration * 5)
|
||||
mtwOutputChannel <- "2" // slot 5
|
||||
|
@ -52,7 +53,7 @@ func TestMicroTaskWaiting(t *testing.T) { //nolint:paralleltest // Too much inte
|
|||
time.Sleep(mtwSleepDuration * 1)
|
||||
|
||||
// clear clearances
|
||||
_ = mtModule.RunMicroTask(&mtTestName, func(ctx context.Context) error {
|
||||
_ = mtModule.RunHighPriorityMicroTask(mtTestName, func(ctx context.Context) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
|
@ -60,7 +61,7 @@ func TestMicroTaskWaiting(t *testing.T) { //nolint:paralleltest // Too much inte
|
|||
go func() {
|
||||
defer mtwWaitGroup.Done()
|
||||
// exec at slot 2
|
||||
_ = mtModule.RunLowPriorityMicroTask(&mtTestName, func(ctx context.Context) error {
|
||||
_ = mtModule.RunLowPriorityMicroTask(mtTestName, 0, func(ctx context.Context) error {
|
||||
mtwOutputChannel <- "7" // slot 16
|
||||
return nil
|
||||
})
|
||||
|
@ -73,7 +74,7 @@ func TestMicroTaskWaiting(t *testing.T) { //nolint:paralleltest // Too much inte
|
|||
defer mtwWaitGroup.Done()
|
||||
time.Sleep(mtwSleepDuration * 8)
|
||||
// exec at slot 10
|
||||
_ = mtModule.RunMicroTask(&mtTestName, func(ctx context.Context) error {
|
||||
_ = mtModule.RunHighPriorityMicroTask(mtTestName, func(ctx context.Context) error {
|
||||
mtwOutputChannel <- "4" // slot 10
|
||||
time.Sleep(mtwSleepDuration * 5)
|
||||
mtwOutputChannel <- "6" // slot 15
|
||||
|
@ -85,7 +86,7 @@ func TestMicroTaskWaiting(t *testing.T) { //nolint:paralleltest // Too much inte
|
|||
go func() {
|
||||
defer mtwWaitGroup.Done()
|
||||
// exec at slot 3
|
||||
_ = mtModule.RunMediumPriorityMicroTask(&mtTestName, func(ctx context.Context) error {
|
||||
_ = mtModule.RunMicroTask(mtTestName, 0, func(ctx context.Context) error {
|
||||
mtwOutputChannel <- "3" // slot 6
|
||||
time.Sleep(mtwSleepDuration * 7)
|
||||
mtwOutputChannel <- "5" // slot 13
|
||||
|
@ -121,64 +122,98 @@ var (
|
|||
|
||||
// Microtask test functions.
|
||||
|
||||
func highPrioTaskTester() {
|
||||
defer mtoWaitGroup.Done()
|
||||
<-mtoWaitCh
|
||||
_ = mtModule.RunHighPriorityMicroTask(mtTestName, func(ctx context.Context) error {
|
||||
mtoOutputChannel <- "0"
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func highPrioSignalledTaskTester() {
|
||||
defer mtoWaitGroup.Done()
|
||||
<-mtoWaitCh
|
||||
go func() {
|
||||
done := mtModule.SignalHighPriorityMicroTask()
|
||||
defer done()
|
||||
|
||||
mtoOutputChannel <- "0"
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
}()
|
||||
}
|
||||
|
||||
func mediumPrioTaskTester() {
|
||||
defer mtoWaitGroup.Done()
|
||||
<-mtoWaitCh
|
||||
_ = mtModule.RunMediumPriorityMicroTask(&mtTestName, func(ctx context.Context) error {
|
||||
_ = mtModule.RunMicroTask(mtTestName, 0, func(ctx context.Context) error {
|
||||
mtoOutputChannel <- "1"
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func mediumPrioSignalledTaskTester() {
|
||||
defer mtoWaitGroup.Done()
|
||||
<-mtoWaitCh
|
||||
go func() {
|
||||
done := mtModule.SignalMicroTask(0)
|
||||
defer done()
|
||||
|
||||
mtoOutputChannel <- "1"
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
}()
|
||||
}
|
||||
|
||||
func lowPrioTaskTester() {
|
||||
defer mtoWaitGroup.Done()
|
||||
<-mtoWaitCh
|
||||
_ = mtModule.RunLowPriorityMicroTask(&mtTestName, func(ctx context.Context) error {
|
||||
_ = mtModule.RunLowPriorityMicroTask(mtTestName, 0, func(ctx context.Context) error {
|
||||
mtoOutputChannel <- "2"
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestMicroTaskOrdering(t *testing.T) { //nolint:paralleltest // Too much interference expected.
|
||||
func lowPrioSignalledTaskTester() {
|
||||
defer mtoWaitGroup.Done()
|
||||
<-mtoWaitCh
|
||||
go func() {
|
||||
done := mtModule.SignalLowPriorityMicroTask(0)
|
||||
defer done()
|
||||
|
||||
mtoOutputChannel <- "2"
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
}()
|
||||
}
|
||||
|
||||
func TestMicroTaskOrdering(t *testing.T) { //nolint:paralleltest // Too much interference expected.
|
||||
// skip
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode, as it is not fully deterministic")
|
||||
}
|
||||
|
||||
// Only allow a single concurrent task for testing.
|
||||
atomic.StoreInt32(microTasksThreshhold, 1)
|
||||
defer SetMaxConcurrentMicroTasks(runtime.GOMAXPROCS(0))
|
||||
|
||||
// init
|
||||
mtoOutputChannel = make(chan string, 100)
|
||||
mtoWaitCh = make(chan struct{})
|
||||
|
||||
// TEST
|
||||
mtoWaitGroup.Add(20)
|
||||
|
||||
// ensure we only execute one microtask at once
|
||||
atomic.StoreInt32(microTasksThreshhold, 1)
|
||||
|
||||
// kick off
|
||||
go mediumPrioTaskTester()
|
||||
go mediumPrioTaskTester()
|
||||
go lowPrioTaskTester()
|
||||
go lowPrioTaskTester()
|
||||
go lowPrioTaskTester()
|
||||
go mediumPrioTaskTester()
|
||||
go lowPrioTaskTester()
|
||||
go mediumPrioTaskTester()
|
||||
go mediumPrioTaskTester()
|
||||
go mediumPrioTaskTester()
|
||||
go lowPrioTaskTester()
|
||||
go mediumPrioTaskTester()
|
||||
go lowPrioTaskTester()
|
||||
go mediumPrioTaskTester()
|
||||
go lowPrioTaskTester()
|
||||
go mediumPrioTaskTester()
|
||||
go lowPrioTaskTester()
|
||||
go lowPrioTaskTester()
|
||||
go mediumPrioTaskTester()
|
||||
go lowPrioTaskTester()
|
||||
// init all in waiting state
|
||||
for i := 0; i < 5; i++ {
|
||||
mtoWaitGroup.Add(6)
|
||||
go lowPrioTaskTester()
|
||||
go lowPrioSignalledTaskTester()
|
||||
go mediumPrioTaskTester()
|
||||
go mediumPrioSignalledTaskTester()
|
||||
go highPrioTaskTester()
|
||||
go highPrioSignalledTaskTester()
|
||||
}
|
||||
|
||||
// wait for all goroutines to be ready
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
@ -197,12 +232,15 @@ func TestMicroTaskOrdering(t *testing.T) { //nolint:paralleltest // Too much int
|
|||
// collect output
|
||||
close(mtoOutputChannel)
|
||||
completeOutput := ""
|
||||
for s := <-mtoOutputChannel; s != ""; s = <-mtoOutputChannel {
|
||||
for s := range mtoOutputChannel {
|
||||
completeOutput += s
|
||||
}
|
||||
|
||||
// check if test succeeded
|
||||
t.Logf("microTask exec order: %s", completeOutput)
|
||||
if !strings.Contains(completeOutput, "11111") || !strings.Contains(completeOutput, "22222") {
|
||||
if !strings.Contains(completeOutput, "000") ||
|
||||
!strings.Contains(completeOutput, "1111") ||
|
||||
!strings.Contains(completeOutput, "22222") {
|
||||
t.Errorf("MicroTask ordering test failed, output was %s. This happens occasionally, please run the test multiple times to verify", completeOutput)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue