Skip to content

Commit

Permalink
Avoid subthread signal handling (#1752)
Browse files Browse the repository at this point in the history
* Avoid subthread signal handling

* subthread signal handling

Since multiple threads responding simultaneously to a signal leading
to race condition, this is used to ensure that only the main thread
handles the signal.

* aesthetic improvements

* Revert IEPTHREADATTRDESTROY to original value
  • Loading branch information
xTire authored Sep 13, 2024
1 parent 36deba4 commit d5713db
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/iperf_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ enum {
IEPTHREADJOIN=152, // Unable to join thread (check perror)
IEPTHREADATTRINIT=153, // Unable to initialize thread attribute (check perror)
IEPTHREADATTRDESTROY=154, // Unable to destroy thread attribute (check perror)
IEPTHREADSIGMASK=155, // Unable to initialize sub thread signal mask (check perror)
/* Stream errors */
IECREATESTREAM = 200, // Unable to create a new stream (check herror/perror)
IEINITSTREAM = 201, // Unable to initialize stream (check herror/perror)
Expand Down
18 changes: 18 additions & 0 deletions src/iperf_client_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <sys/select.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <signal.h>

#include "iperf.h"
#include "iperf_api.h"
Expand All @@ -56,6 +57,23 @@ iperf_client_worker_run(void *s) {
struct iperf_stream *sp = (struct iperf_stream *) s;
struct iperf_test *test = sp->test;

/* Blocking signal to make sure that signal will be handled by main thread */
sigset_t set;
sigemptyset(&set);
#ifdef SIGTERM
sigaddset(&set, SIGTERM);
#endif
#ifdef SIGHUP
sigaddset(&set, SIGHUP);
#endif
#ifdef SIGINT
sigaddset(&set, SIGINT);
#endif
if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
i_errno = IEPTHREADSIGMASK;
goto cleanup_and_fail;
}

/* Allow this thread to be cancelled even if it's in a syscall */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
Expand Down
3 changes: 3 additions & 0 deletions src/iperf_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,9 @@ iperf_strerror(int int_errno)
snprintf(errstr, len, "unable to create thread attributes");
perr = 1;
break;
case IEPTHREADSIGMASK:
snprintf(errstr, len, "unable to change mask of blocked signals");
break;
case IEPTHREADATTRDESTROY:
snprintf(errstr, len, "unable to destroy thread attributes");
perr = 1;
Expand Down
18 changes: 18 additions & 0 deletions src/iperf_server_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <sys/resource.h>
#include <sched.h>
#include <setjmp.h>
#include <signal.h>

#include "iperf.h"
#include "iperf_api.h"
Expand All @@ -69,6 +70,23 @@ iperf_server_worker_run(void *s) {
struct iperf_stream *sp = (struct iperf_stream *) s;
struct iperf_test *test = sp->test;

/* Blocking signal to make sure that signal will be handled by main thread */
sigset_t set;
sigemptyset(&set);
#ifdef SIGTERM
sigaddset(&set, SIGTERM);
#endif
#ifdef SIGHUP
sigaddset(&set, SIGHUP);
#endif
#ifdef SIGINT
sigaddset(&set, SIGINT);
#endif
if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
i_errno = IEPTHREADSIGMASK;
goto cleanup_and_fail;
}

/* Allow this thread to be cancelled even if it's in a syscall */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
Expand Down

0 comments on commit d5713db

Please sign in to comment.