Dan Willemsen | c78f714 | 2017-07-26 13:08:14 -0700 | [diff] [blame] | 1 | // Copyright 2017 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 | |
Dan Willemsen | 1cbb82a | 2022-08-08 23:13:50 -0700 | [diff] [blame] | 5 | //go:build unix |
Dan Willemsen | c78f714 | 2017-07-26 13:08:14 -0700 | [diff] [blame] | 6 | |
| 7 | package runtime |
| 8 | |
Patrice Arruda | 7f4776e | 2020-06-25 11:55:41 -0700 | [diff] [blame] | 9 | import "unsafe" |
| 10 | |
| 11 | var NonblockingPipe = nonblockingPipe |
Patrice Arruda | 7f4776e | 2020-06-25 11:55:41 -0700 | [diff] [blame] | 12 | |
Dan Willemsen | c78f714 | 2017-07-26 13:08:14 -0700 | [diff] [blame] | 13 | func sigismember(mask *sigset, i int) bool { |
| 14 | clear := *mask |
| 15 | sigdelset(&clear, i) |
| 16 | return clear != *mask |
| 17 | } |
| 18 | |
| 19 | func Sigisblocked(i int) bool { |
| 20 | var sigmask sigset |
| 21 | sigprocmask(_SIG_SETMASK, nil, &sigmask) |
| 22 | return sigismember(&sigmask, i) |
| 23 | } |
Patrice Arruda | 7f4776e | 2020-06-25 11:55:41 -0700 | [diff] [blame] | 24 | |
| 25 | type M = m |
| 26 | |
| 27 | var waitForSigusr1 struct { |
| 28 | rdpipe int32 |
| 29 | wrpipe int32 |
| 30 | mID int64 |
| 31 | } |
| 32 | |
| 33 | // WaitForSigusr1 blocks until a SIGUSR1 is received. It calls ready |
| 34 | // when it is set up to receive SIGUSR1. The ready function should |
| 35 | // cause a SIGUSR1 to be sent. The r and w arguments are a pipe that |
| 36 | // the signal handler can use to report when the signal is received. |
| 37 | // |
| 38 | // Once SIGUSR1 is received, it returns the ID of the current M and |
| 39 | // the ID of the M the SIGUSR1 was received on. If the caller writes |
| 40 | // a non-zero byte to w, WaitForSigusr1 returns immediately with -1, -1. |
| 41 | func WaitForSigusr1(r, w int32, ready func(mp *M)) (int64, int64) { |
| 42 | lockOSThread() |
| 43 | // Make sure we can receive SIGUSR1. |
| 44 | unblocksig(_SIGUSR1) |
| 45 | |
| 46 | waitForSigusr1.rdpipe = r |
| 47 | waitForSigusr1.wrpipe = w |
| 48 | |
| 49 | mp := getg().m |
| 50 | testSigusr1 = waitForSigusr1Callback |
| 51 | ready(mp) |
| 52 | |
| 53 | // Wait for the signal. We use a pipe rather than a note |
| 54 | // because write is always async-signal-safe. |
| 55 | entersyscallblock() |
| 56 | var b byte |
| 57 | read(waitForSigusr1.rdpipe, noescape(unsafe.Pointer(&b)), 1) |
| 58 | exitsyscall() |
| 59 | |
| 60 | gotM := waitForSigusr1.mID |
| 61 | testSigusr1 = nil |
| 62 | |
| 63 | unlockOSThread() |
| 64 | |
| 65 | if b != 0 { |
| 66 | // timeout signal from caller |
| 67 | return -1, -1 |
| 68 | } |
| 69 | return mp.id, gotM |
| 70 | } |
| 71 | |
| 72 | // waitForSigusr1Callback is called from the signal handler during |
| 73 | // WaitForSigusr1. It must not have write barriers because there may |
| 74 | // not be a P. |
| 75 | // |
| 76 | //go:nowritebarrierrec |
| 77 | func waitForSigusr1Callback(gp *g) bool { |
| 78 | if gp == nil || gp.m == nil { |
| 79 | waitForSigusr1.mID = -1 |
| 80 | } else { |
| 81 | waitForSigusr1.mID = gp.m.id |
| 82 | } |
| 83 | b := byte(0) |
| 84 | write(uintptr(waitForSigusr1.wrpipe), noescape(unsafe.Pointer(&b)), 1) |
| 85 | return true |
| 86 | } |
| 87 | |
| 88 | // SendSigusr1 sends SIGUSR1 to mp. |
| 89 | func SendSigusr1(mp *M) { |
| 90 | signalM(mp, _SIGUSR1) |
| 91 | } |
Dan Willemsen | b8ef64a | 2023-04-04 01:48:15 -0400 | [diff] [blame^] | 92 | |
| 93 | const ( |
| 94 | O_WRONLY = _O_WRONLY |
| 95 | O_CREAT = _O_CREAT |
| 96 | O_TRUNC = _O_TRUNC |
| 97 | ) |