コード例 #1
0
ファイル: work_queue.c プロジェクト: Jicheng-Yan/Firmware
int work_queue(int qid, struct work_s *work, worker_t worker, void *arg, uint32_t delay)
{
  struct wqueue_s *wqueue = &g_work[qid];

  //DEBUGASSERT(work != NULL && (unsigned)qid < NWORKERS);

  /* First, initialize the work structure */

  work->worker = worker;           /* Work callback */
  work->arg    = arg;              /* Callback argument */
  work->delay  = delay;            /* Delay until work performed */

  /* Now, time-tag that entry and put it in the work queue.  This must be
   * done with interrupts disabled.  This permits this function to be called
   * from with task logic or interrupt handlers.
   */

  work_lock(qid);
  work->qtime  = clock_systimer(); /* Time work queued */

  dq_addlast((dq_entry_t *)work, &wqueue->q);
#ifdef __PX4_QURT
  px4_task_kill(wqueue->pid, SIGALRM);      /* Wake up the worker thread */
#else
  px4_task_kill(wqueue->pid, SIGCONT);      /* Wake up the worker thread */
#endif

  work_unlock(qid);
  return PX4_OK;
}
コード例 #2
0
ファイル: work_cancel.c プロジェクト: FreddieChopin/NuttX
static int work_qcancel(FAR struct usr_wqueue_s *wqueue, FAR struct work_s *work)
{
  int ret = -ENOENT;

  DEBUGASSERT(work != NULL);

  /* Get exclusive access to the work queue */

  while (work_lock() < 0);

  /* Cancelling the work is simply a matter of removing the work structure
   * from the work queue.  This must be done with interrupts disabled because
   * new work is typically added to the work queue from interrupt handlers.
   */

  if (work->worker != NULL)
    {
      /* A little test of the integrity of the work queue */

      DEBUGASSERT(work->dq.flink || (FAR dq_entry_t *)work == wqueue->q.tail);
      DEBUGASSERT(work->dq.blink || (FAR dq_entry_t *)work == wqueue->q.head);

      /* Remove the entry from the work queue and make sure that it is
       * mark as available (i.e., the worker field is nullified).
       */

      dq_rem((FAR dq_entry_t *)work, &wqueue->q);
      work->worker = NULL;
      ret = OK;
    }

  work_unlock();
  return ret;
}
コード例 #3
0
ファイル: work_queue.c プロジェクト: jrosberg/NuttX-L21
static int work_qqueue(FAR struct usr_wqueue_s *wqueue,
                       FAR struct work_s *work, worker_t worker,
                       FAR void *arg, uint32_t delay)
{
    DEBUGASSERT(work != NULL);

    /* First, initialize the work structure */

    work->worker = worker;           /* Work callback */
    work->arg    = arg;              /* Callback argument */
    work->delay  = delay;            /* Delay until work performed */

    /* Get exclusive access to the work queue */

    while (work_lock() < 0);

    /* Now, time-tag that entry and put it in the work queue. */

    work->qtime  = clock_systimer(); /* Time work queued */

    dq_addlast((FAR dq_entry_t *)work, &wqueue->q);
    kill(wqueue->pid, SIGWORK);   /* Wake up the worker thread */

    work_unlock();
    return OK;
}
コード例 #4
0
ファイル: work_queue.c プロジェクト: dagar/NuttX
static int work_qqueue(FAR struct usr_wqueue_s *wqueue,
                       FAR struct work_s *work, worker_t worker,
                       FAR void *arg, clock_t delay)
{
  DEBUGASSERT(work != NULL);

  /* Get exclusive access to the work queue */

  while (work_lock() < 0);

  /* Is there already pending work? */

  if (work->worker != NULL)
    {
      /* Remove the entry from the work queue.  It will re requeued at the
       * end of the work queue.
       */

      dq_rem((FAR dq_entry_t *)work, &wqueue->q);
    }

  /* Initialize the work structure */

  work->worker = worker;           /* Work callback. non-NULL means queued */
  work->arg    = arg;              /* Callback argument */
  work->delay  = delay;            /* Delay until work performed */

  /* Now, time-tag that entry and put it in the work queue. */

  work->qtime  = clock(); /* Time work queued */

  dq_addlast((FAR dq_entry_t *)work, &wqueue->q);
  kill(wqueue->pid, SIGWORK);   /* Wake up the worker thread */

  work_unlock();
  return OK;
}
コード例 #5
0
ファイル: work_usrthread.c プロジェクト: bherrera/NuttX
void work_process(FAR struct usr_wqueue_s *wqueue)
{
  volatile FAR struct work_s *work;
  worker_t  worker;
  FAR void *arg;
  uint32_t elapsed;
  uint32_t remaining;
  uint32_t stick;
  uint32_t ctick;
  uint32_t next;
  int ret;

  /* Then process queued work.  Lock the work queue while we process items
   * in the work list.
   */

  next = wqueue->delay;
  ret = work_lock();
  if (ret < 0)
    {
      /* Break out earlier if we were awakened by a signal */

      return;
    }

  /* Get the time that we started this polling cycle in clock ticks. */

  stick = clock_systimer();

  /* And check each entry in the work queue.  Since we have locked the
   * work queue we know:  (1) we will not be suspended unless we do
   * so ourselves, and (2) there will be no changes to the work queue
   */

  work = (FAR struct work_s *)wqueue->q.head;
  while (work)
    {
      /* Is this work ready?  It is ready if there is no delay or if
       * the delay has elapsed. qtime is the time that the work was added
       * to the work queue.  It will always be greater than or equal to
       * zero.  Therefore a delay of zero will always execute immediately.
       */

      ctick   = clock_systimer();
      elapsed = ctick - work->qtime;
      if (elapsed >= work->delay)
        {
          /* Remove the ready-to-execute work from the list */

          (void)dq_rem((struct dq_entry_s *)work, &wqueue->q);

          /* Extract the work description from the entry (in case the work
           * instance by the re-used after it has been de-queued).
           */

          worker = work->worker;

          /* Check for a race condition where the work may be nullified
           * before it is removed from the queue.
           */

          if (worker != NULL)
            {
              /* Extract the work argument (before unlocking the work queue) */

              arg = work->arg;

              /* Mark the work as no longer being queued */

              work->worker = NULL;

              /* Do the work.  Unlock the the work queue while the work is being
               * performed... we don't have any idea how long this will take!
               */

              work_unlock();
              worker(arg);

              /* Now, unfortunately, since we unlocked the work queue we don't
               * know the state of the work list and we will have to start
               * back at the head of the list.
               */

              ret = work_lock();
              if (ret < 0)
                {
                  /* Break out earlier if we were awakened by a signal */

                  return;
                }

              work = (FAR struct work_s *)wqueue->q.head;
            }
          else
            {
              /* Cancelled.. Just move to the next work in the list with
               * the work queue still locked.
               */

              work = (FAR struct work_s *)work->dq.flink;
            }
        }
      else /* elapsed < work->delay */
        {
          /* This one is not ready.
           *
           * NOTE that elapsed is relative to the the current time,
           * not the time of beginning of this queue processing pass.
           * So it may need an adjustment.
           */

          elapsed += (ctick - stick);
          if (elapsed > work->delay)
            {
              /* The delay has expired while we are processing */

              elapsed = work->delay;
            }

          /* Will it be ready before the next scheduled wakeup interval? */

          remaining = work->delay - elapsed;
          if (remaining < next)
            {
              /* Yes.. Then schedule to wake up when the work is ready */

              next = remaining;
            }

          /* Then try the next in the list. */

          work = (FAR struct work_s *)work->dq.flink;
        }
    }

  /* Get the delay (in clock ticks) since we started the sampling */

  elapsed = clock_systimer() - stick;
  if (elapsed < wqueue->delay && next > 0)
    {
      /* How must time would we need to delay to get to the end of the 
       * sampling period?  The amount of time we delay should be the smaller
       * of the time to the end of the sampling period and the time to the
       * next work expiry.
       */

      remaining = wqueue->delay - elapsed;
      next      = MIN(next, remaining);

      /* Wait awhile to check the work list.  We will wait here until
       * either the time elapses or until we are awakened by a signal.
       * Interrupts will be re-enabled while we wait.
       */

      usleep(next * USEC_PER_TICK);
    }

  work_unlock();
}
コード例 #6
0
ファイル: work_thread.c プロジェクト: JW-CHOI/Firmware
static void work_process(struct wqueue_s *wqueue, int lock_id)
{
	volatile struct work_s *work;
	worker_t  worker;
	void *arg;
	uint64_t elapsed;
	uint32_t remaining;
	uint32_t next;

	/* Then process queued work.  We need to keep interrupts disabled while
	 * we process items in the work list.
	 */

	next  = CONFIG_SCHED_WORKPERIOD;

	work_lock(lock_id);

	work  = (struct work_s *)wqueue->q.head;

	while (work) {
		/* Is this work ready?  It is ready if there is no delay or if
		 * the delay has elapsed. qtime is the time that the work was added
		 * to the work queue.  It will always be greater than or equal to
		 * zero.  Therefore a delay of zero will always execute immediately.
		 */

		elapsed = USEC2TICK(clock_systimer() - work->qtime);

		//printf("work_process: in ticks elapsed=%lu delay=%u\n", elapsed, work->delay);
		if (elapsed >= work->delay) {
			/* Remove the ready-to-execute work from the list */

			(void)dq_rem((struct dq_entry_s *)work, &wqueue->q);

			/* Extract the work description from the entry (in case the work
			 * instance by the re-used after it has been de-queued).
			 */

			worker = work->worker;
			arg    = work->arg;

			/* Mark the work as no longer being queued */

			work->worker = NULL;

			/* Do the work.  Re-enable interrupts while the work is being
			 * performed... we don't have any idea how long that will take!
			 */

			work_unlock(lock_id);

			if (!worker) {
				PX4_WARN("MESSED UP: worker = 0\n");

			} else {
				worker(arg);
			}

			/* Now, unfortunately, since we re-enabled interrupts we don't
			 * know the state of the work list and we will have to start
			 * back at the head of the list.
			 */

			work_lock(lock_id);
			work  = (struct work_s *)wqueue->q.head;

		} else {
			/* This one is not ready.. will it be ready before the next
			 * scheduled wakeup interval?
			 */

			/* Here: elapsed < work->delay */
			remaining = USEC_PER_TICK * (work->delay - elapsed);

			if (remaining < next) {
				/* Yes.. Then schedule to wake up when the work is ready */

				next = remaining;
			}

			/* Then try the next in the list. */

			work = (struct work_s *)work->dq.flink;
		}
	}

	/* Wait awhile to check the work list.  We will wait here until either
	 * the time elapses or until we are awakened by a signal.
	 */
	work_unlock(lock_id);

	usleep(next);
}