| /* ThreadLocal -- a variable with a unique value per thread |
| Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| package java.lang; |
| |
| import java.lang.ref.WeakReference; |
| |
| /** |
| * ThreadLocalMap is the basic storage for the map of ThreadLocal instance |
| * to a thread's current value. |
| * |
| * Some applications really work out ThreadLocals, leading to this |
| * optimized implementation. |
| */ |
| final class ThreadLocalMap |
| { |
| /** |
| * The log (base 2) of the initial size of the map |
| */ |
| private static final int LOG_INITIAL_SIZE = 3; |
| |
| /** |
| * The maximum occupancy rate (after which we grow) |
| */ |
| private static final float MAX_OCCUPANCY = 0.7f; |
| |
| /** |
| * The target occupancy rate. |
| */ |
| private static final float TARGET_OCCUPANCY = 0.5f; |
| |
| /** |
| * The deleted entry sentinel value. |
| */ |
| private static final Entry deletedEntry = new Entry(null); |
| |
| /** |
| * Constructor |
| */ |
| ThreadLocalMap() |
| { |
| /* Dummy value to ensure fast path can be optimized */ |
| entries = new Entry[1]; |
| hashMask = 0; |
| count = 0; |
| } |
| |
| /** |
| * The map entries |
| */ |
| private Entry[] entries; |
| |
| /** |
| * Used for start index computation |
| */ |
| private int hashMask; |
| |
| /** |
| * The number of entries currently in the map |
| */ |
| private int count; |
| |
| /** |
| * Create or grow the table to the specified size. The size must be a |
| * power of two for the efficient mask/hash computation. |
| * |
| * @param newSize The new table size. |
| */ |
| private void newEntryArray(int newSize) |
| { |
| int mask = newSize - 1; |
| Entry[] oldEntries = this.entries; |
| this.entries = new Entry[newSize]; |
| this.hashMask = mask; |
| |
| /* Copy old entries to new table */ |
| count = 0; |
| if (oldEntries != null) |
| { |
| for(Entry e: oldEntries) |
| { |
| if (e != null) |
| { |
| ThreadLocal<?> key = e.get(); |
| if (e != deletedEntry && key != null) |
| { |
| for(int i = key.fastHash & mask;; i = (i + 1) & mask) |
| { |
| if (entries[i] == null) |
| { |
| entries[i] = e; |
| count++; |
| break; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * We have run out of space in our locals. We use this as the |
| * trigger to attempt to find unused slots as ThreadLocals have |
| * died. If we recover any slots this way then we do not grow. |
| */ |
| private void overflow() |
| { |
| /* First 'actual' use */ |
| if (entries.length == 1) |
| { |
| newEntryArray(1 << LOG_INITIAL_SIZE); |
| return; |
| } |
| |
| /* Attempt to recover unused slots */ |
| int deleted = 0; |
| for(int i=0; i < entries.length; i++) |
| { |
| Entry e = entries[i]; |
| if (e != null) |
| { |
| if (e == deletedEntry) |
| { |
| deleted++; |
| } |
| else if (e.get() == null) |
| { |
| entries[i] = deletedEntry; |
| deleted++; |
| } |
| } |
| } |
| |
| if ((count-deleted) <= (TARGET_OCCUPANCY * entries.length)) |
| { |
| /* We currently rehash by simple reallocating into a same-sized table. |
| * An alternative would be to implement a clever hashing algorithm but |
| * as this happens infrequently this seems preferred */ |
| newEntryArray(entries.length); |
| return; |
| } |
| |
| /* Double the size */ |
| newEntryArray(entries.length << 1); |
| } |
| |
| /** |
| * This is the class that is used to refer to a thread local weakly. |
| * |
| * As we want to minimize indirections we extend WeakReference. |
| */ |
| static final class Entry extends WeakReference<ThreadLocal<?>> { |
| /** |
| * The value stored in this slot |
| */ |
| Object value; |
| |
| /** |
| * Constructor |
| */ |
| Entry(ThreadLocal<?> threadLocal) { |
| super(threadLocal); |
| } |
| } |
| |
| /** |
| * Gets the value associated with the ThreadLocal object for the currently |
| * executing Thread. If this is the first time the current thread has called |
| * get(), and it has not already called set(), the sentinel value is returned. |
| * |
| * @return the value of the variable in this thread, or sentinel if not present. |
| */ |
| public Object get(ThreadLocal<?> key) |
| { |
| int mask = this.hashMask; |
| for(int i = key.fastHash & mask;; i = (i + 1) & mask) { |
| Entry e = entries[i]; |
| if (e != null) { |
| if (e.get() == key) { |
| return e.value; |
| } |
| } else { |
| return ThreadLocal.sentinel; |
| } |
| } |
| } |
| |
| /** |
| * Sets the value associated with the ThreadLocal object for the currently |
| * executing Thread. This overrides any existing value associated with the |
| * current Thread and prevents <code>initialValue()</code> from being |
| * called if this is the first access to this ThreadLocal in this Thread. |
| * |
| * @param value the value to set this thread's view of the variable to |
| */ |
| public void set(ThreadLocal<?> key, Object value) |
| { |
| /* Overflow ? */ |
| if ((count+1) >= (MAX_OCCUPANCY * entries.length)) |
| { |
| overflow(); |
| } |
| |
| /* Set the entry */ |
| int mask = this.hashMask; |
| for(int i = key.fastHash & mask;; i = (i + 1) & mask) |
| { |
| Entry e = entries[i]; |
| if (e == null || e == deletedEntry) |
| { |
| /* Create entry */ |
| if (e == null) count++; |
| entries[i] = e = new Entry(key); |
| e.value = value; |
| return; |
| } |
| else |
| { |
| ThreadLocal<?> entryKey = e.get(); |
| if (entryKey == null) |
| { |
| entries[i] = deletedEntry; |
| } |
| else if (entryKey == key) |
| { |
| /* Update entry */ |
| e.value = value; |
| return; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Removes the value associated with the ThreadLocal object for the |
| * currently executing Thread. |
| * @since 1.5 |
| */ |
| public void remove(ThreadLocal<?> key) |
| { |
| int mask = this.hashMask; |
| for(int i = key.fastHash & mask;; i = (i + 1) & mask) |
| { |
| Entry e = entries[i]; |
| if (e != null) |
| { |
| ThreadLocal<?> entryKey = e.get(); |
| if (entryKey != key) |
| { |
| if (entryKey == null) { |
| entries[i] = deletedEntry; |
| } |
| continue; |
| } |
| else |
| { |
| /* Remove from the table */ |
| entries[i] = deletedEntry; |
| } |
| } |
| return; |
| } |
| } |
| |
| /** |
| * Clear out the map. Done once during thread death. |
| */ |
| void clear() { |
| entries = null; |
| } |
| |
| /** |
| * Inherit all the InheritableThreadLocal instances from the given parent. |
| * |
| * @param parentMap The map to inherit from. |
| */ |
| public void inherit(ThreadLocalMap parentMap) { |
| for(Entry e: parentMap.entries) |
| { |
| if (e != null && e != deletedEntry) |
| { |
| ThreadLocal<?> key = e.get(); |
| if (key instanceof InheritableThreadLocal) |
| { |
| set(key, ((InheritableThreadLocal)key).childValue(e.value)); |
| } |
| } |
| } |
| } |
| } |