]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/os1_linux.go
[dev.garbage] all: merge dev.cc into dev.garbage
[gostls13.git] / src / runtime / os1_linux.go
1 // Copyright 2009 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 var sigset_none sigset
10 var sigset_all sigset = sigset{^uint32(0), ^uint32(0)}
11
12 // Linux futex.
13 //
14 //      futexsleep(uint32 *addr, uint32 val)
15 //      futexwakeup(uint32 *addr)
16 //
17 // Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
18 // Futexwakeup wakes up threads sleeping on addr.
19 // Futexsleep is allowed to wake up spuriously.
20
21 const (
22         _FUTEX_WAIT = 0
23         _FUTEX_WAKE = 1
24 )
25
26 // Atomically,
27 //      if(*addr == val) sleep
28 // Might be woken up spuriously; that's allowed.
29 // Don't sleep longer than ns; ns < 0 means forever.
30 //go:nosplit
31 func futexsleep(addr *uint32, val uint32, ns int64) {
32         var ts timespec
33
34         // Some Linux kernels have a bug where futex of
35         // FUTEX_WAIT returns an internal error code
36         // as an errno.  Libpthread ignores the return value
37         // here, and so can we: as it says a few lines up,
38         // spurious wakeups are allowed.
39         if ns < 0 {
40                 futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, nil, nil, 0)
41                 return
42         }
43
44         // It's difficult to live within the no-split stack limits here.
45         // On ARM and 386, a 64-bit divide invokes a general software routine
46         // that needs more stack than we can afford. So we use timediv instead.
47         // But on real 64-bit systems, where words are larger but the stack limit
48         // is not, even timediv is too heavy, and we really need to use just an
49         // ordinary machine instruction.
50         if ptrSize == 8 {
51                 ts.set_sec(ns / 1000000000)
52                 ts.set_nsec(int32(ns % 1000000000))
53         } else {
54                 ts.tv_nsec = 0
55                 ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
56         }
57         futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, unsafe.Pointer(&ts), nil, 0)
58 }
59
60 // If any procs are sleeping on addr, wake up at most cnt.
61 //go:nosplit
62 func futexwakeup(addr *uint32, cnt uint32) {
63         ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE, cnt, nil, nil, 0)
64         if ret >= 0 {
65                 return
66         }
67
68         // I don't know that futex wakeup can return
69         // EAGAIN or EINTR, but if it does, it would be
70         // safe to loop and call futex again.
71         systemstack(func() {
72                 print("futexwakeup addr=", addr, " returned ", ret, "\n")
73         })
74
75         *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
76 }
77
78 func getproccount() int32 {
79         var buf [16]uintptr
80         r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0])
81         n := int32(0)
82         for _, v := range buf[:r/ptrSize] {
83                 for i := 0; i < 64; i++ {
84                         n += int32(v & 1)
85                         v >>= 1
86                 }
87         }
88         if n == 0 {
89                 n = 1
90         }
91         return n
92 }
93
94 // Clone, the Linux rfork.
95 const (
96         _CLONE_VM             = 0x100
97         _CLONE_FS             = 0x200
98         _CLONE_FILES          = 0x400
99         _CLONE_SIGHAND        = 0x800
100         _CLONE_PTRACE         = 0x2000
101         _CLONE_VFORK          = 0x4000
102         _CLONE_PARENT         = 0x8000
103         _CLONE_THREAD         = 0x10000
104         _CLONE_NEWNS          = 0x20000
105         _CLONE_SYSVSEM        = 0x40000
106         _CLONE_SETTLS         = 0x80000
107         _CLONE_PARENT_SETTID  = 0x100000
108         _CLONE_CHILD_CLEARTID = 0x200000
109         _CLONE_UNTRACED       = 0x800000
110         _CLONE_CHILD_SETTID   = 0x1000000
111         _CLONE_STOPPED        = 0x2000000
112         _CLONE_NEWUTS         = 0x4000000
113         _CLONE_NEWIPC         = 0x8000000
114 )
115
116 func newosproc(mp *m, stk unsafe.Pointer) {
117         /*
118          * note: strace gets confused if we use CLONE_PTRACE here.
119          */
120         var flags int32 = _CLONE_VM | /* share memory */
121                 _CLONE_FS | /* share cwd, etc */
122                 _CLONE_FILES | /* share fd table */
123                 _CLONE_SIGHAND | /* share sig handler table */
124                 _CLONE_THREAD /* revisit - okay for now */
125
126         mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
127         if false {
128                 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
129         }
130
131         // Disable signals during clone, so that the new thread starts
132         // with signals disabled.  It will enable them in minit.
133         var oset sigset
134         rtsigprocmask(_SIG_SETMASK, &sigset_all, &oset, int32(unsafe.Sizeof(oset)))
135         ret := clone(flags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
136         rtsigprocmask(_SIG_SETMASK, &oset, nil, int32(unsafe.Sizeof(oset)))
137
138         if ret < 0 {
139                 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n")
140                 gothrow("newosproc")
141         }
142 }
143
144 func osinit() {
145         ncpu = getproccount()
146 }
147
148 // Random bytes initialized at startup.  These come
149 // from the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.c).
150 // byte*        runtime·startup_random_data;
151 // uint32       runtime·startup_random_data_len;
152
153 var urandom_data [_HashRandomBytes]byte
154 var urandom_dev = []byte("/dev/random\x00")
155
156 //go:nosplit
157 func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
158         if startup_random_data != nil {
159                 *rnd = unsafe.Pointer(startup_random_data)
160                 *rnd_len = int32(startup_random_data_len)
161                 return
162         }
163         fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
164         if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes {
165                 *rnd = unsafe.Pointer(&urandom_data[0])
166                 *rnd_len = _HashRandomBytes
167         } else {
168                 *rnd = nil
169                 *rnd_len = 0
170         }
171         close(fd)
172 }
173
174 func goenvs() {
175         goenvs_unix()
176 }
177
178 // Called to initialize a new m (including the bootstrap m).
179 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
180 func mpreinit(mp *m) {
181         mp.gsignal = malg(32 * 1024) // Linux wants >= 2K
182         mp.gsignal.m = mp
183 }
184
185 // Called to initialize a new m (including the bootstrap m).
186 // Called on the new thread, can not allocate memory.
187 func minit() {
188         // Initialize signal handling.
189         _g_ := getg()
190         signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
191         rtsigprocmask(_SIG_SETMASK, &sigset_none, nil, int32(unsafe.Sizeof(sigset_none)))
192 }
193
194 // Called from dropm to undo the effect of an minit.
195 func unminit() {
196         signalstack(nil, 0)
197 }
198
199 func memlimit() uintptr {
200         /*
201                 TODO: Convert to Go when something actually uses the result.
202
203                 Rlimit rl;
204                 extern byte runtime·text[], runtime·end[];
205                 uintptr used;
206
207                 if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
208                         return 0;
209                 if(rl.rlim_cur >= 0x7fffffff)
210                         return 0;
211
212                 // Estimate our VM footprint excluding the heap.
213                 // Not an exact science: use size of binary plus
214                 // some room for thread stacks.
215                 used = runtime·end - runtime·text + (64<<20);
216                 if(used >= rl.rlim_cur)
217                         return 0;
218
219                 // If there's not at least 16 MB left, we're probably
220                 // not going to be able to do much.  Treat as no limit.
221                 rl.rlim_cur -= used;
222                 if(rl.rlim_cur < (16<<20))
223                         return 0;
224
225                 return rl.rlim_cur - used;
226         */
227
228         return 0
229 }
230
231 //#ifdef GOARCH_386
232 //#define sa_handler k_sa_handler
233 //#endif
234
235 func sigreturn()
236 func sigtramp()
237
238 func setsig(i int32, fn uintptr, restart bool) {
239         var sa sigactiont
240         memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
241         sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTORER
242         if restart {
243                 sa.sa_flags |= _SA_RESTART
244         }
245         sa.sa_mask = ^uint64(0)
246         // Although Linux manpage says "sa_restorer element is obsolete and
247         // should not be used". x86_64 kernel requires it. Only use it on
248         // x86.
249         if GOARCH == "386" || GOARCH == "amd64" {
250                 sa.sa_restorer = funcPC(sigreturn)
251         }
252         if fn == funcPC(sighandler) {
253                 fn = funcPC(sigtramp)
254         }
255         sa.sa_handler = fn
256         if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 {
257                 gothrow("rt_sigaction failure")
258         }
259 }
260
261 func getsig(i int32) uintptr {
262         var sa sigactiont
263
264         memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
265         if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
266                 gothrow("rt_sigaction read failure")
267         }
268         if sa.sa_handler == funcPC(sigtramp) {
269                 return funcPC(sighandler)
270         }
271         return sa.sa_handler
272 }
273
274 func signalstack(p *byte, n int32) {
275         var st sigaltstackt
276         st.ss_sp = p
277         st.ss_size = uintptr(n)
278         st.ss_flags = 0
279         if p == nil {
280                 st.ss_flags = _SS_DISABLE
281         }
282         sigaltstack(&st, nil)
283 }
284
285 func unblocksignals() {
286         rtsigprocmask(_SIG_SETMASK, &sigset_none, nil, int32(unsafe.Sizeof(sigset_none)))
287 }