<p>fixeria <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmocom-bb/+/16177">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, but someone else must approve
  pespin: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">trx_toolkit/clck_gen.py: refactor CLCKGen to use a single thread<br><br>The previous approach was based on threading.Timer, so on each clock<br>iteration one thread spawned another new thread.  So far it worked<br>well, but such frequent spawning involves an additional overhead.<br><br>After this change, CLCKGen.start() allocates and starts a new thread,<br>that periodically sends clock indications and sleep()s during the<br>indication intervals.  The CLCKGen.stop() in its turn terminates<br>that thread and frees the memory.<br><br>Change-Id: Ibe477eb0a1ee2193c1ff16452a407be7e858b2ef<br>---<br>M src/target/trx_toolkit/clck_gen.py<br>M src/target/trx_toolkit/transceiver.py<br>2 files changed, 41 insertions(+), 22 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/target/trx_toolkit/clck_gen.py b/src/target/trx_toolkit/clck_gen.py</span><br><span>index c58d8bd..92ca217 100755</span><br><span>--- a/src/target/trx_toolkit/clck_gen.py</span><br><span>+++ b/src/target/trx_toolkit/clck_gen.py</span><br><span>@@ -4,7 +4,7 @@</span><br><span> # TRX Toolkit</span><br><span> # Simple TDMA frame clock generator</span><br><span> #</span><br><span style="color: hsl(0, 100%, 40%);">-# (C) 2017-2018 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2017-2019 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span> #</span><br><span> # All Rights Reserved</span><br><span> #</span><br><span>@@ -22,13 +22,14 @@</span><br><span> # with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span> # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-APP_CR_HOLDERS = [("2017-2018", "Vadim Yanitskiy <axilirator@gmail.com>")]</span><br><span style="color: hsl(120, 100%, 40%);">+APP_CR_HOLDERS = [("2017-2019", "Vadim Yanitskiy <axilirator@gmail.com>")]</span><br><span> </span><br><span> import logging as log</span><br><span style="color: hsl(120, 100%, 40%);">+import threading</span><br><span> import signal</span><br><span style="color: hsl(120, 100%, 40%);">+import time</span><br><span> </span><br><span> from app_common import ApplicationBase</span><br><span style="color: hsl(0, 100%, 40%);">-from threading import Timer</span><br><span> from udp_link import UDPLink</span><br><span> from gsm_shared import *</span><br><span> </span><br><span>@@ -40,32 +41,54 @@</span><br><span>       # Average loop back delay</span><br><span>    LO_DELAY_US = 90.0</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  # State variables</span><br><span style="color: hsl(0, 100%, 40%);">-       timer = None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         def __init__(self, clck_links, clck_start = 0, ind_period = 102):</span><br><span style="color: hsl(120, 100%, 40%);">+             # This event is needed to control the thread</span><br><span style="color: hsl(120, 100%, 40%);">+          self._breaker = threading.Event()</span><br><span style="color: hsl(120, 100%, 40%);">+             self._thread = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                self.clck_links = clck_links</span><br><span>                 self.ind_period = ind_period</span><br><span>                 self.clck_start = clck_start</span><br><span style="color: hsl(0, 100%, 40%);">-            self.clck_src = clck_start</span><br><span> </span><br><span>               # Calculate counter time</span><br><span>             self.ctr_interval  = self.GSM_FRAME_US - self.LO_DELAY_US</span><br><span>            self.ctr_interval /= self.SEC_DELAY_US</span><br><span>               self.ctr_interval *= self.ind_period</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      @property</span><br><span style="color: hsl(120, 100%, 40%);">+     def running(self):</span><br><span style="color: hsl(120, 100%, 40%);">+            if self._thread is None:</span><br><span style="color: hsl(120, 100%, 40%);">+                      return False</span><br><span style="color: hsl(120, 100%, 40%);">+          return self._thread.isAlive()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      def start(self):</span><br><span style="color: hsl(0, 100%, 40%);">-                # Send the first indication</span><br><span style="color: hsl(0, 100%, 40%);">-             self.send_clck_ind()</span><br><span style="color: hsl(120, 100%, 40%);">+          # Make sure we won't start two threads</span><br><span style="color: hsl(120, 100%, 40%);">+            assert(self._thread is None)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                # (Re)set the clock counter</span><br><span style="color: hsl(120, 100%, 40%);">+           self.clck_src = self.clck_start</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             # Initialize and start a new thread</span><br><span style="color: hsl(120, 100%, 40%);">+           self._thread = threading.Thread(target = self._worker)</span><br><span style="color: hsl(120, 100%, 40%);">+                self._thread.start()</span><br><span> </span><br><span>     def stop(self):</span><br><span style="color: hsl(0, 100%, 40%);">-         # Stop pending timer</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.timer is not None:</span><br><span style="color: hsl(0, 100%, 40%);">-                      self.timer.cancel()</span><br><span style="color: hsl(0, 100%, 40%);">-                     self.timer = None</span><br><span style="color: hsl(120, 100%, 40%);">+             # No thread, no problem ;)</span><br><span style="color: hsl(120, 100%, 40%);">+            if self._thread is None:</span><br><span style="color: hsl(120, 100%, 40%);">+                      return</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              # Reset the clock source</span><br><span style="color: hsl(0, 100%, 40%);">-                self.clck_src = self.clck_start</span><br><span style="color: hsl(120, 100%, 40%);">+               # Stop the thread first</span><br><span style="color: hsl(120, 100%, 40%);">+               self._breaker.set()</span><br><span style="color: hsl(120, 100%, 40%);">+           self._thread.join()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         # Free memory, reset breaker</span><br><span style="color: hsl(120, 100%, 40%);">+          del self._thread</span><br><span style="color: hsl(120, 100%, 40%);">+              self._thread = None</span><br><span style="color: hsl(120, 100%, 40%);">+           self._breaker.clear()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       def _worker(self):</span><br><span style="color: hsl(120, 100%, 40%);">+            while not self._breaker.wait(self.ctr_interval):</span><br><span style="color: hsl(120, 100%, 40%);">+                      self.send_clck_ind()</span><br><span> </span><br><span>     def send_clck_ind(self):</span><br><span>             # Keep clock cycle</span><br><span>@@ -87,10 +110,6 @@</span><br><span>             # Increase frame count</span><br><span>               self.clck_src += self.ind_period</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            # Schedule a new indication</span><br><span style="color: hsl(0, 100%, 40%);">-             self.timer = Timer(self.ctr_interval, self.send_clck_ind)</span><br><span style="color: hsl(0, 100%, 40%);">-               self.timer.start()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> # Just a wrapper for independent usage</span><br><span> class Application(ApplicationBase):</span><br><span>  def __init__(self):</span><br><span>@@ -102,7 +121,7 @@</span><br><span> </span><br><span>                # Configure logging</span><br><span>          log.basicConfig(level = log.DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">-                      format = "[%(levelname)s] %(filename)s:%(lineno)d %(message)s")</span><br><span style="color: hsl(120, 100%, 40%);">+                     format = "[%(levelname)s] TID#%(thread)s %(filename)s:%(lineno)d %(message)s")</span><br><span> </span><br><span>         def run(self):</span><br><span>               self.link = UDPLink("127.0.0.1", 5800, "0.0.0.0", 5700)</span><br><span>diff --git a/src/target/trx_toolkit/transceiver.py b/src/target/trx_toolkit/transceiver.py</span><br><span>index 37680e7..b1a5c11 100644</span><br><span>--- a/src/target/trx_toolkit/transceiver.py</span><br><span>+++ b/src/target/trx_toolkit/transceiver.py</span><br><span>@@ -172,10 +172,10 @@</span><br><span>                                 # Transceiver was started</span><br><span>                            clck_links.append(self.clck_if)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                     if not self.clck_gen.timer and len(clck_links) > 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                        if not self.clck_gen.running and len(clck_links) > 0:</span><br><span>                             log.info("Starting clock generator")</span><br><span>                               self.clck_gen.start()</span><br><span style="color: hsl(0, 100%, 40%);">-                   elif self.clck_gen.timer and not clck_links:</span><br><span style="color: hsl(120, 100%, 40%);">+                  elif self.clck_gen.running and not clck_links:</span><br><span>                               log.info("Stopping clock generator")</span><br><span>                               self.clck_gen.stop()</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmocom-bb/+/16177">change 16177</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/c/osmocom-bb/+/16177"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmocom-bb </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ibe477eb0a1ee2193c1ff16452a407be7e858b2ef </div>
<div style="display:none"> Gerrit-Change-Number: 16177 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: fixeria <axilirator@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: fixeria <axilirator@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>