Skip to content

Commit fd2744a

Browse files
Refactor signal handler in mbpoll.c to use volatile flag
The previous signal handler implementation called unsafe functions (printf, exit, free) directly from the signal context, which is undefined behavior and can lead to deadlocks or crashes. This commit refactors the signal handling logic: - Introduces a global `volatile sig_atomic_t g_bExitSignal` flag. - Updates `vSigIntHandler` to only set this flag. - Renames the old handler logic to `vCleanup` and calls it from `main` after the loop exits. - Updates the main polling loop to check `g_bExitSignal` periodically and break the loop on signal. - Suppresses error messages from blocking Modbus calls if the exit signal is set, ensuring a clean exit experience. This change ensures async-signal-safety while preserving the existing behavior of printing statistics and exit messages on SIGINT. Co-authored-by: zknpr <96851588+zknpr@users.noreply.github.com>
1 parent 0d5b8ec commit fd2744a

1 file changed

Lines changed: 36 additions & 14 deletions

File tree

src/mbpoll.c

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ typedef struct xMbPollContext {
266266

267267
/* private variables ======================================================== */
268268

269+
static volatile sig_atomic_t g_bExitSignal = 0;
270+
269271
static xMbPollContext ctx = {
270272
// Parameters
271273
.eMode = DEFAULT_MODE,
@@ -367,6 +369,7 @@ const char * sEnumToStr (int iElmt, const int * iList,
367369
const char ** psStrList, int iSize);
368370
const char * sFunctionToStr (eFunctions eFunction);
369371
const char * sModeToStr (eModes eMode);
372+
void vCleanup (void);
370373
void vSigIntHandler (int sig);
371374
float fSwapFloat (float f);
372375
int32_t lSwapLong (int32_t l);
@@ -932,6 +935,9 @@ main (int argc, char **argv) {
932935

933936
// Start of polling loop
934937
do {
938+
if (g_bExitSignal) {
939+
break;
940+
}
935941

936942
if (ctx.bIsWrite) {
937943

@@ -985,9 +991,11 @@ main (int argc, char **argv) {
985991
printf ("Written %d references.\n", ctx.iCount);
986992
}
987993
else {
988-
ctx.iErrorCount++;
989-
fprintf (stderr, "Write %s failed: %s\n",
990-
sFunctionToStr (ctx.eFunction), modbus_strerror (errno));
994+
if (!g_bExitSignal) {
995+
ctx.iErrorCount++;
996+
fprintf (stderr, "Write %s failed: %s\n",
997+
sFunctionToStr (ctx.eFunction), modbus_strerror (errno));
998+
}
991999
}
9921000
// End write --------------------------------------------------------
9931001
}
@@ -996,6 +1004,9 @@ main (int argc, char **argv) {
9961004

9971005
// Read -------------------------------------------------------------
9981006
for (i = 0; i < ctx.iSlaveCount; i++) {
1007+
if (g_bExitSignal) {
1008+
break;
1009+
}
9991010

10001011
iRet = modbus_set_slave (ctx.xBus, ctx.piSlaveAddr[i]);
10011012
if (iRet != 0) {
@@ -1016,6 +1027,10 @@ main (int argc, char **argv) {
10161027

10171028
int j;
10181029
for (j = 0; j < ctx.iStartCount; j++) {
1030+
if (g_bExitSignal) {
1031+
break;
1032+
}
1033+
10191034
// libmodbus utilise les adresses PDU !
10201035
iStartReg = ctx.piStartRef[j] - ctx.iPduOffset;
10211036

@@ -1050,25 +1065,27 @@ main (int argc, char **argv) {
10501065
vPrintReadValues (ctx.piStartRef[j], ctx.iCount, &ctx);
10511066
}
10521067
else {
1053-
ctx.iErrorCount++;
1054-
fprintf (stderr, "Read %s failed: %s\n",
1055-
sFunctionToStr (ctx.eFunction),
1056-
modbus_strerror (errno));
1068+
if (!g_bExitSignal) {
1069+
ctx.iErrorCount++;
1070+
fprintf (stderr, "Read %s failed: %s\n",
1071+
sFunctionToStr (ctx.eFunction),
1072+
modbus_strerror (errno));
1073+
}
10571074
}
10581075
}
1059-
if (ctx.bIsPolling) {
1076+
if (ctx.bIsPolling && !g_bExitSignal) {
10601077

10611078
mb_delay (ctx.iPollRate);
10621079
}
10631080
}
10641081
// End read ---------------------------------------------------------
10651082
}
10661083
}
1067-
while (ctx.bIsPolling);
1084+
while (ctx.bIsPolling && !g_bExitSignal);
10681085
}
10691086

1070-
vSigIntHandler (SIGTERM);
1071-
return 0;
1087+
vCleanup ();
1088+
return (ctx.iErrorCount == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
10721089
}
10731090

10741091

@@ -1341,7 +1358,7 @@ vAllocate (xMbPollContext * ctx) {
13411358

13421359
// -----------------------------------------------------------------------------
13431360
void
1344-
vSigIntHandler (int sig) {
1361+
vCleanup (void) {
13451362

13461363
if ( (ctx.bIsPolling) && (!ctx.bIsWrite)) {
13471364

@@ -1366,14 +1383,19 @@ vSigIntHandler (int sig) {
13661383
iChipIoClose (xChip);
13671384
// -----------------------------------------------------------------------------
13681385
#endif /* USE_CHIPIO defined */
1369-
if (sig == SIGINT) {
1386+
if (g_bExitSignal == SIGINT) {
13701387
printf ("\neverything was closed.\nHave a nice day !\n");
13711388
}
13721389
else {
13731390
putchar ('\n');
13741391
}
13751392
fflush (stdout);
1376-
exit (ctx.iErrorCount == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
1393+
}
1394+
1395+
// -----------------------------------------------------------------------------
1396+
void
1397+
vSigIntHandler (int sig) {
1398+
g_bExitSignal = sig;
13771399
}
13781400

13791401
// -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)