runtime: portable access to sigev_notify_thread_id

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.

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/434755
This commit is contained in:
Ian Lance Taylor 2022-09-26 15:03:53 -04:00
parent f38162977e
commit e73d9fcafb
3 changed files with 30 additions and 2 deletions

View File

@ -1,4 +1,4 @@
0140cca9bc0fad1108c7ed369376ac71cc4bfecf
8f1a91aeff400d572857895b7f5e863ec5a4d93e
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -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

View File

@ -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.