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