[Live-devel] correct way to use TaskScheduler::unscheduleDelayedTask?

Helmut Grohne h.grohne at intenta.de
Tue Aug 23 07:25:20 PDT 2016


Hi,

I'm wondering about the correct way to use
TaskScheduler::unscheduleDelayedTask. I see a few options, but none seem
to be consistent with the live555 code base or sane.

Option 1
~~~~~~~~
scheduleDelayedTask never returns the same token. A user can call
unscheduleDelayedTask before or after the task has expired at will and
the TaskScheduler is responsible for deciding whether it needs to
process the unscheduleDelayedTask call.

This seems to be the way BasicTaskScheduler0 is implemented. The
TaskToken type is used as an integral type incrementing with each
scheduled task. Unfortunately, we can have many tasks. When using e.g. a
multi framed source, there can be hundreds of tasks per second. At this
rate an overflow occurs after about a year on 32bit architectures. When
delivering multiple streams, overflows can happen in the range of days.
Assuming that TaskTokens are unique seems to contradict reality.

After an overflow has happened, we can no longer tell whether an
unscheduleDelayedTask call was issued for an old task or a new task that
happens to use the same token. Undefined behaviour ensues.

It could be mitigated by moving to 64bit values for TaskTokens, but of
course that'd be an ABI break. Still this decision would be rather
limiting for people implementing TaskScheduler.

Option 2
~~~~~~~~
unscheduleDelayedTask must always be called for every issued TaskToken
(either before expiry or after expiry).  This way the user acknowledges
that she stops using a particular TaskToken and it can be reused.

This is not what the live555 code base is doing. There are a number of
handlers that overwrite their TaskToken after being called without
issuing an unscheduleDelayedTask (e.g.
BasicUDPSink::afterGettingFrame1). It could be implemented by carefully
placing unscheduleDelayedTask in the relevant locations.  Failure to do
so generally can result in memory leaks.

With this variant, it is possible to implement TaskSchedulers where
unscheduleDelayedTask can be made thread-safe, which will not be the
case for option 3.

Option 3
~~~~~~~~
An issued TaskToken may either expire or be unscheduled once using
unscheduleDelayedTask. This is a bit like option 2, except that expiry
is understood as an implicit acknowledgement. Reuse of TaskToken is
possible here as well.

This is not what the live555 code base is doing either. A number of
places unschedule TaskTokens despite having expired (e.g.
BasicUDPSink::sendNext does not invalidate nextTask). It could be
implemented by carefully placing NULL assignments in the relevant
locations. Failure to do so generally results in double frees which tend
to be hard to debug.  It also means that TaskToken no longer is an
opaque type and that NULL is officially is the invalid TaskToken.

Are there any other options I missed?

So how do I correctly unschedule delayed tasks?

Helmut


More information about the live-devel mailing list