Fix a potential race condition

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2234 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2009-11-06 13:42:49 +00:00
parent 7f84a8bea1
commit bf7555cc4a
4 changed files with 56 additions and 27 deletions

View File

@ -101,6 +101,13 @@ EXTERN pid_t g_worker;
* Queue work to be performed at a later time. All queued work will be * Queue work to be performed at a later time. All queued work will be
* performed on the worker thread of of execution (not the caller's). * performed on the worker thread of of execution (not the caller's).
* *
* The work structure is allocated by caller, but completely managed by
* the work queue logic. The caller should never modify the contents of
* the work queue structure; the caller should not call work_queue()
* again until either (1) the previous work has been performed and removed
* from the queue, or (2) work_cancel() has been called to cancel the work
* and remove it from the work queue.
*
* Input parameters: * Input parameters:
* work - The work structure to queue * work - The work structure to queue
* worker - The worker callback to be invoked. The callback will invoked * worker - The worker callback to be invoked. The callback will invoked
@ -121,7 +128,9 @@ EXTERN int work_queue(struct work_s *work, worker_t worker, FAR void *arg, uint3
* Name: work_cancel * Name: work_cancel
* *
* Description: * Description:
* Cancel previously queued work. * Cancel previously queued work. This removes work from the work queue.
* After work has been canceled, it may be re-queue by calling work_queue()
* again.
* *
* Input parameters: * Input parameters:
* work - The previously queue work structure to cancel * work - The previously queue work structure to cancel
@ -137,7 +146,9 @@ EXTERN int work_cancel(struct work_s *work);
* Name: work_signal * Name: work_signal
* *
* Description: * Description:
* Signal the worker thread to process the work queue now. * Signal the worker thread to process the work queue now. This function
* is used internally by the work logic but could also be used by the
* user to force an immediate re-assessment of pending work.
* *
* Input parameters: * Input parameters:
* None * None

View File

@ -79,7 +79,9 @@
* Name: work_cancel * Name: work_cancel
* *
* Description: * Description:
* Cancel previously queued work. * Cancel previously queued work. This removes work from the work queue.
* After work has been canceled, it may be re-queue by calling work_queue()
* again.
* *
* Input parameters: * Input parameters:
* work - The previously queue work structure to cancel * work - The previously queue work structure to cancel

View File

@ -83,6 +83,13 @@
* Queue work to be performed at a later time. All queued work will be * Queue work to be performed at a later time. All queued work will be
* performed on the worker thread of of execution (not the caller's). * performed on the worker thread of of execution (not the caller's).
* *
* The work structure is allocated by caller, but completely managed by
* the work queue logic. The caller should never modify the contents of
* the work queue structure; the caller should not call work_queue()
* again until either (1) the previous work has been performed and removed
* from the queue, or (2) work_cancel() has been called to cancel the work
* and remove it from the work queue.
*
* Input parameters: * Input parameters:
* work - The work structure to queue * work - The work structure to queue
* worker - The worker callback to be invoked. The callback will invoked * worker - The worker callback to be invoked. The callback will invoked

View File

@ -101,6 +101,8 @@ struct dq_queue_s g_work;
int work_thread(int argc, char *argv[]) int work_thread(int argc, char *argv[])
{ {
volatile FAR struct work_s *work; volatile FAR struct work_s *work;
worker_t worker;
FAR void *arg;
irqstate_t flags; irqstate_t flags;
/* Loop forever */ /* Loop forever */
@ -130,37 +132,44 @@ int work_thread(int argc, char *argv[])
work = (FAR struct work_s *)g_work.head; work = (FAR struct work_s *)g_work.head;
while (work) while (work)
{ {
/* Is this work ready? It is ready if there is no delay or if /* Is this work ready? It is ready if there is no delay or if
* the delay has elapsed. * the delay has elapsed.
*/ */
if (work->delay == 0 || g_system_timer - work->qtime > work->delay) if (work->delay == 0 || g_system_timer - work->qtime > work->delay)
{ {
/* Remove the ready-to-execute work from the list */ /* Remove the ready-to-execute work from the list */
(void)dq_rem((struct dq_entry_s *)work, &g_work); (void)dq_rem((struct dq_entry_s *)work, &g_work);
/* Do the work. Re-enable interrupts while the work is being /* Extract the work description from the entry (in case the work
* performed... we don't have any idea how long that will take! * instance by the re-used after it has been de-queued).
*/ */
irqrestore(flags); worker = work->worker;
work->worker(work->arg); arg = work->arg;
/* Now, unfortunately, since we re-enabled interrupts we don't /* Do the work. Re-enable interrupts while the work is being
* the state of the work list and we will have to start back at * performed... we don't have any idea how long that will take!
* the head of the list. */
*/
flags = irqsave(); irqrestore(flags);
work = (FAR struct work_s *)g_work.head; worker(arg);
}
else
{
/* This one is not ready, try the next in the list. */
work = (FAR struct work_s *)work->dq.flink; /* 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.
*/
flags = irqsave();
work = (FAR struct work_s *)g_work.head;
}
else
{
/* This one is not ready, try the next in the list. */
work = (FAR struct work_s *)work->dq.flink;
}
} }
irqrestore(flags); irqrestore(flags);
} }