<p>Harald Welte has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/14200">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">fsm: Allow millisecond granularity in osmo_fsm built-in timer<br><br>So far, the public API of osmo_fsm only allowed integral seconds as<br>timeout.  Let's change that to milli-seconds in order to cover more<br>use cases.<br><br>This introduces<br>* osmo_fsm_inst_state_chg_ms()<br>* osmo_fsm_inst_state_chg_keep_or_start_timer_ms()<br><br>Which both work exactly like their previous counterparts without the _ms<br>suffix - the only difference being that the timeout parameter is<br>specified in milli-seconds, not in seconds.<br><br>The value range for an unsigned long in milli-seconds even on a 32bit<br>platform extends to about 48 days.<br><br>This patch also removes the documentation notice about limiting the<br>maximum value to 0x7fffffff due to time_t signed-ness.  We don't use<br>time_t but unsigned long.<br><br>Change-Id: I35b330e460e80bb67376c77e997e464439ac5397<br>---<br>M include/osmocom/core/fsm.h<br>M src/fsm.c<br>2 files changed, 37 insertions(+), 21 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/00/14200/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/core/fsm.h b/include/osmocom/core/fsm.h</span><br><span>index 41d01a5..1701c45 100644</span><br><span>--- a/include/osmocom/core/fsm.h</span><br><span>+++ b/include/osmocom/core/fsm.h</span><br><span>@@ -243,6 +243,13 @@</span><br><span>                        unsigned long timeout_secs, int T,</span><br><span>                           const char *file, int line);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define osmo_fsm_inst_state_chg_ms(fi, new_state, timeout_ms, T) \</span><br><span style="color: hsl(120, 100%, 40%);">+     _osmo_fsm_inst_state_chg_ms(fi, new_state, timeout_ms, T, \</span><br><span style="color: hsl(120, 100%, 40%);">+                            __FILE__, __LINE__)</span><br><span style="color: hsl(120, 100%, 40%);">+int _osmo_fsm_inst_state_chg_ms(struct osmo_fsm_inst *fi, uint32_t new_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                           unsigned long timeout_ms, int T,</span><br><span style="color: hsl(120, 100%, 40%);">+                              const char *file, int line);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! perform a state change while keeping the current timer running.</span><br><span>  *</span><br><span>  *  This is useful to keep a timeout across several states (without having to round the</span><br><span>@@ -273,6 +280,14 @@</span><br><span>                                                 unsigned long timeout_secs, int T,</span><br><span>                                           const char *file, int line);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define osmo_fsm_inst_state_chg_keep_or_start_timer_ms(fi, new_state, timeout_ms, T) \</span><br><span style="color: hsl(120, 100%, 40%);">+     _osmo_fsm_inst_state_chg_keep_or_start_timer_ms(fi, new_state, timeout_ms, T, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    __FILE__, __LINE__)</span><br><span style="color: hsl(120, 100%, 40%);">+int _osmo_fsm_inst_state_chg_keep_or_start_timer_ms(struct osmo_fsm_inst *fi, uint32_t new_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              unsigned long timeout_ms, int T,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              const char *file, int line);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! dispatch an event to an osmocom finite state machine instance</span><br><span>  *</span><br><span>  *  This is a macro that calls _osmo_fsm_inst_dispatch() with the given</span><br><span>diff --git a/src/fsm.c b/src/fsm.c</span><br><span>index 882a2b4..2d769b8 100644</span><br><span>--- a/src/fsm.c</span><br><span>+++ b/src/fsm.c</span><br><span>@@ -1,7 +1,7 @@</span><br><span> /*! \file fsm.c</span><br><span>  * Osmocom generic Finite State Machine implementation. */</span><br><span> /*</span><br><span style="color: hsl(0, 100%, 40%);">- * (C) 2016 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2016-2019 by Harald Welte <laforge@gnumonks.org></span><br><span>  *</span><br><span>  * SPDX-License-Identifier: GPL-2.0+</span><br><span>  *</span><br><span>@@ -584,7 +584,7 @@</span><br><span> }</span><br><span> </span><br><span> static int state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,</span><br><span style="color: hsl(0, 100%, 40%);">-                  bool keep_timer, unsigned long timeout_secs, int T,</span><br><span style="color: hsl(120, 100%, 40%);">+                   bool keep_timer, unsigned long timeout_ms, int T,</span><br><span>                    const char *file, int line)</span><br><span> {</span><br><span>        struct osmo_fsm *fsm = fi->fsm;</span><br><span>@@ -592,11 +592,6 @@</span><br><span>    const struct osmo_fsm_state *st = &fsm->states[fi->state];</span><br><span>         struct timeval remaining;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Limit to 0x7fffffff seconds as explained by</span><br><span style="color: hsl(0, 100%, 40%);">-   * _osmo_fsm_inst_state_chg()'s API doc. */</span><br><span style="color: hsl(0, 100%, 40%);">- if (timeout_secs > 0x7fffffff)</span><br><span style="color: hsl(0, 100%, 40%);">-               timeout_secs = 0x7fffffff;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>   /* validate if new_state is a valid state */</span><br><span>         if (!(st->out_state_mask & (1 << new_state))) {</span><br><span>                 LOGPFSMLSRC(fi, LOGL_ERROR, file, line,</span><br><span>@@ -627,10 +622,10 @@</span><br><span>                                         "State change to %s (keeping " OSMO_T_FMT ", %ld.%03lds remaining)\n",</span><br><span>                                           osmo_fsm_state_name(fsm, new_state),</span><br><span>                                         OSMO_T_FMT_ARGS(fi->T), remaining.tv_sec, remaining.tv_usec / 1000);</span><br><span style="color: hsl(0, 100%, 40%);">-              } else if (timeout_secs)</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOGPFSMSRC(fi, file, line, "State change to %s (" OSMO_T_FMT ", %lus)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+         } else if (timeout_ms)</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGPFSMSRC(fi, file, line, "State change to %s (" OSMO_T_FMT ", %lums)\n",</span><br><span>                                  osmo_fsm_state_name(fsm, new_state),</span><br><span style="color: hsl(0, 100%, 40%);">-                            OSMO_T_FMT_ARGS(T), timeout_secs);</span><br><span style="color: hsl(120, 100%, 40%);">+                            OSMO_T_FMT_ARGS(T), timeout_ms);</span><br><span>          else</span><br><span>                         LOGPFSMSRC(fi, file, line, "State change to %s (no timeout)\n",</span><br><span>                               osmo_fsm_state_name(fsm, new_state));</span><br><span>@@ -645,8 +640,8 @@</span><br><span>       if (!keep_timer</span><br><span>          || (keep_timer && !osmo_timer_pending(&fi->timer))) {</span><br><span>             fi->T = T;</span><br><span style="color: hsl(0, 100%, 40%);">-           if (timeout_secs)</span><br><span style="color: hsl(0, 100%, 40%);">-                       osmo_timer_schedule(&fi->timer, timeout_secs, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (timeout_ms)</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_timer_schedule(&fi->timer, timeout_ms / 1000, timeout_ms % 1000);</span><br><span>        }</span><br><span> </span><br><span>        /* Call 'onenter' last, user might terminate FSM from there */</span><br><span>@@ -686,13 +681,6 @@</span><br><span>  *  provides a unified way to configure and apply GSM style Tnnnn timers to FSM</span><br><span>  *  state transitions.</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- *  Range: since time_t's maximum value is not well defined in a cross platform</span><br><span style="color: hsl(0, 100%, 40%);">- *  way, clamp timeout_secs to the maximum of the signed 32bit range, or roughly</span><br><span style="color: hsl(0, 100%, 40%);">- *  68 years (float(0x7fffffff) / (60. * 60 * 24 * 365.25) = 68.0497). Thus</span><br><span style="color: hsl(0, 100%, 40%);">- *  ensure that very large timeouts do not wrap around to become very small</span><br><span style="color: hsl(0, 100%, 40%);">- *  ones. Note though that this might still be unsafe on systems with a time_t</span><br><span style="color: hsl(0, 100%, 40%);">- *  range below 32 bits.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span>  *  \param[in] fi FSM instance whose state is to change</span><br><span>  *  \param[in] new_state The new state into which we should change</span><br><span>  *  \param[in] timeout_secs Timeout in seconds (if !=0), maximum-clamped to 2147483647 seconds.</span><br><span>@@ -707,7 +695,13 @@</span><br><span>                              unsigned long timeout_secs, int T,</span><br><span>                           const char *file, int line)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   return state_chg(fi, new_state, false, timeout_secs, T, file, line);</span><br><span style="color: hsl(120, 100%, 40%);">+  return state_chg(fi, new_state, false, timeout_secs*1000, T, file, line);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int _osmo_fsm_inst_state_chg_ms(struct osmo_fsm_inst *fi, uint32_t new_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                           unsigned long timeout_ms, int T,</span><br><span style="color: hsl(120, 100%, 40%);">+                              const char *file, int line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return state_chg(fi, new_state, false, timeout_ms, T, file, line);</span><br><span> }</span><br><span> </span><br><span> /*! perform a state change while keeping the current timer running.</span><br><span>@@ -761,8 +755,15 @@</span><br><span>                                             unsigned long timeout_secs, int T,</span><br><span>                                           const char *file, int line)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       return state_chg(fi, new_state, true, timeout_secs, T, file, line);</span><br><span style="color: hsl(120, 100%, 40%);">+   return state_chg(fi, new_state, true, timeout_secs*1000, T, file, line);</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+int _osmo_fsm_inst_state_chg_keep_or_start_timer_ms(struct osmo_fsm_inst *fi, uint32_t new_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  unsigned long timeout_ms, int T,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              const char *file, int line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return state_chg(fi, new_state, true, timeout_ms, T, file, line);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> </span><br><span> /*! dispatch an event to an osmocom finite state machine instance</span><br><span>  *</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/14200">change 14200</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/14200"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I35b330e460e80bb67376c77e997e464439ac5397 </div>
<div style="display:none"> Gerrit-Change-Number: 14200 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Harald Welte <laforge@gnumonks.org> </div>