diff options
| author | Harald Welte <laforge@gnumonks.org> | 2019-05-18 21:03:55 +0200 | 
|---|---|---|
| committer | Harald Welte <laforge@gnumonks.org> | 2019-06-05 10:01:20 +0000 | 
| commit | 7b74551b93421d30d5f0346042993ff763ddbe25 (patch) | |
| tree | 16d05cdaf21e172d5ca5f94424cb58be0c45a996 | |
| parent | 7a56952307a0d1ff673900e68a73a0a961b5197c (diff) | |
fsm: Allow millisecond granularity in osmo_fsm built-in timer
So far, the public API of osmo_fsm only allowed integral seconds as
timeout.  Let's change that to milli-seconds in order to cover more
use cases.
This introduces
* osmo_fsm_inst_state_chg_ms()
* osmo_fsm_inst_state_chg_keep_or_start_timer_ms()
Which both work exactly like their previous counterparts without the _ms
suffix - the only difference being that the timeout parameter is
specified in milli-seconds, not in seconds.
The value range for an unsigned long in milli-seconds even on a 32bit
platform extends to about 48 days.
This patch also removes the documentation notice about limiting the
maximum value to 0x7fffffff due to time_t signed-ness.  We don't use
time_t but unsigned long.
Change-Id: I35b330e460e80bb67376c77e997e464439ac5397
| -rw-r--r-- | include/osmocom/core/fsm.h | 15 | ||||
| -rw-r--r-- | src/fsm.c | 54 | 
2 files changed, 46 insertions, 23 deletions
| diff --git a/include/osmocom/core/fsm.h b/include/osmocom/core/fsm.h index 41d01a58..1701c45e 100644 --- a/include/osmocom/core/fsm.h +++ b/include/osmocom/core/fsm.h @@ -243,6 +243,13 @@ int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,  			     unsigned long timeout_secs, int T,  			     const char *file, int line); +#define osmo_fsm_inst_state_chg_ms(fi, new_state, timeout_ms, T) \ +	_osmo_fsm_inst_state_chg_ms(fi, new_state, timeout_ms, T, \ +				 __FILE__, __LINE__) +int _osmo_fsm_inst_state_chg_ms(struct osmo_fsm_inst *fi, uint32_t new_state, +				unsigned long timeout_ms, int T, +				const char *file, int line); +  /*! perform a state change while keeping the current timer running.   *   *  This is useful to keep a timeout across several states (without having to round the @@ -273,6 +280,14 @@ int _osmo_fsm_inst_state_chg_keep_or_start_timer(struct osmo_fsm_inst *fi, uint3  						 unsigned long timeout_secs, int T,  						 const char *file, int line); +#define osmo_fsm_inst_state_chg_keep_or_start_timer_ms(fi, new_state, timeout_ms, T) \ +	_osmo_fsm_inst_state_chg_keep_or_start_timer_ms(fi, new_state, timeout_ms, T, \ +						     __FILE__, __LINE__) +int _osmo_fsm_inst_state_chg_keep_or_start_timer_ms(struct osmo_fsm_inst *fi, uint32_t new_state, +						   unsigned long timeout_ms, int T, +						   const char *file, int line); + +  /*! dispatch an event to an osmocom finite state machine instance   *   *  This is a macro that calls _osmo_fsm_inst_dispatch() with the given @@ -1,7 +1,7 @@  /*! \file fsm.c   * Osmocom generic Finite State Machine implementation. */  /* - * (C) 2016 by Harald Welte <laforge@gnumonks.org> + * (C) 2016-2019 by Harald Welte <laforge@gnumonks.org>   *   * SPDX-License-Identifier: GPL-2.0+   * @@ -584,7 +584,7 @@ const char *osmo_fsm_state_name(struct osmo_fsm *fsm, uint32_t state)  }  static int state_chg(struct osmo_fsm_inst *fi, uint32_t new_state, -		     bool keep_timer, unsigned long timeout_secs, int T, +		     bool keep_timer, unsigned long timeout_ms, int T,  		     const char *file, int line)  {  	struct osmo_fsm *fsm = fi->fsm; @@ -592,11 +592,6 @@ static int state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,  	const struct osmo_fsm_state *st = &fsm->states[fi->state];  	struct timeval remaining; -	/* Limit to 0x7fffffff seconds as explained by -	 * _osmo_fsm_inst_state_chg()'s API doc. */ -	if (timeout_secs > 0x7fffffff) -		timeout_secs = 0x7fffffff; -  	/* validate if new_state is a valid state */  	if (!(st->out_state_mask & (1 << new_state))) {  		LOGPFSMLSRC(fi, LOGL_ERROR, file, line, @@ -627,11 +622,18 @@ static int state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,  					   "State change to %s (keeping " OSMO_T_FMT ", %ld.%03lds remaining)\n",  					   osmo_fsm_state_name(fsm, new_state),  					   OSMO_T_FMT_ARGS(fi->T), remaining.tv_sec, remaining.tv_usec / 1000); -		} else if (timeout_secs) -			LOGPFSMSRC(fi, file, line, "State change to %s (" OSMO_T_FMT ", %lus)\n", -				   osmo_fsm_state_name(fsm, new_state), -				   OSMO_T_FMT_ARGS(T), timeout_secs); -		else +		} else if (timeout_ms) { +			if (timeout_ms % 1000 == 0) { +				/* keep log output legacy compatible to avoid autotest failures */ +				LOGPFSMSRC(fi, file, line, "State change to %s (" OSMO_T_FMT ", %lus)\n", +					   osmo_fsm_state_name(fsm, new_state), +					   OSMO_T_FMT_ARGS(T), timeout_ms/1000); +			} else { +				LOGPFSMSRC(fi, file, line, "State change to %s (" OSMO_T_FMT ", %lums)\n", +					   osmo_fsm_state_name(fsm, new_state), +					   OSMO_T_FMT_ARGS(T), timeout_ms); +			} +		} else  			LOGPFSMSRC(fi, file, line, "State change to %s (no timeout)\n",  				   osmo_fsm_state_name(fsm, new_state));  	} else { @@ -645,8 +647,8 @@ static int state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,  	if (!keep_timer  	    || (keep_timer && !osmo_timer_pending(&fi->timer))) {  		fi->T = T; -		if (timeout_secs) -			osmo_timer_schedule(&fi->timer, timeout_secs, 0); +		if (timeout_ms) +			osmo_timer_schedule(&fi->timer, timeout_ms / 1000, timeout_ms % 1000);  	}  	/* Call 'onenter' last, user might terminate FSM from there */ @@ -686,13 +688,6 @@ static int state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,   *  provides a unified way to configure and apply GSM style Tnnnn timers to FSM   *  state transitions.   * - *  Range: since time_t's maximum value is not well defined in a cross platform - *  way, clamp timeout_secs to the maximum of the signed 32bit range, or roughly - *  68 years (float(0x7fffffff) / (60. * 60 * 24 * 365.25) = 68.0497). Thus - *  ensure that very large timeouts do not wrap around to become very small - *  ones. Note though that this might still be unsafe on systems with a time_t - *  range below 32 bits. - *   *  \param[in] fi FSM instance whose state is to change   *  \param[in] new_state The new state into which we should change   *  \param[in] timeout_secs Timeout in seconds (if !=0), maximum-clamped to 2147483647 seconds. @@ -707,7 +702,13 @@ int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,  			     unsigned long timeout_secs, int T,  			     const char *file, int line)  { -	return state_chg(fi, new_state, false, timeout_secs, T, file, line); +	return state_chg(fi, new_state, false, timeout_secs*1000, T, file, line); +} +int _osmo_fsm_inst_state_chg_ms(struct osmo_fsm_inst *fi, uint32_t new_state, +				unsigned long timeout_ms, int T, +				const char *file, int line) +{ +	return state_chg(fi, new_state, false, timeout_ms, T, file, line);  }  /*! perform a state change while keeping the current timer running. @@ -761,8 +762,15 @@ int _osmo_fsm_inst_state_chg_keep_or_start_timer(struct osmo_fsm_inst *fi, uint3  						 unsigned long timeout_secs, int T,  						 const char *file, int line)  { -	return state_chg(fi, new_state, true, timeout_secs, T, file, line); +	return state_chg(fi, new_state, true, timeout_secs*1000, T, file, line);  } +int _osmo_fsm_inst_state_chg_keep_or_start_timer_ms(struct osmo_fsm_inst *fi, uint32_t new_state, +						    unsigned long timeout_ms, int T, +						    const char *file, int line) +{ +	return state_chg(fi, new_state, true, timeout_ms, T, file, line); +} +  /*! dispatch an event to an osmocom finite state machine instance   * | 
