109 lines
3.5 KiB
Diff
109 lines
3.5 KiB
Diff
|
From 8f1a91aeff400d572857895b7f5e863ec5a4d93e Mon Sep 17 00:00:00 2001
|
||
|
From: Ian Lance Taylor <iant@golang.org>
|
||
|
Date: Mon, 26 Sep 2022 15:03:53 -0400
|
||
|
Subject: [PATCH] runtime: portable access to sigev_notify_thread_id
|
||
|
MIME-Version: 1.0
|
||
|
Content-Type: text/plain; charset=UTF-8
|
||
|
Content-Transfer-Encoding: 8bit
|
||
|
|
||
|
Previously, libgo relied on the _sigev_un implementation-specific
|
||
|
field in struct sigevent, which is only available on glibc.
|
||
|
This patch uses the sigev_notify_thread_id macro instead which is
|
||
|
mandated by timer_create(2). In theory, this should work with any libc
|
||
|
implementation for Linux. Unfortunately, there is an open glibc bug
|
||
|
as glibc does not define this macro. For this reason, a glibc-specific
|
||
|
workaround is required. Other libcs (such as musl) define the macro
|
||
|
and don't require the workaround.
|
||
|
|
||
|
See https://sourceware.org/bugzilla/show_bug.cgi?id=27417
|
||
|
|
||
|
This makes libgo compatible with musl libc.
|
||
|
|
||
|
Based on patch by Sören Tempel.
|
||
|
|
||
|
Change-Id: I0924a53d5212730ebc395ecf9199f85967be8cc6
|
||
|
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/434755
|
||
|
Reviewed-by: Cherry Mui <cherryyz@google.com>
|
||
|
Reviewed-by: Than McIntosh <thanm@google.com>
|
||
|
---
|
||
|
libgo/go/runtime/os_linux.go | 12 +++++++++++-
|
||
|
libgo/runtime/go-signal.c | 18 ++++++++++++++++++
|
||
|
2 files changed, 29 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/libgo/go/runtime/os_linux.go b/libgo/go/runtime/os_linux.go
|
||
|
index 96fb1788..2b2d827c 100644
|
||
|
--- a/libgo/go/runtime/os_linux.go
|
||
|
+++ b/libgo/go/runtime/os_linux.go
|
||
|
@@ -22,6 +22,12 @@ type mOS struct {
|
||
|
profileTimerValid uint32
|
||
|
}
|
||
|
|
||
|
+// setSigeventTID is written in C to set the sigev_notify_thread_id
|
||
|
+// field of a sigevent struct.
|
||
|
+//
|
||
|
+//go:noescape
|
||
|
+func setSigeventTID(*_sigevent, int32)
|
||
|
+
|
||
|
func getProcID() uint64 {
|
||
|
return uint64(gettid())
|
||
|
}
|
||
|
@@ -52,9 +58,12 @@ const (
|
||
|
)
|
||
|
|
||
|
// Atomically,
|
||
|
+//
|
||
|
// if(*addr == val) sleep
|
||
|
+//
|
||
|
// Might be woken up spuriously; that's allowed.
|
||
|
// Don't sleep longer than ns; ns < 0 means forever.
|
||
|
+//
|
||
|
//go:nosplit
|
||
|
func futexsleep(addr *uint32, val uint32, ns int64) {
|
||
|
// Some Linux kernels have a bug where futex of
|
||
|
@@ -73,6 +82,7 @@ func futexsleep(addr *uint32, val uint32, ns int64) {
|
||
|
}
|
||
|
|
||
|
// If any procs are sleeping on addr, wake up at most cnt.
|
||
|
+//
|
||
|
//go:nosplit
|
||
|
func futexwakeup(addr *uint32, cnt uint32) {
|
||
|
ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE_PRIVATE, cnt, nil, nil, 0)
|
||
|
@@ -365,7 +375,7 @@ func setThreadCPUProfiler(hz int32) {
|
||
|
var sevp _sigevent
|
||
|
sevp.sigev_notify = _SIGEV_THREAD_ID
|
||
|
sevp.sigev_signo = _SIGPROF
|
||
|
- *((*int32)(unsafe.Pointer(&sevp._sigev_un))) = int32(mp.procid)
|
||
|
+ setSigeventTID(&sevp, int32(mp.procid))
|
||
|
ret := timer_create(_CLOCK_THREAD_CPUTIME_ID, &sevp, &timerid)
|
||
|
if ret != 0 {
|
||
|
// If we cannot create a timer for this M, leave profileTimerValid false
|
||
|
diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c
|
||
|
index 528d9b6d..aa1b6305 100644
|
||
|
--- a/libgo/runtime/go-signal.c
|
||
|
+++ b/libgo/runtime/go-signal.c
|
||
|
@@ -183,6 +183,24 @@ setSigactionHandler(struct sigaction* sa, uintptr handler)
|
||
|
sa->sa_sigaction = (void*)(handler);
|
||
|
}
|
||
|
|
||
|
+#ifdef __linux__
|
||
|
+
|
||
|
+// Workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=27417
|
||
|
+#ifndef sigev_notify_thread_id
|
||
|
+ #define sigev_notify_thread_id _sigev_un._tid
|
||
|
+#endif
|
||
|
+
|
||
|
+void setSigeventTID(struct sigevent*, int32_t)
|
||
|
+ __asm__ (GOSYM_PREFIX "runtime.setSigeventTID");
|
||
|
+
|
||
|
+void
|
||
|
+setSigeventTID(struct sigevent *sev, int32_t v)
|
||
|
+{
|
||
|
+ sev->sigev_notify_thread_id = v;
|
||
|
+}
|
||
|
+
|
||
|
+#endif // defined(__linux__)
|
||
|
+
|
||
|
// C code to fetch values from the siginfo_t and ucontext_t pointers
|
||
|
// passed to a signal handler.
|
||
|
|