lockRankSched
lockRankAllg
lockRankAllp
+ lockRankNotifyList
+ lockRankSudog
lockRankTimers
lockRankTimer
lockRankNetpollInit
- lockRankNotifyList
- lockRankSudog
lockRankRoot
lockRankItab
lockRankReflectOffs
lockRankSched: "sched",
lockRankAllg: "allg",
lockRankAllp: "allp",
+ lockRankNotifyList: "notifyList",
+ lockRankSudog: "sudog",
lockRankTimers: "timers",
lockRankTimer: "timer",
lockRankNetpollInit: "netpollInit",
- lockRankNotifyList: "notifyList",
- lockRankSudog: "sudog",
lockRankRoot: "root",
lockRankItab: "itab",
lockRankReflectOffs: "reflectOffs",
lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR},
lockRankAllg: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched},
lockRankAllp: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched},
+ lockRankNotifyList: {},
+ lockRankSudog: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankWakeableSleep, lockRankHchan, lockRankNotifyList},
lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers},
lockRankTimer: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers},
lockRankNetpollInit: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers, lockRankTimer},
- lockRankNotifyList: {},
- lockRankSudog: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankWakeableSleep, lockRankHchan, lockRankNotifyList},
lockRankRoot: {},
lockRankItab: {},
lockRankReflectOffs: {lockRankItab},
lockRankUserArenaState: {},
lockRankTraceBuf: {lockRankSysmon, lockRankScavenge},
lockRankTraceStrings: {lockRankSysmon, lockRankScavenge, lockRankTraceBuf},
- lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
- lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
- lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
- lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial},
- lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
- lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
- lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
- lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive},
- lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture},
- lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
- lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
- lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf},
- lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
- lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans},
- lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap},
- lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankMheapSpecial},
- lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap},
- lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace},
+ lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
+ lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
+ lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
+ lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial},
+ lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
+ lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
+ lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
+ lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive},
+ lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture},
+ lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
+ lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
+ lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf},
+ lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
+ lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans},
+ lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap},
+ lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankMheapSpecial},
+ lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap},
+ lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace},
lockRankPanic: {},
lockRankDeadlock: {lockRankPanic, lockRankDeadlock},
lockRankRaceFini: {lockRankPanic},
// mu protects reads and writes to all fields, with exceptions noted below.
mu mutex
- astate atomic.Uint8 // atomic copy of state bits at last unlock; can be read without lock
- state uint8 // state bits
+ astate atomic.Uint8 // atomic copy of state bits at last unlock
+ state uint8 // state bits
+ isChan bool // timer has a channel; immutable; can be read without lock
+ blocked uint32 // number of goroutines blocked on timer's channel
// Timer wakes up at when, and then at when+period, ... (period > 0 only)
- // each time calling f(arg, now) in the timer goroutine, so f must be
+ // each time calling f(arg, seq, delay) in the timer goroutine, so f must be
// a well-behaved function and not block.
+ //
+ // The arg and seq are client-specified opaque arguments passed back to f.
+ // When used from package time, arg is a channel (for After, NewTicker)
+ // or the function to call (for AfterFunc) and seq is unused (0).
+ // When used from netpoll, arg and seq have meanings defined by netpoll
+ // and are completely opaque to this code; in that context, seq is a sequence
+ // number to recognize and squech stale function invocations.
+ //
+ // The delay argument is nanotime() - t.when, meaning the delay in ns between
+ // when the timer should have gone off and now. Normally that amount is
+ // small enough not to matter, but for channel timers that are fed lazily,
+ // the delay can be arbitrarily long; package time subtracts it out to make
+ // it look like the send happened earlier than it actually did.
+ // (No one looked at the channel since then, or the send would have
+ // not happened so late, so no one can tell the difference.)
when int64
period int64
- f func(any, uintptr)
+ f func(arg any, seq uintptr, delay int64)
arg any
seq uintptr
// Any code that allocates a timer must call t.init before using it.
// The arg and f can be set during init, or they can be nil in init
// and set by a future call to t.modify.
-func (t *timer) init(f func(any, uintptr), arg any) {
+func (t *timer) init(f func(arg any, seq uintptr, delay int64), arg any) {
lockInit(&t.mu, lockRankTimer)
t.f = f
t.arg = arg
// Only set when timerHeaped is also set.
// It is possible for timerModified and timerZombie to both
// be set, meaning that the timer was modified and then stopped.
+ // A timer sending to a channel may be placed in timerZombie
+ // to take it out of the heap even though the timer is not stopped,
+ // as long as nothing is reading from the channel.
timerZombie
)
if !timerDebug {
return
}
- bits := [3]string{"h", "m", "z"}
+ bits := [4]string{"h", "m", "z", "c"}
for i := range bits {
if t.state&(1<<i) == 0 {
bits[i] = "-"
}
}
- print("T ", t, " ", bits[0], bits[1], bits[2], " ", op, "\n")
+ if !t.isChan {
+ bits[3] = "-"
+ }
+ print("T ", t, " ", bits[0], bits[1], bits[2], bits[3], " b=", t.blocked, " ", op, "\n")
}
func (ts *timers) trace(op string) {
func (t *timer) unlock() {
t.trace("unlock")
// Let heap fast paths know whether t.whenHeap is accurate.
+ // Also let maybeRunChan know whether channel is in heap.
t.astate.Store(t.state)
unlock(&t.mu)
}
// with the given parameters.
//
//go:linkname newTimer time.newTimer
-func newTimer(when, period int64, f func(any, uintptr), arg any) *timeTimer {
+func newTimer(when, period int64, f func(arg any, seq uintptr, delay int64), arg any, c *hchan) *timeTimer {
t := new(timeTimer)
t.timer.init(nil, nil)
t.trace("new")
if raceenabled {
racerelease(unsafe.Pointer(&t.timer))
}
+ if c != nil {
+ t.isChan = true
+ c.timer = &t.timer
+ if c.dataqsiz == 0 {
+ throw("invalid timer channel: no capacity")
+ }
+ }
t.modify(when, period, f, arg, 0)
t.init = true
return t
// Go runtime.
// Ready the goroutine arg.
-func goroutineReady(arg any, seq uintptr) {
+func goroutineReady(arg any, _ uintptr, _ int64) {
goready(arg.(*g), 0)
}
func (t *timer) stop() bool {
t.lock()
t.trace("stop")
+ if t.state&timerHeaped == 0 && t.isChan && t.when > 0 {
+ // If timer should have triggered already (but nothing looked at it yet),
+ // trigger now, so that a receive after the stop sees the "old" value
+ // that should be there.
+ if now := nanotime(); t.when <= now {
+ systemstack(func() {
+ t.unlockAndRun(now) // resets t.when
+ })
+ t.lock()
+ }
+ }
if t.state&timerHeaped != 0 {
t.state |= timerModified
if t.state&timerZombie == 0 {
// This is called by the netpoll code or time.Ticker.Reset or time.Timer.Reset.
// Reports whether the timer was modified before it was run.
// If f == nil, then t.f, t.arg, and t.seq are not modified.
-func (t *timer) modify(when, period int64, f func(any, uintptr), arg any, seq uintptr) bool {
+func (t *timer) modify(when, period int64, f func(arg any, seq uintptr, delay int64), arg any, seq uintptr) bool {
if when <= 0 {
throw("timer when must be positive")
}
t.seq = seq
}
+ if t.state&timerHeaped == 0 && t.isChan && t.when > 0 {
+ // This is a timer for an unblocked channel.
+ // Perhaps it should have expired already.
+ if now := nanotime(); t.when <= now {
+ // The timer should have run already,
+ // but nothing has checked it yet.
+ // Run it now.
+ systemstack(func() {
+ t.unlockAndRun(now) // resets t.when
+ })
+ t.lock()
+ }
+ }
+
wake := false
pending := t.when > 0
t.when = when
// t must be locked.
func (t *timer) needsAdd() bool {
assertLockHeld(&t.mu)
- need := t.state&timerHeaped == 0 && t.when > 0
+ need := t.state&timerHeaped == 0 && t.when > 0 && (!t.isChan || t.blocked > 0)
if need {
t.trace("needsAdd+")
} else {
// too clever and respect the static ordering.
// (If we don't, we have to change the static lock checking of t and ts.)
//
-// Concurrent calls to time.Timer.Reset
+// Concurrent calls to time.Timer.Reset or blockTimerChan
// may result in concurrent calls to t.maybeAdd,
// so we cannot assume that t is not in a heap on entry to t.maybeAdd.
func (t *timer) maybeAdd() {
if ts != nil {
ts.unlock()
}
- f(arg, seq)
+ f(arg, seq, delay)
if ts != nil {
ts.lock()
}
func badTimer() {
throw("timer data corruption")
}
+
+// Timer channels.
+
+// maybeRunChan checks whether the timer needs to run
+// to send a value to its associated channel. If so, it does.
+// The timer must not be locked.
+func (t *timer) maybeRunChan() {
+ if t.astate.Load()&timerHeaped != 0 {
+ // If the timer is in the heap, the ordinary timer code
+ // is in charge of sending when appropriate.
+ return
+ }
+
+ t.lock()
+ now := nanotime()
+ if t.state&timerHeaped != 0 || t.when == 0 || t.when > now {
+ t.trace("maybeRunChan-")
+ // Timer in the heap, or not running at all, or not triggered.
+ t.unlock()
+ return
+ }
+ t.trace("maybeRunChan+")
+ systemstack(func() {
+ t.unlockAndRun(now)
+ })
+}
+
+// blockTimerChan is called when a channel op has decided to block on c.
+// The caller holds the channel lock for c and possibly other channels.
+// blockTimerChan makes sure that c is in a timer heap,
+// adding it if needed.
+func blockTimerChan(c *hchan) {
+ t := c.timer
+ t.lock()
+ t.trace("blockTimerChan")
+ if !t.isChan {
+ badTimer()
+ }
+
+ t.blocked++
+
+ // If this is the first enqueue after a recent dequeue,
+ // the timer may still be in the heap but marked as a zombie.
+ // Unmark it in this case, if the timer is still pending.
+ if t.state&timerHeaped != 0 && t.state&timerZombie != 0 && t.when > 0 {
+ t.state &^= timerZombie
+ t.ts.zombies.Add(-1)
+ }
+
+ // t.maybeAdd must be called with t unlocked,
+ // because it needs to lock t.ts before t.
+ // Then it will do nothing if t.needsAdd(state) is false.
+ // Check that now before the unlock,
+ // avoiding the extra lock-lock-unlock-unlock
+ // inside maybeAdd when t does not need to be added.
+ add := t.needsAdd()
+ t.unlock()
+ if add {
+ t.maybeAdd()
+ }
+}
+
+// unblockTimerChan is called when a channel op that was blocked on c
+// is no longer blocked. Every call to blockTimerChan must be paired with
+// a call to unblockTimerChan.
+// The caller holds the channel lock for c and possibly other channels.
+// unblockTimerChan removes c from the timer heap when nothing is
+// blocked on it anymore.
+func unblockTimerChan(c *hchan) {
+ t := c.timer
+ t.lock()
+ t.trace("unblockTimerChan")
+ if !t.isChan || t.blocked == 0 {
+ badTimer()
+ }
+ t.blocked--
+ if t.blocked == 0 && t.state&timerHeaped != 0 && t.state&timerZombie == 0 {
+ // Last goroutine that was blocked on this timer.
+ // Mark for removal from heap but do not clear t.when,
+ // so that we know what time it is still meant to trigger.
+ t.state |= timerZombie
+ t.ts.zombies.Add(1)
+ }
+ t.unlock()
+}
)
func TestTicker(t *testing.T) {
+ t.Parallel()
+
// We want to test that a ticker takes as much time as expected.
// Since we don't want the test to run for too long, we don't
// want to use lengthy times. This makes the test inherently flaky.
// Test that a bug tearing down a ticker has been fixed. This routine should not deadlock.
func TestTeardown(t *testing.T) {
+ t.Parallel()
+
Delta := 100 * Millisecond
if testing.Short() {
Delta = 20 * Millisecond
ticker.Stop()
})
}
+
+func TestTimerGC(t *testing.T) {
+ run := func(t *testing.T, what string, f func()) {
+ t.Helper()
+ t.Run(what, func(t *testing.T) {
+ t.Helper()
+ const N = 1e4
+ var stats runtime.MemStats
+ runtime.GC()
+ runtime.GC()
+ runtime.GC()
+ runtime.ReadMemStats(&stats)
+ before := int64(stats.Mallocs - stats.Frees)
+
+ for j := 0; j < N; j++ {
+ f()
+ }
+
+ runtime.GC()
+ runtime.GC()
+ runtime.GC()
+ runtime.ReadMemStats(&stats)
+ after := int64(stats.Mallocs - stats.Frees)
+
+ // Allow some slack, but inuse >= N means at least 1 allocation per iteration.
+ inuse := after - before
+ if inuse >= N {
+ t.Errorf("%s did not get GC'ed: %d allocations", what, inuse)
+
+ Sleep(1 * Second)
+ runtime.ReadMemStats(&stats)
+ after := int64(stats.Mallocs - stats.Frees)
+ inuse = after - before
+ t.Errorf("after a sleep: %d allocations", inuse)
+ }
+ })
+ }
+
+ run(t, "After", func() { After(Hour) })
+ run(t, "Tick", func() { Tick(Hour) })
+ run(t, "NewTimer", func() { NewTimer(Hour) })
+ run(t, "NewTicker", func() { NewTicker(Hour) })
+ run(t, "NewTimerStop", func() { NewTimer(Hour).Stop() })
+ run(t, "NewTickerStop", func() { NewTicker(Hour).Stop() })
+}
+
+func TestTimerChan(t *testing.T) {
+ t.Parallel()
+ tick := &timer2{NewTimer(10000 * Second)}
+ testTimerChan(t, tick, tick.C)
+}
+
+func TestTickerChan(t *testing.T) {
+ t.Parallel()
+ tick := NewTicker(10000 * Second)
+ testTimerChan(t, tick, tick.C)
+}
+
+// timer2 is a Timer with Reset and Stop methods with no result,
+// to have the same signatures as Ticker.
+type timer2 struct {
+ *Timer
+}
+
+func (t *timer2) Stop() {
+ t.Timer.Stop()
+}
+
+func (t *timer2) Reset(d Duration) {
+ t.Timer.Reset(d)
+}
+
+type ticker interface {
+ Stop()
+ Reset(Duration)
+}
+
+func testTimerChan(t *testing.T, tick ticker, C <-chan Time) {
+ // Retry parameters. Enough to deflake even on slow machines.
+ // Windows in particular has very coarse timers so we have to
+ // wait 10ms just to make a timer go off.
+ const (
+ sched = 10 * Millisecond
+ tries = 10
+ )
+
+ drain := func() {
+ select {
+ case <-C:
+ default:
+ }
+ }
+ noTick := func() {
+ t.Helper()
+ select {
+ default:
+ case <-C:
+ t.Fatalf("extra tick")
+ }
+ }
+ assertTick := func() {
+ t.Helper()
+ select {
+ default:
+ case <-C:
+ return
+ }
+ for i := 0; i < tries; i++ {
+ Sleep(sched)
+ select {
+ default:
+ case <-C:
+ return
+ }
+ }
+ t.Fatalf("missing tick")
+ }
+ assertLen := func() {
+ t.Helper()
+ var n int
+ if n = len(C); n == 1 {
+ return
+ }
+ for i := 0; i < tries; i++ {
+ Sleep(sched)
+ if n = len(C); n == 1 {
+ return
+ }
+ }
+ t.Fatalf("len(C) = %d, want 1", n)
+ }
+
+ // Test simple stop; timer never in heap.
+ tick.Stop()
+ noTick()
+
+ // Test modify of timer not in heap.
+ tick.Reset(10000 * Second)
+ noTick()
+
+ // Test modify of timer in heap.
+ tick.Reset(1)
+ assertTick()
+
+ // Sleep long enough that a second tick must happen if this is a ticker.
+ // Test that Reset does not lose the tick that should have happened.
+ Sleep(sched)
+ tick.Reset(10000 * Second)
+ _, isTicker := tick.(*Ticker)
+ if isTicker {
+ assertTick()
+ }
+ noTick()
+
+ // Test that len sees an immediate tick arrive
+ // for Reset of timer in heap.
+ tick.Reset(1)
+ assertLen()
+ assertTick()
+
+ // Test that len sees an immediate tick arrive
+ // for Reset of timer NOT in heap.
+ tick.Stop()
+ drain()
+ tick.Reset(1)
+ assertLen()
+ assertTick()
+
+ // Sleep long enough that a second tick must happen if this is a ticker.
+ // Test that Reset does not lose the tick that should have happened.
+ Sleep(sched)
+ tick.Reset(10000 * Second)
+ if isTicker {
+ assertLen()
+ assertTick()
+ }
+ noTick()
+
+ notDone := func(done chan bool) {
+ t.Helper()
+ select {
+ default:
+ case <-done:
+ t.Fatalf("early done")
+ }
+ }
+
+ waitDone := func(done chan bool) {
+ t.Helper()
+ for i := 0; i < tries; i++ {
+ Sleep(sched)
+ select {
+ case <-done:
+ return
+ default:
+ }
+ }
+ t.Fatalf("never got done")
+ }
+
+ // Reset timer in heap (already reset above, but just in case).
+ tick.Reset(10000 * Second)
+ drain()
+
+ // Test stop while timer in heap (because goroutine is blocked on <-C).
+ done := make(chan bool)
+ notDone(done)
+ go func() {
+ <-C
+ close(done)
+ }()
+ Sleep(sched)
+ notDone(done)
+
+ // Test reset far away while timer in heap.
+ tick.Reset(20000 * Second)
+ Sleep(sched)
+ notDone(done)
+
+ // Test imminent reset while in heap.
+ tick.Reset(1)
+ waitDone(done)
+
+ // If this is a ticker, another tick should have come in already
+ // (they are 1ns apart). If a timer, it should have stopped.
+ if isTicker {
+ assertTick()
+ } else {
+ noTick()
+ }
+
+ tick.Stop()
+ if isTicker {
+ drain()
+ }
+ noTick()
+
+ // Again using select and with two goroutines waiting.
+ tick.Reset(10000 * Second)
+ done = make(chan bool, 2)
+ done1 := make(chan bool)
+ done2 := make(chan bool)
+ stop := make(chan bool)
+ go func() {
+ select {
+ case <-C:
+ done <- true
+ case <-stop:
+ }
+ close(done1)
+ }()
+ go func() {
+ select {
+ case <-C:
+ done <- true
+ case <-stop:
+ }
+ close(done2)
+ }()
+ Sleep(sched)
+ notDone(done)
+ tick.Reset(sched / 2)
+ Sleep(sched)
+ waitDone(done)
+ tick.Stop()
+ close(stop)
+ waitDone(done1)
+ waitDone(done2)
+ if isTicker {
+ // extra send might have sent done again
+ // (handled by buffering done above).
+ select {
+ default:
+ case <-done:
+ }
+ // extra send after that might have filled C.
+ select {
+ default:
+ case <-C:
+ }
+ }
+ notDone(done)
+
+ // Test enqueueTimerChan when timer is stopped.
+ stop = make(chan bool)
+ done = make(chan bool, 2)
+ for i := 0; i < 2; i++ {
+ go func() {
+ select {
+ case <-C:
+ panic("unexpected data")
+ case <-stop:
+ }
+ done <- true
+ }()
+ }
+ Sleep(sched)
+ close(stop)
+ waitDone(done)
+ waitDone(done)
+}
+
+func TestManualTicker(t *testing.T) {
+ // Code should not do this, but some old code dating to Go 1.9 does.
+ // Make sure this doesn't crash.
+ // See go.dev/issue/21874.
+ c := make(chan Time)
+ tick := &Ticker{C: c}
+ tick.Stop()
+}
+
+func TestAfterTimes(t *testing.T) {
+ t.Parallel()
+ // Using After(10ms) but waiting for 500ms to read the channel
+ // should produce a time from start+10ms, not start+500ms.
+ // Make sure it does.
+ // To avoid flakes due to very long scheduling delays,
+ // require 10 failures in a row before deciding something is wrong.
+ for i := 0; i < 10; i++ {
+ start := Now()
+ c := After(10 * Millisecond)
+ Sleep(500 * Millisecond)
+ dt := (<-c).Sub(start)
+ if dt < 400*Millisecond {
+ return
+ }
+ t.Logf("After(10ms) time is +%v, want <400ms", dt)
+ }
+ t.Errorf("not working")
+}
+
+func TestTickTimes(t *testing.T) {
+ t.Parallel()
+ // See comment in TestAfterTimes
+ for i := 0; i < 10; i++ {
+ start := Now()
+ c := Tick(10 * Millisecond)
+ Sleep(500 * Millisecond)
+ dt := (<-c).Sub(start)
+ if dt < 400*Millisecond {
+ return
+ }
+ t.Logf("Tick(10ms) time is +%v, want <400ms", dt)
+ }
+ t.Errorf("not working")
+}