Updated question - first version below
I have set up a custom signal handler to buffer frames being removed from a CAN interface. In the handler, I block the signal first, and unblock it last, using pthread_sigmask()
.
In bufferMessageDirect()
, the interface ID iface_id
is checked, and in case of error, because this can only normally be my fault, assert(0)
is called.
After my programme has been running for some time, but the exact time varies, with a stream of CAN frames arriving, this assert()
is tripped and execution ends. When I inspect the signal handler stack frame, iface_id
is 0
which is valid, but the argument can_interface_id
as passed into bufferMessageDirect()
is -1
.
I have a dump of the incoming CAN frames, and there is nothing unusual about them. The stack frame for the signal handler indicates that the converted CAN message is as expected and the the interface ID is 0
. In the stack frame of bufferMessageDirect()
, the interface ID is -1
.
Please would you offer advice on what might be causing this issue?
I added the calls to pthread_sigmask()
because I thought that, maybe, the signal was firing while its handler was already in progress.
/************************************************************** 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;
}
Old question
I have set up a custom signal handler to buffer frames being removed from a CAN interface. In the handler, I block the signal first, and unblock it last, using pthread_sigmask()
.
The basic recipe is:
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);
}
In buffer_push()
, the interface ID iface_id
is checked, and in case of error, because this can only normally be my fault, assert(0)
is called.
After my programme has been running for some time, but the exact time varies, with a stream of CAN frames arriving, this assert()
is tripped and execution ends. When I inspect the signal handler stack frame, iface_id
is 0
which is valid, but the argument as passed into buffer_push()
is -1
.
I added the calls to pthread_sigmask()
because I thought that, maybe, the signal was firing while its handler was already in progress.
The prototype for buffer_push()
is:
result_enum_type
buffer_push(
iface_enum_type const can_interface_id,
can_frame_type const *const p_message)
iface_id
is declared outside the function like so:
static volatile uint32_t iface_id = 0;
For the avoidance of doubt, below the call to buffer_push()
it is all my own code --- no external calls. Also, I have a dump of the incoming CAN frames, and this signal handler correctly parses each one.
Please would you offer advice on what might be causing this issue?