001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2007 - Javolution (http://javolution.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javolution.context;
010:
011: import j2me.lang.ThreadLocal;
012: import j2mex.realtime.MemoryArea;
013: import javolution.util.FastMap;
014: import javolution.util.FastTable;
015:
016: /**
017: * <p> This class represents an allocator from immortal memory (RTSJ).</p>
018: *
019: * <p> It is typically used to allocate (and recycle) from immortal memory
020: * allowing dynamically created static instances to be accessible by
021: * <code>NoHeapRealtimeThread</code>:[code]
022: * public synchronized Text intern() {
023: * if (!INTERN_INSTANCES.containsKey(this)) {
024: * ImmortalContext.enter();
025: * try { // Forces interned instance to be in immortal memory.
026: * Text txt = this.copy(); // In ImmortalMemory.
027: * INTERN_INSTANCES.put(txt, txt);
028: * } finally {
029: * ImmortalContext.exit();
030: * }
031: * }
032: * return (Text) INTERN_INSTANCES.get(str);
033: * }[/code]</p>
034: * <p> Because class initialization may occur while running in a non-heap
035: * context (e.g. {@link StackContext}), it is recommended to force
036: * factory produced constants to immortal memory:[code]
037: * public class Rational {
038: * public static final Rational ZERO;
039: * public static final Rational ONE;
040: * ...
041: * static { // Forces constants to ImmortalMemory.
042: * ImmortalContext.enter();
043: * try {
044: * ZERO = Rational.valueOf(0, 1); // Factory produced.
045: * ONE = Rational.valueOf(1, 1); // Factory produced.
046: * } finally {
047: * ImmortalContext.exit();
048: * }
049: * }
050: * }[/code]</p>
051: *
052: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
053: * @version 5.2, August 19, 2007
054: */
055: public final class ImmortalContext extends AllocatorContext {
056:
057: /**
058: * Holds the class.
059: */
060: private static final Class CLASS = new ImmortalContext().getClass();
061:
062: /**
063: * Holds the factory to allocator mapping (per thread).
064: */
065: private static final ThreadLocal FACTORY_TO_ALLOCATOR = new ThreadLocal() {
066: protected Object initialValue() {
067: return new FastMap();
068: }
069: };
070:
071: /**
072: * Holds the allocators which have been activated (per thread).
073: */
074: private static final ThreadLocal ACTIVE_ALLOCATORS = new ThreadLocal() {
075: protected Object initialValue() {
076: return new FastTable();
077: }
078: };
079:
080: /**
081: * Enters an immortal memory context.
082: *
083: * @return the immortal memory context entered.
084: */
085: public static ImmortalContext enter() {
086: return (ImmortalContext) Context.enter(ImmortalContext.CLASS);
087: }
088:
089: /**
090: * Exits the current immortal memory context.
091: *
092: * @return the immortal context being exited.
093: * @throws ClassCastException if the context is not an immortal context.
094: */
095: public static/*ImmortalContext*/Context exit() {
096: return (ImmortalContext) Context.exit();
097: }
098:
099: /**
100: * Default constructor (private, instances are factory produced).
101: */
102: private ImmortalContext() {
103: }
104:
105: // Overrides.
106: protected void deactivate() {
107: FastTable allocators = (FastTable) ACTIVE_ALLOCATORS.get();
108: for (int i = 0, n = allocators.size(); i < n;) {
109: ((Allocator) allocators.get(i++)).user = null;
110: }
111: allocators.clear();
112: }
113:
114: // Overrides.
115: protected Allocator getAllocator(ObjectFactory factory) {
116: final FastMap factoryToAllocator = (FastMap) FACTORY_TO_ALLOCATOR
117: .get();
118: ImmortalAllocator allocator = (ImmortalAllocator) factoryToAllocator
119: .get(factory);
120: if (allocator == null) {
121: allocator = new ImmortalAllocator(factory);
122: factoryToAllocator.put(factory, allocator);
123: }
124: if (allocator.user == null) { // Activate.
125: allocator.user = Thread.currentThread();
126: FastTable activeAllocators = (FastTable) ACTIVE_ALLOCATORS
127: .get();
128: activeAllocators.add(allocator);
129: }
130: return allocator;
131: }
132:
133: // Overrides.
134: protected void enterAction() {
135: getOuter().getAllocatorContext().deactivate();
136: }
137:
138: // Overrides.
139: protected void exitAction() {
140: this .deactivate();
141: }
142:
143: // Holds immortal allocator implementation.
144: private static final class ImmortalAllocator extends Allocator {
145:
146: private static final MemoryArea IMMORTAL = MemoryArea
147: .getMemoryArea("");
148:
149: private final ObjectFactory _factory;
150:
151: private Object _allocated;
152:
153: public ImmortalAllocator(ObjectFactory factory) {
154: _factory = factory;
155: }
156:
157: private final Runnable _allocate = new Runnable() {
158: public void run() {
159: _allocated = _factory.create();
160: }
161: };
162:
163: private final Runnable _resize = new Runnable() {
164: public void run() {
165: resize();
166: }
167: };
168:
169: protected Object allocate() {
170: IMMORTAL.executeInArea(_allocate);
171: return _allocated;
172: }
173:
174: protected void recycle(Object object) {
175: if (_factory.doCleanup()) {
176: _factory.cleanup(object);
177: }
178: if (queueSize >= queue.length) {
179: IMMORTAL.executeInArea(_resize);
180: }
181: queue[queueSize++] = object;
182: }
183:
184: public String toString() {
185: return "Immortal allocator for " + _factory.getClass();
186: }
187: }
188:
189: // Allows instances to be factory produced (private constructor).
190: static {
191: ObjectFactory.setInstance(new ObjectFactory() {
192: protected Object create() {
193: return new ImmortalContext();
194: }
195: }, ImmortalContext.CLASS);
196: }
197: }
|