github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/src/runtime/os1_darwin.go (about)

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