private bool ScheduleCallbackHelper(Action <object> callback, object state)
        {
            // See if there's a free slot. Fortunately the overflow bit is simply lost.
            int slot = Interlocked.Add(ref _headTail, Bits.HiOne);

            // If this brings us to 'empty', then the IOTS used to be 'idle'. Remember that, and increment
            // again. This doesn't need to be in a loop, because until we call Post(), we can't go back to idle.
            bool wasIdle = Bits.Count(slot) == 0;

            if (wasIdle)
            {
                slot = Interlocked.Add(ref _headTail, Bits.HiOne);
                Fx.Assert(Bits.Count(slot) != 0, "IOTS went idle when it shouldn't have.");
            }

            // Check if we wrapped *around* to idle.
            if (Bits.Count(slot) == -1)
            {
                // Since the capacity is limited to 32k, this means we wrapped the array at least twice. That's bad
                // because headTail no longer knows how many work items we have - it looks like zero. This can
                // only happen if 32k threads come through here while one is swapped out.
                throw Fx.AssertAndThrowFatal("Head/Tail overflow!");
            }

            bool queued = _slots[slot >> Bits.HiShift & SlotMask].TryEnqueueWorkItem(callback, state, out bool wrapped);

            if (wrapped)
            {
                // Wrapped around the circular buffer. Create a new, bigger IoThreadScheduler.
                var next = new IoThreadScheduler(Math.Min(_slots.Length * 2, MaximumCapacity), _slotsLowPri.Length);
                Interlocked.CompareExchange(ref current, next, this);
            }

            if (wasIdle)
            {
                // It's our responsibility to kick off the overlapped.
                overlapped.Post(this);
            }

            return(queued);
        }