簡體   English   中英

從信號處理程序調用的 function 中的參數值如何與傳入的值不同?

[英]How can the value of an argument in a function called from a signal handler be different from the value passed in?

更新的問題-下面的第一個版本

我已經設置了一個自定義信號處理程序來緩沖從 CAN 接口中刪除的幀。 在處理程序中,我首先阻塞信號,最后使用pthread_sigmask()解除阻塞。

bufferMessageDirect()中,檢查接口 ID iface_id ,如果出現錯誤,因為這通常只能是我的錯,所以調用assert(0)

在我的程序運行了一段時間后,但確切時間有所不同,隨着 stream 的 CAN 幀到達,此assert()被觸發並執行結束。 當我檢查信號處理程序堆棧幀時, iface_id0這是有效的,但是傳遞給bufferMessageDirect()的參數can_interface_id-1

我有一個傳入的 CAN 幀的轉儲,它們沒有任何異常。 信號處理程序的堆棧幀表明轉換后的 CAN 消息符合預期,接口 ID 為0 bufferMessageDirect()的堆棧幀中,接口 ID 為-1

請您就可能導致此問題的原因提供建議?

我添加了對pthread_sigmask()的調用,因為我認為,也許信號在其處理程序已經在進行中時正在觸發。

/************************************************************** EXTERNAL DATA */
extern can_metadata_t  can_metadata;
extern internal_time_t otherthing_heartbeat[THING_QUANTITY];
extern internal_time_t something_heartbeat[THING_QUANTITY];


/************************************************************** INTERNAL DATA */
STATIC volatile ssize_t          bytes_read  = 0;
STATIC volatile int              socket_desc = 0;
STATIC volatile struct can_frame frame       = {0};
STATIC volatile uint32_t         receiver_id = 0u;
STATIC volatile uint32_t         command_id  = 0u;
STATIC volatile uint32_t         function_id = 0u;
STATIC volatile int32_t          iface_id    = 0;
STATIC volatile cand_result_t    d_result    = CAND_RESULT_OK;
STATIC volatile canh_result_t    h_result    = CANH_RESULT_OK;

STATIC volatile internal_time_t *const heartbeats[2] =
{
    otherthing_heartbeat,
    something_heartbeat,
};

// ============================================================================
void
myHandler(int       const        signal_number,
          siginfo_t       *const p_signal_info,
          void            *const p_ucontext)
{
    uint8_t       ii           = 0u;
    uint8_t       thing_id     = 0u;
    bool          is_something = 0u;
    can_message_t message      = {0};
    int           std_result = 0;

    /* Mark as unwanted */
    (void) p_ucontext;

    if ((HANDLERS_SIGNUM_CAN_RX != signal_number) ||
        (NULL                   == p_signal_info))
    {
        /* No penalty for these conditions */
        return;
    }

    else
    {
        /* Block this signal */
        std_result = pthread_sigmask(SIG_BLOCK, &signal_set_can, NULL);

        /* This result is asserted because the only failure is if the SIG_BLOCK
         * action is invalid
         */
        assert(0 == std_result);

        socket_desc = p_signal_info->si_fd;
        bytes_read = read(socket_desc, &frame, sizeof(frame));

        if (bytes_read != sizeof(frame))
        {
            // ...
            goto unblock_signal;
        }
    }

    /* Is this an error frame? */
    if ((frame.can_id & CAN_ERR_FLAG) != 0u)
    {
        // ...
        goto unblock_signal;
    }

    /* Is this a frame with an 11-bit ID? */
    else if ((frame.can_id & CAN_EFF_FLAG) == 0u)
    {
        // ...
        goto unblock_signal;
    }

    /* Is this a frame with a 29-bit ID? */
    else
    {
        function_id = frame.can_id & CAN_EFF_MASK;
        command_id  = function_id;
        receiver_id = function_id;

        function_id &= MASK_FUNCTION_ID;
        function_id >>= POSITION_FUNCTION_ID;

        command_id &= MASK_COMMAND_ID;
        command_id >>= POSITION_COMMAND_ID;

        receiver_id &= MASK_RECEIVER_ID;

        thing_id = (frame.can_id & MASK_THING_ID) - 1u;
        is_something  = frame.can_id & MASK_RECEIVER_IS_SOMETHING;

        /* Update the housekeeping stats */
        if (function_id < FUNCTIONCODE_QUANTITY)
        {
            delivered_for_function_id[function_id]++;
        }
        else
        {
            delivered_for_function_id[FUNCTIONCODE_QUANTITY]++;
        }
    }

    /* Handle emergency messages */
    if (FUNCTIONCODE_EMGC == function_id)
    {
        // ...
        goto unblock_signal;
    }

    /* Handle heartbeats */
    if (FUNCTIONCODE_HB == function_id)
    {
        // Gets time from CLOCK_MONOTONIC_RAW and converts to microseconds
        (void) getRawTimeFormatInternal(&(heartbeats[is_something][thing_id]));

        goto unblock_signal;
    }

    /* Discard anything but Responses */
    if (FUNCTIONCODE_RESPONSE != function_id)
    {
        // ...
        goto unblock_signal;
    }

    /* Make the busy something available again */
    if (true == is_something)
    {
        something_busy_bits &= ~(1 << thing_id);
    }

    /* Otherwise, find the interface ID and push to the buffer */
    iface_id = -1;

    /* Find buffer first */
    for (ii = 0u; ii < CAN_INTERFACE_QUANTITY; ii++)
    {
        if (can_metadata.socket[ii] == socket_desc)
        {
            iface_id = (int32_t) ii;
            break;
        }
    }

    if (-1 == iface_id)
    {
        goto unblock_signal;
    }

    /* Otherwise convert and buffer */
    h_result = canFrameToMessage(&message, &frame);

    if (CAN_RESULT_OK != h_result)
    {
        // ...
        goto unblock_signal;
    }

    d_result = bufferMessageDirect((can_interface_id_t) iface_id, &message);

    if (CAN_RESULT_OK != d_result)
    {
        // ...
        assert(0);
    }

    // ........................................................................
    unblock_signal:

    /* Unblock this signal */
    std_result = pthread_sigmask(SIG_UNBLOCK, &signal_set_can, NULL);

    /* This result is asserted because the only failure is if the SIG_BLOCK
     * action is invalid
     */
    assert(0 == std_result);
}

// ============================================================================
cand_result_t
bufferMessageDirect(
    can_interface_id_t const        can_interface_id,
    can_message_t      const *const p_message)
{
    canh_result_t h_result = CANH_RESULT_OK;
    cand_result_t result   = CAND_RESULT_OK;

    h_result = validateInterfaceId(can_interface_id);

    if (CANH_RESULT_OK != h_result)
    {
        result = CAND_RESULT_INTERNAL_ERROR;
        assert(0); // This is tripped, because can_interface_id is -1
    }

    // ...
    // Push into buffer (call to buffer utility)

    return result;
}

老問題

我已經設置了一個自定義信號處理程序來緩沖從 CAN 接口中刪除的幀。 在處理程序中,我首先阻塞信號,最后使用pthread_sigmask()解除阻塞。

基本配方是:

void
myHandler(
    int       const        signal_number,
    siginfo_t       *const p_signal_info,
    void            *const p_ucontext)
{
  check_signal_info();
  pthread_sigmask(SIG_BLOCK, set_of_this_signal_only);
  read(socket, &can_frame, sizeof(can_frame));
  derive_can_iface_id(&iface_id);

  buffer_push((iface_enum_type) iface_id, can_frame);

  pthread_sigmask(SIG_UNBLOCK, set_of_this_signal_only);
}

buffer_push()中,檢查接口 ID iface_id ,如果出現錯誤,因為這通常只能是我的錯,所以調用assert(0)

在我的程序運行了一段時間后,但確切時間有所不同,隨着 stream 的 CAN 幀到達,此assert()被觸發並執行結束。 當我檢查信號處理程序堆棧幀時, iface_id0這是有效的,但傳遞給buffer_push()的參數是-1

我添加了對pthread_sigmask()的調用,因為我認為,也許信號在其處理程序已經在進行中時正在觸發。

buffer_push()的原型是:

result_enum_type
buffer_push(
    iface_enum_type const        can_interface_id,
    can_frame_type  const *const p_message)

iface_id在 function 之外聲明,如下所示:

static volatile uint32_t iface_id = 0;

為避免疑義,在對buffer_push()的調用下面是我自己的所有代碼 --- 沒有外部調用。 另外,我有一個傳入的 CAN 幀的轉儲,這個信號處理程序正確地解析了每個幀。

請您就可能導致此問題的原因提供建議?

從信號處理程序調用的 function 中的參數值如何與傳入的值不同?

怎么會這樣? 因為C 標准說它可以

當抽象機的處理因收到信號而中斷時,既不是無鎖原子對象也不是volatile sig_atomic_t類型的對象的值是未指定的,浮點環境的 state 也是如此。 當處理程序退出時,處理程序修改的任何 object 的值既不是無鎖原子 object 也不是volatile sig_atomic_t類型的值變得不確定,如果它被處理程序修改且未恢復,浮點環境的 state 也是如此到原來的 state。

以下都不是“無鎖原子對象”或“類型volatile sig_atomic_t ”:

STATIC volatile ssize_t          bytes_read  = 0;
STATIC volatile int              socket_desc = 0;
STATIC volatile struct can_frame frame       = {0};
STATIC volatile uint32_t         receiver_id = 0u;
STATIC volatile uint32_t         command_id  = 0u;
STATIC volatile uint32_t         function_id = 0u;
STATIC volatile int32_t          iface_id    = 0;
STATIC volatile cand_result_t    d_result    = CAND_RESULT_OK;
STATIC volatile canh_result_t    h_result    = CANH_RESULT_OK;

STATIC volatile internal_time_t *const heartbeats[2] =
{
    otherthing_heartbeat,
    something_heartbeat,
};

當您的信號處理程序被調用時,這些變量中的每一個都具有不確定的值,並且如果它們在信號處理程序中被修改,那么當您的信號處理程序返回時,這些變量中的每一個都將變得不確定。

另請注意(草案)C11 標准的腳注 188

因此,信號處理程序通常不能調用標准庫函數。

基本上,您不能安全地在信號處理程序中做任何事情。 嚴格符合 C 的代碼只能修改上面提到的對象。 POSIX 擴展了信號處理程序可以安全地執行的操作,以調用異步信號安全的函數——一個非常有限的集合 Windows也有類似規定。 Linux signal-safety手冊頁提供了特定於 Linux 的功能列表,這些功能在 Linux 上是異步信號安全的。

可能發生的情況是您的正常處理和信號處理之間存在競爭條件。 它在大多數情況下都有效,但時不時會出現其中一個競爭條件,並且您會得到損壞的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM