am a0cd0584: Merge "Preemptive anti-deadlock device" into jb-mr1-dev

* commit 'a0cd05842e26e802121823a25274190f65a2450f':
  Preemptive anti-deadlock device
This commit is contained in:
Jean Chalard 2012-08-14 01:11:22 -07:00 committed by Android Git Automerger
commit 4de3bc305b
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)) { if (shouldFilterOut(inText, mScript)) {
DictAndProximity dictInfo = null; DictAndProximity dictInfo = null;
try { try {
dictInfo = mDictionaryPool.takeOrGetNull(); dictInfo = mDictionaryPool.pollWithDefaultTimeout();
if (null == dictInfo) { if (null == dictInfo) {
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); return AndroidSpellCheckerService.getNotInDictEmptySuggestions();
} }
@ -236,7 +236,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
boolean isInDict = true; boolean isInDict = true;
DictAndProximity dictInfo = null; DictAndProximity dictInfo = null;
try { try {
dictInfo = mDictionaryPool.takeOrGetNull(); dictInfo = mDictionaryPool.pollWithDefaultTimeout();
if (null == dictInfo) { if (null == dictInfo) {
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(); return AndroidSpellCheckerService.getNotInDictEmptySuggestions();
} }

View file

@ -16,14 +16,24 @@
package com.android.inputmethod.latin.spellcheck; package com.android.inputmethod.latin.spellcheck;
import android.util.Log;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/** /**
* A blocking queue that creates dictionaries up to a certain limit as necessary. * 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") @SuppressWarnings("serial")
public class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> { 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 AndroidSpellCheckerService mService;
private final int mMaxSize; private final int mMaxSize;
private final Locale mLocale; private final Locale mLocale;
@ -41,13 +51,23 @@ public class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> {
} }
@Override @Override
public DictAndProximity take() throws InterruptedException { public DictAndProximity poll(final long timeout, final TimeUnit unit)
throws InterruptedException {
final DictAndProximity dict = poll(); final DictAndProximity dict = poll();
if (null != dict) return dict; if (null != dict) return dict;
synchronized(this) { synchronized(this) {
if (mSize >= mMaxSize) { if (mSize >= mMaxSize) {
// Our pool is already full. Wait until some dictionary is ready. // Our pool is already full. Wait until some dictionary is ready, or TIMEOUT
return super.take(); // 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 { } else {
++mSize; ++mSize;
return mService.createDictAndProximity(mLocale); return mService.createDictAndProximity(mLocale);
@ -56,9 +76,9 @@ public class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> {
} }
// Convenience method // Convenience method
public DictAndProximity takeOrGetNull() { public DictAndProximity pollWithDefaultTimeout() {
try { try {
return take(); return poll(TIMEOUT, TimeUnit.SECONDS);
} catch (InterruptedException e) { } catch (InterruptedException e) {
return null; return null;
} }