Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 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 ( |
Matthew Dempsky | 95ab84a | 2015-02-16 18:18:13 +0900 | [diff] [blame] | 10 | _ESRCH = 3 |
| 11 | _EAGAIN = 35 |
| 12 | _EWOULDBLOCK = _EAGAIN |
| 13 | _ENOTSUP = 91 |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 14 | |
| 15 | // From OpenBSD's sys/time.h |
Matthew Dempsky | 95ab84a | 2015-02-16 18:18:13 +0900 | [diff] [blame] | 16 | _CLOCK_REALTIME = 0 |
| 17 | _CLOCK_VIRTUAL = 1 |
| 18 | _CLOCK_PROF = 2 |
| 19 | _CLOCK_MONOTONIC = 3 |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 20 | ) |
| 21 | |
Matthew Dempsky | 5324cf2 | 2015-03-01 19:13:50 -0800 | [diff] [blame] | 22 | const ( |
| 23 | sigset_none = uint32(0) |
| 24 | sigset_all = ^uint32(0) |
| 25 | ) |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 26 | |
| 27 | // From OpenBSD's <sys/sysctl.h> |
| 28 | const ( |
Matthew Dempsky | 95ab84a | 2015-02-16 18:18:13 +0900 | [diff] [blame] | 29 | _CTL_HW = 6 |
| 30 | _HW_NCPU = 3 |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 31 | ) |
| 32 | |
| 33 | func getncpu() int32 { |
Matthew Dempsky | 95ab84a | 2015-02-16 18:18:13 +0900 | [diff] [blame] | 34 | mib := [2]uint32{_CTL_HW, _HW_NCPU} |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 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() |
Russ Cox | 580cba4 | 2014-11-14 14:50:00 -0500 | [diff] [blame] | 61 | ts.set_sec(int64(timediv(ns, 1000000000, &nsec))) |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 62 | ts.set_nsec(nsec) |
| 63 | tsp = &ts |
| 64 | } |
| 65 | |
| 66 | for { |
Matthew Dempsky | 9f926e8 | 2015-02-23 17:05:30 +0900 | [diff] [blame] | 67 | v := atomicload(&_g_.m.waitsemacount) |
| 68 | if v > 0 { |
| 69 | if cas(&_g_.m.waitsemacount, v, v-1) { |
| 70 | return 0 // semaphore acquired |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 71 | } |
Matthew Dempsky | 9f926e8 | 2015-02-23 17:05:30 +0900 | [diff] [blame] | 72 | continue |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 73 | } |
| 74 | |
Matthew Dempsky | 9f926e8 | 2015-02-23 17:05:30 +0900 | [diff] [blame] | 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) |
Matthew Dempsky | 95ab84a | 2015-02-16 18:18:13 +0900 | [diff] [blame] | 83 | if ret == _EWOULDBLOCK { |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 84 | return -1 |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | //go:nosplit |
| 90 | func semawakeup(mp *m) { |
Matthew Dempsky | 9f926e8 | 2015-02-23 17:05:30 +0900 | [diff] [blame] | 91 | xadd(&mp.waitsemacount, 1) |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 92 | ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1) |
Matthew Dempsky | 95ab84a | 2015-02-16 18:18:13 +0900 | [diff] [blame] | 93 | if ret != 0 && ret != _ESRCH { |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 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 | } |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 99 | } |
| 100 | |
Austin Clements | 9e6f7aa | 2015-03-29 10:20:54 -0400 | [diff] [blame] | 101 | // May run with m.p==nil, so write barriers are not allowed. |
Austin Clements | 392336f | 2015-03-26 15:50:22 -0400 | [diff] [blame] | 102 | //go:nowritebarrier |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 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") |
Keith Randall | b2a950b | 2014-12-27 20:58:00 -0800 | [diff] [blame] | 122 | throw("runtime.newosproc") |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 123 | } |
| 124 | } |
| 125 | |
| 126 | func osinit() { |
| 127 | ncpu = getncpu() |
| 128 | } |
| 129 | |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 130 | var urandom_dev = []byte("/dev/urandom\x00") |
| 131 | |
| 132 | //go:nosplit |
Keith Randall | 6820be2 | 2014-12-09 14:40:40 -0800 | [diff] [blame] | 133 | func getRandomData(r []byte) { |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 134 | fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) |
Keith Randall | 6820be2 | 2014-12-09 14:40:40 -0800 | [diff] [blame] | 135 | n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) |
David Crawshaw | cea272d | 2015-04-13 19:37:04 -0400 | [diff] [blame] | 136 | closefd(fd) |
Keith Randall | 6820be2 | 2014-12-09 14:40:40 -0800 | [diff] [blame] | 137 | extendRandom(r, int(n)) |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 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 | |
Elias Naur | 84cfba1 | 2015-05-18 11:00:24 +0200 | [diff] [blame] | 151 | func msigsave(mp *m) { |
Elias Naur | 8017ace | 2015-05-23 11:26:22 +0200 | [diff] [blame] | 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) |
Elias Naur | 84cfba1 | 2015-05-18 11:00:24 +0200 | [diff] [blame] | 157 | } |
| 158 | |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 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 |
Austin Clements | c02b891 | 2015-05-21 14:12:29 -0400 | [diff] [blame] | 168 | signalstack(&_g_.m.gsignal.stack) |
Elias Naur | 8017ace | 2015-05-23 11:26:22 +0200 | [diff] [blame] | 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) |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | // Called from dropm to undo the effect of an minit. |
| 181 | func unminit() { |
Elias Naur | 8017ace | 2015-05-23 11:26:22 +0200 | [diff] [blame] | 182 | _g_ := getg() |
| 183 | smask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask)) |
| 184 | sigprocmask(_SIG_SETMASK, smask) |
Austin Clements | c02b891 | 2015-05-21 14:12:29 -0400 | [diff] [blame] | 185 | signalstack(nil) |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 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 | |
Austin Clements | 675eb72 | 2014-12-19 16:16:17 -0500 | [diff] [blame] | 214 | func setsigstack(i int32) { |
Keith Randall | b2a950b | 2014-12-27 20:58:00 -0800 | [diff] [blame] | 215 | throw("setsigstack") |
Austin Clements | 675eb72 | 2014-12-19 16:16:17 -0500 | [diff] [blame] | 216 | } |
| 217 | |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 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 | |
Austin Clements | c02b891 | 2015-05-21 14:12:29 -0400 | [diff] [blame] | 227 | func signalstack(s *stack) { |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 228 | var st stackt |
Austin Clements | c02b891 | 2015-05-21 14:12:29 -0400 | [diff] [blame] | 229 | if s == nil { |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 230 | st.ss_flags = _SS_DISABLE |
Austin Clements | c02b891 | 2015-05-21 14:12:29 -0400 | [diff] [blame] | 231 | } else { |
| 232 | st.ss_sp = s.lo |
| 233 | st.ss_size = s.hi - s.lo |
| 234 | st.ss_flags = 0 |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 235 | } |
| 236 | sigaltstack(&st, nil) |
| 237 | } |
| 238 | |
Elias Naur | 84cfba1 | 2015-05-18 11:00:24 +0200 | [diff] [blame] | 239 | func updatesigmask(m sigmask) { |
| 240 | sigprocmask(_SIG_SETMASK, m[0]) |
Joel Sing | ba603c3 | 2014-11-14 13:01:12 +1100 | [diff] [blame] | 241 | } |
Ian Lance Taylor | 872b168 | 2015-07-21 22:34:48 -0700 | [diff] [blame] | 242 | |
| 243 | func unblocksig(sig int32) { |
| 244 | mask := uint32(1) << (uint32(sig) - 1) |
| 245 | sigprocmask(_SIG_UNBLOCK, mask) |
| 246 | } |