| // Copyright 2014 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | package runtime | 
 |  | 
 | import ( | 
 | 	"runtime/internal/atomic" | 
 | 	"runtime/internal/sys" | 
 | 	"unsafe" | 
 | ) | 
 |  | 
 | type mOS struct { | 
 | 	waitsemacount uint32 | 
 | } | 
 |  | 
 | func getProcID() uint64 { | 
 | 	return uint64(lwp_self()) | 
 | } | 
 |  | 
 | //extern-sysinfo _lwp_self | 
 | func lwp_self() int32 | 
 |  | 
 | //go:noescape | 
 | //extern-sysinfo _lwp_park | 
 | func lwp_park(ts int32, rel int32, abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32 | 
 |  | 
 | //go:noescape | 
 | //extern-sysinfo _lwp_unpark | 
 | func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 | 
 |  | 
 | //go:noescape | 
 | //extern-sysinfo sysctl | 
 | func sysctl(*uint32, uint32, *byte, *uintptr, *byte, uintptr) int32 | 
 |  | 
 | func sysctlInt(mib []uint32) (int32, bool) { | 
 | 	var out int32 | 
 | 	nout := unsafe.Sizeof(out) | 
 | 	ret := sysctl(&mib[0], uint32(len(mib)), (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) | 
 | 	if ret < 0 { | 
 | 		return 0, false | 
 | 	} | 
 | 	return out, true | 
 | } | 
 |  | 
 | func getncpu() int32 { | 
 | 	if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPUONLINE}); ok { | 
 | 		return int32(n) | 
 | 	} | 
 | 	if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPU}); ok { | 
 | 		return int32(n) | 
 | 	} | 
 | 	return 1 | 
 | } | 
 |  | 
 | func getPageSize() uintptr { | 
 | 	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE} | 
 | 	out := uint32(0) | 
 | 	nout := unsafe.Sizeof(out) | 
 | 	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) | 
 | 	if ret >= 0 { | 
 | 		return uintptr(out) | 
 | 	} | 
 | 	return 0 | 
 | } | 
 |  | 
 | //go:nosplit | 
 | func semacreate(mp *m) { | 
 | } | 
 |  | 
 | //go:nosplit | 
 | func semasleep(ns int64) int32 { | 
 | 	_g_ := getg() | 
 | 	var deadline int64 | 
 | 	if ns >= 0 { | 
 | 		deadline = nanotime() + ns | 
 | 	} | 
 |  | 
 | 	for { | 
 | 		v := atomic.Load(&_g_.m.waitsemacount) | 
 | 		if v > 0 { | 
 | 			if atomic.Cas(&_g_.m.waitsemacount, v, v-1) { | 
 | 				return 0 // semaphore acquired | 
 | 			} | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		// Sleep until unparked by semawakeup or timeout. | 
 | 		var tsp *timespec | 
 | 		var ts timespec | 
 | 		if ns >= 0 { | 
 | 			wait := deadline - nanotime() | 
 | 			if wait <= 0 { | 
 | 				return -1 | 
 | 			} | 
 | 			ts.setNsec(wait) | 
 | 			tsp = &ts | 
 | 		} | 
 | 		ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) | 
 | 		if ret != 0 && errno() == _ETIMEDOUT { | 
 | 			return -1 | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | //go:nosplit | 
 | func semawakeup(mp *m) { | 
 | 	atomic.Xadd(&mp.waitsemacount, 1) | 
 | 	// From NetBSD's _lwp_unpark(2) manual: | 
 | 	// "If the target LWP is not currently waiting, it will return | 
 | 	// immediately upon the next call to _lwp_park()." | 
 | 	ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount)) | 
 | 	if ret != 0 && errno() != _ESRCH { | 
 | 		// semawakeup can be called on signal stack. | 
 | 		systemstack(func() { | 
 | 			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " errno=", errno(), "\n") | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | func osinit() { | 
 | 	ncpu = getncpu() | 
 | 	if physPageSize == 0 { | 
 | 		physPageSize = getPageSize() | 
 | 	} | 
 | } | 
 |  | 
 | func sysargs(argc int32, argv **byte) { | 
 | 	n := argc + 1 | 
 |  | 
 | 	// skip over argv, envp to get to auxv | 
 | 	for argv_index(argv, n) != nil { | 
 | 		n++ | 
 | 	} | 
 |  | 
 | 	// skip NULL separator | 
 | 	n++ | 
 |  | 
 | 	// now argv+n is auxv | 
 | 	auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) | 
 | 	sysauxv(auxv[:]) | 
 | } | 
 |  | 
 | const ( | 
 | 	_AT_NULL   = 0 // Terminates the vector | 
 | 	_AT_PAGESZ = 6 // Page size in bytes | 
 | ) | 
 |  | 
 | func sysauxv(auxv []uintptr) { | 
 | 	for i := 0; auxv[i] != _AT_NULL; i += 2 { | 
 | 		tag, val := auxv[i], auxv[i+1] | 
 | 		switch tag { | 
 | 		case _AT_PAGESZ: | 
 | 			physPageSize = val | 
 | 		} | 
 | 	} | 
 | } |