/** * Delete this Notifier from the timer queue. * WARNING: this method does not do synchronization! It must be called from somewhere * that is taking care of synchronizing access to the queue. * Remove this Notifier from the timer queue and adjust the next interrupt time to reflect * the current top of the queue. */ void Notifier::DeleteFromQueue() { if (m_queued) { m_queued = false; wpi_assert(timerQueueHead != NULL); if (timerQueueHead == this) { // remove the first item in the list - update the alarm timerQueueHead = this->m_nextEvent; UpdateAlarm(); } else { for (Notifier *n = timerQueueHead; n != NULL; n = n->m_nextEvent) { if (n->m_nextEvent == this) { // this element is the next element from *n from the queue n->m_nextEvent = this->m_nextEvent; // point around this one } } } } }
/** * Insert this Notifier into the timer queue in right place. * WARNING: this method does not do synchronization! It must be called from somewhere * that is taking care of synchronizing access to the queue. * @param updateAlarm If true, the UpdateAlarm method is called which will enable the * alarm if necessary. Only updated when called from the interrupt routine. This ensures * that the public methods only update the queue after finishing inserting. */ void Notifier::InsertInQueue(bool updateAlarm) { tRioStatusCode status = 0; m_expirationTime = GetClock() + m_period; if (timerQueueHead == NULL || timerQueueHead->m_expirationTime >= this->m_expirationTime) { // the queue is empty or greater than the new entry // the new entry becomes the first element this->m_nextEvent = timerQueueHead; timerQueueHead = this; if (updateAlarm) UpdateAlarm(); // since the first element changed, update alarm wpi_assertCleanStatus(status); } else { for (Notifier * n = timerQueueHead; n != NULL; n = n->m_nextEvent) { if (n->m_nextEvent == NULL || n->m_expirationTime > this->m_expirationTime) { // if the new element goes after the *n element this->m_nextEvent = n->m_nextEvent; n->m_nextEvent = this; break; } } } m_queued = true; }
/** * Insert this Notifier into the timer queue in right place. * WARNING: this method does not do synchronization! It must be called from * somewhere * that is taking care of synchronizing access to the queue. * @param reschedule If false, the scheduled alarm is based on the current time * and UpdateAlarm * method is called which will enable the alarm if necessary. * If true, update the time by adding the period (no drift) when rescheduled * periodic from ProcessQueue. * This ensures that the public methods only update the queue after finishing * inserting. */ void Notifier::InsertInQueue(bool reschedule) { if (reschedule) { m_expirationTime += m_period; } else { m_expirationTime = GetClock() + m_period; } if (m_expirationTime > Timer::kRolloverTime) { m_expirationTime -= Timer::kRolloverTime; } if (timerQueueHead == nullptr || timerQueueHead->m_expirationTime >= this->m_expirationTime) { // the queue is empty or greater than the new entry // the new entry becomes the first element this->m_nextEvent = timerQueueHead; timerQueueHead = this; if (!reschedule) { // since the first element changed, update alarm, unless we already plan // to UpdateAlarm(); } } else { for (Notifier **npp = &(timerQueueHead->m_nextEvent);; npp = &(*npp)->m_nextEvent) { Notifier *n = *npp; if (n == nullptr || n->m_expirationTime > this->m_expirationTime) { *npp = this; this->m_nextEvent = n; break; } } } m_queued = true; }
/** * ProcessQueue is called whenever there is a timer interrupt. * We need to wake up and process the current top item in the timer queue as long * as its scheduled time is after the current time. Then the item is removed or * rescheduled (repetitive events) in the queue. */ void Notifier::ProcessQueue(tNIRIO_u32 mask, void *params) { Notifier *current; while (1) // keep processing past events until no more { CRITICAL_REGION(m_semaphore) { double currentTime = GetClock(); current = timerQueueHead; if (current == NULL || current->m_expirationTime > currentTime) { break; // no more timer events to process } // need to process this entry timerQueueHead = current->m_nextEvent; if (current->m_periodic) { // if periodic, requeue the event // compute when to put into queue current->InsertInQueue(false); } } END_REGION; current->m_handler(current->m_param); // call the event handler } // reschedule the first item in the queue CRITICAL_REGION(m_semaphore) { UpdateAlarm(); } END_REGION; }
/** * ProcessQueue is called whenever there is a timer interrupt. * We need to wake up and process the current top item in the timer queue as * long * as its scheduled time is after the current time. Then the item is removed or * rescheduled (repetitive events) in the queue. */ void Notifier::ProcessQueue(uint32_t currentTimeInt, void *params) { Notifier *current; while (true) // keep processing past events until no more { { std::lock_guard<priority_recursive_mutex> sync(queueMutex); double currentTime = currentTimeInt * 1.0e-6; current = timerQueueHead; if (current == nullptr || current->m_expirationTime > currentTime) { break; // no more timer events to process } // need to process this entry timerQueueHead = current->m_nextEvent; if (current->m_periodic) { // if periodic, requeue the event // compute when to put into queue current->InsertInQueue(true); } else { // not periodic; removed from queue current->m_queued = false; } // Take handler mutex while holding queue mutex to make sure // the handler will execute to completion in case we are being deleted. current->m_handlerMutex.lock(); } current->m_handler(current->m_param); // call the event handler current->m_handlerMutex.unlock(); } // reschedule the first item in the queue std::lock_guard<priority_recursive_mutex> sync(queueMutex); UpdateAlarm(); }
void CheckAlarms() { SYSTEMTIME time; GetLocalTime(&time); // put triggered alarms in another list - so we don't keep the critical section locked for longer than necessary AlarmList triggered_list, remove_list; mir_cslock lck(alarm_cs); ALARM *i; for(alarms.reset(); i = alarms.current(); alarms.next()) { if (!UpdateAlarm(i->time, i->occurrence)) { // somehow an expired one-off alarm is in our list remove_list.push_back(i); continue; } switch(i->occurrence) { case OC_ONCE: if (IsBetween(i->time, last_check, time)) { if (!startup || !(i->flags & ALF_NOSTARTUP)) triggered_list.push_back(i); // erase and fix iterator - alarm has now been triggered and has therefore expired remove_list.push_back(i); } break; default: if (IsBetween(i->time, last_check, time)) { if (i->flags & ALF_SUSPENDED) i->flags = i->flags & ~ALF_SUSPENDED; else if (!startup || !(i->flags & ALF_NOSTARTUP)) triggered_list.push_back(i); } break; } } last_check = time; WriteLastCheckTime(); startup = false; for(triggered_list.reset(); i = triggered_list.current(); triggered_list.next()) DoAlarm(i); for(remove_list.reset(); i = remove_list.current(); remove_list.next()) remove(i->id); }
/** * ProcessQueue is called whenever there is a timer interrupt. * We need to wake up and process the current top item in the timer queue as long * as its scheduled time is after the current time. Then the item is removed or * rescheduled (repetitive events) in the queue. */ void Notifier::ProcessQueue(uint32_t mask, void *params) { Notifier *current; while (true) // keep processing past events until no more { { std::lock_guard<priority_recursive_mutex> sync(queueMutex); double currentTime = GetClock(); if (timerQueue.empty()) { break; } current = timerQueue.front(); if (current->m_expirationTime > currentTime) { break; // no more timer events to process } // remove next entry before processing it timerQueue.pop_front(); current->m_queued = false; if (current->m_periodic) { // if periodic, requeue the event // compute when to put into queue current->InsertInQueue(true); } else { // not periodic; removed from queue current->m_queued = false; } // Take handler mutex while holding queue semaphore to make sure // the handler will execute to completion in case we are being deleted. current->m_handlerMutex.lock(); } current->m_handler(); // call the event handler current->m_handlerMutex.unlock(); } // reschedule the first item in the queue std::lock_guard<priority_recursive_mutex> sync(queueMutex); UpdateAlarm(); }
/** * Insert this Notifier into the timer queue in right place. * WARNING: this method does not do synchronization! It must be called from somewhere * that is taking care of synchronizing access to the queue. * @param reschedule If false, the scheduled alarm is based on the curent time and UpdateAlarm * method is called which will enable the alarm if necessary. * If true, update the time by adding the period (no drift) when rescheduled periodic from ProcessQueue. * This ensures that the public methods only update the queue after finishing inserting. */ void Notifier::InsertInQueue(bool reschedule) { if (reschedule) { m_expirationTime += m_period; } else { m_expirationTime = GetClock() + m_period; } // Attempt to insert new entry into queue for (auto i = timerQueue.begin(); i != timerQueue.end(); i++) { if ((*i)->m_expirationTime > m_expirationTime) { timerQueue.insert(i, this); m_queued = true; // BUG 1: wpi version doesn't break here so it keeps inserting in front of all elements // with expiration times > current element break; } } /* If the new entry wasn't queued, either the queue was empty or the first * element was greater than the new entry. */ if (!m_queued) { // BUG 2: wpi version uses "push_front" which is wrong since it adds the longest time to the front timerQueue.push_back(this); //timerQueue.push_front(this); if (!reschedule) { /* Since the first element changed, update alarm, unless we already * plan to */ UpdateAlarm(); } m_queued = true; } }
/** * Delete this Notifier from the timer queue. * WARNING: this method does not do synchronization! It must be called from somewhere * that is taking care of synchronizing access to the queue. * Remove this Notifier from the timer queue and adjust the next interrupt time to reflect * the current top of the queue. */ void Notifier::DeleteFromQueue() { if (m_queued) { m_queued = false; wpi_assert(!timerQueue.empty()); if (timerQueue.front() == this) { // remove the first item in the list - update the alarm timerQueue.pop_front(); UpdateAlarm(); } else { timerQueue.remove(this); } } }
int MinutesInFuture(SYSTEMTIME time, Occurrence occ) { if (!UpdateAlarm(time, occ)) return 0; SYSTEMTIME now; GetPluginTime(&now); FILETIME ft_now, ft_then; SystemTimeToFileTime(&now, &ft_now); SystemTimeToFileTime(&time, &ft_then); ULARGE_INTEGER uli_now, uli_then, diff; uli_now.HighPart = ft_now.dwHighDateTime; uli_now.LowPart = ft_now.dwLowDateTime; uli_then.HighPart = ft_then.dwHighDateTime; uli_then.LowPart = ft_then.dwLowDateTime; diff.QuadPart = uli_then.QuadPart - uli_now.QuadPart; bool inc = false; if (diff.QuadPart % mult.QuadPart >= mult.QuadPart / 2) inc = true; return (int)(diff.QuadPart / mult.QuadPart + (inc ? 1 : 0)); }
/** * ProcessQueue is called whenever there is a timer interrupt. * We need to wake up and process the current top item in the timer queue as long * as its scheduled time is after the current time. Then the item is removed or * rescheduled (repetitive events) in the queue. */ void Notifier::ProcessQueue(uint32_t mask, void *params) { Notifier *current; while (true) // keep processing past events until no more { { Synchronized sync(queueSemaphore); double currentTime = GetClock(); current = timerQueueHead; if (current == NULL || current->m_expirationTime > currentTime) { break; // no more timer events to process } // need to process this entry timerQueueHead = current->m_nextEvent; if (current->m_periodic) { // if periodic, requeue the event // compute when to put into queue current->InsertInQueue(true); } else { // not periodic; removed from queue current->m_queued = false; } // Take handler semaphore while holding queue semaphore to make sure // the handler will execute to completion in case we are being deleted. semTake(current->m_handlerSemaphore, WAIT_FOREVER); } current->m_handler(current->m_param); // call the event handler semGive(current->m_handlerSemaphore); } // reschedule the first item in the queue Synchronized sync(queueSemaphore); UpdateAlarm(); }
void LoadAlarms() { int num_alarms = db_get_w(0, MODULE, "Count", 0); char buff[256]; DBVARIANT dbv; ALARM alarm; SYSTEMTIME now; GetLocalTime(&now); mir_cslock lck(alarm_cs); alarms.clear(); for(int i = 0; i < num_alarms; i++) { memset(&alarm, 0, sizeof(ALARM)); mir_snprintf(buff, "Title%d", i); if (!db_get_ts(0, MODULE, buff, &dbv)) { alarm.szTitle = mir_tstrdup(dbv.ptszVal); db_free(&dbv); } mir_snprintf(buff, "Desc%d", i); if (!db_get_ts(0, MODULE, buff, &dbv)) { alarm.szDesc = mir_tstrdup(dbv.ptszVal); db_free(&dbv); } mir_snprintf(buff, "Occ%d", i); alarm.occurrence = (Occurrence)db_get_w(0, MODULE, buff, 0); mir_snprintf(buff, "STHour%d", i); alarm.time.wHour = db_get_w(0, MODULE, buff, 0); mir_snprintf(buff, "STMinute%d", i); alarm.time.wMinute = db_get_w(0, MODULE, buff, 0); mir_snprintf(buff, "STSecond%d", i); alarm.time.wSecond = db_get_w(0, MODULE, buff, 0); switch(alarm.occurrence) { case OC_ONCE: mir_snprintf(buff, "STYear%d", i); alarm.time.wYear = db_get_w(0, MODULE, buff, 0); mir_snprintf(buff, "STMonth%d", i); alarm.time.wMonth = db_get_w(0, MODULE, buff, 0); mir_snprintf(buff, "STDay%d", i); alarm.time.wDay = db_get_w(0, MODULE, buff, 0); break; case OC_WEEKLY: mir_snprintf(buff, "STDayOfWeek%d", i); alarm.time.wDayOfWeek = db_get_w(0, MODULE, buff, 0); break; case OC_WEEKDAYS: break; case OC_DAILY: break; case OC_MONTHLY: mir_snprintf(buff, "STDay%d", i); alarm.time.wDay = db_get_w(0, MODULE, buff, 0); break; case OC_YEARLY: mir_snprintf(buff, "STMonth%d", i); alarm.time.wMonth = db_get_w(0, MODULE, buff, 0); mir_snprintf(buff, "STDay%d", i); alarm.time.wDay = db_get_w(0, MODULE, buff, 0); break; } if (UpdateAlarm(alarm.time, alarm.occurrence)) { mir_snprintf(buff, "ActionFlags%d", i); alarm.action = (unsigned short)db_get_dw(0, MODULE, buff, AAF_POPUP | AAF_SOUND); if (alarm.action & AAF_COMMAND) { mir_snprintf(buff, "ActionCommand%d", i); if (!db_get_ts(0, MODULE, buff, &dbv)) { alarm.szCommand = mir_tstrdup(dbv.ptszVal); db_free(&dbv); mir_snprintf(buff, "ActionParams%d", i); if (!db_get_ts(0, MODULE, buff, &dbv)) { alarm.szCommandParams = mir_tstrdup(dbv.ptszVal); db_free(&dbv); } } } mir_snprintf(buff, "SoundNum%d", i); alarm.sound_num = (int)db_get_b(0, MODULE, buff, 1); mir_snprintf(buff, "Snoozer%d", i); alarm.snoozer = db_get_b(0, MODULE, buff, 0) == 1; mir_snprintf(buff, "Hidden%d", i); alarm.flags |= (db_get_b(0, MODULE, buff, 0) == 1 ? ALF_HIDDEN : 0); mir_snprintf(buff, "Suspended%d", i); alarm.flags |= (db_get_b(0, MODULE, buff, 0) == 1 ? ALF_SUSPENDED : 0); mir_snprintf(buff, "NoStartup%d", i); alarm.flags |= (db_get_b(0, MODULE, buff, 0) == 1 ? ALF_NOSTARTUP : 0); mir_snprintf(buff, "Flags%d", i); alarm.flags = db_get_dw(0, MODULE, buff, alarm.flags); alarm.id = next_alarm_id++; alarms.push_back(&alarm); } free_alarm_data(&alarm); } }