1 // Copyright 2011 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 package runtime 6 7 import "unsafe" 8 9 const ( 10 _ESRCH = 3 11 _EAGAIN = 35 12 _EWOULDBLOCK = _EAGAIN 13 _ENOTSUP = 91 14 15 // From OpenBSD's sys/time.h 16 _CLOCK_REALTIME = 0 17 _CLOCK_VIRTUAL = 1 18 _CLOCK_PROF = 2 19 _CLOCK_MONOTONIC = 3 20 ) 21 22 const ( 23 sigset_none = uint32(0) 24 sigset_all = ^uint32(0) 25 ) 26 27 // From OpenBSD's <sys/sysctl.h> 28 const ( 29 _CTL_HW = 6 30 _HW_NCPU = 3 31 ) 32 33 func getncpu() int32 { 34 mib := [2]uint32{_CTL_HW, _HW_NCPU} 35 out := uint32(0) 36 nout := unsafe.Sizeof(out) 37 38 // Fetch hw.ncpu via sysctl. 39 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 40 if ret >= 0 { 41 return int32(out) 42 } 43 return 1 44 } 45 46 //go:nosplit 47 func semacreate() uintptr { 48 return 1 49 } 50 51 //go:nosplit 52 func semasleep(ns int64) int32 { 53 _g_ := getg() 54 55 // Compute sleep deadline. 56 var tsp *timespec 57 if ns >= 0 { 58 var ts timespec 59 var nsec int32 60 ns += nanotime() 61 ts.set_sec(int64(timediv(ns, 1000000000, &nsec))) 62 ts.set_nsec(nsec) 63 tsp = &ts 64 } 65 66 for { 67 v := atomicload(&_g_.m.waitsemacount) 68 if v > 0 { 69 if cas(&_g_.m.waitsemacount, v, v-1) { 70 return 0 // semaphore acquired 71 } 72 continue 73 } 74 75 // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0. 76 // 77 // From OpenBSD's __thrsleep(2) manual: 78 // "The abort argument, if not NULL, points to an int that will 79 // be examined [...] immediately before blocking. If that int 80 // is non-zero then __thrsleep() will immediately return EINTR 81 // without blocking." 82 ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount) 83 if ret == _EWOULDBLOCK { 84 return -1 85 } 86 } 87 } 88 89 //go:nosplit 90 func semawakeup(mp *m) { 91 xadd(&mp.waitsemacount, 1) 92 ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1) 93 if ret != 0 && ret != _ESRCH { 94 // semawakeup can be called on signal stack. 95 systemstack(func() { 96 print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") 97 }) 98 } 99 } 100 101 // May run with m.p==nil, so write barriers are not allowed. 102 //go:nowritebarrier 103 func newosproc(mp *m, stk unsafe.Pointer) { 104 if false { 105 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n") 106 } 107 108 mp.tls[0] = uintptr(mp.id) // so 386 asm can find it 109 110 param := tforkt{ 111 tf_tcb: unsafe.Pointer(&mp.tls[0]), 112 tf_tid: (*int32)(unsafe.Pointer(&mp.procid)), 113 tf_stack: uintptr(stk), 114 } 115 116 oset := sigprocmask(_SIG_SETMASK, sigset_all) 117 ret := tfork(¶m, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart)) 118 sigprocmask(_SIG_SETMASK, oset) 119 120 if ret < 0 { 121 print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") 122 throw("runtime.newosproc") 123 } 124 } 125 126 func osinit() { 127 ncpu = getncpu() 128 } 129 130 var urandom_dev = []byte("/dev/urandom\x00") 131 132 //go:nosplit 133 func getRandomData(r []byte) { 134 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 135 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 136 closefd(fd) 137 extendRandom(r, int(n)) 138 } 139 140 func goenvs() { 141 goenvs_unix() 142 } 143 144 // Called to initialize a new m (including the bootstrap m). 145 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 146 func mpreinit(mp *m) { 147 mp.gsignal = malg(32 * 1024) 148 mp.gsignal.m = mp 149 } 150 151 func msigsave(mp *m) { 152 smask := (*uint32)(unsafe.Pointer(&mp.sigmask)) 153 if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) { 154 throw("insufficient storage for signal mask") 155 } 156 *smask = sigprocmask(_SIG_BLOCK, 0) 157 } 158 159 // Called to initialize a new m (including the bootstrap m). 160 // Called on the new thread, can not allocate memory. 161 func minit() { 162 _g_ := getg() 163 164 // m.procid is a uint64, but tfork writes an int32. Fix it up. 165 _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid))) 166 167 // Initialize signal handling 168 signalstack(&_g_.m.gsignal.stack) 169 170 // restore signal mask from m.sigmask and unblock essential signals 171 nmask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask)) 172 for i := range sigtable { 173 if sigtable[i].flags&_SigUnblock != 0 { 174 nmask &^= 1 << (uint32(i) - 1) 175 } 176 } 177 sigprocmask(_SIG_SETMASK, nmask) 178 } 179 180 // Called from dropm to undo the effect of an minit. 181 func unminit() { 182 _g_ := getg() 183 smask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask)) 184 sigprocmask(_SIG_SETMASK, smask) 185 signalstack(nil) 186 } 187 188 func memlimit() uintptr { 189 return 0 190 } 191 192 func sigtramp() 193 194 type sigactiont struct { 195 sa_sigaction uintptr 196 sa_mask uint32 197 sa_flags int32 198 } 199 200 func setsig(i int32, fn uintptr, restart bool) { 201 var sa sigactiont 202 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK 203 if restart { 204 sa.sa_flags |= _SA_RESTART 205 } 206 sa.sa_mask = sigset_all 207 if fn == funcPC(sighandler) { 208 fn = funcPC(sigtramp) 209 } 210 sa.sa_sigaction = fn 211 sigaction(i, &sa, nil) 212 } 213 214 func setsigstack(i int32) { 215 throw("setsigstack") 216 } 217 218 func getsig(i int32) uintptr { 219 var sa sigactiont 220 sigaction(i, nil, &sa) 221 if sa.sa_sigaction == funcPC(sigtramp) { 222 return funcPC(sighandler) 223 } 224 return sa.sa_sigaction 225 } 226 227 func signalstack(s *stack) { 228 var st stackt 229 if s == nil { 230 st.ss_flags = _SS_DISABLE 231 } else { 232 st.ss_sp = s.lo 233 st.ss_size = s.hi - s.lo 234 st.ss_flags = 0 235 } 236 sigaltstack(&st, nil) 237 } 238 239 func updatesigmask(m sigmask) { 240 sigprocmask(_SIG_SETMASK, m[0]) 241 } 242 243 func unblocksig(sig int32) { 244 mask := uint32(1) << (uint32(sig) - 1) 245 sigprocmask(_SIG_UNBLOCK, mask) 246 } 247