Changeset View
Changeset View
Standalone View
Standalone View
sys/compat/linuxkpi/common/src/linux_work.c
| Show First 20 Lines • Show All 429 Lines • ▼ Show 20 Lines | linux_cancel_delayed_work(struct delayed_work *dwork) | ||||
| static const uint8_t states[WORK_ST_MAX] __aligned(8) = { | static const uint8_t states[WORK_ST_MAX] __aligned(8) = { | ||||
| [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */ | [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */ | ||||
| [WORK_ST_TIMER] = WORK_ST_CANCEL, /* try to cancel */ | [WORK_ST_TIMER] = WORK_ST_CANCEL, /* try to cancel */ | ||||
| [WORK_ST_TASK] = WORK_ST_CANCEL, /* try to cancel */ | [WORK_ST_TASK] = WORK_ST_CANCEL, /* try to cancel */ | ||||
| [WORK_ST_EXEC] = WORK_ST_EXEC, /* NOP */ | [WORK_ST_EXEC] = WORK_ST_EXEC, /* NOP */ | ||||
| [WORK_ST_CANCEL] = WORK_ST_CANCEL, /* NOP */ | [WORK_ST_CANCEL] = WORK_ST_CANCEL, /* NOP */ | ||||
| }; | }; | ||||
| struct taskqueue *tq; | struct taskqueue *tq; | ||||
| bool cancelled; | |||||
| mtx_lock(&dwork->timer.mtx); | |||||
| switch (linux_update_state(&dwork->work.state, states)) { | switch (linux_update_state(&dwork->work.state, states)) { | ||||
| case WORK_ST_TIMER: | case WORK_ST_TIMER: | ||||
| case WORK_ST_CANCEL: | case WORK_ST_CANCEL: | ||||
| if (linux_cancel_timer(dwork, 0)) { | cancelled = (callout_stop(&dwork->timer.callout) == 1); | ||||
| if (cancelled) { | |||||
| atomic_cmpxchg(&dwork->work.state, | atomic_cmpxchg(&dwork->work.state, | ||||
| WORK_ST_CANCEL, WORK_ST_IDLE); | WORK_ST_CANCEL, WORK_ST_IDLE); | ||||
| mtx_unlock(&dwork->timer.mtx); | |||||
| return (true); | return (true); | ||||
| } | } | ||||
| /* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
| case WORK_ST_TASK: | case WORK_ST_TASK: | ||||
| tq = dwork->work.work_queue->taskqueue; | tq = dwork->work.work_queue->taskqueue; | ||||
| if (taskqueue_cancel(tq, &dwork->work.work_task, NULL) == 0) { | if (taskqueue_cancel(tq, &dwork->work.work_task, NULL) == 0) { | ||||
| atomic_cmpxchg(&dwork->work.state, | atomic_cmpxchg(&dwork->work.state, | ||||
| WORK_ST_CANCEL, WORK_ST_IDLE); | WORK_ST_CANCEL, WORK_ST_IDLE); | ||||
| mtx_unlock(&dwork->timer.mtx); | |||||
| return (true); | return (true); | ||||
| } | } | ||||
| /* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
| default: | default: | ||||
| mtx_unlock(&dwork->timer.mtx); | |||||
| return (false); | return (false); | ||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| * This function cancels the given work structure in a synchronous | * This function cancels the given work structure in a synchronous | ||||
| * fashion. It returns non-zero if the work was successfully | * fashion. It returns non-zero if the work was successfully | ||||
| * cancelled. Else the work was already cancelled. | * cancelled. Else the work was already cancelled. | ||||
| */ | */ | ||||
| bool | bool | ||||
| linux_cancel_delayed_work_sync(struct delayed_work *dwork) | linux_cancel_delayed_work_sync(struct delayed_work *dwork) | ||||
| { | { | ||||
| static const uint8_t states[WORK_ST_MAX] __aligned(8) = { | static const uint8_t states[WORK_ST_MAX] __aligned(8) = { | ||||
| [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */ | [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */ | ||||
| [WORK_ST_TIMER] = WORK_ST_IDLE, /* cancel and drain */ | [WORK_ST_TIMER] = WORK_ST_IDLE, /* cancel and drain */ | ||||
| [WORK_ST_TASK] = WORK_ST_IDLE, /* cancel and drain */ | [WORK_ST_TASK] = WORK_ST_IDLE, /* cancel and drain */ | ||||
| [WORK_ST_EXEC] = WORK_ST_IDLE, /* too late, drain */ | [WORK_ST_EXEC] = WORK_ST_IDLE, /* too late, drain */ | ||||
| [WORK_ST_CANCEL] = WORK_ST_IDLE, /* cancel and drain */ | [WORK_ST_CANCEL] = WORK_ST_IDLE, /* cancel and drain */ | ||||
| }; | }; | ||||
| struct taskqueue *tq; | struct taskqueue *tq; | ||||
| bool retval = false; | bool retval = false; | ||||
| int ret, state; | |||||
| bool cancelled; | |||||
| WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, | WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, | ||||
| "linux_cancel_delayed_work_sync() might sleep"); | "linux_cancel_delayed_work_sync() might sleep"); | ||||
| retry: | mtx_lock(&dwork->timer.mtx); | ||||
| switch (linux_update_state(&dwork->work.state, states)) { | |||||
| state = linux_update_state(&dwork->work.state, states); | |||||
| switch (state) { | |||||
| case WORK_ST_IDLE: | case WORK_ST_IDLE: | ||||
| mtx_unlock(&dwork->timer.mtx); | |||||
| return (retval); | return (retval); | ||||
| case WORK_ST_EXEC: | |||||
| tq = dwork->work.work_queue->taskqueue; | |||||
| if (taskqueue_cancel(tq, &dwork->work.work_task, NULL) != 0) | |||||
| taskqueue_drain(tq, &dwork->work.work_task); | |||||
| goto retry; /* work may have restarted itself */ | |||||
| case WORK_ST_TIMER: | case WORK_ST_TIMER: | ||||
hselasky: Missing mtx_unlock() before this return statement. | |||||
| case WORK_ST_CANCEL: | case WORK_ST_CANCEL: | ||||
| if (linux_cancel_timer(dwork, 1)) { | cancelled = (callout_stop(&dwork->timer.callout) == 1); | ||||
| /* | |||||
| * Make sure taskqueue is also drained before | |||||
| * returning: | |||||
| */ | |||||
| tq = dwork->work.work_queue->taskqueue; | tq = dwork->work.work_queue->taskqueue; | ||||
| ret = taskqueue_cancel(tq, &dwork->work.work_task, NULL); | |||||
| mtx_unlock(&dwork->timer.mtx); | |||||
| callout_drain(&dwork->timer.callout); | |||||
| taskqueue_drain(tq, &dwork->work.work_task); | taskqueue_drain(tq, &dwork->work.work_task); | ||||
| retval = true; | return (cancelled || (ret != 0)); | ||||
| goto retry; | |||||
| } | |||||
| /* FALLTHROUGH */ | |||||
| default: | default: | ||||
| tq = dwork->work.work_queue->taskqueue; | tq = dwork->work.work_queue->taskqueue; | ||||
| if (taskqueue_cancel(tq, &dwork->work.work_task, NULL) != 0) | ret = taskqueue_cancel(tq, &dwork->work.work_task, NULL); | ||||
| mtx_unlock(&dwork->timer.mtx); | |||||
| if (ret != 0) | |||||
| taskqueue_drain(tq, &dwork->work.work_task); | taskqueue_drain(tq, &dwork->work.work_task); | ||||
| retval = true; | return (ret != 0); | ||||
| goto retry; | |||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| * This function waits until the given work structure is completed. | * This function waits until the given work structure is completed. | ||||
| * It returns non-zero if the work was successfully | * It returns non-zero if the work was successfully | ||||
| * waited for. Else the work was not waited for. | * waited for. Else the work was not waited for. | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 217 Lines • Show Last 20 Lines | |||||
Missing mtx_unlock() before this return statement.