github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/thread-linux.c (about) 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 #include "runtime.h" 6 #include "defs.h" 7 #include "signal_unix.h" 8 9 // Linux futex. 10 // 11 // futexsleep(uint32 *addr, uint32 val) 12 // futexwakeup(uint32 *addr) 13 // 14 // Futexsleep atomically checks if *addr == val and if so, sleeps on addr. 15 // Futexwakeup wakes up threads sleeping on addr. 16 // Futexsleep is allowed to wake up spuriously. 17 18 #include <errno.h> 19 #include <string.h> 20 #include <time.h> 21 #include <sys/types.h> 22 #include <sys/stat.h> 23 #include <fcntl.h> 24 #include <unistd.h> 25 #include <syscall.h> 26 #include <linux/futex.h> 27 28 typedef struct timespec Timespec; 29 30 // Atomically, 31 // if(*addr == val) sleep 32 // Might be woken up spuriously; that's allowed. 33 // Don't sleep longer than ns; ns < 0 means forever. 34 void 35 runtime_futexsleep(uint32 *addr, uint32 val, int64 ns) 36 { 37 Timespec ts; 38 int32 nsec; 39 40 // Some Linux kernels have a bug where futex of 41 // FUTEX_WAIT returns an internal error code 42 // as an errno. Libpthread ignores the return value 43 // here, and so can we: as it says a few lines up, 44 // spurious wakeups are allowed. 45 46 if(ns < 0) { 47 syscall(__NR_futex, addr, FUTEX_WAIT, val, nil, nil, 0); 48 return; 49 } 50 ts.tv_sec = runtime_timediv(ns, 1000000000LL, &nsec); 51 ts.tv_nsec = nsec; 52 syscall(__NR_futex, addr, FUTEX_WAIT, val, &ts, nil, 0); 53 } 54 55 // If any procs are sleeping on addr, wake up at most cnt. 56 void 57 runtime_futexwakeup(uint32 *addr, uint32 cnt) 58 { 59 int64 ret; 60 61 ret = syscall(__NR_futex, addr, FUTEX_WAKE, cnt, nil, nil, 0); 62 63 if(ret >= 0) 64 return; 65 66 // I don't know that futex wakeup can return 67 // EAGAIN or EINTR, but if it does, it would be 68 // safe to loop and call futex again. 69 runtime_printf("futexwakeup addr=%p returned %D\n", addr, ret); 70 *(int32*)0x1006 = 0x1006; 71 } 72 73 void 74 runtime_osinit(void) 75 { 76 runtime_ncpu = getproccount(); 77 } 78 79 void 80 runtime_goenvs(void) 81 { 82 runtime_goenvs_unix(); 83 }