github.com/zxy12/golang151_with_comment@v0.0.0-20190507085033-721809559d3c/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  	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)) // runtimeĀ·sigtramp'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  }