Как можно получить список доступных операционной системы сигналов в кросс-платформенный способ пойти?

Как можно получить список доступных операционной системы сигналов в кросс-платформенный способ пойти?

04.03.2017 07:43:10 Просмотров 31 Источник

Допустим, я внедряю программу killв Go. Я могу принимать числовые сигналы и PID из командной строки и отправлять их в syscall.Kill не проблема.

Однако я не знаю, как реализовать "строковую" форму отправки сигнала, напримерkill -INT 12345.

Реальный случай использования-это часть более крупной программы, которая предлагает пользователю посылать сигналы убийства, а не замена kill.

Вопрос:

Как я могу преобразовать допустимые имена сигналов в номера сигналов на любой поддерживаемой платформе во время выполнения (или, по крайней мере, без написания кода для каждой платформы, который будет выполняться во время компиляции)?

Что я уже пробовал:

  • Сохраняйте статическую карту имен сигналов с числами. Это не работает кросс-платформенным способом (например, различные списки сигналов возвращаются kill -lНа Mac OSX по сравнению с современным Linux по сравнению со старым Linux, например). Единственным способом заставить это решение работать в целом было бы создание карт для каждой ОС, что потребовало бы от меня знать поведение каждой ОС и быть в курсе, поскольку они добавляют новую поддержку сигнала.
  • Раскошелитесь на GNU killtool и захватите из него списки сигналов. Это неэлегантно и своего рода парадокс , а также требует а) способности находить kill, б) наличия способности/разрешения на выполнение подпроцессов и в) способности предсказывать/анализировать выходные kill-the-binary.
  • Используйте Signal. Это просто возвращает строки, содержащие номер сигнала, например String, который не является полезным.
  • Вызов частной функции os.Signal(4).String() == "signal 4", которая делает именно то, что я хочу. runtime.signameхаки linkname будут работать, но я предполагаю, что такого рода вещи не одобряются по какой-то причине.

Идеи / вещи, которые я еще не пробовал:

  • Используйте CGo как-нибудь. Я бы предпочел не рисковать на территории CGO для проекта, который в противном случае не является низкоуровневым/нуждающимся в родной интеграции вообще. Если это единственный вариант, я сделаю это, но понятия не имею, с чего начать.
  • Используйте шаблоны и генерацию кода для построения списков сигналов на основе внешних источников во время компиляции. Это не является предпочтительным по тем же причинам, что и CGo.
  • Поразмыслите и проанализируйте члены go://linkname, которые каким-то образом начинаются с syscall. Мне говорят, что это невозможно, потому что имена компилируются; возможно ли, что для чего-то столь фундаментального, как имена сигналов, есть место, где они не компилируются?
У вопроса есть решение - Посмотреть?

https://stackoverflow.com/questions/42598522/how-can-i-list-available-operating-system-signals-by-name-in-a-cross-platform-wa#comment72333415_42598522
Потенциально; я дал ему шанс, но не использовал Cgo раньше, поэтому он продолжал не хранить выходные значения в структуре go, которую я использовал. Я буду продолжать тыкать в него и публиковать здесь, если что-нибудь получится; вы знаете какой-нибудь пример кода для этого?

Ответы - Как можно получить список доступных операционной системы сигналов в кросс-платформенный способ пойти? / How can I list available operating system signals by name in a cross-platform way in Go?

Является ответом!
Zac B

17.11.2017 08:23:33

Поскольку ответы не были опубликованы,я опубликую менее чем идеальное решение, которое я смог использовать, "взломав" частную функцию перечисления сигналов внутри стандартной библиотеки Go.

signame/assembler. В принципе, сделайте файл в вашем проекте под названием linkname или без содержания, а затем функция декларации, как так:

empty.s

Затем вы можете получить список всех сигналов, известных операционной системе, вызывая //go:linkname signame runtime.signame func signame(sig uint32) string по возрастающему номеру, пока он не вернет значение, например:

signame

После этого signum := uint32(0) signalmap = make(map[uint32]string) for len(signame(signum)) > 0 { words := strings.Fields(signame(signum)) if words[0] == "signal" || ! strings.HasPrefix(words[0], "SIG") { signalmap[signum] = "" } else { // Remove leading SIG and trailing colon. signalmap[signum] = strings.TrimRight(words[0][3:], ":") } signum++ } будет иметь ключи для каждого сигнала, который может быть отправлен в текущей операционной системе. Это будет пустой строкой, куда идти не думаю, что ОС имеет название сигнала ( убьем(1) может назвать некоторые сигналы, которые идут не возвращать имена, я находил, но это, как правило, более высоким номером/нестандартные), или строку название, например, "ИНТ", где имя может быть найдено.

Это поведение недокументировано, подвержено изменениям и может не соответствовать действительности на некоторых платформах. Хотя было бы неплохо, если бы это стало достоянием общественности.

marco.m

06.02.2020 08:42:38

Совершать d455e41 добавили эту функцию в марте 2019 года, в sys/unix.SignalNum()и таким образом доступен по крайней мере с Go 1.13. Подробнее в выпуске GitHub №28027 .

Из документации golang.org/x/sys/unixупаковка:

func SignalNum(s string) syscall.Signal

SignalNum возвращает syscall.Сигнал для сигнала с именем s или 0, если сигнал с таким именем не найден. Название сигнала должно начинаться с "SIG".

Чтобы ответить на аналогичный вопрос: "как я могу перечислить имена всех доступных сигналов (на данной Unix-подобной платформе)", мы можем использовать обратную функцию sys/unix.SignalName():

    import "golang.org/x/sys/unix"

    // See https://github.com/golang/go/issues/28027#issuecomment-427377759
    // for why looping in range 0,255 is enough.
    for i := syscall.Signal(0); i < syscall.Signal(255); i++ {
        name := unix.SignalName(i)
        // Signal numbers are not guaranteed to be contiguous.
        if name != "" {
            fmt.Println(name)
        }
    }
Закрыть X