github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/os_aix.go (about)

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