work_queue() must cancel existing work prior to queuing new work, otherwise the work queue can become corrupted. Problem noted by Pascal Speck.

This commit is contained in:
Gregory Nutt 2017-08-28 07:46:48 -06:00
parent 809569cda9
commit bbf4d5048a
5 changed files with 37 additions and 40 deletions

View File

@ -2954,7 +2954,10 @@ int work_queue(int qid, FAR struct work_s *work, worker_t worker,
Queue work to be performed at a later time. All queued work will be performed on the worker thread of execution (not the caller's).
</p>
<p>
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 <code>work_queue()</code> again until either (1) the previous work has been performed and removed from the queue, or (2) <code>work_cancel()</code> has been called to cancel the work and remove it from the work queue.
The work structure is allocated and must be initialized to all zero by the caller.
Otherwise, the work structure is completely managed by the work queue logic.
The caller should never modify the contents of the work queue structure directly.
If <code>work_queue()</code> is called before the previous work as been performed and removed from the queue, then any pending work will be canceled and lost.
</p>
<p>
<b>Input Parameters</b>:

View File

@ -1,7 +1,7 @@
/****************************************************************************
* include/nuttx/wqueue.h
*
* Copyright (C) 2009, 2011-2014 Gregory Nutt. All rights reserved.
* Copyright (C) 2009, 2011-2014, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -338,12 +338,12 @@ int work_usrstart(void);
* Queue work to be performed at a later time. All queued work will be
* performed on the worker thread 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.
* The work structure is allocated and must be initialized to all zero by
* the caller. Otherwise, the work structure is completely managed by the
* work queue logic. The caller should never modify the contents of the
* work queue structure directly. If work_queue() is called before the
* previous work as been performed and removed from the queue, then any
* pending work will be canceled and lost.
*
* Input parameters:
* qid - The work queue ID

View File

@ -50,22 +50,6 @@
#if defined(CONFIG_LIB_USRWORK) && !defined(__KERNEL__)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/

View File

@ -1,7 +1,7 @@
/****************************************************************************
* libc/wqueue/work_queue.c
*
* Copyright (C) 2009-2011, 2014, 2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2009-2011, 2014, 2016-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -65,7 +65,7 @@
*
* 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()
* the work queue structure; the caller should not call work_qqueue()
* 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.
@ -91,6 +91,10 @@ static int work_qqueue(FAR struct usr_wqueue_s *wqueue,
{
DEBUGASSERT(work != NULL);
/* Cancel any pending work in the work stucture */
work_cancel(qid, work);
/* Get exclusive access to the work queue */
while (work_lock() < 0);
@ -123,12 +127,12 @@ static int work_qqueue(FAR struct usr_wqueue_s *wqueue,
* Queue user-mode 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).
*
* 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.
* The work structure is allocated and must be initialized to all zero by
* the caller. Otherwise, the work structure is completely managed by the
* work queue logic. The caller should never modify the contents of the
* work queue structure directly. If work_queue() is called before the
* previous work as been performed and removed from the queue, then any
* pending work will be canceled and lost.
*
* Input parameters:
* qid - The work queue ID (index)

View File

@ -1,7 +1,7 @@
/****************************************************************************
* sched/wqueue/kwork_queue.c
*
* Copyright (C) 2014, 2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2014, 2016-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -66,7 +66,7 @@
*
* 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()
* the work queue structure; the caller should not call work_qqueue()
* 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.
@ -124,12 +124,12 @@ static void work_qqueue(FAR struct kwork_wqueue_s *wqueue,
* Queue kernel-mode 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).
*
* 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.
* The work structure is allocated and must be initialized to all zero by
* the caller. Otherwise, the work structure is completely managed by the
* work queue logic. The caller should never modify the contents of the
* work queue structure directly. If work_queue() is called before the
* previous work as been performed and removed from the queue, then any
* pending work will be canceled and lost.
*
* Input parameters:
* qid - The work queue ID (index)
@ -149,6 +149,12 @@ static void work_qqueue(FAR struct kwork_wqueue_s *wqueue,
int work_queue(int qid, FAR struct work_s *work, worker_t worker,
FAR void *arg, systime_t delay)
{
/* Cancel any pending work in the work stucture */
work_cancel(qid, work);
/* Then queue the new work */
#ifdef CONFIG_SCHED_HPWORK
if (qid == HPWORK)
{