Skip to content

Commit b3863fb

Browse files
committed
runtime: make newproc1 not start the goroutine
Currently, newproc1 allocates, initializes, and schedules a new goroutine. We're about to change debug call injection in a way that will need to create a new goroutine without immediately scheduling it. To prepare for that, make scheduling the responsibility of newproc1's caller. Currently, there's exactly one caller (newproc), so this simply shifts that responsibility. For #36365. Change-Id: Idacd06b63e738982e840fe995d891bfd377ce23b Reviewed-on: https://go-review.googlesource.com/c/go/+/229298 Run-TryBot: Austin Clements <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Cherry Zhang <[email protected]>
1 parent 197a2a3 commit b3863fb

File tree

1 file changed

+31
-13
lines changed

1 file changed

+31
-13
lines changed

src/runtime/proc.go

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3454,23 +3454,44 @@ func malg(stacksize int32) *g {
34543454
// Create a new g running fn with siz bytes of arguments.
34553455
// Put it on the queue of g's waiting to run.
34563456
// The compiler turns a go statement into a call to this.
3457-
// Cannot split the stack because it assumes that the arguments
3458-
// are available sequentially after &fn; they would not be
3459-
// copied if a stack split occurred.
3457+
//
3458+
// The stack layout of this call is unusual: it assumes that the
3459+
// arguments to pass to fn are on the stack sequentially immediately
3460+
// after &fn. Hence, they are logically part of newproc's argument
3461+
// frame, even though they don't appear in its signature (and can't
3462+
// because their types differ between call sites).
3463+
//
3464+
// This must be nosplit because this stack layout means there are
3465+
// untyped arguments in newproc's argument frame. Stack copies won't
3466+
// be able to adjust them and stack splits won't be able to copy them.
3467+
//
34603468
//go:nosplit
34613469
func newproc(siz int32, fn *funcval) {
34623470
argp := add(unsafe.Pointer(&fn), sys.PtrSize)
34633471
gp := getg()
34643472
pc := getcallerpc()
34653473
systemstack(func() {
3466-
newproc1(fn, argp, siz, gp, pc)
3474+
newg := newproc1(fn, argp, siz, gp, pc)
3475+
3476+
_p_ := getg().m.p.ptr()
3477+
runqput(_p_, newg, true)
3478+
3479+
if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 && mainStarted {
3480+
wakep()
3481+
}
34673482
})
34683483
}
34693484

3470-
// Create a new g running fn with narg bytes of arguments starting
3471-
// at argp. callerpc is the address of the go statement that created
3472-
// this. The new g is put on the queue of g's waiting to run.
3473-
func newproc1(fn *funcval, argp unsafe.Pointer, narg int32, callergp *g, callerpc uintptr) {
3485+
// Create a new g in state _Grunnable, starting at fn, with narg bytes
3486+
// of arguments starting at argp. callerpc is the address of the go
3487+
// statement that created this. The caller is responsible for adding
3488+
// the new g to the scheduler.
3489+
//
3490+
// This must run on the system stack because it's the continuation of
3491+
// newproc, which cannot split the stack.
3492+
//
3493+
//go:systemstack
3494+
func newproc1(fn *funcval, argp unsafe.Pointer, narg int32, callergp *g, callerpc uintptr) *g {
34743495
_g_ := getg()
34753496

34763497
if fn == nil {
@@ -3566,12 +3587,9 @@ func newproc1(fn *funcval, argp unsafe.Pointer, narg int32, callergp *g, callerp
35663587
if trace.enabled {
35673588
traceGoCreate(newg, newg.startpc)
35683589
}
3569-
runqput(_p_, newg, true)
3570-
3571-
if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 && mainStarted {
3572-
wakep()
3573-
}
35743590
releasem(_g_.m)
3591+
3592+
return newg
35753593
}
35763594

35773595
// saveAncestors copies previous ancestors of the given caller g and

0 commit comments

Comments
 (0)