v / vlib / goroutines / init.v
111 lines · 98 sloc · 2.37 KB · e21acca549c0df34c98beb389088dbf7cee4c4d0
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4//
5// Goroutine runtime initialization.
6// Translated from Go's schedinit() and procresize() in proc.go.
7module goroutines
8
9import runtime
10
11// init initializes the goroutine scheduler.
12// Creates P's (one per CPU core by default) and the initial M.
13// Translated from Go's schedinit() + procresize().
14fn init() {
15 // Determine number of processors
16 n := runtime.nr_cpus()
17 if n < 1 {
18 gomaxprocs = 1
19 } else if n > 256 {
20 gomaxprocs = 256
21 } else {
22 gomaxprocs = i32(n)
23 }
24
25 // Initialize the scheduler
26 gsched.maxmcount = 10000
27 gsched.mnext = 1
28
29 // Create all P's (translated from procresize in proc.go)
30 gsched.allp = []&Processor{cap: int(gomaxprocs)}
31 for i in 0 .. gomaxprocs {
32 mut pp := &Processor{
33 id: i
34 status: .idle
35 }
36 // Initialize the local run queue
37 for j in 0 .. local_queue_size {
38 pp.runq[j] = unsafe { nil }
39 }
40 gsched.allp << pp
41 }
42
43 // Create the initial M (M0) for the main thread
44 mut m0 := &Machine{
45 id: 0
46 g0: &Goroutine{
47 id: 0
48 status: .running
49 }
50 }
51
52 // Create a "main goroutine" so chan_send/recv work from the main thread
53 mut main_g := &Goroutine{
54 id: 0
55 status: .running
56 }
57 m0.curg = main_g
58 main_g.m = m0
59
60 // Wire M0 to P0
61 mut p0 := gsched.allp[0]
62 wire_p(mut m0, mut p0)
63
64 // Set the current thread's M
65 set_current_m(m0)
66
67 // Put remaining P's on the idle list
68 for i in 1 .. gomaxprocs {
69 pid_put(gsched.allp[i])
70 }
71}
72
73// set_max_procs changes the number of active processors.
74// Returns the previous value. Translated from Go's GOMAXPROCS().
75pub fn set_max_procs(n int) int {
76 old := int(gomaxprocs)
77 if n < 1 || n == old {
78 return old
79 }
80
81 // TODO: implement full procresize like Go does
82 // For now, just update the count
83 gomaxprocs = i32(n)
84 return old
85}
86
87// num_goroutine returns the number of goroutines that currently exist.
88pub fn num_goroutine() int {
89 allgs_mu.acquire()
90 mut count := 0
91 for g in allgs {
92 if g.status != .dead {
93 count++
94 }
95 }
96 allgs_mu.release()
97 return count
98}
99
100// shutdown gracefully shuts down the goroutine scheduler.
101pub fn shutdown() {
102 gsched.stopped = true
103 // Wake all idle M's so they can exit
104 gsched.mu.acquire()
105 mut mp := gsched.midle
106 for mp != unsafe { nil } {
107 mp.park.post()
108 mp = mp.sched_link
109 }
110 gsched.mu.release()
111}
112