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

View as plain text