Black Lives Matter. Support the Equal Justice Initiative.

Source file src/runtime/os_aix.go

Documentation: runtime

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

View as plain text