Linux Device Mapper development
 help / color / mirror / Atom feed
From: "Benjamin Marzinski" <bmarzins@redhat.com>
To: Martin Wilck <mwilck@suse.com>
Cc: dm-devel@redhat.com
Subject: Re: [RFC PATCH] multipathd: strict_timing without signals
Date: Wed, 7 Mar 2018 23:19:58 -0600	[thread overview]
Message-ID: <20180308051958.GA14513@octiron.msp.redhat.com> (raw)
In-Reply-To: <20180307141751.29084-1-mwilck@suse.com>

On Wed, Mar 07, 2018 at 03:17:51PM +0100, Martin Wilck wrote:
> The internal usage of SIGALRM by setitimer() function may cause subtle
> conflicts with other uses of SIGALRM, either by multipath-tools code itself
> (e.g. lock_file()) or libc (e.g. glob()).
> 
> This patch changes the checkerloop to use an interval timer and a pthread
> condition variable. No signals are used except those used by libpthread
> behind the scenes.
> 

I'm not sure that I'd call this simpler. Personally, I prefer using
nanosleep(), since it is just a system call instead of a library that
creates a thread every second to wake up the checker thread. But I don't
actually think that there's anything wrong with this, and I'm sure it
will come closer to waking the checker loop on the second, so if you're
strongly in favor of it, that's fine. Otherwise, I'll just rebase my
nanosleep patch.

-Ben


> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  multipathd/Makefile |   2 +-
>  multipathd/main.c   | 113 ++++++++++++++++++++++++++++++++++++++--------------
>  2 files changed, 85 insertions(+), 30 deletions(-)
> 
> diff --git a/multipathd/Makefile b/multipathd/Makefile
> index 4c9d29634160..c348f02ef7f8 100644
> --- a/multipathd/Makefile
> +++ b/multipathd/Makefile
> @@ -10,7 +10,7 @@ CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) \
>  	  -I$(mpathcmddir) -I$(thirdpartydir)
>  LDFLAGS += $(BIN_LDFLAGS)
>  LIBDEPS += -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist \
> -	   -L$(mpathcmddir) -lmpathcmd -ludev -ldl -lurcu -lpthread \
> +	   -L$(mpathcmddir) -lmpathcmd -ludev -ldl -lurcu -lpthread -lrt \
>  	   -ldevmapper -lreadline
>  
>  ifdef SYSTEMD
> diff --git a/multipathd/main.c b/multipathd/main.c
> index 6e6c52a52783..c9c57c5baece 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -1848,6 +1848,68 @@ static void init_path_check_interval(struct vectors *vecs)
>  	}
>  }
>  
> +static pthread_mutex_t checker_lock = PTHREAD_MUTEX_INITIALIZER;
> +static pthread_cond_t checker_cond = PTHREAD_COND_INITIALIZER;
> +
> +static void checker_notify(union sigval sv) {
> +
> +	pthread_mutex_lock(&checker_lock);
> +	pthread_cond_broadcast(&checker_cond);
> +	pthread_mutex_unlock(&checker_lock);
> +}
> +
> +static void unlock_mutex(void *arg)
> +{
> +	pthread_mutex_unlock((pthread_mutex_t*)arg);
> +}
> +
> +void cleanup_timer(void *arg)
> +{
> +	timer_t tmr = (timer_t)arg;
> +
> +	if (tmr != 0)
> +		timer_delete(tmr);
> +}
> +
> +static timer_t setup_check_timer(void)
> +{
> +	timer_t tmr = (timer_t)0;
> +	struct sigevent se;
> +
> +	memset(&se, 0, sizeof(se));
> +	se.sigev_notify = SIGEV_THREAD;
> +	se.sigev_notify_function = checker_notify;
> +
> +	if (timer_create(CLOCK_MONOTONIC, &se, &tmr)) {
> +		condlog(2, "%s: errno %d creating monotonic timer",
> +			__func__, errno);
> +		if (timer_create(CLOCK_REALTIME, &se, &tmr))
> +			condlog(0, "%s: errno %d creating timer",
> +				__func__, errno);
> +	}
> +	return tmr;
> +}
> +
> +static int set_check_timer(timer_t tmr, bool arm)
> +{
> +	struct itimerspec is;
> +
> +	if (tmr == 0)
> +		return -1;
> +
> +	if (arm) {
> +		is.it_value.tv_sec = 1;
> +		is.it_interval.tv_sec = 1;
> +	} else {
> +		is.it_value.tv_sec = 0;
> +		is.it_interval.tv_sec = 0;
> +	}
> +	is.it_value.tv_nsec = 0;
> +	is.it_interval.tv_nsec = 0;
> +
> +	return timer_settime(tmr, 0, &is, NULL);
> +}
> +
>  static void *
>  checkerloop (void *ap)
>  {
> @@ -1855,9 +1917,10 @@ checkerloop (void *ap)
>  	struct path *pp;
>  	int count = 0;
>  	unsigned int i;
> -	struct itimerval timer_tick_it;
>  	struct timespec last_time;
>  	struct config *conf;
> +	timer_t check_timer;
> +	int old_strict_timing = 0;
>  
>  	pthread_cleanup_push(rcu_unregister, NULL);
>  	rcu_register_thread();
> @@ -1865,6 +1928,9 @@ checkerloop (void *ap)
>  	vecs = (struct vectors *)ap;
>  	condlog(2, "path checkers start up");
>  
> +	check_timer = setup_check_timer();
> +	pthread_cleanup_push(cleanup_timer, (void*)check_timer);
> +
>  	/* Tweak start time for initial path check */
>  	if (clock_gettime(CLOCK_MONOTONIC, &last_time) != 0)
>  		last_time.tv_sec = 0;
> @@ -1873,8 +1939,7 @@ checkerloop (void *ap)
>  
>  	while (1) {
>  		struct timespec diff_time, start_time, end_time;
> -		int num_paths = 0, ticks = 0, signo, strict_timing, rc = 0;
> -		sigset_t mask;
> +		int num_paths = 0, ticks = 0, strict_timing, rc = 0;
>  
>  		if (clock_gettime(CLOCK_MONOTONIC, &start_time) != 0)
>  			start_time.tv_sec = 0;
> @@ -1956,40 +2021,30 @@ checkerloop (void *ap)
>  		}
>  		check_foreign();
>  		post_config_state(DAEMON_IDLE);
> +
>  		conf = get_multipath_config();
>  		strict_timing = conf->strict_timing;
>  		put_multipath_config(conf);
> -		if (!strict_timing)
> +
> +		if (check_timer && (old_strict_timing != strict_timing) &&
> +		    set_check_timer(check_timer, !!strict_timing) != 0) {
> +			condlog(1, "%s: errno %d %sarming interrupt timer",
> +				__func__, errno, strict_timing ? "" : "dis");
> +			strict_timing = 0;
> +		}
> +		old_strict_timing = strict_timing;
> +
> +		if (!strict_timing || !check_timer)
>  			sleep(1);
>  		else {
> -			timer_tick_it.it_interval.tv_sec = 0;
> -			timer_tick_it.it_interval.tv_usec = 0;
> -			if (diff_time.tv_nsec) {
> -				timer_tick_it.it_value.tv_sec = 0;
> -				timer_tick_it.it_value.tv_usec =
> -				     1000UL * 1000 * 1000 - diff_time.tv_nsec;
> -			} else {
> -				timer_tick_it.it_value.tv_sec = 1;
> -				timer_tick_it.it_value.tv_usec = 0;
> -			}
> -			setitimer(ITIMER_REAL, &timer_tick_it, NULL);
> -
> -			sigemptyset(&mask);
> -			sigaddset(&mask, SIGALRM);
> -			condlog(3, "waiting for %lu.%06lu secs",
> -				timer_tick_it.it_value.tv_sec,
> -				timer_tick_it.it_value.tv_usec);
> -			if (sigwait(&mask, &signo) != 0) {
> -				condlog(3, "sigwait failed with error %d",
> -					errno);
> -				conf = get_multipath_config();
> -				conf->strict_timing = 0;
> -				put_multipath_config(conf);
> -				break;
> -			}
> +			pthread_mutex_lock(&checker_lock);
> +			pthread_cleanup_push(unlock_mutex, &checker_lock);
> +			pthread_cond_wait(&checker_cond, &checker_lock);
> +			pthread_cleanup_pop(1);
>  		}
>  	}
>  	pthread_cleanup_pop(1);
> +	pthread_cleanup_pop(1);
>  	return NULL;
>  }
>  
> -- 
> 2.16.1

      reply	other threads:[~2018-03-08  5:19 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-07 14:17 [RFC PATCH] multipathd: strict_timing without signals Martin Wilck
2018-03-08  5:19 ` Benjamin Marzinski [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180308051958.GA14513@octiron.msp.redhat.com \
    --to=bmarzins@redhat.com \
    --cc=dm-devel@redhat.com \
    --cc=mwilck@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox