summaryrefslogtreecommitdiff
path: root/src/runtime/os_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/os_linux.c')
-rw-r--r--src/runtime/os_linux.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/src/runtime/os_linux.c b/src/runtime/os_linux.c
index 0d8ffc995..9bd123d59 100644
--- a/src/runtime/os_linux.c
+++ b/src/runtime/os_linux.c
@@ -49,9 +49,22 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
runtime·futex(addr, FUTEX_WAIT, val, nil, nil, 0);
return;
}
- // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
+
+ // It's difficult to live within the no-split stack limits here.
+ // On ARM and 386, a 64-bit divide invokes a general software routine
+ // that needs more stack than we can afford. So we use timediv instead.
+ // But on real 64-bit systems, where words are larger but the stack limit
+ // is not, even timediv is too heavy, and we really need to use just an
+ // ordinary machine instruction.
+ // Sorry for the #ifdef.
+ // For what it's worth, the #ifdef eliminated an implicit little-endian assumption.
+#ifdef _64BIT
+ ts.tv_sec = ns / 1000000000LL;
+ ts.tv_nsec = ns % 1000000000LL;
+#else
ts.tv_nsec = 0;
ts.tv_sec = runtime·timediv(ns, 1000000000LL, (int32*)&ts.tv_nsec);
+#endif
runtime·futex(addr, FUTEX_WAIT, val, &ts, nil, 0);
}
@@ -98,19 +111,22 @@ static int32
getproccount(void)
{
uintptr buf[16], t;
- int32 r, cnt, i;
+ int32 r, n, i;
- cnt = 0;
r = runtime·sched_getaffinity(0, sizeof(buf), buf);
- if(r > 0)
+ if(r <= 0)
+ return 1;
+ n = 0;
for(i = 0; i < r/sizeof(buf[0]); i++) {
t = buf[i];
- t = t - ((t >> 1) & 0x5555555555555555ULL);
- t = (t & 0x3333333333333333ULL) + ((t >> 2) & 0x3333333333333333ULL);
- cnt += (int32)((((t + (t >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56);
+ while(t != 0) {
+ n += t&1;
+ t >>= 1;
+ }
}
-
- return cnt ? cnt : 1;
+ if(n < 1)
+ n = 1;
+ return n;
}
// Clone, the Linux rfork.
@@ -298,7 +314,8 @@ runtime·setsig(int32 i, GoSighandler *fn, bool restart)
if(fn == runtime·sighandler)
fn = (void*)runtime·sigtramp;
sa.sa_handler = fn;
- if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0)
+ // Qemu rejects rt_sigaction of SIGRTMAX (64).
+ if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0 && i != 64)
runtime·throw("rt_sigaction failure");
}