Обработать сигнал с помощью cgo, go не может обработать сигнал

Вот мой main.go

package main

/*
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

// Global variable to store old action
struct sigaction old_action;

// Signal handler function
void handler(int signum, siginfo_t *info, void *context) {
    printf("Received signal: %d\n", signum);
    printf("Sent by PID: %d\n", info->si_pid);
    printf("Signal code: %d\n", info->si_code);
    printf("User ID: %d\n", info->si_uid);
    if (info->si_pid != 0) {
        char proc_status_path[256];
        snprintf(proc_status_path, sizeof(proc_status_path), "/rootfs/proc/%d/status", info->si_pid);
        FILE *fp = fopen(proc_status_path, "r");
        if (fp == NULL) {
            perror("fopen");
            return;
        }
        char buffer[256];
        while (fgets(buffer, sizeof(buffer), fp)) {
            printf("%s", buffer);
        }
        fclose(fp);
    }
}


// Function to set up signal handling
void setup_signal_handler() {
    struct sigaction action;
    // Initialize the action structure
    memset(&action, 0, sizeof(action));
    sigfillset(&action.sa_mask); // Block all signals while the handler is executing
    action.sa_sigaction = handler; // Set the signal handler function
    action.sa_flags = SA_SIGINFO | SA_ONSTACK; // Set flags

    // Set up the signal handler for SIGTERM
    if (sigaction(SIGTERM, &action, &old_action) < 0) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }
}
*/
import "C"
import "fmt"

func main() {
    C.setup_signal_handler()
    for {
        fmt.Println("Sleeping..., waiting for signal")
        C.sleep(10)
    }
}

Я пытаюсь использовать язык C, чтобы помочь мне обработать сигнал и распечатать pid отправителя сигнала. Исходные пакеты Go (syscall, os,... и т.д.) не предоставляют такой информации. Однако, когда я запускаю приведенный выше код, запускаются два процесса. Один — go run ., а другой — signal, это имя моего пакета go. Когда я посылаю сигнал на go run ., ничего не происходит, а на signal появляется всплывающая информация.

Я понимаю, что пакет Implicity C является ответвлением другого процесса для запуска этого кода C. Я не могу применить обработчик сигнала в C к своему процессу go.

Моя цель — распечатать информацию о любом виде сигнала, отправленного в мой go процесс. Сопутствующая информация должна включать как минимум pid, ppid. Возможно, есть другое лучшее решение для моей ситуации.

Есть ли какой-нибудь документ о cgo? Мне не удалось найти документ, описывающий механизм управления процессом пакета cgo.


[ОБНОВЛЯТЬ]

Спасибо @kostix и @eik за ответы! Я попробовал go build и запустил двоичный файл позже.

Перед возвратом handler я заменяю обработчик SIGTERM старым действием и снова вызываю SIGTERM. Это работает и подает сигнал Go. Notify успешно передает os.Signal в канал. Однако когда я заменяю обработчик обратно на исходный, это оказывается рекурсивным сигналом.

        // ...
        fclose(fp);
    }
    fflush(stdout);
    sigaction(SIGTERM, &old_action, &action);
    raise(SIGTERM);   
}

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

Никогда не используйте go run. Он компилирует ваш код, запускает полученный исполняемый файл образа и затем выбрасывает его. Итак, if не создает ничего, кроме путаницы, и, следовательно, применим только в тех случаях, когда вы очень хорошо понимаете, что происходит, и довольны результатом. Просто используйте go build/go install + проведите результат вручную.

kostix 03.06.2024 11:54

Спасибо за комментарий! Я попробовал go build и обновил свой пост. До сих пор неясно, как обрабатывать сигнал от обработчика C и Go.

WeiAnHsieh 04.06.2024 03:06

«… пакет C неявно является ответвлением другого процесса для запуска этого кода C». — нет, это определенно не тот случай. «Есть ли какой-нибудь документ о cgo?» – конечно, есть . Что касается вашего первоначального вопроса: читали ли вы документацию по os/signal относительно ее взаимодействия с кодом, отличным от Go?

kostix 04.06.2024 11:20
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
0
3
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Процесс go run . — это ваш компилятор Go. Он компилирует вашу программу (включая код C) в исполняемый файл, а затем запускает полученную программу (сборку) с помощью buildRunProgram , которая вызывает RunStdin , который запускает новый прогресс с помощью Cmd.Run.

Итак, то, что вы видите, — это нормально, и signal — это ваша программа. Если вам это не нравится, используйте go build и запустите его отдельно с помощью ./signal.

Обновлено: в cgo код C находится в том же двоичном виде, что и код Go. Поскольку они выполняются в одном и том же процессе, сигнал доставляется только один раз, поэтому сигнал получает только один обработчик. Это не имеет ничего общего с Go или программой, написанной на нескольких языках. Попробуйте написать программу на C с двумя обработчиками сигналов.

Спасибо за комментарий! Я попробовал go build создать исполняемый файл и запустить программу непосредственно в своей Linux-подобной среде. На этот раз есть только один процесс. Однако мне все еще нужно обрабатывать сигнал как в обработчике C, так и в Go.

WeiAnHsieh 04.06.2024 03:09

Я исправил ответ. Попробуйте написать программу на чистом C с двумя обработчиками сигналов :D Также отметьте ответ как полезный, если он полезен ;)

eik 04.06.2024 11:08

Я понимаю, что сигнал мог быть доставлен только один раз. Пакет сигналов Go волшебным образом вызывает signal_enable в signal_unix.go. Я уверен, что golang заставляет обработчик сигнала cgo сосуществовать с обработчиком в go (с помощью invoke или других уловок). Я пытаюсь вставить os.Signal в сигнальный канал Go после того, как cgo получит его, вручную вызываю себя...

WeiAnHsieh 05.06.2024 08:10

Другие вопросы по теме