Home | History | Annotate | Download | only in runtime
      1 // Copyright 2009 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 //extern SigTabTT runtimesigtab[];
     10 
     11 var sigset_all = ^uint32(0)
     12 
     13 func unimplemented(name string) {
     14 	println(name, "not implemented")
     15 	*(*int)(unsafe.Pointer(uintptr(1231))) = 1231
     16 }
     17 
     18 //go:nosplit
     19 func semawakeup(mp *m) {
     20 	mach_semrelease(uint32(mp.waitsema))
     21 }
     22 
     23 //go:nosplit
     24 func semacreate() uintptr {
     25 	var x uintptr
     26 	systemstack(func() {
     27 		x = uintptr(mach_semcreate())
     28 	})
     29 	return x
     30 }
     31 
     32 // BSD interface for threading.
     33 func osinit() {
     34 	// bsdthread_register delayed until end of goenvs so that we
     35 	// can look at the environment first.
     36 
     37 	ncpu = getncpu()
     38 }
     39 
     40 func getncpu() int32 {
     41 	// Use sysctl to fetch hw.ncpu.
     42 	mib := [2]uint32{6, 3}
     43 	out := uint32(0)
     44 	nout := unsafe.Sizeof(out)
     45 	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
     46 	if ret >= 0 && int32(out) > 0 {
     47 		return int32(out)
     48 	}
     49 	return 1
     50 }
     51 
     52 var urandom_dev = []byte("/dev/urandom\x00")
     53 
     54 //go:nosplit
     55 func getRandomData(r []byte) {
     56 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
     57 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
     58 	closefd(fd)
     59 	extendRandom(r, int(n))
     60 }
     61 
     62 func goenvs() {
     63 	goenvs_unix()
     64 
     65 	// Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
     66 	// but only if we're not using cgo.  If we are using cgo we need
     67 	// to let the C pthread library install its own thread-creation callback.
     68 	if !iscgo {
     69 		if bsdthread_register() != 0 {
     70 			if gogetenv("DYLD_INSERT_LIBRARIES") != "" {
     71 				throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)")
     72 			}
     73 			throw("runtime: bsdthread_register error")
     74 		}
     75 	}
     76 }
     77 
     78 // May run with m.p==nil, so write barriers are not allowed.
     79 //go:nowritebarrier
     80 func newosproc(mp *m, stk unsafe.Pointer) {
     81 	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
     82 	if false {
     83 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int(mp.tls[0]), " ostk=", &mp, "\n")
     84 	}
     85 
     86 	var oset uint32
     87 	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
     88 	errno := bsdthread_create(stk, unsafe.Pointer(mp), funcPC(mstart))
     89 	sigprocmask(_SIG_SETMASK, &oset, nil)
     90 
     91 	if errno < 0 {
     92 		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -errno, ")\n")
     93 		throw("runtime.newosproc")
     94 	}
     95 }
     96 
     97 // newosproc0 is a version of newosproc that can be called before the runtime
     98 // is initialized.
     99 //
    100 // As Go uses bsdthread_register when running without cgo, this function is
    101 // not safe to use after initialization as it does not pass an M as fnarg.
    102 //
    103 //go:nosplit
    104 func newosproc0(stacksize uintptr, fn unsafe.Pointer, fnarg uintptr) {
    105 	stack := sysAlloc(stacksize, &memstats.stacks_sys)
    106 	if stack == nil {
    107 		write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
    108 		exit(1)
    109 	}
    110 	stk := unsafe.Pointer(uintptr(stack) + stacksize)
    111 
    112 	var oset uint32
    113 	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
    114 	errno := bsdthread_create(stk, fn, fnarg)
    115 	sigprocmask(_SIG_SETMASK, &oset, nil)
    116 
    117 	if errno < 0 {
    118 		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
    119 		exit(1)
    120 	}
    121 }
    122 
    123 var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
    124 var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
    125 
    126 // Called to initialize a new m (including the bootstrap m).
    127 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
    128 func mpreinit(mp *m) {
    129 	mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
    130 	mp.gsignal.m = mp
    131 }
    132 
    133 func msigsave(mp *m) {
    134 	smask := (*uint32)(unsafe.Pointer(&mp.sigmask))
    135 	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
    136 		throw("insufficient storage for signal mask")
    137 	}
    138 	sigprocmask(_SIG_SETMASK, nil, smask)
    139 }
    140 
    141 // Called to initialize a new m (including the bootstrap m).
    142 // Called on the new thread, can not allocate memory.
    143 func minit() {
    144 	// Initialize signal handling.
    145 	_g_ := getg()
    146 	signalstack(&_g_.m.gsignal.stack)
    147 
    148 	// restore signal mask from m.sigmask and unblock essential signals
    149 	nmask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
    150 	for i := range sigtable {
    151 		if sigtable[i].flags&_SigUnblock != 0 {
    152 			nmask &^= 1 << (uint32(i) - 1)
    153 		}
    154 	}
    155 	sigprocmask(_SIG_SETMASK, &nmask, nil)
    156 }
    157 
    158 // Called from dropm to undo the effect of an minit.
    159 func unminit() {
    160 	_g_ := getg()
    161 	smask := (*uint32)(unsafe.Pointer(&_g_.m.sigmask))
    162 	sigprocmask(_SIG_SETMASK, smask, nil)
    163 	signalstack(nil)
    164 }
    165 
    166 // Mach IPC, to get at semaphores
    167 // Definitions are in /usr/include/mach on a Mac.
    168 
    169 func macherror(r int32, fn string) {
    170 	print("mach error ", fn, ": ", r, "\n")
    171 	throw("mach error")
    172 }
    173 
    174 const _DebugMach = false
    175 
    176 var zerondr machndr
    177 
    178 func mach_msgh_bits(a, b uint32) uint32 {
    179 	return a | b<<8
    180 }
    181 
    182 func mach_msg(h *machheader, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 {
    183 	// TODO: Loop on interrupt.
    184 	return mach_msg_trap(unsafe.Pointer(h), op, send_size, rcv_size, rcv_name, timeout, notify)
    185 }
    186 
    187 // Mach RPC (MIG)
    188 const (
    189 	_MinMachMsg = 48
    190 	_MachReply  = 100
    191 )
    192 
    193 type codemsg struct {
    194 	h    machheader
    195 	ndr  machndr
    196 	code int32
    197 }
    198 
    199 func machcall(h *machheader, maxsize int32, rxsize int32) int32 {
    200 	_g_ := getg()
    201 	port := _g_.m.machport
    202 	if port == 0 {
    203 		port = mach_reply_port()
    204 		_g_.m.machport = port
    205 	}
    206 
    207 	h.msgh_bits |= mach_msgh_bits(_MACH_MSG_TYPE_COPY_SEND, _MACH_MSG_TYPE_MAKE_SEND_ONCE)
    208 	h.msgh_local_port = port
    209 	h.msgh_reserved = 0
    210 	id := h.msgh_id
    211 
    212 	if _DebugMach {
    213 		p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
    214 		print("send:\t")
    215 		var i uint32
    216 		for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
    217 			print(" ", p[i])
    218 			if i%8 == 7 {
    219 				print("\n\t")
    220 			}
    221 		}
    222 		if i%8 != 0 {
    223 			print("\n")
    224 		}
    225 	}
    226 	ret := mach_msg(h, _MACH_SEND_MSG|_MACH_RCV_MSG, h.msgh_size, uint32(maxsize), port, 0, 0)
    227 	if ret != 0 {
    228 		if _DebugMach {
    229 			print("mach_msg error ", ret, "\n")
    230 		}
    231 		return ret
    232 	}
    233 	if _DebugMach {
    234 		p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
    235 		var i uint32
    236 		for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
    237 			print(" ", p[i])
    238 			if i%8 == 7 {
    239 				print("\n\t")
    240 			}
    241 		}
    242 		if i%8 != 0 {
    243 			print("\n")
    244 		}
    245 	}
    246 	if h.msgh_id != id+_MachReply {
    247 		if _DebugMach {
    248 			print("mach_msg _MachReply id mismatch ", h.msgh_id, " != ", id+_MachReply, "\n")
    249 		}
    250 		return -303 // MIG_REPLY_MISMATCH
    251 	}
    252 	// Look for a response giving the return value.
    253 	// Any call can send this back with an error,
    254 	// and some calls only have return values so they
    255 	// send it back on success too.  I don't quite see how
    256 	// you know it's one of these and not the full response
    257 	// format, so just look if the message is right.
    258 	c := (*codemsg)(unsafe.Pointer(h))
    259 	if uintptr(h.msgh_size) == unsafe.Sizeof(*c) && h.msgh_bits&_MACH_MSGH_BITS_COMPLEX == 0 {
    260 		if _DebugMach {
    261 			print("mig result ", c.code, "\n")
    262 		}
    263 		return c.code
    264 	}
    265 	if h.msgh_size != uint32(rxsize) {
    266 		if _DebugMach {
    267 			print("mach_msg _MachReply size mismatch ", h.msgh_size, " != ", rxsize, "\n")
    268 		}
    269 		return -307 // MIG_ARRAY_TOO_LARGE
    270 	}
    271 	return 0
    272 }
    273 
    274 // Semaphores!
    275 
    276 const (
    277 	tmach_semcreate = 3418
    278 	rmach_semcreate = tmach_semcreate + _MachReply
    279 
    280 	tmach_semdestroy = 3419
    281 	rmach_semdestroy = tmach_semdestroy + _MachReply
    282 
    283 	_KERN_ABORTED             = 14
    284 	_KERN_OPERATION_TIMED_OUT = 49
    285 )
    286 
    287 type tmach_semcreatemsg struct {
    288 	h      machheader
    289 	ndr    machndr
    290 	policy int32
    291 	value  int32
    292 }
    293 
    294 type rmach_semcreatemsg struct {
    295 	h         machheader
    296 	body      machbody
    297 	semaphore machport
    298 }
    299 
    300 type tmach_semdestroymsg struct {
    301 	h         machheader
    302 	body      machbody
    303 	semaphore machport
    304 }
    305 
    306 func mach_semcreate() uint32 {
    307 	var m [256]uint8
    308 	tx := (*tmach_semcreatemsg)(unsafe.Pointer(&m))
    309 	rx := (*rmach_semcreatemsg)(unsafe.Pointer(&m))
    310 
    311 	tx.h.msgh_bits = 0
    312 	tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
    313 	tx.h.msgh_remote_port = mach_task_self()
    314 	tx.h.msgh_id = tmach_semcreate
    315 	tx.ndr = zerondr
    316 
    317 	tx.policy = 0 // 0 = SYNC_POLICY_FIFO
    318 	tx.value = 0
    319 
    320 	for {
    321 		r := machcall(&tx.h, int32(unsafe.Sizeof(m)), int32(unsafe.Sizeof(*rx)))
    322 		if r == 0 {
    323 			break
    324 		}
    325 		if r == _KERN_ABORTED { // interrupted
    326 			continue
    327 		}
    328 		macherror(r, "semaphore_create")
    329 	}
    330 	if rx.body.msgh_descriptor_count != 1 {
    331 		unimplemented("mach_semcreate desc count")
    332 	}
    333 	return rx.semaphore.name
    334 }
    335 
    336 func mach_semdestroy(sem uint32) {
    337 	var m [256]uint8
    338 	tx := (*tmach_semdestroymsg)(unsafe.Pointer(&m))
    339 
    340 	tx.h.msgh_bits = _MACH_MSGH_BITS_COMPLEX
    341 	tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
    342 	tx.h.msgh_remote_port = mach_task_self()
    343 	tx.h.msgh_id = tmach_semdestroy
    344 	tx.body.msgh_descriptor_count = 1
    345 	tx.semaphore.name = sem
    346 	tx.semaphore.disposition = _MACH_MSG_TYPE_MOVE_SEND
    347 	tx.semaphore._type = 0
    348 
    349 	for {
    350 		r := machcall(&tx.h, int32(unsafe.Sizeof(m)), 0)
    351 		if r == 0 {
    352 			break
    353 		}
    354 		if r == _KERN_ABORTED { // interrupted
    355 			continue
    356 		}
    357 		macherror(r, "semaphore_destroy")
    358 	}
    359 }
    360 
    361 // The other calls have simple system call traps in sys_darwin_{amd64,386}.s
    362 
    363 func mach_semaphore_wait(sema uint32) int32
    364 func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
    365 func mach_semaphore_signal(sema uint32) int32
    366 func mach_semaphore_signal_all(sema uint32) int32
    367 
    368 func semasleep1(ns int64) int32 {
    369 	_g_ := getg()
    370 
    371 	if ns >= 0 {
    372 		var nsecs int32
    373 		secs := timediv(ns, 1000000000, &nsecs)
    374 		r := mach_semaphore_timedwait(uint32(_g_.m.waitsema), uint32(secs), uint32(nsecs))
    375 		if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT {
    376 			return -1
    377 		}
    378 		if r != 0 {
    379 			macherror(r, "semaphore_wait")
    380 		}
    381 		return 0
    382 	}
    383 
    384 	for {
    385 		r := mach_semaphore_wait(uint32(_g_.m.waitsema))
    386 		if r == 0 {
    387 			break
    388 		}
    389 		if r == _KERN_ABORTED { // interrupted
    390 			continue
    391 		}
    392 		macherror(r, "semaphore_wait")
    393 	}
    394 	return 0
    395 }
    396 
    397 //go:nosplit
    398 func semasleep(ns int64) int32 {
    399 	var r int32
    400 	systemstack(func() {
    401 		r = semasleep1(ns)
    402 	})
    403 	return r
    404 }
    405 
    406 //go:nosplit
    407 func mach_semrelease(sem uint32) {
    408 	for {
    409 		r := mach_semaphore_signal(sem)
    410 		if r == 0 {
    411 			break
    412 		}
    413 		if r == _KERN_ABORTED { // interrupted
    414 			continue
    415 		}
    416 
    417 		// mach_semrelease must be completely nosplit,
    418 		// because it is called from Go code.
    419 		// If we're going to die, start that process on the system stack
    420 		// to avoid a Go stack split.
    421 		systemstack(func() { macherror(r, "semaphore_signal") })
    422 	}
    423 }
    424 
    425 //go:nosplit
    426 func osyield() {
    427 	usleep(1)
    428 }
    429 
    430 func memlimit() uintptr {
    431 	// NOTE(rsc): Could use getrlimit here,
    432 	// like on FreeBSD or Linux, but Darwin doesn't enforce
    433 	// ulimit -v, so it's unclear why we'd try to stay within
    434 	// the limit.
    435 	return 0
    436 }
    437 
    438 func setsig(i int32, fn uintptr, restart bool) {
    439 	var sa sigactiont
    440 	memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
    441 	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
    442 	if restart {
    443 		sa.sa_flags |= _SA_RESTART
    444 	}
    445 	sa.sa_mask = ^uint32(0)
    446 	sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtimesigtramp's job is to call into real handler
    447 	*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
    448 	sigaction(uint32(i), &sa, nil)
    449 }
    450 
    451 func setsigstack(i int32) {
    452 	throw("setsigstack")
    453 }
    454 
    455 func getsig(i int32) uintptr {
    456 	var sa sigactiont
    457 	memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
    458 	sigaction(uint32(i), nil, &sa)
    459 	return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
    460 }
    461 
    462 func signalstack(s *stack) {
    463 	var st stackt
    464 	if s == nil {
    465 		st.ss_flags = _SS_DISABLE
    466 	} else {
    467 		st.ss_sp = (*byte)(unsafe.Pointer(s.lo))
    468 		st.ss_size = s.hi - s.lo
    469 		st.ss_flags = 0
    470 	}
    471 	sigaltstack(&st, nil)
    472 }
    473 
    474 func updatesigmask(m sigmask) {
    475 	sigprocmask(_SIG_SETMASK, &m[0], nil)
    476 }
    477 
    478 func unblocksig(sig int32) {
    479 	mask := uint32(1) << (uint32(sig) - 1)
    480 	sigprocmask(_SIG_UNBLOCK, &mask, nil)
    481 }
    482