Пример #1
0
/**
 * 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
                }
            }
        }
    }
}
Пример #2
0
/**
 * 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;
}
Пример #3
0
/**
 * 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;
}
Пример #4
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(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;
}
Пример #5
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 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();
}
Пример #6
0
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);


}
Пример #7
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
	{
		{
			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();
}
Пример #8
0
/**
 * 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;
	}
}
Пример #9
0
/**
 * 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);
		}
	}
}
Пример #10
0
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));
}
Пример #11
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();
}
Пример #12
0
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);
	}
}