#!/usr/bin/env python
##############################################################################
##
# This file is part of Sardana
##
# http://www.sardana-controls.org/
##
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
##
# Sardana is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
##
# Sardana is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
##
# You should have received a copy of the GNU Lesser General Public License
# along with Sardana. If not, see <http://www.gnu.org/licenses/>.
##
##############################################################################
"""This file contains the pool monitor class"""
__all__ = ["PoolMonitor"]
__docformat__ = 'restructuredtext'
import time
import threading
from taurus.core.util.log import Logger
from sardana import ElementType, TYPE_PSEUDO_ELEMENTS
from sardana.pool.poolobject import PoolObject
[docs]
class PoolMonitor(Logger, threading.Thread):
MIN_THREADS = 1
MAX_THREADS = 10
def __init__(self, pool, name='PoolMonitor', period=5.0, min_sleep=1.0,
auto_start=True):
Logger.__init__(self, name)
threading.Thread.__init__(self, name=name)
self.daemon = True
self._period = period
self._min_sleep = min_sleep
self._pool = pool
self._stop = False
self._pause = threading.Event()
self._thread_pool = None
self._ctrl_ids = []
self._elem_ids = []
pool.add_listener(self.on_pool_changed)
if not auto_start:
self.pause()
self.start()
[docs]
def on_pool_changed(self, evt_src, evt_type, evt_value):
evt_name = evt_type.name.lower()
if "created" in evt_name or "deleted" in evt_name:
pool = self._pool
pool_ctrls = pool.get_elements_by_type(ElementType.Controller)
pool_ctrls.sort(key=PoolObject.get_id)
ctrl_ids = []
elem_ids = []
for pool_ctrl in pool_ctrls:
if not pool_ctrl.is_online():
continue
types = set(pool_ctrl.get_ctrl_types())
if types.isdisjoint(TYPE_PSEUDO_ELEMENTS):
ctrl_ids.append(pool_ctrl.id)
elem_ids.extend(list(pool_ctrl.get_element_ids().keys()))
elem_ids.sort()
self._elem_ids = elem_ids
self._ctrl_ids = ctrl_ids
[docs]
def update_state_info(self):
"""Update state information of every element."""
pool = self._pool
elems, ctrls, ctrl_items = [], [], {}
try:
blocked_ctrls = set()
for elem_id in self._elem_ids:
elem = pool.get_element_by_id(elem_id)
ctrl = elem.controller
if elem.is_in_operation():
blocked_ctrls.add(ctrl)
continue
if ctrl in blocked_ctrls:
continue
ret = elem.lock(blocking=False)
if ret:
elems.append(elem)
ctrl_elems = ctrl_items.get(ctrl)
if ctrl_elems is None:
ctrl_items[ctrl] = ctrl_elems = []
ctrl_elems.append(elem)
else:
blocked_ctrls.add(ctrl)
for ctrl, ctrl_elems in list(ctrl_items.items()):
ret = ctrl.lock(blocking=False)
if ret:
ctrls.append(ctrl)
else:
for elem in reversed(ctrl_elems):
elem.unlock()
elems.remove(elem)
self._update_state_info_serial(ctrl_items)
finally:
for ctrl in reversed(ctrls):
ctrl.unlock()
for elem in reversed(elems):
elem.unlock()
def _update_state_info_serial(self, pool_ctrls):
for pool_ctrl, elems in list(pool_ctrls.items()):
self._update_ctrl_state_info(pool_ctrl, elems)
def _update_ctrl_state_info(self, pool_ctrl, elems):
axes = [elem.axis for elem in elems]
state_infos, exc_info = pool_ctrl.raw_read_axis_states(axes)
if len(exc_info):
self.info("STATE ERROR %s", exc_info)
for elem, state_info in list(state_infos.items()):
state_info = elem._from_ctrl_state_info(state_info)
elem.set_state_info(state_info)
[docs]
def stop(self):
self.resume()
self._stop = True
[docs]
def pause(self):
self._pause.clear()
[docs]
def resume(self):
self._pause.set()
[docs]
def monitor(self):
ret = self.update_state_info()
[docs]
def run(self):
nap_time = period = self._period
i, startup = 0, time.time()
while True:
if self._stop:
break
time.sleep(nap_time)
self._pause.wait()
self.monitor()
finish = time.time()
nap_time = -1
while nap_time < 0:
i += 1
nap_time = (startup + i * self._period) - finish