Preemptive anti-deadlock device

We don't know of any actual bug in the implementation of the
pool that may result in a deadlock, but this still implements
a means out of a deadlock if one ever arises anyway. It's
meant to improve the resilience of the spell checker.

Bug: 5441027
Change-Id: I689491090792dbb89110ee56631965c5bb2dc712
main
Jean Chalard 2012-08-14 15:11:53 +09:00
parent 5d6b8e1818
commit e30c05800f
2 changed files with 27 additions and 7 deletions

View File

@ -193,7 +193,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
if (shouldFilterOut(inText, mScript)) {
DictAndProximity dictInfo = null;
try {
dictInfo = mDictionaryPool.takeOrGetNull();
dictInfo = mDictionaryPool.pollWithDefaultTimeout();
if (null == dictInfo) {
return AndroidSpellCheckerService.getNotInDictEmptySuggestions();
}
@ -236,7 +236,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
boolean isInDict = true;
DictAndProximity dictInfo = null;
try {
dictInfo = mDictionaryPool.takeOrGetNull();
dictInfo = mDictionaryPool.pollWithDefaultTimeout();
if (null == dictInfo) {
return AndroidSpellCheckerService.getNotInDictEmptySuggestions();
}

View File

@ -16,14 +16,24 @@
package com.android.inputmethod.latin.spellcheck;
import android.util.Log;
import java.util.Locale;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* A blocking queue that creates dictionaries up to a certain limit as necessary.
* As a deadlock-detecting device, if waiting for more than TIMEOUT = 3 seconds, we
* will clear the queue and generate its contents again. This is transparent for
* the client code, but may help with sloppy clients.
*/
@SuppressWarnings("serial")
public class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> {
private final static String TAG = DictionaryPool.class.getSimpleName();
// How many seconds we wait for a dictionary to become available. Past this delay, we give up in
// fear some bug caused a deadlock, and reset the whole pool.
private final static int TIMEOUT = 3;
private final AndroidSpellCheckerService mService;
private final int mMaxSize;
private final Locale mLocale;
@ -41,13 +51,23 @@ public class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> {
}
@Override
public DictAndProximity take() throws InterruptedException {
public DictAndProximity poll(final long timeout, final TimeUnit unit)
throws InterruptedException {
final DictAndProximity dict = poll();
if (null != dict) return dict;
synchronized(this) {
if (mSize >= mMaxSize) {
// Our pool is already full. Wait until some dictionary is ready.
return super.take();
// Our pool is already full. Wait until some dictionary is ready, or TIMEOUT
// expires to avoid a deadlock.
final DictAndProximity result = super.poll(timeout, unit);
if (null == result) {
Log.e(TAG, "Deadlock detected ! Resetting dictionary pool");
clear();
mSize = 1;
return mService.createDictAndProximity(mLocale);
} else {
return result;
}
} else {
++mSize;
return mService.createDictAndProximity(mLocale);
@ -56,9 +76,9 @@ public class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> {
}
// Convenience method
public DictAndProximity takeOrGetNull() {
public DictAndProximity pollWithDefaultTimeout() {
try {
return take();
return poll(TIMEOUT, TimeUnit.SECONDS);
} catch (InterruptedException e) {
return null;
}