source: modules/mod_cron.py @ 223a597

Last change on this file since 223a597 was 223a597, checked in by Martin Kolman <martin.kolman@…>, 3 years ago

removing TODO -> Qt support already added :)

  • Property mode set to 100644
File size: 8.8 KB
Line 
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3#----------------------------------------------------------------------------
4# A timing and scheduling module for modRana.
5#----------------------------------------------------------------------------
6# Copyright 2007, Oliver White
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20#---------------------------------------------------------------------------
21from __future__ import with_statement # for python 2.5
22from base_module import ranaModule
23import threading
24
25# only import GKT libs if GTK GUI is used
26from core import gs
27if gs.GUIString == "GTK":
28  import gobject
29  ready = True
30else:
31  from PySide import QtCore
32  ready = False
33
34def getModule(m,d,i):
35  """
36  return module version corresponding to the currently used toolkit
37  (eq. one that uses the timers provided by the toolkit
38  - gobject.timeout_add, QTimer, etc.
39  """
40  if gs.GUIString == 'QML':
41    return(CronQt(m,d,i))
42  else: # GTK for now
43    return(Cron(m,d,i))
44
45class Cron(ranaModule):
46  """A timing and scheduling module for modRana"""
47
48  """
49  -> this is an abstract class
50  that specifies and interface for concrete implementations
51  """
52
53  """Why is there a special module for timing ?
54     The reason is twofold:
55     Toolkit independence and power saving/monitoring.
56
57     If all timing calls go through this module,
58     the underlying engine (currently glibs gobject)
59     can be more easily changed than rewriting code everywhere.
60
61     Also, modRana targets mobile devices with limited power budget.
62     If all timing goes through this module, rogue modules many frequent
63     timers can be easily identified.
64     It might be also possible to stop or pause some/all of the timers
65     after a period of inactivity, or some such.
66  """
67
68  def __init__(self, m, d, i):
69    ranaModule.__init__(self, m, d, i)
70
71  def addIdle(self, callback, args):
72    """add a callback that is called once the main loop becomes idle"""
73    pass
74
75  def addTimeout(self, callback, timeout, caller, description, args=[]):
76    """the callback will be called timeout + time needed to execute the callback
77    and other events"""
78    pass
79
80  def _doTimeout(self, id, callback, args):
81    """wrapper about the timeout function, which makes it possible to check
82    if a timeout is still in progress from the "outside"
83    - like this, the underlying timer should also be easily replaceable
84    """
85
86    if callback(*args) == False:
87      # the callback returned False,
88      # that means it wants to quit the timeout
89
90      # stop tracking
91      self.removeTimeout(id)
92      # propagate the quit signal
93      return False
94    else:
95      return True # just run the loop
96
97  def removeTimeout(self, id):
98    """remove timeout with a given id"""
99    pass
100
101  def modifyTimeout(self,id, newTimeout):
102    """modify the duration of a timeout in progress"""
103    pass
104
105class CronGTK(Cron):
106  """A timing and scheduling module for modRana
107  -> this is an implementation that uses GObject & the GTK main loop
108  to do the timing
109  """
110 
111  def __init__(self, m, d, i):
112    Cron.__init__(self, m, d, i)
113    gui = self.modrana.gui
114
115    self.nextId = 0
116    # cronTab and activeIds should be in sync
117    self.cronTab = {"idle":{}, "timeout":{}}
118#    self.info = {}
119    self.dataLock = threading.RLock()
120
121  def _getID(self):
122    """get an unique id for timing related request that can be
123    returned to the callers and used as a handle
124    TODO: can int overflow in Python ?"""
125    id = self.nextId
126    self.nextId+=1
127    return id
128
129  def addIdle(self, callback, args):
130    """add a callback that is called once the main loop becomes idle"""
131    if not ready:
132      return
133    gobject.idle_add(callback, *args)
134
135  def addTimeout(self, callback, timeout, caller, description, args=[]):
136    """the callback will be called timeout + time needed to execute the callback
137    and other events"""
138    if not ready:
139      return
140    id = self._getID()
141    realId = gobject.timeout_add(timeout, self._doTimeout, id, callback, args)
142    timeoutTuple = (callback, args, timeout, caller, description, realId)
143    with self.dataLock:
144      self.cronTab['timeout'][id] = timeoutTuple
145
146  def removeTimeout(self, id):
147    """remove timeout with a given id"""
148    if not ready:
149      return
150    with self.dataLock:
151      if id in self.cronTab['timeout'].keys():
152        (callback, args, timeout, caller, description, realId) = self.cronTab['timeout'][id]
153        del self.cronTab['timeout'][id]
154        gobject.source_remove(realId)
155      else:
156        print("cron: can't remove timeout, wrong id: ", id)
157
158  def modifyTimeout(self,id, newTimeout):
159    """modify the duration of a timeout in progress"""
160    if not ready:
161      return
162    with self.dataLock:
163      if id in self.cronTab['timeout'].keys():
164        # load the timeout description
165        (callback, args, timeout, caller, description, realId) = self.cronTab['timeout'][id]
166        gobject.source_remove(realId) # remove the old timeout
167        realId = gobject.timeout_add(self._doTimeout, newTimeout, id, callback, args) # new timeout
168        # update the timeout description
169        self.cronTab['timeout'][id] = (callback, args, newTimeout, caller, description, realId)
170      else:
171        print("cron: can't modify timeout, wrong id: ", id)
172
173class CronQt(Cron):
174  """A timing and scheduling module for modRana
175  -> this class is an specifies and interface for
176  concrete implementations
177  """
178
179  def __init__(self, m, d, i):
180    Cron.__init__(self, m, d, i)
181    self.nextId = 0
182    # cronTab and activeIds should be in sync
183    self.cronTab = {"idle":{}, "timeout":{}}
184    #    self.info = {}
185    self.dataLock = threading.RLock()
186
187  def _getID(self):
188    """get an unique id for timing related request that can be
189    returned to the callers and used as a handle
190    TODO: can int overflow in Python ?
191    TODO: id recycling ?"""
192    with self.dataLock:
193      id = self.nextId
194      self.nextId+=1
195      return id
196
197  def addIdle(self, callback, args):
198    """add a callback that is called once the main loop becomes idle"""
199    pass
200
201  def addTimeout(self, callback, timeout, caller, description, args=[]):
202    """the callback will be called timeout + time needed to execute the callback
203    and other events
204    """
205    # create and configure the timer
206    timer = QtCore.QTimer()
207#    timer.setInterval(timeout)
208    id = self._getID()
209    """create a new function that calls the callback processing function
210     with thh provided arguments"""
211    handleThisTimeout = lambda: self._doTimeout(id, callback, args)
212    # connect this function to the timeout
213    timer.timeout.connect(handleThisTimeout)
214    # store timer data
215    timeoutTuple = (callback, args, timeout, caller, description, id, timer)
216    with self.dataLock:
217      self.cronTab['timeout'][id] = timeoutTuple
218    # start the timer
219    timer.start(timeout)
220
221  def removeTimeout(self, id):
222    """remove timeout with a given id"""
223    with self.dataLock:
224      if id in self.cronTab['timeout'].keys():
225        (callback, args, timeout, caller, description, id, timer) = self.cronTab['timeout'][id]
226        timer.stop()
227        del self.cronTab['timeout'][id]
228      else:
229        print("cron: can't remove timeout, wrong id: ", id)
230
231  def modifyTimeout(self, id, newTimeout):
232    """modify the duration of a timeout in progress"""
233    with self.dataLock:
234      if id in self.cronTab['timeout'].keys():
235        # load the timeout data
236        (callback, args, timeout, caller, description, id, timer) = self.cronTab['timeout'][id]
237        # reset the timeout duration
238        timer.setInterval(newTimeout)
239        # update the timeout data
240        self.cronTab['timeout'][id] = (callback, args, newTimeout, caller, description, id, timer)
241      else:
242        print("cron: can't modify timeout, wrong id: ", id)
243
244#  def _addInfo(self, id, info):
245#    """add a message for a timeout handler to read"""
246#    with self.dataLock:
247#      if id in self.info:
248#        self.info[id].append(info) # add message to queue
249#      else:
250#        self.info[id] = [info] # create message queue
251#
252#  def _popInfo(self, id):
253#    with self.dataLock:
254#      if id in self.info:
255#        try:
256#          return self.info[id].pop() # try to return the message
257#        except IndexError:
258#          del self.info[id] # message queue empty, delete it
259#          return None
260#      else:
261#        return None
Note: See TracBrowser for help on using the repository browser.