diff options
author | Roman Kennke <roman@kennke.org> | 2006-11-20 10:51:37 +0000 |
---|---|---|
committer | Roman Kennke <roman@kennke.org> | 2006-11-20 10:51:37 +0000 |
commit | 306331a3743616637d2c42b7a830a9853f2c1488 (patch) | |
tree | 20d4258399cb5780177367b725abad1f686cbe57 /javax | |
parent | b4a86c0172ed4e2a8a49cb7d1d9f33c1fbae2c50 (diff) | |
download | classpath-306331a3743616637d2c42b7a830a9853f2c1488.tar.gz |
2006-11-20 Roman Kennke <kennke@aicas.com>
* javax/swing/text/AbstractDocument.java
(DefaultDocumentEvent.changes): Changed to be a HashMap.
(DefaultDocumentEvent.modified): Made private.
(DefaultDocumentEvent.THRESHOLD): New constant field.
(DefaultDocumentEvent.DefaultDocumentEvent): Don't initialize
changes table.
(DefaultDocumentEvent.addEdit): Switch to hashmap only when
exceeding threshold.
(DefaultDocumentEvent.getChange): Use iterative approach
when we have no hashmap yet.
(documentCV): Removed.
(numWriters): Renamed from numWritersWaiting.
(createPosition): Reformat.
(getCurrentWriter): Synchronized.
(readLock): Implement more straightforward.
(readUnlock): Implement more straightforward.
(writeLock): Implement more straightforward.
(writeUnlock): Implement more straightforward.
(remove): Write-lock here.
(removeImpl): Don't write-lock here.
Diffstat (limited to 'javax')
-rw-r--r-- | javax/swing/text/AbstractDocument.java | 203 |
1 files changed, 116 insertions, 87 deletions
diff --git a/javax/swing/text/AbstractDocument.java b/javax/swing/text/AbstractDocument.java index 089785aa8..1e12d5c11 100644 --- a/javax/swing/text/AbstractDocument.java +++ b/javax/swing/text/AbstractDocument.java @@ -46,6 +46,7 @@ import java.util.ArrayList; import java.util.Dictionary; import java.util.Enumeration; import java.util.EventListener; +import java.util.HashMap; import java.util.Hashtable; import java.util.Vector; @@ -158,14 +159,10 @@ public abstract class AbstractDocument implements Document, Serializable private int numReaders = 0; /** - * Tells if there are one or more writers waiting. + * The number of current writers. If this is > 1 then the same thread entered + * the write lock more than once. */ - private int numWritersWaiting = 0; - - /** - * A condition variable that readers and writers wait on. - */ - private Object documentCV = new Object(); + private int numWriters = 0; /** An instance of a DocumentFilter.FilterBypass which allows calling * the insert, remove and replace method without checking for an installed @@ -315,7 +312,8 @@ public abstract class AbstractDocument implements Document, Serializable * @throws BadLocationException if <code>offset</code> is not a valid * location in the documents content model */ - public Position createPosition(final int offset) throws BadLocationException + public synchronized Position createPosition(final int offset) + throws BadLocationException { return content.createPosition(offset); } @@ -432,7 +430,7 @@ public abstract class AbstractDocument implements Document, Serializable * @return the thread that currently modifies this <code>Document</code> * if there is one, otherwise <code>null</code> */ - protected final Thread getCurrentWriter() + protected final synchronized Thread getCurrentWriter() { return currentWriter; } @@ -1022,25 +1020,21 @@ public abstract class AbstractDocument implements Document, Serializable * Blocks until a read lock can be obtained. Must block if there is * currently a writer modifying the <code>Document</code>. */ - public final void readLock() + public final synchronized void readLock() { - if (currentWriter != null && currentWriter.equals(Thread.currentThread())) - return; - synchronized (documentCV) + try { - while (currentWriter != null || numWritersWaiting > 0) + while (currentWriter != null) { - - try - { - documentCV.wait(); - } - catch (InterruptedException ie) - { - throw new Error("interrupted trying to get a readLock"); - } + if (currentWriter == Thread.currentThread()) + return; + wait(); } - numReaders++; + numReaders++; + } + catch (InterruptedException ex) + { + throw new Error("Interrupted during grab read lock"); } } @@ -1048,7 +1042,7 @@ public abstract class AbstractDocument implements Document, Serializable * Releases the read lock. If this was the only reader on this * <code>Document</code>, writing may begin now. */ - public final void readUnlock() + public final synchronized void readUnlock() { // Note we could have a problem here if readUnlock was called without a // prior call to readLock but the specs simply warn users to ensure that @@ -1075,21 +1069,14 @@ public abstract class AbstractDocument implements Document, Serializable // FIXME: the reference implementation throws a // javax.swing.text.StateInvariantError here - if (numReaders == 0) + if (numReaders <= 0) throw new IllegalStateException("document lock failure"); - synchronized (documentCV) - { - // If currentWriter is not null, the application code probably had a - // writeLock and then tried to obtain a readLock, in which case - // numReaders wasn't incremented - if (currentWriter == null) - { - numReaders --; - if (numReaders == 0 && numWritersWaiting != 0) - documentCV.notify(); - } - } + // If currentWriter is not null, the application code probably had a + // writeLock and then tried to obtain a readLock, in which case + // numReaders wasn't incremented + numReaders--; + notify(); } /** @@ -1113,12 +1100,21 @@ public abstract class AbstractDocument implements Document, Serializable */ public void remove(int offset, int length) throws BadLocationException { - if (documentFilter == null) - removeImpl(offset, length); - else - documentFilter.remove(getBypass(), offset, length); + writeLock(); + try + { + DocumentFilter f = getDocumentFilter(); + if (f == null) + removeImpl(offset, length); + else + f.remove(getBypass(), offset, length); + } + finally + { + writeUnlock(); + } } - + void removeImpl(int offset, int length) throws BadLocationException { // The RI silently ignores all requests that have a negative length. @@ -1135,21 +1131,12 @@ public abstract class AbstractDocument implements Document, Serializable new DefaultDocumentEvent(offset, length, DocumentEvent.EventType.REMOVE); - try - { - writeLock(); - - // The order of the operations below is critical! - removeUpdate(event); - UndoableEdit temp = content.remove(offset, length); - - postRemoveUpdate(event); - fireRemoveUpdate(event); - } - finally - { - writeUnlock(); - } + // The order of the operations below is critical! + removeUpdate(event); + UndoableEdit temp = content.remove(offset, length); + + postRemoveUpdate(event); + fireRemoveUpdate(event); } } @@ -1343,26 +1330,25 @@ public abstract class AbstractDocument implements Document, Serializable * Blocks until a write lock can be obtained. Must wait if there are * readers currently reading or another thread is currently writing. */ - protected final void writeLock() + protected synchronized final void writeLock() { - if (currentWriter != null && currentWriter.equals(Thread.currentThread())) - return; - synchronized (documentCV) + try { - numWritersWaiting++; - while (numReaders > 0) + while (numReaders > 0 || currentWriter != null) { - try + if (Thread.currentThread() == currentWriter) { - documentCV.wait(); - } - catch (InterruptedException ie) - { - throw new Error("interruped while trying to obtain write lock"); + numWriters++; + return; } + wait(); } - numWritersWaiting --; currentWriter = Thread.currentThread(); + numWriters = 1; + } + catch (InterruptedException ex) + { + throw new Error("Interupted during grab write lock"); } } @@ -1370,16 +1356,14 @@ public abstract class AbstractDocument implements Document, Serializable * Releases the write lock. This allows waiting readers or writers to * obtain the lock. */ - protected final void writeUnlock() + protected final synchronized void writeUnlock() { - synchronized (documentCV) - { - if (Thread.currentThread().equals(currentWriter)) - { - currentWriter = null; - documentCV.notifyAll(); - } - } + if (--numWriters <= 0) + { + numWriters = 0; + currentWriter = null; + notifyAll(); + } } /** @@ -2384,6 +2368,11 @@ public abstract class AbstractDocument implements Document, Serializable /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = 5230037221564563284L; + /** + * The threshold that indicates when we switch to using a Hashtable. + */ + private static final int THRESHOLD = 10; + /** The starting offset of the change. */ private int offset; @@ -2394,15 +2383,18 @@ public abstract class AbstractDocument implements Document, Serializable private DocumentEvent.EventType type; /** - * Maps <code>Element</code> to their change records. + * Maps <code>Element</code> to their change records. This is only + * used when the changes array gets too big. We can use an + * (unsync'ed) HashMap here, since changes to this are (should) always + * be performed inside a write lock. */ - Hashtable changes; + private HashMap changes; /** * Indicates if this event has been modified or not. This is used to * determine if this event is thrown. */ - boolean modified; + private boolean modified; /** * Creates a new <code>DefaultDocumentEvent</code>. @@ -2417,7 +2409,6 @@ public abstract class AbstractDocument implements Document, Serializable this.offset = offset; this.length = length; this.type = type; - changes = new Hashtable(); modified = false; } @@ -2431,9 +2422,27 @@ public abstract class AbstractDocument implements Document, Serializable public boolean addEdit(UndoableEdit edit) { // XXX - Fully qualify ElementChange to work around gcj bug #2499. - if (edit instanceof DocumentEvent.ElementChange) + + // Start using Hashtable when we pass a certain threshold. This + // gives a good memory/performance compromise. + if (changes == null && edits.size() > THRESHOLD) + { + changes = new HashMap(); + int count = edits.size(); + for (int i = 0; i < count; i++) + { + Object o = edits.elementAt(i); + if (o instanceof DocumentEvent.ElementChange) + { + DocumentEvent.ElementChange ec = + (DocumentEvent.ElementChange) o; + changes.put(ec.getElement(), ec); + } + } + } + + if (changes != null && edit instanceof DocumentEvent.ElementChange) { - modified = true; DocumentEvent.ElementChange elEdit = (DocumentEvent.ElementChange) edit; changes.put(elEdit.getElement(), elEdit); @@ -2492,7 +2501,27 @@ public abstract class AbstractDocument implements Document, Serializable public DocumentEvent.ElementChange getChange(Element elem) { // XXX - Fully qualify ElementChange to work around gcj bug #2499. - return (DocumentEvent.ElementChange) changes.get(elem); + DocumentEvent.ElementChange change = null; + if (changes != null) + { + change = (DocumentEvent.ElementChange) changes.get(elem); + } + else + { + int count = edits.size(); + for (int i = 0; i < count && change == null; i++) + { + Object o = edits.get(i); + if (o instanceof DocumentEvent.ElementChange) + { + DocumentEvent.ElementChange ec = + (DocumentEvent.ElementChange) o; + if (elem.equals(ec.getElement())) + change = ec; + } + } + } + return change; } /** |