Home | History | Annotate | Download | only in runtime
      1 // Copyright 2011 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package runtime
      6 
      7 import "unsafe"
      8 
      9 //go:cgo_export_dynamic runtime.end _end
     10 //go:cgo_export_dynamic runtime.etext _etext
     11 //go:cgo_export_dynamic runtime.edata _edata
     12 
     13 //go:cgo_import_dynamic libc____errno ___errno "libc.so"
     14 //go:cgo_import_dynamic libc_clock_gettime clock_gettime "libc.so"
     15 //go:cgo_import_dynamic libc_close close "libc.so"
     16 //go:cgo_import_dynamic libc_exit exit "libc.so"
     17 //go:cgo_import_dynamic libc_fstat fstat "libc.so"
     18 //go:cgo_import_dynamic libc_getcontext getcontext "libc.so"
     19 //go:cgo_import_dynamic libc_getrlimit getrlimit "libc.so"
     20 //go:cgo_import_dynamic libc_kill kill "libc.so"
     21 //go:cgo_import_dynamic libc_madvise madvise "libc.so"
     22 //go:cgo_import_dynamic libc_malloc malloc "libc.so"
     23 //go:cgo_import_dynamic libc_mmap mmap "libc.so"
     24 //go:cgo_import_dynamic libc_munmap munmap "libc.so"
     25 //go:cgo_import_dynamic libc_open open "libc.so"
     26 //go:cgo_import_dynamic libc_pthread_attr_destroy pthread_attr_destroy "libc.so"
     27 //go:cgo_import_dynamic libc_pthread_attr_getstack pthread_attr_getstack "libc.so"
     28 //go:cgo_import_dynamic libc_pthread_attr_init pthread_attr_init "libc.so"
     29 //go:cgo_import_dynamic libc_pthread_attr_setdetachstate pthread_attr_setdetachstate "libc.so"
     30 //go:cgo_import_dynamic libc_pthread_attr_setstack pthread_attr_setstack "libc.so"
     31 //go:cgo_import_dynamic libc_pthread_create pthread_create "libc.so"
     32 //go:cgo_import_dynamic libc_raise raise "libc.so"
     33 //go:cgo_import_dynamic libc_read read "libc.so"
     34 //go:cgo_import_dynamic libc_select select "libc.so"
     35 //go:cgo_import_dynamic libc_sched_yield sched_yield "libc.so"
     36 //go:cgo_import_dynamic libc_sem_init sem_init "libc.so"
     37 //go:cgo_import_dynamic libc_sem_post sem_post "libc.so"
     38 //go:cgo_import_dynamic libc_sem_reltimedwait_np sem_reltimedwait_np "libc.so"
     39 //go:cgo_import_dynamic libc_sem_wait sem_wait "libc.so"
     40 //go:cgo_import_dynamic libc_setitimer setitimer "libc.so"
     41 //go:cgo_import_dynamic libc_sigaction sigaction "libc.so"
     42 //go:cgo_import_dynamic libc_sigaltstack sigaltstack "libc.so"
     43 //go:cgo_import_dynamic libc_sigprocmask sigprocmask "libc.so"
     44 //go:cgo_import_dynamic libc_sysconf sysconf "libc.so"
     45 //go:cgo_import_dynamic libc_usleep usleep "libc.so"
     46 //go:cgo_import_dynamic libc_write write "libc.so"
     47 
     48 //go:linkname libc____errno libc____errno
     49 //go:linkname libc_clock_gettime libc_clock_gettime
     50 //go:linkname libc_close libc_close
     51 //go:linkname libc_exit libc_exit
     52 //go:linkname libc_fstat libc_fstat
     53 //go:linkname libc_getcontext libc_getcontext
     54 //go:linkname libc_getrlimit libc_getrlimit
     55 //go:linkname libc_kill libc_kill
     56 //go:linkname libc_madvise libc_madvise
     57 //go:linkname libc_malloc libc_malloc
     58 //go:linkname libc_mmap libc_mmap
     59 //go:linkname libc_munmap libc_munmap
     60 //go:linkname libc_open libc_open
     61 //go:linkname libc_pthread_attr_destroy libc_pthread_attr_destroy
     62 //go:linkname libc_pthread_attr_getstack libc_pthread_attr_getstack
     63 //go:linkname libc_pthread_attr_init libc_pthread_attr_init
     64 //go:linkname libc_pthread_attr_setdetachstate libc_pthread_attr_setdetachstate
     65 //go:linkname libc_pthread_attr_setstack libc_pthread_attr_setstack
     66 //go:linkname libc_pthread_create libc_pthread_create
     67 //go:linkname libc_raise libc_raise
     68 //go:linkname libc_read libc_read
     69 //go:linkname libc_select libc_select
     70 //go:linkname libc_sched_yield libc_sched_yield
     71 //go:linkname libc_sem_init libc_sem_init
     72 //go:linkname libc_sem_post libc_sem_post
     73 //go:linkname libc_sem_reltimedwait_np libc_sem_reltimedwait_np
     74 //go:linkname libc_sem_wait libc_sem_wait
     75 //go:linkname libc_setitimer libc_setitimer
     76 //go:linkname libc_sigaction libc_sigaction
     77 //go:linkname libc_sigaltstack libc_sigaltstack
     78 //go:linkname libc_sigprocmask libc_sigprocmask
     79 //go:linkname libc_sysconf libc_sysconf
     80 //go:linkname libc_usleep libc_usleep
     81 //go:linkname libc_write libc_write
     82 
     83 var (
     84 	libc____errno,
     85 	libc_clock_gettime,
     86 	libc_close,
     87 	libc_exit,
     88 	libc_fstat,
     89 	libc_getcontext,
     90 	libc_getrlimit,
     91 	libc_kill,
     92 	libc_madvise,
     93 	libc_malloc,
     94 	libc_mmap,
     95 	libc_munmap,
     96 	libc_open,
     97 	libc_pthread_attr_destroy,
     98 	libc_pthread_attr_getstack,
     99 	libc_pthread_attr_init,
    100 	libc_pthread_attr_setdetachstate,
    101 	libc_pthread_attr_setstack,
    102 	libc_pthread_create,
    103 	libc_raise,
    104 	libc_read,
    105 	libc_sched_yield,
    106 	libc_select,
    107 	libc_sem_init,
    108 	libc_sem_post,
    109 	libc_sem_reltimedwait_np,
    110 	libc_sem_wait,
    111 	libc_setitimer,
    112 	libc_sigaction,
    113 	libc_sigaltstack,
    114 	libc_sigprocmask,
    115 	libc_sysconf,
    116 	libc_usleep,
    117 	libc_write libcFunc
    118 )
    119 
    120 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
    121 
    122 func getncpu() int32 {
    123 	n := int32(sysconf(__SC_NPROCESSORS_ONLN))
    124 	if n < 1 {
    125 		return 1
    126 	}
    127 	return n
    128 }
    129 
    130 func getPageSize() uintptr {
    131 	n := int32(sysconf(__SC_PAGESIZE))
    132 	if n <= 0 {
    133 		return 0
    134 	}
    135 	return uintptr(n)
    136 }
    137 
    138 func osinit() {
    139 	ncpu = getncpu()
    140 	physPageSize = getPageSize()
    141 }
    142 
    143 func tstart_sysvicall(newm *m) uint32
    144 
    145 // May run with m.p==nil, so write barriers are not allowed.
    146 //go:nowritebarrier
    147 func newosproc(mp *m, _ unsafe.Pointer) {
    148 	var (
    149 		attr pthreadattr
    150 		oset sigset
    151 		tid  pthread
    152 		ret  int32
    153 		size uint64
    154 	)
    155 
    156 	if pthread_attr_init(&attr) != 0 {
    157 		throw("pthread_attr_init")
    158 	}
    159 	if pthread_attr_setstack(&attr, 0, 0x200000) != 0 {
    160 		throw("pthread_attr_setstack")
    161 	}
    162 	if pthread_attr_getstack(&attr, unsafe.Pointer(&mp.g0.stack.hi), &size) != 0 {
    163 		throw("pthread_attr_getstack")
    164 	}
    165 	mp.g0.stack.lo = mp.g0.stack.hi - uintptr(size)
    166 	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
    167 		throw("pthread_attr_setdetachstate")
    168 	}
    169 
    170 	// Disable signals during create, so that the new thread starts
    171 	// with signals disabled. It will enable them in minit.
    172 	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
    173 	ret = pthread_create(&tid, &attr, funcPC(tstart_sysvicall), unsafe.Pointer(mp))
    174 	sigprocmask(_SIG_SETMASK, &oset, nil)
    175 	if ret != 0 {
    176 		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n")
    177 		if ret == -_EAGAIN {
    178 			println("runtime: may need to increase max user processes (ulimit -u)")
    179 		}
    180 		throw("newosproc")
    181 	}
    182 }
    183 
    184 func exitThread(wait *uint32) {
    185 	// We should never reach exitThread on Solaris because we let
    186 	// libc clean up threads.
    187 	throw("exitThread")
    188 }
    189 
    190 var urandom_dev = []byte("/dev/urandom\x00")
    191 
    192 //go:nosplit
    193 func getRandomData(r []byte) {
    194 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
    195 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
    196 	closefd(fd)
    197 	extendRandom(r, int(n))
    198 }
    199 
    200 func goenvs() {
    201 	goenvs_unix()
    202 }
    203 
    204 // Called to initialize a new m (including the bootstrap m).
    205 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
    206 func mpreinit(mp *m) {
    207 	mp.gsignal = malg(32 * 1024)
    208 	mp.gsignal.m = mp
    209 }
    210 
    211 func miniterrno()
    212 
    213 // Called to initialize a new m (including the bootstrap m).
    214 // Called on the new thread, cannot allocate memory.
    215 func minit() {
    216 	asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno))
    217 
    218 	minitSignals()
    219 }
    220 
    221 // Called from dropm to undo the effect of an minit.
    222 func unminit() {
    223 	unminitSignals()
    224 }
    225 
    226 func memlimit() uintptr {
    227 	/*
    228 		TODO: Convert to Go when something actually uses the result.
    229 		Rlimit rl;
    230 		extern byte runtimetext[], runtimeend[];
    231 		uintptr used;
    232 
    233 		if(runtimegetrlimit(RLIMIT_AS, &rl) != 0)
    234 			return 0;
    235 		if(rl.rlim_cur >= 0x7fffffff)
    236 			return 0;
    237 
    238 		// Estimate our VM footprint excluding the heap.
    239 		// Not an exact science: use size of binary plus
    240 		// some room for thread stacks.
    241 		used = runtimeend - runtimetext + (64<<20);
    242 		if(used >= rl.rlim_cur)
    243 			return 0;
    244 
    245 		// If there's not at least 16 MB left, we're probably
    246 		// not going to be able to do much. Treat as no limit.
    247 		rl.rlim_cur -= used;
    248 		if(rl.rlim_cur < (16<<20))
    249 			return 0;
    250 
    251 		return rl.rlim_cur - used;
    252 	*/
    253 
    254 	return 0
    255 }
    256 
    257 func sigtramp()
    258 
    259 //go:nosplit
    260 //go:nowritebarrierrec
    261 func setsig(i uint32, fn uintptr) {
    262 	var sa sigactiont
    263 
    264 	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
    265 	sa.sa_mask = sigset_all
    266 	if fn == funcPC(sighandler) {
    267 		fn = funcPC(sigtramp)
    268 	}
    269 	*((*uintptr)(unsafe.Pointer(&sa._funcptr))) = fn
    270 	sigaction(i, &sa, nil)
    271 }
    272 
    273 //go:nosplit
    274 //go:nowritebarrierrec
    275 func setsigstack(i uint32) {
    276 	var sa sigactiont
    277 	sigaction(i, nil, &sa)
    278 	if sa.sa_flags&_SA_ONSTACK != 0 {
    279 		return
    280 	}
    281 	sa.sa_flags |= _SA_ONSTACK
    282 	sigaction(i, &sa, nil)
    283 }
    284 
    285 //go:nosplit
    286 //go:nowritebarrierrec
    287 func getsig(i uint32) uintptr {
    288 	var sa sigactiont
    289 	sigaction(i, nil, &sa)
    290 	return *((*uintptr)(unsafe.Pointer(&sa._funcptr)))
    291 }
    292 
    293 // setSignaltstackSP sets the ss_sp field of a stackt.
    294 //go:nosplit
    295 func setSignalstackSP(s *stackt, sp uintptr) {
    296 	*(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
    297 }
    298 
    299 //go:nosplit
    300 //go:nowritebarrierrec
    301 func sigaddset(mask *sigset, i int) {
    302 	mask.__sigbits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
    303 }
    304 
    305 func sigdelset(mask *sigset, i int) {
    306 	mask.__sigbits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
    307 }
    308 
    309 func (c *sigctxt) fixsigcode(sig uint32) {
    310 }
    311 
    312 //go:nosplit
    313 func semacreate(mp *m) {
    314 	if mp.waitsema != 0 {
    315 		return
    316 	}
    317 
    318 	var sem *semt
    319 	_g_ := getg()
    320 
    321 	// Call libc's malloc rather than malloc. This will
    322 	// allocate space on the C heap. We can't call malloc
    323 	// here because it could cause a deadlock.
    324 	_g_.m.libcall.fn = uintptr(unsafe.Pointer(&libc_malloc))
    325 	_g_.m.libcall.n = 1
    326 	_g_.m.scratch = mscratch{}
    327 	_g_.m.scratch.v[0] = unsafe.Sizeof(*sem)
    328 	_g_.m.libcall.args = uintptr(unsafe.Pointer(&_g_.m.scratch))
    329 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_g_.m.libcall))
    330 	sem = (*semt)(unsafe.Pointer(_g_.m.libcall.r1))
    331 	if sem_init(sem, 0, 0) != 0 {
    332 		throw("sem_init")
    333 	}
    334 	mp.waitsema = uintptr(unsafe.Pointer(sem))
    335 }
    336 
    337 //go:nosplit
    338 func semasleep(ns int64) int32 {
    339 	_m_ := getg().m
    340 	if ns >= 0 {
    341 		_m_.ts.tv_sec = ns / 1000000000
    342 		_m_.ts.tv_nsec = ns % 1000000000
    343 
    344 		_m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_reltimedwait_np))
    345 		_m_.libcall.n = 2
    346 		_m_.scratch = mscratch{}
    347 		_m_.scratch.v[0] = _m_.waitsema
    348 		_m_.scratch.v[1] = uintptr(unsafe.Pointer(&_m_.ts))
    349 		_m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
    350 		asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_m_.libcall))
    351 		if *_m_.perrno != 0 {
    352 			if *_m_.perrno == _ETIMEDOUT || *_m_.perrno == _EAGAIN || *_m_.perrno == _EINTR {
    353 				return -1
    354 			}
    355 			throw("sem_reltimedwait_np")
    356 		}
    357 		return 0
    358 	}
    359 	for {
    360 		_m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_wait))
    361 		_m_.libcall.n = 1
    362 		_m_.scratch = mscratch{}
    363 		_m_.scratch.v[0] = _m_.waitsema
    364 		_m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
    365 		asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_m_.libcall))
    366 		if _m_.libcall.r1 == 0 {
    367 			break
    368 		}
    369 		if *_m_.perrno == _EINTR {
    370 			continue
    371 		}
    372 		throw("sem_wait")
    373 	}
    374 	return 0
    375 }
    376 
    377 //go:nosplit
    378 func semawakeup(mp *m) {
    379 	if sem_post((*semt)(unsafe.Pointer(mp.waitsema))) != 0 {
    380 		throw("sem_post")
    381 	}
    382 }
    383 
    384 //go:nosplit
    385 func closefd(fd int32) int32 {
    386 	return int32(sysvicall1(&libc_close, uintptr(fd)))
    387 }
    388 
    389 //go:nosplit
    390 func exit(r int32) {
    391 	sysvicall1(&libc_exit, uintptr(r))
    392 }
    393 
    394 //go:nosplit
    395 func getcontext(context *ucontext) /* int32 */ {
    396 	sysvicall1(&libc_getcontext, uintptr(unsafe.Pointer(context)))
    397 }
    398 
    399 //go:nosplit
    400 func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
    401 	sysvicall3(&libc_madvise, uintptr(addr), uintptr(n), uintptr(flags))
    402 }
    403 
    404 //go:nosplit
    405 func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (unsafe.Pointer, int) {
    406 	p, err := doMmap(uintptr(addr), n, uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off))
    407 	if p == ^uintptr(0) {
    408 		return nil, int(err)
    409 	}
    410 	return unsafe.Pointer(p), 0
    411 }
    412 
    413 //go:nosplit
    414 func doMmap(addr, n, prot, flags, fd, off uintptr) (uintptr, uintptr) {
    415 	var libcall libcall
    416 	libcall.fn = uintptr(unsafe.Pointer(&libc_mmap))
    417 	libcall.n = 6
    418 	libcall.args = uintptr(noescape(unsafe.Pointer(&addr)))
    419 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall))
    420 	return libcall.r1, libcall.err
    421 }
    422 
    423 //go:nosplit
    424 func munmap(addr unsafe.Pointer, n uintptr) {
    425 	sysvicall2(&libc_munmap, uintptr(addr), uintptr(n))
    426 }
    427 
    428 func nanotime1()
    429 
    430 //go:nosplit
    431 func nanotime() int64 {
    432 	return int64(sysvicall0((*libcFunc)(unsafe.Pointer(funcPC(nanotime1)))))
    433 }
    434 
    435 //go:nosplit
    436 func open(path *byte, mode, perm int32) int32 {
    437 	return int32(sysvicall3(&libc_open, uintptr(unsafe.Pointer(path)), uintptr(mode), uintptr(perm)))
    438 }
    439 
    440 func pthread_attr_destroy(attr *pthreadattr) int32 {
    441 	return int32(sysvicall1(&libc_pthread_attr_destroy, uintptr(unsafe.Pointer(attr))))
    442 }
    443 
    444 func pthread_attr_getstack(attr *pthreadattr, addr unsafe.Pointer, size *uint64) int32 {
    445 	return int32(sysvicall3(&libc_pthread_attr_getstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(unsafe.Pointer(size))))
    446 }
    447 
    448 func pthread_attr_init(attr *pthreadattr) int32 {
    449 	return int32(sysvicall1(&libc_pthread_attr_init, uintptr(unsafe.Pointer(attr))))
    450 }
    451 
    452 func pthread_attr_setdetachstate(attr *pthreadattr, state int32) int32 {
    453 	return int32(sysvicall2(&libc_pthread_attr_setdetachstate, uintptr(unsafe.Pointer(attr)), uintptr(state)))
    454 }
    455 
    456 func pthread_attr_setstack(attr *pthreadattr, addr uintptr, size uint64) int32 {
    457 	return int32(sysvicall3(&libc_pthread_attr_setstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(size)))
    458 }
    459 
    460 func pthread_create(thread *pthread, attr *pthreadattr, fn uintptr, arg unsafe.Pointer) int32 {
    461 	return int32(sysvicall4(&libc_pthread_create, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(fn), uintptr(arg)))
    462 }
    463 
    464 //go:nosplit
    465 //go:nowritebarrierrec
    466 func raise(sig uint32) /* int32 */ {
    467 	sysvicall1(&libc_raise, uintptr(sig))
    468 }
    469 
    470 func raiseproc(sig uint32) /* int32 */ {
    471 	pid := sysvicall0(&libc_getpid)
    472 	sysvicall2(&libc_kill, pid, uintptr(sig))
    473 }
    474 
    475 //go:nosplit
    476 func read(fd int32, buf unsafe.Pointer, nbyte int32) int32 {
    477 	return int32(sysvicall3(&libc_read, uintptr(fd), uintptr(buf), uintptr(nbyte)))
    478 }
    479 
    480 //go:nosplit
    481 func sem_init(sem *semt, pshared int32, value uint32) int32 {
    482 	return int32(sysvicall3(&libc_sem_init, uintptr(unsafe.Pointer(sem)), uintptr(pshared), uintptr(value)))
    483 }
    484 
    485 //go:nosplit
    486 func sem_post(sem *semt) int32 {
    487 	return int32(sysvicall1(&libc_sem_post, uintptr(unsafe.Pointer(sem))))
    488 }
    489 
    490 //go:nosplit
    491 func sem_reltimedwait_np(sem *semt, timeout *timespec) int32 {
    492 	return int32(sysvicall2(&libc_sem_reltimedwait_np, uintptr(unsafe.Pointer(sem)), uintptr(unsafe.Pointer(timeout))))
    493 }
    494 
    495 //go:nosplit
    496 func sem_wait(sem *semt) int32 {
    497 	return int32(sysvicall1(&libc_sem_wait, uintptr(unsafe.Pointer(sem))))
    498 }
    499 
    500 func setitimer(which int32, value *itimerval, ovalue *itimerval) /* int32 */ {
    501 	sysvicall3(&libc_setitimer, uintptr(which), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(ovalue)))
    502 }
    503 
    504 //go:nosplit
    505 //go:nowritebarrierrec
    506 func sigaction(sig uint32, act *sigactiont, oact *sigactiont) /* int32 */ {
    507 	sysvicall3(&libc_sigaction, uintptr(sig), uintptr(unsafe.Pointer(act)), uintptr(unsafe.Pointer(oact)))
    508 }
    509 
    510 //go:nosplit
    511 //go:nowritebarrierrec
    512 func sigaltstack(ss *stackt, oss *stackt) /* int32 */ {
    513 	sysvicall2(&libc_sigaltstack, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(oss)))
    514 }
    515 
    516 //go:nosplit
    517 //go:nowritebarrierrec
    518 func sigprocmask(how int32, set *sigset, oset *sigset) /* int32 */ {
    519 	sysvicall3(&libc_sigprocmask, uintptr(how), uintptr(unsafe.Pointer(set)), uintptr(unsafe.Pointer(oset)))
    520 }
    521 
    522 func sysconf(name int32) int64 {
    523 	return int64(sysvicall1(&libc_sysconf, uintptr(name)))
    524 }
    525 
    526 func usleep1(usec uint32)
    527 
    528 //go:nosplit
    529 func usleep(s uint32) {
    530 	usleep1(s)
    531 }
    532 
    533 //go:nosplit
    534 func write(fd uintptr, buf unsafe.Pointer, nbyte int32) int32 {
    535 	return int32(sysvicall3(&libc_write, uintptr(fd), uintptr(buf), uintptr(nbyte)))
    536 }
    537 
    538 func osyield1()
    539 
    540 //go:nosplit
    541 func osyield() {
    542 	_g_ := getg()
    543 
    544 	// Check the validity of m because we might be called in cgo callback
    545 	// path early enough where there isn't a m available yet.
    546 	if _g_ != nil && _g_.m != nil {
    547 		sysvicall0(&libc_sched_yield)
    548 		return
    549 	}
    550 	osyield1()
    551 }
    552