问题
I had a look into the Blink codebase to answer this question about the maximum possible number of timers in JavaScript.
New timers are created by DOMTimerCoordinator::InstallNewTimeout(). It calls NextID() to retrieve an available integer key. Then, it inserts the new timer and the corresponding key into timers_.
int timeout_id = NextID();
timers_.insert(timeout_id, DOMTimer::Create(context, action, timeout,
single_shot, timeout_id));
NextID()
gets the next id in a circular sequence from 1 to 231-1:
int DOMTimerCoordinator::NextID() {
while (true) {
++circular_sequential_id_;
if (circular_sequential_id_ <= 0)
circular_sequential_id_ = 1;
if (!timers_.Contains(circular_sequential_id_))
return circular_sequential_id_;
}
}
What happen if all the IDs are in use?
What does prevent NextID()
from entering in a endless loop?
The whole process is explained with more detail in my answer to that question.
回答1:
I needed a bit to understand this but I believe I got it.
These are the steps which turned it into sense for me.
circular_sequential_id_
is used as unique identifier. It's not exposed but from the other info I suspect it's anint
with 32 bit (e.g.std::int32_t
).I suspect
circular_sequential_id_
is a member variable ofclass
(orstruct
)DOMTimerCoordinator
. Hence, after each call ofNextID()
it “remembers” the last returned value. WhenNextID()
is enteredcircular_sequential_id_
is incremented first:++circular_sequential_id_;
The increment
++circular_sequential_id_;
may sooner or later cause an overflow (Uuuh. If I remember right this is considered as Undefined Behavior but in real world it mostly simply wraps around.) and becomes negative. To handle this, the next line is good for:if (circular_sequential_id_ <= 0) circular_sequential_id_ = 1;
The last statement in loop checks whether the generated ID is still in use in any timer:
if (!timers_.Contains(circular_sequential_id_)) return circular_sequential_id_;
If not used the ID is returned. Otherwise, “Play it again, Sam.”
This brings me to the most reasonable answer:
Yes, this can become an endless loop...
...if 231 - 1 timers have been occupied and, hence, all IDs have been consumed.
I assume with 231 - 1 timers you have much more essential other problems. (Alone, imaging the storage that those timers may need and the time to handle all of them...)
Even if 231 - 1 timers are not a fatal problem, the function may cycle further until one of the timers releases it's ID and it can be occupied again. So,
NextID()
would be blocking if a resource (a free ID for a timer) is temporarily not available.
Thinking twice, the 2. option is rather theoretically. I cannot believe that somebody would manage limited resources this way.
I guess, this code works under assumption that there will never be 231 - 1 timers concurrently and hence it will find a free ID with a few iterations.
来源:https://stackoverflow.com/questions/53127713/what-does-prevent-domtimercoordinatornextid-from-entering-a-endless-loop