// 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; }