Bug 996132: Make allocations in the event queue infallible. r=bsmedberg

This commit is contained in:
Kyle Huey 2014-05-23 12:53:14 -07:00
Родитель 5c5c731fae
Коммит 7af104c03a
4 изменённых файлов: 37 добавлений и 52 удалений

Просмотреть файл

@ -80,48 +80,40 @@ nsEventQueue::GetEvent(bool mayWait, nsIRunnable **result)
return true;
}
bool
void
nsEventQueue::PutEvent(nsIRunnable *runnable)
{
// Avoid calling AddRef+Release while holding our monitor.
nsRefPtr<nsIRunnable> event(runnable);
bool rv = true;
{
if (ChaosMode::isActive()) {
// With probability 0.5, yield so other threads have a chance to
// dispatch events to this queue first.
if (ChaosMode::randomUint32LessThan(2)) {
PR_Sleep(PR_INTERVAL_NO_WAIT);
}
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (!mHead) {
mHead = NewPage();
if (!mHead) {
rv = false;
} else {
mTail = mHead;
mOffsetHead = 0;
mOffsetTail = 0;
}
} else if (mOffsetTail == EVENTS_PER_PAGE) {
Page *page = NewPage();
if (!page) {
rv = false;
} else {
mTail->mNext = page;
mTail = page;
mOffsetTail = 0;
}
}
if (rv) {
event.swap(mTail->mEvents[mOffsetTail]);
++mOffsetTail;
LOG(("EVENTQ(%p): notify\n", this));
mon.NotifyAll();
if (ChaosMode::isActive()) {
// With probability 0.5, yield so other threads have a chance to
// dispatch events to this queue first.
if (ChaosMode::randomUint32LessThan(2)) {
PR_Sleep(PR_INTERVAL_NO_WAIT);
}
}
return rv;
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (!mHead) {
mHead = NewPage();
MOZ_ASSERT(mHead);
mTail = mHead;
mOffsetHead = 0;
mOffsetTail = 0;
} else if (mOffsetTail == EVENTS_PER_PAGE) {
Page *page = NewPage();
MOZ_ASSERT(page);
mTail->mNext = page;
mTail = page;
mOffsetTail = 0;
}
event.swap(mTail->mEvents[mOffsetTail]);
++mOffsetTail;
LOG(("EVENTQ(%p): notify\n", this));
mon.NotifyAll();
}

Просмотреть файл

@ -20,11 +20,10 @@ public:
nsEventQueue();
~nsEventQueue();
// This method adds a new event to the pending event queue. The event object
// is AddRef'd if this method succeeds. This method returns true if the
// event was stored in the event queue, and it returns false if it could
// not allocate sufficient memory.
bool PutEvent(nsIRunnable *event);
// This method adds a new event to the pending event queue. The queue holds
// a strong reference to the event after this method returns. This method
// cannot fail.
void PutEvent(nsIRunnable *event);
// This method gets an event from the event queue. If mayWait is true, then
// the method will block the calling thread until an event is available. If
@ -44,11 +43,6 @@ public:
return GetEvent(false, runnable);
}
// This method waits for and returns the next pending event.
bool WaitPendingEvent(nsIRunnable **runnable) {
return GetEvent(true, runnable);
}
// Expose the event queue's monitor for "power users"
ReentrantMonitor& GetReentrantMonitor() {
return mReentrantMonitor;
@ -73,7 +67,7 @@ private:
"sizeof(Page) should be a power of two to avoid heap slop.");
static Page *NewPage() {
return static_cast<Page *>(calloc(1, sizeof(Page)));
return static_cast<Page *>(moz_xcalloc(1, sizeof(Page)));
}
static void FreePage(Page *p) {

Просмотреть файл

@ -432,8 +432,7 @@ nsThread::PutEvent(nsIRunnable *event, nsNestedEventTarget *target)
NS_WARNING("An event was posted to a thread that will never run it (rejected)");
return NS_ERROR_UNEXPECTED;
}
if (!queue->PutEvent(event))
return NS_ERROR_OUT_OF_MEMORY;
queue->PutEvent(event);
}
nsCOMPtr<nsIThreadObserver> obs = GetObserver();

Просмотреть файл

@ -97,8 +97,8 @@ protected:
return mQueue.GetEvent(mayWait, event);
}
bool PutEvent(nsIRunnable *event) {
return mQueue.PutEvent(event);
void PutEvent(nsIRunnable *event) {
mQueue.PutEvent(event);
}
bool HasPendingEvent() {