// Timer IDs are implemented using a free-list;
// there's a vector initialized with:
//    X[i] = i + 1
// and nextFreeTimerId starts with 1.
//
// Allocating a timer ID involves taking the ID from
//    X[nextFreeTimerId]
// updating nextFreeTimerId to this value and returning the old value
//
// When the timer ID is allocated, its cell in the vector is unused (it's a
// free list). As an added protection, we use the cell to store an invalid
// (negative) value that we can later check for integrity.
//
// (continues below).
int QAbstractEventDispatcherPrivate::allocateTimerId()
{
    int timerId, newTimerId;
    int at, *b;
    do {
        timerId = nextFreeTimerId; //.loadAcquire(); // ### FIXME Proper memory ordering semantics

        // which bucket are we looking in?
        int which = timerId & TimerIdMask;
        int bucket = bucketOffset(which);
        at = bucketIndex(bucket, which);
        b = timerIds[bucket];

        if (!b) {
            // allocate a new bucket
            b = allocateBucket(bucket);
            if (!timerIds[bucket].testAndSetRelease(0, b)) {
                // another thread won the race to allocate the bucket
                delete [] b;
                b = timerIds[bucket];
            }
        }

        newTimerId = prepareNewValueWithSerialNumber(timerId, b[at]);
    } while (!nextFreeTimerId.testAndSetRelaxed(timerId, newTimerId));

    b[at] = -timerId;

    return timerId;
}
int QAbstractEventDispatcherPrivate::allocateTimerId()
{
    int timerId, newTimerId;
    do {
        timerId = nextFreeTimerId;

        // which bucket are we looking in?
        int which = timerId & 0x00ffffff;
        int bucket = bucketOffset(which);
        int at = bucketIndex(bucket, which);
        int *b = timerIds[bucket];

        if (!b) {
            // allocate a new bucket
            b = allocateBucket(bucket);
            if (!timerIds[bucket].testAndSetRelease(0, b)) {
                // another thread won the race to allocate the bucket
                delete [] b;
                b = timerIds[bucket];
            }
        }

        newTimerId = b[at];
    } while (!nextFreeTimerId.testAndSetRelaxed(timerId, newTimerId));

    return timerId;
}
void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId)
{
    int which = timerId & 0x00ffffff;
    int bucket = bucketOffset(which);
    int at = bucketIndex(bucket, which);
    int *b = timerIds[bucket];

    int freeId, newTimerId;
    do {
        freeId = nextFreeTimerId;
        b[at] = freeId & 0x00ffffff;

        newTimerId = prepareNewValueWithSerialNumber(freeId, timerId);
    } while (!nextFreeTimerId.testAndSetRelease(freeId, newTimerId));
}
// Releasing a timer ID requires putting the current ID back in the vector;
// we do it by setting:
//    X[timerId] = nextFreeTimerId;
// then we update nextFreeTimerId to the timer we've just released
//
// The extra code in allocateTimerId and releaseTimerId are ABA prevention
// and bucket memory. The buckets are simply to make sure we allocate only
// the necessary number of timers. See above.
//
// ABA prevention simply adds a value to 7 of the top 8 bits when resetting
// nextFreeTimerId.
void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId)
{
    int which = timerId & TimerIdMask;
    int bucket = bucketOffset(which);
    int at = bucketIndex(bucket, which);
    int *b = timerIds[bucket];

    Q_ASSERT_X(timerId == -b[at], "QAbstractEventDispatcher::releaseTimerId",
               "Internal error: timer ID not found");

    int freeId, newTimerId;
    do {
        freeId = nextFreeTimerId;//.loadAcquire(); // ### FIXME Proper memory ordering semantics
        b[at] = freeId & TimerIdMask;

        newTimerId = prepareNewValueWithSerialNumber(freeId, timerId);
    } while (!nextFreeTimerId.testAndSetRelease(freeId, newTimerId));
}