scheduler_none.mx raw
1 //go:build scheduler.none
2
3 package runtime
4
5 import (
6 "internal/task"
7 "runtime/interrupt"
8 )
9
10 const hasScheduler = false
11
12 // No goroutines — single-threaded event dispatch.
13 const hasParallelism = false
14
15 // Set to true after main.main returns.
16 var mainExited bool
17
18 // dummy flag, not used without scheduler
19 var schedulerExit bool
20
21 // run is called by the program entry point to execute the go program.
22 func run() {
23 initRand()
24 initHeap()
25 initAll()
26 callMain()
27 mainExited = true
28 }
29
30 //go:linkname sleep time.Sleep
31 func sleep(duration int64) {
32 if duration <= 0 {
33 return
34 }
35
36 // Sleep in chunks, firing expired timers between chunks.
37 target := ticks() + nanosecondsToTicks(duration)
38 for {
39 now := ticks()
40 remaining := target - now
41 if remaining <= 0 {
42 break
43 }
44
45 // If a timer fires before our target, only sleep until that timer.
46 if timerQueue != nil {
47 nextTimer := timerQueue.whenTicks() - now
48 if nextTimer < remaining {
49 remaining = nextTimer
50 }
51 }
52
53 if remaining > 0 {
54 sleepTicks(remaining)
55 }
56
57 // Fire all expired timers.
58 fireTimers()
59 }
60
61 // Final timer check after sleep completes.
62 fireTimers()
63 }
64
65 // fireTimers runs callbacks for all expired timers.
66 func fireTimers() {
67 now := ticks()
68 for timerQueue != nil && timerQueue.whenTicks() <= now {
69 tn := timerQueue
70 timerQueue = tn.next
71 tn.next = nil
72 tn.callback(tn, int64(ticksToNanoseconds(now-tn.whenTicks())))
73 }
74 }
75
76 // addTimer adds a timer to the queue. Timers fire during sleep or
77 // at explicit yield points.
78 func addTimer(tim *timerNode) {
79 mask := interrupt.Disable()
80 timerQueueAdd(tim)
81 interrupt.Restore(mask)
82 }
83
84 // removeTimer removes a timer from the queue.
85 func removeTimer(tim *timer) *timerNode {
86 mask := interrupt.Disable()
87 n := timerQueueRemove(tim)
88 interrupt.Restore(mask)
89 return n
90 }
91
92 func deadlock() {
93 runtimePanic("all goroutines are asleep - deadlock!")
94 }
95
96 func scheduleTask(t *task.Task) {
97 // Single-threaded: no task scheduling. Channel operations
98 // that would block will deadlock (by design).
99 }
100
101 func Gosched() {
102 // Single-threaded: fire pending timers as a yield point.
103 fireTimers()
104 }
105
106 func scheduler(returnAtDeadlock bool) {
107 runtimePanic("unreachable: scheduler must not be called without goroutines")
108 }
109
110 func schedulerRunQueue() *task.Queue {
111 runtimePanic("unreachable: no runqueue without goroutines")
112 return nil
113 }
114
115 // NumCPU returns the number of logical CPUs usable by the current process.
116 func NumCPU() int {
117 return 1
118 }
119
120 func lockAtomics() interrupt.State {
121 return interrupt.Disable()
122 }
123
124 func unlockAtomics(mask interrupt.State) {
125 interrupt.Restore(mask)
126 }
127
128 func printlock() {
129 // nothing to do
130 }
131
132 func printunlock() {
133 // nothing to do
134 }
135
136 // eventLoopTick runs one iteration of the single-threaded event loop.
137 // Called from internal/task when blocking operations need to poll for
138 // I/O events and timers without a scheduler.
139 func eventLoopTick() {
140 if hasPoll {
141 netpollBlock(1) // 1ms poll
142 }
143 fireTimers()
144 }
145