work queue:fix work_cancel_sync can not cancel the work which call work_queue in handler

1.work_queue a work which call work_queue again
2.work_cancel_sync the work
3.the work is just calling in workthread
4.work_queue the work again,and post the work_cancel_sync wakeup
5.the work is not canceled

Signed-off-by: dulibo1 <dulibo1@xiaomi.com>
This commit is contained in:
dulibo1 2023-12-07 13:00:41 +08:00 committed by Xiang Xiao
parent e48d5d8271
commit 5e8ce0b9f0

View File

@ -46,11 +46,11 @@
do \
{ \
int sem_count; \
dq_addlast((FAR dq_entry_t *)(work), &(wqueue).q); \
nxsem_get_value(&(wqueue).sem, &sem_count); \
dq_addlast((FAR dq_entry_t *)(work), &(wqueue)->q); \
nxsem_get_value(&(wqueue)->sem, &sem_count); \
if (sem_count < 0) /* There are threads waiting for sem. */ \
{ \
nxsem_post(&(wqueue).sem); \
nxsem_post(&(wqueue)->sem); \
} \
} \
while (0)
@ -67,7 +67,7 @@
static void hp_work_timer_expiry(wdparm_t arg)
{
irqstate_t flags = enter_critical_section();
queue_work(g_hpwork, arg);
queue_work(&g_hpwork, arg);
leave_critical_section(flags);
}
#endif
@ -80,11 +80,31 @@ static void hp_work_timer_expiry(wdparm_t arg)
static void lp_work_timer_expiry(wdparm_t arg)
{
irqstate_t flags = enter_critical_section();
queue_work(g_lpwork, arg);
queue_work(&g_lpwork, arg);
leave_critical_section(flags);
}
#endif
static bool work_is_canceling(FAR struct kworker_s *kworkers, int nthreads,
FAR struct work_s *work)
{
int semcount;
for (int wndx = 0; wndx < nthreads; wndx++)
{
if (kworkers[wndx].work == work)
{
nxsem_get_value(&kworkers[wndx].wait, &semcount);
if (semcount < 0)
{
return true;
}
}
}
return false;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -122,7 +142,10 @@ static void lp_work_timer_expiry(wdparm_t arg)
int work_queue(int qid, FAR struct work_s *work, worker_t worker,
FAR void *arg, clock_t delay)
{
FAR struct kwork_wqueue_s * wqueue;
wdentry_t expiry;
irqstate_t flags;
int nthreads;
int ret = OK;
/* Interrupts are disabled so that this logic can be called from with
@ -138,6 +161,34 @@ int work_queue(int qid, FAR struct work_s *work, worker_t worker,
work_cancel(qid, work);
}
#ifdef CONFIG_SCHED_HPWORK
if (qid == HPWORK)
{
wqueue = (FAR struct kwork_wqueue_s *)&g_hpwork;
expiry = hp_work_timer_expiry;
nthreads = CONFIG_SCHED_HPNTHREADS;
}
else
#endif
#ifdef CONFIG_SCHED_LPWORK
if (qid == LPWORK)
{
wqueue = (FAR struct kwork_wqueue_s *)&g_lpwork;
expiry = lp_work_timer_expiry;
nthreads = CONFIG_SCHED_LPNTHREADS;
}
else
#endif
{
ret = -EINVAL;
goto out;
}
if (work_is_canceling(wqueue->worker, nthreads, work))
{
goto out;
}
/* Initialize the work structure. */
work->worker = worker; /* Work callback. non-NULL means queued */
@ -145,46 +196,18 @@ int work_queue(int qid, FAR struct work_s *work, worker_t worker,
/* Queue the new work */
#ifdef CONFIG_SCHED_HPWORK
if (qid == HPWORK)
if (!delay)
{
/* Queue high priority work */
if (!delay)
{
queue_work(g_hpwork, work);
}
else
{
wd_start(&work->u.timer, delay, hp_work_timer_expiry,
(wdparm_t)work);
}
queue_work(wqueue, work);
}
else
#endif
#ifdef CONFIG_SCHED_LPWORK
if (qid == LPWORK)
{
/* Queue low priority work */
if (!delay)
{
queue_work(g_lpwork, work);
}
else
{
wd_start(&work->u.timer, delay, lp_work_timer_expiry,
(wdparm_t)work);
}
}
else
#endif
{
ret = -EINVAL;
wd_start(&work->u.timer, delay, expiry,
(wdparm_t)work);
}
out:
leave_critical_section(flags);
return ret;
}