* Check through all managed objects and properly refcount them
  using shared_ptr.
* Ensure that we comb through the current code and enforce the distinction
  between user errors and program exceptions.
* Investigate using UMONITOR/UMWAIT for spinlocks to reduce busy-waiting
  stress/power consumption. Look for a parallel on ARM.
* Investigate WFE/SEV to reduce busy-waiting in spinlocks on ARM.
* The input arg `requiredLocks` to LockSet::LockSet() should be
  a ref and not by-value. Propagate this upward into
  SerializedAsyncContin and into all derived classes'
  constructors.
* In classes like udpCommandDemuxer and possibly other such background tasks,
  use a spinlock to ensure that the stop() function doesn't deallocate the
  data to be used by the daemon task while the daemon task is executing.
  * Alternatively we could re-emqueue the message;
  * Alternatively, if select/poll don't consume the read-data-rdy flag,
    we can just return and let the next timer invocation run instead.
  * Alternatively, we can use an xchg'd flag between the udp listener
    and the timed enforcer.
* In livoxProto1/device.cpp, migrate the registerUdpCommandHandler() calls
  from using the inProgress collection to the per-device collections.
* In cases where we use boost deadline_timers and pass in an async
  contin as context preservation across the delay, but they aren't
  part of a branch pattern, we may still need to call cancel() on them
  after they expire just in case boost doesn't clean up the internal
  callable that we passed it. Or else we'll have circular sh_ptr
  references in our continuations.
* Think of a unified mechanism or a design pattern which will ensure that
  timeouts will always either expire or be canceled before program
  finalization.
  Or more generically, before their lifetime ends.
