ml-batched-timer: fixed possible deadlock and cleaned up locking strategy

The aim of MlBatchedTimer is to batch timer updates in worker threads to
avoid having to make a round-trip between the worker thread and the main
thread. The point is to only make this round-trip when the target time
actually changes.

The locking strategy is deliberately racy at times so that we avoid
grabbing a lock in the fast path.

Signed-off-by: Balazs Scheidler <bazsi@balabit.hu>