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