On Sat, Nov 6, 2010 at 7:22 AM, Hans Petter Selasky <hselasky_at_c2i.net> wrote: > Hi, > > On Saturday 06 November 2010 14:57:50 Matthew Fleming wrote: >> >> I think you're misunderstanding the existing taskqueue(9) implementation. >> >> As long as TQ_LOCK is held, the state of ta->ta_pending cannot change, >> nor can the set of running tasks. So the order of checks is >> irrelevant. > > I agree that the order of checks is not important. That is not the problem. > > Cut & paste from suggested taskqueue patch from Fleming: > > > +int >> > +taskqueue_cancel(struct taskqueue *queue, struct task *task) >> > +{ >> > + int rc; >> > + >> > + TQ_LOCK(queue); >> > + if (!task_is_running(queue, task)) { >> > + if ((rc = task->ta_pending) > 0) >> > + STAILQ_REMOVE(&queue->tq_queue, task, task, >> > ta_link); + task->ta_pending = 0; >> > + } else { >> > + rc = -EBUSY; > > What happens in this case if ta_pending > 0. Are you saying this is not > possible? If ta_pending > 0, shouldn't we also do a STAILQ_REMOVE() ? Ah! I see what you mean. I'm not quite sure what the best thing to do here is; I agree it would be nice if taskqueue_cancel(9) dequeued the task, but I believe it also needs to indicate that the task is currently running. I guess the best thing would be to return the old pending count by reference parameter, and 0 or EBUSY to also indicate if there is a task currently running. Adding jhb_at_ to this mail since he has good thoughts on interfacing. Thanks, matthew > >> > + } >> > + TQ_UNLOCK(queue); >> > + return (rc); >> > +} >> > >> >> As John said, the taskqueue(9) implementation cannot protect consumers >> of it from re-queueing a task; that kind of serialization needs to >> happen at a higher level. > > Agreed, but that is not what I'm pointing at. I'm pointing at what happens if > you re-queue a task and then cancel while it is actually running. Will the > task still be queued for execution after taskqueue_cancel()? > >> taskqueue(9) is not quite like callout(9); the taskqueue(9) >> implementation drops all locks before calling the task's callback >> function. So once the task is running, taskqueue(9) can do nothing >> about it until the task stops running. > > This is not the problem. > >> >> This is why Jeff's >> implementation of taskqueue_cancel(9) slept if the task was running, >> and why mine returns an error code. The only way to know for sure >> that a task is "about" to run is to ask taskqueue(9), because there's >> a window where the TQ_LOCK is dropped before the callback is entered. > > And if you re-queue and cancel in this window, shouldn't this also be handled > like in the other cases? > > Cut & paste from kern/subr_taskqueue.c: > > task->ta_pending = 0; > tb.tb_running = task; > TQ_UNLOCK(queue); > > If a concurrent thread at exactly this point in time calls taskqueue_enqueue() > on this task, then we re-add the task to the "queue->tq_queue". So far we > agree. Imagine now that for some reason a following call to taskqueue_cancel() > on this task at same point in time. Now, shouldn't taskqueue_cancel() also > remove the task from the "queue->tq_queue" in this case aswell? Because in > your implementation you only remove the task if we are not running, and that > is not true when we are at exactly this point in time. > > task->ta_func(task->ta_context, pending); > > TQ_LOCK(queue); > tb.tb_running = NULL; > wakeup(task); > > > Another issue I noticed is that the ta_pending counter should have a wrap > protector. > > --HPS >Received on Sat Nov 06 2010 - 19:33:18 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:08 UTC