/*
 * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
 * Copyright (C) 2005 - Javolution (http://javolution.org/)
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software is
 * freely granted, provided that this notice is preserved.
 */
package javolution37.javolution.realtime;

import javax.realtime.MemoryArea;

import javolution37.javolution.lang.Reflection;
import javolution37.javolution.util.FastMap;
import javolution37.javolution.xml.XmlElement;
import javolution37.javolution.xml.XmlException;
import javolution37.javolution.xml.XmlFormat;

/**
 * 

This class represents a pool context; it is used to recycle objects * transparently, reduce memory allocation and avoid garbage collection.

* *

Threads executing in a pool context may allocate objects from * the context's pools (also called "stack") through an * {@link ObjectFactory}. Allocated objects are recycled automatically * upon {@link PoolContext#exit exit}. This recycling is almost * instantaneous and has no impact on performance.

* *

Objects allocated within a pool context should not be directly * referenced outside of the context unless they are * {@link RealtimeObject#export exported} (e.g. result being returned) * or {@link RealtimeObject#preserve preserved} (e.g. shared static * instance). If this simple rule is followed, then pool context are * completely safe. In fact, pool contexts promote the use of immutable * objects (as their allocation cost is then negligible with no adverse * effect on garbarge collection) and often lead to safer, faster and * more robust applications.

* *

Finally, the framework guarantees that all pool objects belongs to * the same memory area (the memory area where the pool context resides). * In other words, pool contexts allocated in ImmortalMemory can safely * be used by NoHeapRealtimeThread executing in * ScopedMemory.

* * @author Jean-Marie Dautelle * @version 3.7, January 1, 2006 */ public class PoolContext extends Context { /** * Holds the XML representation for pool contexts. It holds the sizes of * the pool being used in order to repopulate these pools during * deserialization. */ protected static final XmlFormat XML = new XmlFormat("javolution37.javolution.realtime.PoolContext") { public void format(Object obj, XmlElement xml) { PoolContext ctx = (PoolContext) obj; FastMap pools = FastMap.newInstance(); for (int i = ObjectFactory.Count; --i >= 0;) { int size = ctx._pools[i].size(); if (size > 0) { pools.put(ObjectFactory.INSTANCES[i].getClass(), new Integer(size)); } } xml.add(pools); } public Object parse(XmlElement xml) { PoolContext ctx = (PoolContext) xml.object(); FastMap pools = (FastMap) xml.getNext(); for (FastMap.Entry e=pools.head(), end = pools.tail(); (e=(FastMap.Entry)e.getNext())!= end;) { Class factoryClass = (Class) e.getKey(); int size = ((Integer)e.getValue()).intValue(); ObjectFactory factory = ObjectFactory.getInstance(factoryClass); if (factory == null) throw new XmlException("Factory for class " + factoryClass + " not found"); ObjectPool pool = factory.newPool(); while (pool.size() < size) { pool.next(); } pool.recycleAll(); ctx._pools[factory._index] = pool; } return ctx; } }; /** * Holds the class object (cannot use .class with j2me). */ private static final Class CLASS = Reflection .getClass("javolution37.javolution.realtime.PoolContext"); /** * Holds the pools for this context. */ final ObjectPool[] _pools = new ObjectPool[ObjectFactory.MAX]; /** * Holds the pools in use. */ private final ObjectPool[] _inUsePools = new ObjectPool[ObjectFactory.MAX]; /** * Holds the number of pools used. */ private int _inUsePoolsLength; /** * Default constructor. */ public PoolContext() { for (int i = _pools.length; i > 0;) { _pools[--i] = ObjectPool.NULL; } } /** * Returns the current pool context or null if the current * thread does not execute within a pool context. * * @return the current pool context. */ public static PoolContext current() { return Context.poolContext(Thread.currentThread()); } /** * Enters a {@link PoolContext} allocated in the same memory area * as the memory area of the current context. */ public static void enter() { Context.enter(PoolContext.CLASS); } /** * Exits the current {@link PoolContext}. * * @throws java.lang.IllegalStateException if the current context * is not an instance of PoolContext. */ public static void exit() { Context.exit(PoolContext.CLASS); } /** * Moves all objects belonging to this pool context to the heap. */ public void clear() { super.clear(); for (int i = ObjectFactory.Count; i > 0;) { ObjectPool pool = _pools[--i]; if (pool != ObjectPool.NULL) { pool.clearAll(); } } _inUsePoolsLength = 0; } // Implements Context abstract method. protected void enterAction() { inheritedPoolContext = this; // Overrides inherited. PoolContext outer = getOuter().inheritedPoolContext; if (outer != null) { outer.setInUsePoolsLocal(false); } } // Implements Context abstract method. protected void exitAction() { recyclePools(); PoolContext outer = getOuter().inheritedPoolContext; if (outer != null) { outer.setInUsePoolsLocal(true); } } /** * Sets the pool currently being used as local or non-local. * * @param areLocal true if this context is the current * pool context; false otherwise. */ void setInUsePoolsLocal(boolean areLocal) { Thread user = areLocal ? getOwner() : null; for (int i = _inUsePoolsLength; i > 0;) { _inUsePools[--i].user = user; } } /** * Returns the pool from the specified factory and marks it as local. * * @param index the factory index for the pool to return. * @return the corresponding pool marked as local. */ ObjectPool getLocalPool(int index) { ObjectPool pool = _pools[index]; return (pool.user != null) ? pool : getLocalPool2(index); } private ObjectPool getLocalPool2(int index) { ObjectPool pool = getPool(index); pool.user = getOwner(); return pool; } /** * Returns the pool from the specified factory in this context. * The pool returned is marked "in use" and its outer is set. * * @param index the factory index of the pool to return. * @return the corresponding pool. */ private ObjectPool getPool(final int index) { ObjectPool pool = _pools[index]; if (pool == ObjectPool.NULL) { // Creates pool. MemoryArea.getMemoryArea(this).executeInArea(new Runnable() { public void run() { _pools[index] = ObjectFactory.INSTANCES[index].newPool(); }}); } pool = _pools[index]; if (!pool.inUse) { // Marks it used and set its outer. pool.inUse = true; _inUsePools[_inUsePoolsLength++] = pool; PoolContext outerPoolContext = this.getOuter().inheritedPoolContext; if (outerPoolContext != null) { synchronized (outerPoolContext) { // Not local. pool.outer = outerPoolContext.getPool(index); } } else { pool.outer = null; } } return pool; } /** * Recycles pools. */ void recyclePools() { // Recycles pools and reset pools used. for (int i = _inUsePoolsLength; i > 0;) { ObjectPool pool = _inUsePools[--i]; pool.recycleAll(); pool.user = null; pool.inUse = false; } _inUsePoolsLength = 0; } }

Ads help maintain this website.