Source file src/runtime/os_aix.go

     1  // Copyright 2018 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  //go:build aix
     6  
     7  package runtime
     8  
     9  import (
    10  	"internal/abi"
    11  	"internal/runtime/atomic"
    12  	"unsafe"
    13  )
    14  
    15  const (
    16  	threadStackSize = 0x100000 // size of a thread stack allocated by OS
    17  )
    18  
    19  // funcDescriptor is a structure representing a function descriptor
    20  // A variable with this type is always created in assembler
    21  type funcDescriptor struct {
    22  	fn         uintptr
    23  	toc        uintptr
    24  	envPointer uintptr // unused in Golang
    25  }
    26  
    27  type mOS struct {
    28  	waitsema uintptr // semaphore for parking on locks
    29  	perrno   uintptr // pointer to tls errno
    30  	libcall  libcall
    31  }
    32  
    33  //go:nosplit
    34  func semacreate(mp *m) {
    35  	if mp.waitsema != 0 {
    36  		return
    37  	}
    38  
    39  	var sem *semt
    40  
    41  	// Call libc's malloc rather than malloc. This will
    42  	// allocate space on the C heap. We can't call mallocgc
    43  	// here because it could cause a deadlock.
    44  	sem = (*semt)(malloc(unsafe.Sizeof(*sem)))
    45  	if sem_init(sem, 0, 0) != 0 {
    46  		throw("sem_init")
    47  	}
    48  	mp.waitsema = uintptr(unsafe.Pointer(sem))
    49  }
    50  
    51  //go:nosplit
    52  func semasleep(ns int64) int32 {
    53  	mp := getg().m
    54  	if ns >= 0 {
    55  		var ts timespec
    56  
    57  		if clock_gettime(_CLOCK_REALTIME, &ts) != 0 {
    58  			throw("clock_gettime")
    59  		}
    60  		ts.tv_sec += ns / 1e9
    61  		ts.tv_nsec += ns % 1e9
    62  		if ts.tv_nsec >= 1e9 {
    63  			ts.tv_sec++
    64  			ts.tv_nsec -= 1e9
    65  		}
    66  
    67  		if r, err := sem_timedwait((*semt)(unsafe.Pointer(mp.waitsema)), &ts); r != 0 {
    68  			if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR {
    69  				return -1
    70  			}
    71  			println("sem_timedwait err ", err, " ts.tv_sec ", ts.tv_sec, " ts.tv_nsec ", ts.tv_nsec, " ns ", ns, " id ", mp.id)
    72  			throw("sem_timedwait")
    73  		}
    74  		return 0
    75  	}
    76  	for {
    77  		r1, err := sem_wait((*semt)(unsafe.Pointer(mp.waitsema)))
    78  		if r1 == 0 {
    79  			break
    80  		}
    81  		if err == _EINTR {
    82  			continue
    83  		}
    84  		throw("sem_wait")
    85  	}
    86  	return 0
    87  }
    88  
    89  //go:nosplit
    90  func semawakeup(mp *m) {
    91  	if sem_post((*semt)(unsafe.Pointer(mp.waitsema))) != 0 {
    92  		throw("sem_post")
    93  	}
    94  }
    95  
    96  func osinit() {
    97  	// Call miniterrno so that we can safely make system calls
    98  	// before calling minit on m0.
    99  	miniterrno()
   100  
   101  	numCPUStartup = getCPUCount()
   102  	physPageSize = sysconf(__SC_PAGE_SIZE)
   103  }
   104  
   105  func getCPUCount() int32 {
   106  	return int32(sysconf(__SC_NPROCESSORS_ONLN))
   107  }
   108  
   109  // newosproc0 is a version of newosproc that can be called before the runtime
   110  // is initialized.
   111  //
   112  // This function is not safe to use after initialization as it does not pass an M as fnarg.
   113  //
   114  //go:nosplit
   115  func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
   116  	var (
   117  		attr pthread_attr
   118  		oset sigset
   119  		tid  pthread
   120  	)
   121  
   122  	if pthread_attr_init(&attr) != 0 {
   123  		writeErrStr(failthreadcreate)
   124  		exit(1)
   125  	}
   126  
   127  	if pthread_attr_setstacksize(&attr, threadStackSize) != 0 {
   128  		writeErrStr(failthreadcreate)
   129  		exit(1)
   130  	}
   131  
   132  	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   133  		writeErrStr(failthreadcreate)
   134  		exit(1)
   135  	}
   136  
   137  	// Disable signals during create, so that the new thread starts
   138  	// with signals disabled. It will enable them in minit.
   139  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   140  	var ret int32
   141  	for tries := 0; tries < 20; tries++ {
   142  		// pthread_create can fail with EAGAIN for no reasons
   143  		// but it will be ok if it retries.
   144  		ret = pthread_create(&tid, &attr, fn, nil)
   145  		if ret != _EAGAIN {
   146  			break
   147  		}
   148  		usleep(uint32(tries+1) * 1000) // Milliseconds.
   149  	}
   150  	sigprocmask(_SIG_SETMASK, &oset, nil)
   151  	if ret != 0 {
   152  		writeErrStr(failthreadcreate)
   153  		exit(1)
   154  	}
   155  
   156  }
   157  
   158  // Called to do synchronous initialization of Go code built with
   159  // -buildmode=c-archive or -buildmode=c-shared.
   160  // None of the Go runtime is initialized.
   161  //
   162  //go:nosplit
   163  //go:nowritebarrierrec
   164  func libpreinit() {
   165  	// On AIX, pthread_create expects a function descriptor pointer,
   166  	// not a raw code address. Set rt0LibGoFn to the descriptor
   167  	// so that libInit passes the right value.
   168  	rt0LibGoFn = uintptr(unsafe.Pointer(&rt0LibGoDesc))
   169  	initsig(true)
   170  }
   171  
   172  // Ms related functions
   173  func mpreinit(mp *m) {
   174  	mp.gsignal = malg(32 * 1024) // AIX wants >= 8K
   175  	mp.gsignal.m = mp
   176  }
   177  
   178  // errno address must be retrieved by calling _Errno libc function.
   179  // This will return a pointer to errno.
   180  func miniterrno() {
   181  	mp := getg().m
   182  	r, _ := syscall0(&libc__Errno)
   183  	mp.perrno = r
   184  
   185  }
   186  
   187  func minit() {
   188  	miniterrno()
   189  	minitSignals()
   190  	getg().m.procid = uint64(pthread_self())
   191  }
   192  
   193  func unminit() {
   194  	unminitSignals()
   195  	getg().m.procid = 0
   196  }
   197  
   198  // Called from mexit, but not from dropm, to undo the effect of thread-owned
   199  // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
   200  //
   201  // This always runs without a P, so //go:nowritebarrierrec is required.
   202  //
   203  //go:nowritebarrierrec
   204  func mdestroy(mp *m) {
   205  }
   206  
   207  // tstart is a function descriptor to _tstart defined in assembly.
   208  var tstart funcDescriptor
   209  
   210  // rt0LibGoDesc is a function descriptor to rt0_lib_go defined in assembly.
   211  var rt0LibGoDesc funcDescriptor
   212  
   213  func newosproc(mp *m) {
   214  	var (
   215  		attr pthread_attr
   216  		oset sigset
   217  		tid  pthread
   218  	)
   219  
   220  	if pthread_attr_init(&attr) != 0 {
   221  		throw("pthread_attr_init")
   222  	}
   223  
   224  	if pthread_attr_setstacksize(&attr, threadStackSize) != 0 {
   225  		throw("pthread_attr_getstacksize")
   226  	}
   227  
   228  	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   229  		throw("pthread_attr_setdetachstate")
   230  	}
   231  
   232  	// Disable signals during create, so that the new thread starts
   233  	// with signals disabled. It will enable them in minit.
   234  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   235  	ret := retryOnEAGAIN(func() int32 {
   236  		return pthread_create(&tid, &attr, unsafe.Pointer(&tstart), unsafe.Pointer(mp))
   237  	})
   238  	sigprocmask(_SIG_SETMASK, &oset, nil)
   239  	if ret != 0 {
   240  		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n")
   241  		if ret == _EAGAIN {
   242  			println("runtime: may need to increase max user processes (ulimit -u)")
   243  		}
   244  		throw("newosproc")
   245  	}
   246  
   247  }
   248  
   249  func exitThread(wait *atomic.Uint32) {
   250  	// We should never reach exitThread on AIX because we let
   251  	// libc clean up threads.
   252  	throw("exitThread")
   253  }
   254  
   255  var urandom_dev = []byte("/dev/urandom\x00")
   256  
   257  //go:nosplit
   258  func readRandom(r []byte) int {
   259  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   260  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   261  	closefd(fd)
   262  	return int(n)
   263  }
   264  
   265  func goenvs() {
   266  	goenvs_unix()
   267  }
   268  
   269  /* SIGNAL */
   270  
   271  const (
   272  	_NSIG = 256
   273  )
   274  
   275  // sigtramp is a function descriptor to _sigtramp defined in assembly
   276  var sigtramp funcDescriptor
   277  
   278  //go:nosplit
   279  //go:nowritebarrierrec
   280  func setsig(i uint32, fn uintptr) {
   281  	var sa sigactiont
   282  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   283  	sa.sa_mask = sigset_all
   284  	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
   285  		fn = uintptr(unsafe.Pointer(&sigtramp))
   286  	}
   287  	sa.sa_handler = fn
   288  	sigaction(uintptr(i), &sa, nil)
   289  
   290  }
   291  
   292  //go:nosplit
   293  //go:nowritebarrierrec
   294  func setsigstack(i uint32) {
   295  	var sa sigactiont
   296  	sigaction(uintptr(i), nil, &sa)
   297  	if sa.sa_flags&_SA_ONSTACK != 0 {
   298  		return
   299  	}
   300  	sa.sa_flags |= _SA_ONSTACK
   301  	sigaction(uintptr(i), &sa, nil)
   302  }
   303  
   304  //go:nosplit
   305  //go:nowritebarrierrec
   306  func getsig(i uint32) uintptr {
   307  	var sa sigactiont
   308  	sigaction(uintptr(i), nil, &sa)
   309  	return sa.sa_handler
   310  }
   311  
   312  // setSignalstackSP sets the ss_sp field of a stackt.
   313  //
   314  //go:nosplit
   315  func setSignalstackSP(s *stackt, sp uintptr) {
   316  	*(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
   317  }
   318  
   319  //go:nosplit
   320  func (c *sigctxt) fixsigcode(sig uint32) {
   321  	switch sig {
   322  	case _SIGPIPE:
   323  		// For SIGPIPE, c.sigcode() isn't set to _SI_USER as on Linux.
   324  		// Therefore, raisebadsignal won't raise SIGPIPE again if
   325  		// it was deliver in a non-Go thread.
   326  		c.set_sigcode(_SI_USER)
   327  	}
   328  }
   329  
   330  //go:nosplit
   331  //go:nowritebarrierrec
   332  func sigaddset(mask *sigset, i int) {
   333  	(*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63)
   334  }
   335  
   336  func sigdelset(mask *sigset, i int) {
   337  	(*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63)
   338  }
   339  
   340  func setProcessCPUProfiler(hz int32) {
   341  	setProcessCPUProfilerTimer(hz)
   342  }
   343  
   344  func setThreadCPUProfiler(hz int32) {
   345  	setThreadCPUProfilerHz(hz)
   346  }
   347  
   348  //go:nosplit
   349  func validSIGPROF(mp *m, c *sigctxt) bool {
   350  	return true
   351  }
   352  
   353  const (
   354  	_CLOCK_REALTIME  = 9
   355  	_CLOCK_MONOTONIC = 10
   356  )
   357  
   358  //go:nosplit
   359  func nanotime1() int64 {
   360  	tp := &timespec{}
   361  	if clock_gettime(_CLOCK_REALTIME, tp) != 0 {
   362  		throw("syscall clock_gettime failed")
   363  	}
   364  	return tp.tv_sec*1000000000 + tp.tv_nsec
   365  }
   366  
   367  func walltime() (sec int64, nsec int32) {
   368  	ts := &timespec{}
   369  	if clock_gettime(_CLOCK_REALTIME, ts) != 0 {
   370  		throw("syscall clock_gettime failed")
   371  	}
   372  	return ts.tv_sec, int32(ts.tv_nsec)
   373  }
   374  
   375  //go:nosplit
   376  func fcntl(fd, cmd, arg int32) (int32, int32) {
   377  	r, errno := syscall3(&libc_fcntl, uintptr(fd), uintptr(cmd), uintptr(arg))
   378  	return int32(r), int32(errno)
   379  }
   380  
   381  //go:nosplit
   382  func setNonblock(fd int32) {
   383  	flags, _ := fcntl(fd, _F_GETFL, 0)
   384  	if flags != -1 {
   385  		fcntl(fd, _F_SETFL, flags|_O_NONBLOCK)
   386  	}
   387  }
   388  
   389  // sigPerThreadSyscall is only used on linux, so we assign a bogus signal
   390  // number.
   391  const sigPerThreadSyscall = 1 << 31
   392  
   393  //go:nosplit
   394  func runPerThreadSyscall() {
   395  	throw("runPerThreadSyscall only valid on linux")
   396  }
   397  
   398  //go:nosplit
   399  func getuid() int32 {
   400  	r, errno := syscall0(&libc_getuid)
   401  	if errno != 0 {
   402  		print("getuid failed ", errno)
   403  		throw("getuid")
   404  	}
   405  	return int32(r)
   406  }
   407  
   408  //go:nosplit
   409  func geteuid() int32 {
   410  	r, errno := syscall0(&libc_geteuid)
   411  	if errno != 0 {
   412  		print("geteuid failed ", errno)
   413  		throw("geteuid")
   414  	}
   415  	return int32(r)
   416  }
   417  
   418  //go:nosplit
   419  func getgid() int32 {
   420  	r, errno := syscall0(&libc_getgid)
   421  	if errno != 0 {
   422  		print("getgid failed ", errno)
   423  		throw("getgid")
   424  	}
   425  	return int32(r)
   426  }
   427  
   428  //go:nosplit
   429  func getegid() int32 {
   430  	r, errno := syscall0(&libc_getegid)
   431  	if errno != 0 {
   432  		print("getegid failed ", errno)
   433  		throw("getegid")
   434  	}
   435  	return int32(r)
   436  }
   437  

View as plain text