30 using namespace basis;
35 #define DEBUG_TIMER_DRIVER
39 #define LOG(tpr) printf("%s", (time_stamp::notarize() + "timer_driver::" + func + tpr).s() )
65 #if defined(__UNIX__) || defined(__GNU_WINDOWS__)
68 class signalling_thread :
public ethread
71 signalling_thread(
int initial_interval) :
ethread(initial_interval) {}
73 void perform_activity(
void *
formal(ptr)) {
81 #if defined(__UNIX__) || defined(__GNU_WINDOWS__)
83 #elif defined(__WIN32__)
87 #error No timer method known for this OS.
90 #ifdef DEBUG_TIMER_DRIVER
91 #undef static_class_name
92 #define static_class_name() "timer_driver"
93 FUNCDEF(
"timer_driver_private_handler");
95 #if defined(__UNIX__) || defined(__GNU_WINDOWS__)
96 int seen = signal_seen;
98 #elif defined(__WIN32__)
104 #ifdef DEBUG_TIMER_DRIVER
105 LOG(
a_sprintf(
"unknown signal/message %d caught.", seen));
110 #undef static_class_name
115 class driven_object_record
121 bool _okay_to_invoke;
122 bool _handling_timer;
124 driven_object_record(
int duration,
timeable *to_invoke)
125 : _duration(duration), _to_invoke(to_invoke), _next_hit(duration),
126 _okay_to_invoke(
true), _handling_timer(
false) {}
129 class driven_objects_list
130 :
public amorph<driven_object_record>,
131 public virtual root_object
137 for (
int i = 0; i < elements(); i++) {
138 if (borrow(i) && (borrow(i)->_to_invoke == obj))
141 return common::NOT_FOUND;
147 timer_driver::timer_driver()
148 : _timers(new driven_objects_list),
150 #if defined(__UNIX__) || defined(__GNU_WINDOWS__)
168 #ifdef DEBUG_TIMER_DRIVER
174 struct sigaction action;
175 action.sa_handler = SIG_DFL;
177 sigemptyset(&action.sa_mask);
194 #ifdef DEBUG_TIMER_DRIVER
195 LOG(
"waiting to acquire timer_driver lock.");
212 #ifdef DEBUG_TIMER_DRIVER
213 LOG(
"timer_driver is closing down.");
223 #ifdef DEBUG_TIMER_DRIVER
226 #ifdef DEBUG_TIMER_DRIVER
228 LOG(
"hmmm: zapping timer while handling previous timer...!");
232 int indy = _timers->find_obj(to_remove);
234 #ifdef DEBUG_TIMER_DRIVER
237 driven_object_record *reco = _timers->borrow(indy);
238 reco->_okay_to_invoke =
false;
239 if (reco->_handling_timer) {
241 #ifdef DEBUG_TIMER_DRIVER
242 LOG(
a_sprintf(
"Logic Error: timer %x being zapped WHILE BEING HANDLED!",
251 #ifdef DEBUG_TIMER_DRIVER
254 LOG(
"hmmm: setting timer while handling previous timer...!");
257 #ifdef DEBUG_TIMER_DRIVER
258 LOG(
a_sprintf(
"setting timer %x to %d ms.", to_invoke, duration));
262 int indy = _timers->find_obj(to_invoke);
265 _timers->append(
new driven_object_record(duration, to_invoke));
268 driven_object_record *reco = _timers->borrow(indy);
269 reco->_duration = duration;
270 reco->_okay_to_invoke =
true;
277 #ifdef DEBUG_TIMER_DRIVER
278 FUNCDEF(
"handle_system_timer");
281 #ifdef DEBUG_TIMER_DRIVER
282 LOG(
"terrible error: invoked system timer while handling previous timer.");
288 #ifdef DEBUG_TIMER_DRIVER
289 LOG(
"into handling OS timer...");
302 for (
int i = 0; i < _timers->elements(); i++) {
303 driven_object_record *funky = _timers->borrow(i);
305 const char *msg =
"error: timer_driver's timer list logic is broken.";
306 #ifdef DEBUG_TIMER_DRIVER
318 to_invoke_now += funky;
323 #ifdef DEBUG_TIMER_DRIVER
325 for (
int i = 0; i < to_invoke_now.
length(); i++) {
326 driven_object_record *funky = to_invoke_now[i];
327 pointer_dump +=
a_sprintf(
"%x ", funky->_to_invoke);
329 if (pointer_dump.
t())
334 for (
int i = 0; i < to_invoke_now.
length(); i++) {
335 driven_object_record *funky = to_invoke_now[i];
338 if (!funky->_okay_to_invoke)
continue;
339 funky->_handling_timer =
true;
342 funky->_to_invoke->handle_timer_callback();
345 funky->_handling_timer =
false;
348 funky->_next_hit.reset(funky->_duration);
354 for (
int i = 0; i < _timers->elements(); i++) {
355 driven_object_record *funky = _timers->borrow(i);
356 int funky_time = int(funky->_next_hit.value() -
now.value());
361 if (funky_time < next_timer_duration)
362 next_timer_duration = funky_time;
369 for (
int i = 0; i < _timers->elements(); i++) {
370 driven_object_record *funky = _timers->borrow(i);
371 if (!funky->_okay_to_invoke) {
379 #ifdef DEBUG_TIMER_DRIVER
380 LOG(
"done handling OS timer.");
384 reset_OS_timer(next_timer_duration);
390 void timer_driver::hookup_OS_timer(
int duration)
394 #ifdef DEBUG_TIMER_DRIVER
395 LOG(
"seeing negative duration for timer!");
398 }
else if (!duration) {
399 #ifdef DEBUG_TIMER_DRIVER
400 LOG(
"patching zero duration for timer.");
404 #ifdef DEBUG_TIMER_DRIVER
405 LOG(
a_sprintf(
"hooking next OS timer in %d ms.", duration));
409 _prompter->reschedule(duration);
427 void timer_driver::unhook_OS_timer()
429 #ifdef DEBUG_TIMER_DRIVER
438 #ifdef DEBUG_TIMER_DRIVER
439 LOG(
"unhooked OS timer.");
443 void timer_driver::reset_OS_timer(
int next_hit)
445 #ifdef DEBUG_TIMER_DRIVER
449 hookup_OS_timer(next_hit);
a_sprintf is a specialization of astring that provides printf style support.
Represents a sequential, ordered, contiguous collection of objects.
int length() const
Returns the current reported length of the allocated C array.
Provides a dynamically resizable ASCII character string.
bool t() const
t() is a shortcut for the string being "true", as in non-empty.
auto_synchronizer simplifies concurrent code by automatically unlocking.
void lock()
Clamps down on the mutex, if possible.
void unlock()
Gives up the possession of the mutex.
Provides a platform-independent object for adding threads to a program.
static void sleep_ms(basis::un_int msec)
a system independent name for a forced snooze measured in milliseconds.
Represents a point in time relative to the operating system startup time.
timeable is the base for objects that can be hooked into timer events.
Provides platform-independent timer support.
bool set_timer(int duration, timeable *to_invoke)
sets a timer to call "to_invoke" every "duration" milliseconds.
void handle_system_timer()
invoked by the OS timer support and must be called by main thread.
bool zap_timer(timeable *to_drop)
removes the timer that was established for "to_drop".
#define formal(parameter)
This macro just eats what it's passed; it marks unused formal parameters.
#define NULL_POINTER
The value representing a pointer to nothing.
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
The guards collection helps in testing preconditions and reporting errors.
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
unsigned long un_long
Abbreviated name for unsigned long integers.
unsigned int un_int
Abbreviated name for unsigned integers.
const int HOUR_ms
Number of milliseconds in an hour.
bool negative(const type &a)
negative returns true if "a" is less than zero.
A dynamic container class that holds any kind of object via pointers.
const int MAX_TIMER_PREDICTION
time_locus now()
returns our current locus in the time continuum.
const int INITIAL_TIMER_GRANULARITY
void timer_driver_private_handler(int signal_seen)
#define SAFE_STATIC(type, func_name, parms)
Statically defines a singleton object whose scope is the program's lifetime.
#define program_wide_timer()
provides access to the singleton timer_driver.
Aids in achievement of platform independence.