github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/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  	"github.com/x04/go/src/internal/cpu"
    11  	"github.com/x04/go/src/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  	setupSystemConf()
    98  }
    99  
   100  // newosproc0 is a version of newosproc that can be called before the runtime
   101  // is initialized.
   102  //
   103  // This function is not safe to use after initialization as it does not pass an M as fnarg.
   104  //
   105  //go:nosplit
   106  func newosproc0(stacksize uintptr, fn *funcDescriptor) {
   107  	var (
   108  		attr	pthread_attr
   109  		oset	sigset
   110  		tid	pthread
   111  	)
   112  
   113  	if pthread_attr_init(&attr) != 0 {
   114  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   115  		exit(1)
   116  	}
   117  
   118  	if pthread_attr_setstacksize(&attr, threadStackSize) != 0 {
   119  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   120  		exit(1)
   121  	}
   122  
   123  	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   124  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   125  		exit(1)
   126  	}
   127  
   128  	// Disable signals during create, so that the new thread starts
   129  	// with signals disabled. It will enable them in minit.
   130  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   131  	var ret int32
   132  	for tries := 0; tries < 20; tries++ {
   133  		// pthread_create can fail with EAGAIN for no reasons
   134  		// but it will be ok if it retries.
   135  		ret = pthread_create(&tid, &attr, fn, nil)
   136  		if ret != _EAGAIN {
   137  			break
   138  		}
   139  		usleep(uint32(tries+1) * 1000)	// Milliseconds.
   140  	}
   141  	sigprocmask(_SIG_SETMASK, &oset, nil)
   142  	if ret != 0 {
   143  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   144  		exit(1)
   145  	}
   146  
   147  }
   148  
   149  var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
   150  
   151  // Called to do synchronous initialization of Go code built with
   152  // -buildmode=c-archive or -buildmode=c-shared.
   153  // None of the Go runtime is initialized.
   154  //go:nosplit
   155  //go:nowritebarrierrec
   156  func libpreinit() {
   157  	initsig(true)
   158  }
   159  
   160  // Ms related functions
   161  func mpreinit(mp *m) {
   162  	mp.gsignal = malg(32 * 1024)	// AIX wants >= 8K
   163  	mp.gsignal.m = mp
   164  }
   165  
   166  // errno address must be retrieved by calling _Errno libc function.
   167  // This will return a pointer to errno
   168  func miniterrno() {
   169  	mp := getg().m
   170  	r, _ := syscall0(&libc__Errno)
   171  	mp.perrno = r
   172  
   173  }
   174  
   175  func minit() {
   176  	miniterrno()
   177  	minitSignals()
   178  	getg().m.procid = uint64(pthread_self())
   179  }
   180  
   181  func unminit() {
   182  	unminitSignals()
   183  }
   184  
   185  // tstart is a function descriptor to _tstart defined in assembly.
   186  var tstart funcDescriptor
   187  
   188  func newosproc(mp *m) {
   189  	var (
   190  		attr	pthread_attr
   191  		oset	sigset
   192  		tid	pthread
   193  	)
   194  
   195  	if pthread_attr_init(&attr) != 0 {
   196  		throw("pthread_attr_init")
   197  	}
   198  
   199  	if pthread_attr_setstacksize(&attr, threadStackSize) != 0 {
   200  		throw("pthread_attr_getstacksize")
   201  	}
   202  
   203  	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   204  		throw("pthread_attr_setdetachstate")
   205  	}
   206  
   207  	// Disable signals during create, so that the new thread starts
   208  	// with signals disabled. It will enable them in minit.
   209  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   210  	var ret int32
   211  	for tries := 0; tries < 20; tries++ {
   212  		// pthread_create can fail with EAGAIN for no reasons
   213  		// but it will be ok if it retries.
   214  		ret = pthread_create(&tid, &attr, &tstart, unsafe.Pointer(mp))
   215  		if ret != _EAGAIN {
   216  			break
   217  		}
   218  		usleep(uint32(tries+1) * 1000)	// Milliseconds.
   219  	}
   220  	sigprocmask(_SIG_SETMASK, &oset, nil)
   221  	if ret != 0 {
   222  		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n")
   223  		if ret == _EAGAIN {
   224  			println("runtime: may need to increase max user processes (ulimit -u)")
   225  		}
   226  		throw("newosproc")
   227  	}
   228  
   229  }
   230  
   231  func exitThread(wait *uint32) {
   232  	// We should never reach exitThread on AIX because we let
   233  	// libc clean up threads.
   234  	throw("exitThread")
   235  }
   236  
   237  var urandom_dev = []byte("/dev/urandom\x00")
   238  
   239  //go:nosplit
   240  func getRandomData(r []byte) {
   241  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   242  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   243  	closefd(fd)
   244  	extendRandom(r, int(n))
   245  }
   246  
   247  func goenvs() {
   248  	goenvs_unix()
   249  }
   250  
   251  /* SIGNAL */
   252  
   253  const (
   254  	_NSIG = 256
   255  )
   256  
   257  // sigtramp is a function descriptor to _sigtramp defined in assembly
   258  var sigtramp funcDescriptor
   259  
   260  //go:nosplit
   261  //go:nowritebarrierrec
   262  func setsig(i uint32, fn uintptr) {
   263  	var sa sigactiont
   264  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   265  	sa.sa_mask = sigset_all
   266  	if fn == funcPC(sighandler) {
   267  		fn = uintptr(unsafe.Pointer(&sigtramp))
   268  	}
   269  	sa.sa_handler = fn
   270  	sigaction(uintptr(i), &sa, nil)
   271  
   272  }
   273  
   274  //go:nosplit
   275  //go:nowritebarrierrec
   276  func setsigstack(i uint32) {
   277  	var sa sigactiont
   278  	sigaction(uintptr(i), nil, &sa)
   279  	if sa.sa_flags&_SA_ONSTACK != 0 {
   280  		return
   281  	}
   282  	sa.sa_flags |= _SA_ONSTACK
   283  	sigaction(uintptr(i), &sa, nil)
   284  }
   285  
   286  //go:nosplit
   287  //go:nowritebarrierrec
   288  func getsig(i uint32) uintptr {
   289  	var sa sigactiont
   290  	sigaction(uintptr(i), nil, &sa)
   291  	return sa.sa_handler
   292  }
   293  
   294  // setSignaltstackSP sets the ss_sp field of a stackt.
   295  //go:nosplit
   296  func setSignalstackSP(s *stackt, sp uintptr) {
   297  	*(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
   298  }
   299  
   300  //go:nosplit
   301  func (c *sigctxt) fixsigcode(sig uint32) {
   302  	switch sig {
   303  	case _SIGPIPE:
   304  		// For SIGPIPE, c.sigcode() isn't set to _SI_USER as on Linux.
   305  		// Therefore, raisebadsignal won't raise SIGPIPE again if
   306  		// it was deliver in a non-Go thread.
   307  		c.set_sigcode(_SI_USER)
   308  	}
   309  }
   310  
   311  //go:nosplit
   312  //go:nowritebarrierrec
   313  func sigaddset(mask *sigset, i int) {
   314  	(*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63)
   315  }
   316  
   317  func sigdelset(mask *sigset, i int) {
   318  	(*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63)
   319  }
   320  
   321  const (
   322  	_CLOCK_REALTIME		= 9
   323  	_CLOCK_MONOTONIC	= 10
   324  )
   325  
   326  //go:nosplit
   327  func nanotime1() int64 {
   328  	tp := &timespec{}
   329  	if clock_gettime(_CLOCK_REALTIME, tp) != 0 {
   330  		throw("syscall clock_gettime failed")
   331  	}
   332  	return tp.tv_sec*1000000000 + tp.tv_nsec
   333  }
   334  
   335  func walltime1() (sec int64, nsec int32) {
   336  	ts := &timespec{}
   337  	if clock_gettime(_CLOCK_REALTIME, ts) != 0 {
   338  		throw("syscall clock_gettime failed")
   339  	}
   340  	return ts.tv_sec, int32(ts.tv_nsec)
   341  }
   342  
   343  const (
   344  	// getsystemcfg constants
   345  	_SC_IMPL	= 2
   346  	_IMPL_POWER8	= 0x10000
   347  	_IMPL_POWER9	= 0x20000
   348  )
   349  
   350  // setupSystemConf retrieves information about the CPU and updates
   351  // cpu.HWCap variables.
   352  func setupSystemConf() {
   353  	impl := getsystemcfg(_SC_IMPL)
   354  	if impl&_IMPL_POWER8 != 0 {
   355  		cpu.HWCap2 |= cpu.PPC_FEATURE2_ARCH_2_07
   356  	}
   357  	if impl&_IMPL_POWER9 != 0 {
   358  		cpu.HWCap2 |= cpu.PPC_FEATURE2_ARCH_3_00
   359  	}
   360  }
   361  
   362  //go:nosplit
   363  func fcntl(fd, cmd, arg int32) int32 {
   364  	r, _ := syscall3(&libc_fcntl, uintptr(fd), uintptr(cmd), uintptr(arg))
   365  	return int32(r)
   366  }
   367  
   368  //go:nosplit
   369  func closeonexec(fd int32) {
   370  	fcntl(fd, _F_SETFD, _FD_CLOEXEC)
   371  }
   372  
   373  //go:nosplit
   374  func setNonblock(fd int32) {
   375  	flags := fcntl(fd, _F_GETFL, 0)
   376  	fcntl(fd, _F_SETFL, flags|_O_NONBLOCK)
   377  }