github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/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  // Ms related functions
    99  func mpreinit(mp *m) {
   100  	mp.gsignal = malg(32 * 1024) // AIX wants >= 8K
   101  	mp.gsignal.m = mp
   102  }
   103  
   104  // errno address must be retrieved by calling _Errno libc function.
   105  // This will return a pointer to errno
   106  func miniterrno() {
   107  	mp := getg().m
   108  	r, _ := syscall0(&libc__Errno)
   109  	mp.perrno = r
   110  
   111  }
   112  
   113  func minit() {
   114  	miniterrno()
   115  	minitSignals()
   116  }
   117  
   118  func unminit() {
   119  	unminitSignals()
   120  }
   121  
   122  // tstart is a function descriptor to _tstart defined in assembly.
   123  var tstart funcDescriptor
   124  
   125  func newosproc(mp *m) {
   126  	var (
   127  		attr pthread_attr
   128  		oset sigset
   129  		tid  pthread
   130  	)
   131  
   132  	if pthread_attr_init(&attr) != 0 {
   133  		throw("pthread_attr_init")
   134  	}
   135  
   136  	if pthread_attr_setstacksize(&attr, threadStackSize) != 0 {
   137  		throw("pthread_attr_getstacksize")
   138  	}
   139  
   140  	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   141  		throw("pthread_attr_setdetachstate")
   142  	}
   143  
   144  	// Disable signals during create, so that the new thread starts
   145  	// with signals disabled. It will enable them in minit.
   146  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   147  	var ret int32
   148  	for tries := 0; tries < 20; tries++ {
   149  		// pthread_create can fail with EAGAIN for no reasons
   150  		// but it will be ok if it retries.
   151  		ret = pthread_create(&tid, &attr, &tstart, unsafe.Pointer(mp))
   152  		if ret != _EAGAIN {
   153  			break
   154  		}
   155  		usleep(uint32(tries+1) * 1000) // Milliseconds.
   156  	}
   157  	sigprocmask(_SIG_SETMASK, &oset, nil)
   158  	if ret != 0 {
   159  		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n")
   160  		if ret == _EAGAIN {
   161  			println("runtime: may need to increase max user processes (ulimit -u)")
   162  		}
   163  		throw("newosproc")
   164  	}
   165  
   166  }
   167  
   168  func exitThread(wait *uint32) {
   169  	// We should never reach exitThread on AIX because we let
   170  	// libc clean up threads.
   171  	throw("exitThread")
   172  }
   173  
   174  var urandom_dev = []byte("/dev/urandom\x00")
   175  
   176  //go:nosplit
   177  func getRandomData(r []byte) {
   178  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   179  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   180  	closefd(fd)
   181  	extendRandom(r, int(n))
   182  }
   183  
   184  func goenvs() {
   185  	goenvs_unix()
   186  }
   187  
   188  /* SIGNAL */
   189  
   190  const (
   191  	_NSIG = 256
   192  )
   193  
   194  // sigtramp is a function descriptor to _sigtramp defined in assembly
   195  var sigtramp funcDescriptor
   196  
   197  //go:nosplit
   198  //go:nowritebarrierrec
   199  func setsig(i uint32, fn uintptr) {
   200  	var sa sigactiont
   201  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   202  	sa.sa_mask = sigset_all
   203  	if fn == funcPC(sighandler) {
   204  		fn = uintptr(unsafe.Pointer(&sigtramp))
   205  	}
   206  	sa.sa_handler = fn
   207  	sigaction(uintptr(i), &sa, nil)
   208  
   209  }
   210  
   211  //go:nosplit
   212  //go:nowritebarrierrec
   213  func setsigstack(i uint32) {
   214  	throw("Not yet implemented\n")
   215  }
   216  
   217  //go:nosplit
   218  //go:nowritebarrierrec
   219  func getsig(i uint32) uintptr {
   220  	var sa sigactiont
   221  	sigaction(uintptr(i), nil, &sa)
   222  	return sa.sa_handler
   223  }
   224  
   225  // setSignaltstackSP sets the ss_sp field of a stackt.
   226  //go:nosplit
   227  func setSignalstackSP(s *stackt, sp uintptr) {
   228  	*(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
   229  }
   230  
   231  func (c *sigctxt) fixsigcode(sig uint32) {
   232  }
   233  
   234  func sigaddset(mask *sigset, i int) {
   235  	(*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63)
   236  }
   237  
   238  func sigdelset(mask *sigset, i int) {
   239  	(*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63)
   240  }
   241  
   242  const (
   243  	_CLOCK_REALTIME  = 9
   244  	_CLOCK_MONOTONIC = 10
   245  )
   246  
   247  //go:nosplit
   248  func nanotime() int64 {
   249  	tp := &timespec{}
   250  	if clock_gettime(_CLOCK_REALTIME, tp) != 0 {
   251  		throw("syscall clock_gettime failed")
   252  	}
   253  	return tp.tv_sec*1000000000 + tp.tv_nsec
   254  }
   255  
   256  func walltime() (sec int64, nsec int32) {
   257  	ts := &timespec{}
   258  	if clock_gettime(_CLOCK_REALTIME, ts) != 0 {
   259  		throw("syscall clock_gettime failed")
   260  	}
   261  	return ts.tv_sec, int32(ts.tv_nsec)
   262  }