...

Source file src/runtime/os_darwin.go

     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	type mOS struct {
    10		initialized bool
    11		mutex       pthreadmutex
    12		cond        pthreadcond
    13		count       int
    14	}
    15	
    16	func unimplemented(name string) {
    17		println(name, "not implemented")
    18		*(*int)(unsafe.Pointer(uintptr(1231))) = 1231
    19	}
    20	
    21	//go:nosplit
    22	func semacreate(mp *m) {
    23		if mp.initialized {
    24			return
    25		}
    26		mp.initialized = true
    27		if err := pthread_mutex_init(&mp.mutex, nil); err != 0 {
    28			throw("pthread_mutex_init")
    29		}
    30		if err := pthread_cond_init(&mp.cond, nil); err != 0 {
    31			throw("pthread_cond_init")
    32		}
    33	}
    34	
    35	//go:nosplit
    36	func semasleep(ns int64) int32 {
    37		var start int64
    38		if ns >= 0 {
    39			start = nanotime()
    40		}
    41		mp := getg().m
    42		pthread_mutex_lock(&mp.mutex)
    43		for {
    44			if mp.count > 0 {
    45				mp.count--
    46				pthread_mutex_unlock(&mp.mutex)
    47				return 0
    48			}
    49			if ns >= 0 {
    50				spent := nanotime() - start
    51				if spent >= ns {
    52					pthread_mutex_unlock(&mp.mutex)
    53					return -1
    54				}
    55				var t timespec
    56				t.setNsec(ns - spent)
    57				err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
    58				if err == _ETIMEDOUT {
    59					pthread_mutex_unlock(&mp.mutex)
    60					return -1
    61				}
    62			} else {
    63				pthread_cond_wait(&mp.cond, &mp.mutex)
    64			}
    65		}
    66	}
    67	
    68	//go:nosplit
    69	func semawakeup(mp *m) {
    70		pthread_mutex_lock(&mp.mutex)
    71		mp.count++
    72		if mp.count > 0 {
    73			pthread_cond_signal(&mp.cond)
    74		}
    75		pthread_mutex_unlock(&mp.mutex)
    76	}
    77	
    78	// The read and write file descriptors used by the sigNote functions.
    79	var sigNoteRead, sigNoteWrite int32
    80	
    81	// sigNoteSetup initializes an async-signal-safe note.
    82	//
    83	// The current implementation of notes on Darwin is not async-signal-safe,
    84	// because the functions pthread_mutex_lock, pthread_cond_signal, and
    85	// pthread_mutex_unlock, called by semawakeup, are not async-signal-safe.
    86	// There is only one case where we need to wake up a note from a signal
    87	// handler: the sigsend function. The signal handler code does not require
    88	// all the features of notes: it does not need to do a timed wait.
    89	// This is a separate implementation of notes, based on a pipe, that does
    90	// not support timed waits but is async-signal-safe.
    91	func sigNoteSetup(*note) {
    92		if sigNoteRead != 0 || sigNoteWrite != 0 {
    93			throw("duplicate sigNoteSetup")
    94		}
    95		var errno int32
    96		sigNoteRead, sigNoteWrite, errno = pipe()
    97		if errno != 0 {
    98			throw("pipe failed")
    99		}
   100		closeonexec(sigNoteRead)
   101		closeonexec(sigNoteWrite)
   102	
   103		// Make the write end of the pipe non-blocking, so that if the pipe
   104		// buffer is somehow full we will not block in the signal handler.
   105		// Leave the read end of the pipe blocking so that we will block
   106		// in sigNoteSleep.
   107		setNonblock(sigNoteWrite)
   108	}
   109	
   110	// sigNoteWakeup wakes up a thread sleeping on a note created by sigNoteSetup.
   111	func sigNoteWakeup(*note) {
   112		var b byte
   113		write(uintptr(sigNoteWrite), unsafe.Pointer(&b), 1)
   114	}
   115	
   116	// sigNoteSleep waits for a note created by sigNoteSetup to be woken.
   117	func sigNoteSleep(*note) {
   118		entersyscallblock()
   119		var b byte
   120		read(sigNoteRead, unsafe.Pointer(&b), 1)
   121		exitsyscall()
   122	}
   123	
   124	// BSD interface for threading.
   125	func osinit() {
   126		// pthread_create delayed until end of goenvs so that we
   127		// can look at the environment first.
   128	
   129		ncpu = getncpu()
   130		physPageSize = getPageSize()
   131	}
   132	
   133	const (
   134		_CTL_HW      = 6
   135		_HW_NCPU     = 3
   136		_HW_PAGESIZE = 7
   137	)
   138	
   139	func getncpu() int32 {
   140		// Use sysctl to fetch hw.ncpu.
   141		mib := [2]uint32{_CTL_HW, _HW_NCPU}
   142		out := uint32(0)
   143		nout := unsafe.Sizeof(out)
   144		ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   145		if ret >= 0 && int32(out) > 0 {
   146			return int32(out)
   147		}
   148		return 1
   149	}
   150	
   151	func getPageSize() uintptr {
   152		// Use sysctl to fetch hw.pagesize.
   153		mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
   154		out := uint32(0)
   155		nout := unsafe.Sizeof(out)
   156		ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   157		if ret >= 0 && int32(out) > 0 {
   158			return uintptr(out)
   159		}
   160		return 0
   161	}
   162	
   163	var urandom_dev = []byte("/dev/urandom\x00")
   164	
   165	//go:nosplit
   166	func getRandomData(r []byte) {
   167		fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   168		n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   169		closefd(fd)
   170		extendRandom(r, int(n))
   171	}
   172	
   173	func goenvs() {
   174		goenvs_unix()
   175	}
   176	
   177	// May run with m.p==nil, so write barriers are not allowed.
   178	//go:nowritebarrierrec
   179	func newosproc(mp *m) {
   180		stk := unsafe.Pointer(mp.g0.stack.hi)
   181		if false {
   182			print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
   183		}
   184	
   185		// Initialize an attribute object.
   186		var attr pthreadattr
   187		var err int32
   188		err = pthread_attr_init(&attr)
   189		if err != 0 {
   190			write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   191			exit(1)
   192		}
   193	
   194		// Find out OS stack size for our own stack guard.
   195		var stacksize uintptr
   196		if pthread_attr_getstacksize(&attr, &stacksize) != 0 {
   197			write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   198			exit(1)
   199		}
   200		mp.g0.stack.hi = stacksize // for mstart
   201		//mSysStatInc(&memstats.stacks_sys, stacksize) //TODO: do this?
   202	
   203		// Tell the pthread library we won't join with this thread.
   204		if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   205			write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   206			exit(1)
   207		}
   208	
   209		// Finally, create the thread. It starts at mstart_stub, which does some low-level
   210		// setup and then calls mstart.
   211		var oset sigset
   212		sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   213		err = pthread_create(&attr, funcPC(mstart_stub), unsafe.Pointer(mp))
   214		sigprocmask(_SIG_SETMASK, &oset, nil)
   215		if err != 0 {
   216			write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   217			exit(1)
   218		}
   219	}
   220	
   221	// glue code to call mstart from pthread_create.
   222	func mstart_stub()
   223	
   224	// newosproc0 is a version of newosproc that can be called before the runtime
   225	// is initialized.
   226	//
   227	// This function is not safe to use after initialization as it does not pass an M as fnarg.
   228	//
   229	//go:nosplit
   230	func newosproc0(stacksize uintptr, fn uintptr) {
   231		// Initialize an attribute object.
   232		var attr pthreadattr
   233		var err int32
   234		err = pthread_attr_init(&attr)
   235		if err != 0 {
   236			write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   237			exit(1)
   238		}
   239	
   240		// The caller passes in a suggested stack size,
   241		// from when we allocated the stack and thread ourselves,
   242		// without libpthread. Now that we're using libpthread,
   243		// we use the OS default stack size instead of the suggestion.
   244		// Find out that stack size for our own stack guard.
   245		if pthread_attr_getstacksize(&attr, &stacksize) != 0 {
   246			write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   247			exit(1)
   248		}
   249		g0.stack.hi = stacksize // for mstart
   250		mSysStatInc(&memstats.stacks_sys, stacksize)
   251	
   252		// Tell the pthread library we won't join with this thread.
   253		if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   254			write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   255			exit(1)
   256		}
   257	
   258		// Finally, create the thread. It starts at mstart_stub, which does some low-level
   259		// setup and then calls mstart.
   260		var oset sigset
   261		sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   262		err = pthread_create(&attr, fn, nil)
   263		sigprocmask(_SIG_SETMASK, &oset, nil)
   264		if err != 0 {
   265			write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   266			exit(1)
   267		}
   268	}
   269	
   270	var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
   271	var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
   272	
   273	// Called to do synchronous initialization of Go code built with
   274	// -buildmode=c-archive or -buildmode=c-shared.
   275	// None of the Go runtime is initialized.
   276	//go:nosplit
   277	//go:nowritebarrierrec
   278	func libpreinit() {
   279		initsig(true)
   280	}
   281	
   282	// Called to initialize a new m (including the bootstrap m).
   283	// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   284	func mpreinit(mp *m) {
   285		mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
   286		mp.gsignal.m = mp
   287	}
   288	
   289	// Called to initialize a new m (including the bootstrap m).
   290	// Called on the new thread, cannot allocate memory.
   291	func minit() {
   292		// The alternate signal stack is buggy on arm and arm64.
   293		// The signal handler handles it directly.
   294		if GOARCH != "arm" && GOARCH != "arm64" {
   295			minitSignalStack()
   296		}
   297		minitSignalMask()
   298	}
   299	
   300	// Called from dropm to undo the effect of an minit.
   301	//go:nosplit
   302	func unminit() {
   303		// The alternate signal stack is buggy on arm and arm64.
   304		// See minit.
   305		if GOARCH != "arm" && GOARCH != "arm64" {
   306			unminitSignals()
   307		}
   308	}
   309	
   310	//go:nosplit
   311	func osyield() {
   312		usleep(1)
   313	}
   314	
   315	const (
   316		_NSIG        = 32
   317		_SI_USER     = 0 /* empirically true, but not what headers say */
   318		_SIG_BLOCK   = 1
   319		_SIG_UNBLOCK = 2
   320		_SIG_SETMASK = 3
   321		_SS_DISABLE  = 4
   322	)
   323	
   324	//extern SigTabTT runtimeĀ·sigtab[];
   325	
   326	type sigset uint32
   327	
   328	var sigset_all = ^sigset(0)
   329	
   330	//go:nosplit
   331	//go:nowritebarrierrec
   332	func setsig(i uint32, fn uintptr) {
   333		var sa usigactiont
   334		sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   335		sa.sa_mask = ^uint32(0)
   336		if fn == funcPC(sighandler) {
   337			if iscgo {
   338				fn = funcPC(cgoSigtramp)
   339			} else {
   340				fn = funcPC(sigtramp)
   341			}
   342		}
   343		*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
   344		sigaction(i, &sa, nil)
   345	}
   346	
   347	// sigtramp is the callback from libc when a signal is received.
   348	// It is called with the C calling convention.
   349	func sigtramp()
   350	func cgoSigtramp()
   351	
   352	//go:nosplit
   353	//go:nowritebarrierrec
   354	func setsigstack(i uint32) {
   355		var osa usigactiont
   356		sigaction(i, nil, &osa)
   357		handler := *(*uintptr)(unsafe.Pointer(&osa.__sigaction_u))
   358		if osa.sa_flags&_SA_ONSTACK != 0 {
   359			return
   360		}
   361		var sa usigactiont
   362		*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler
   363		sa.sa_mask = osa.sa_mask
   364		sa.sa_flags = osa.sa_flags | _SA_ONSTACK
   365		sigaction(i, &sa, nil)
   366	}
   367	
   368	//go:nosplit
   369	//go:nowritebarrierrec
   370	func getsig(i uint32) uintptr {
   371		var sa usigactiont
   372		sigaction(i, nil, &sa)
   373		return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
   374	}
   375	
   376	// setSignaltstackSP sets the ss_sp field of a stackt.
   377	//go:nosplit
   378	func setSignalstackSP(s *stackt, sp uintptr) {
   379		*(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
   380	}
   381	
   382	//go:nosplit
   383	//go:nowritebarrierrec
   384	func sigaddset(mask *sigset, i int) {
   385		*mask |= 1 << (uint32(i) - 1)
   386	}
   387	
   388	func sigdelset(mask *sigset, i int) {
   389		*mask &^= 1 << (uint32(i) - 1)
   390	}
   391	
   392	//go:linkname executablePath os.executablePath
   393	var executablePath string
   394	
   395	func sysargs(argc int32, argv **byte) {
   396		// skip over argv, envv and the first string will be the path
   397		n := argc + 1
   398		for argv_index(argv, n) != nil {
   399			n++
   400		}
   401		executablePath = gostringnocopy(argv_index(argv, n+1))
   402	
   403		// strip "executable_path=" prefix if available, it's added after OS X 10.11.
   404		const prefix = "executable_path="
   405		if len(executablePath) > len(prefix) && executablePath[:len(prefix)] == prefix {
   406			executablePath = executablePath[len(prefix):]
   407		}
   408	}
   409	

View as plain text