// ************************************************************************ // $Id: AsyncEventHandler.java 600 2005-07-22 22:01:54Z mdeters $ // ************************************************************************ // // jRate // // Copyright (C) 2001-2005 by Angelo Corsaro. // // All Rights Reserved. // // Permission to use, copy, modify, and distribute this software and // its documentation for any purpose is hereby granted without fee, // provided that the above copyright notice appear in all copies and // that both that copyright notice and this permission notice appear // in supporting documentation. I don't make any representations // about the suitability of this software for any purpose. It is // provided "as is" without express or implied warranty. // // // ************************************************************************* // // ************************************************************************* package javax.realtime; import gnu.gcj.RawData; /** * An asynchronous event handler encapsulates code that gets run at * some time after an AsyncEvent occurs. It is essentially a * java.lang.Runnable with a set of parameter objects, making it very * much like a RealtimeThread . The expectation is that there may be * thousands of events, with corresponding handlers, averaging about * one handler per event. The number of unblocked (i.e., scheduled) * handlers is expected to be relatively small.
* * It is guaranteed that multiple firings of an event handler will be * serialized. It is also guaranteed that (unless the handler * explicitly chooses otherwise) for each firing of the handler, there * will be one execution of the handleAsyncEvent() method. For * instances of AsyncEventHandler with a release parameter of type * SporadicParameters have a list of release times which correspond to * execution times of AsyncEvent.fire() . The minimum interarrival * time specified in SporadicParameters is enforced as defined * there. Unless the handler explicitly chooses otherwise there will * be one execution of the code in handleAsyncEvent() for each entry * in the list. The i th execution of handleAsyncEvent() will be * released for scheduling at the time of the i th entry in thelist. * There is no restriction on what handlers may do. They may run for a * long or short time, and they may block. (Note: blocked handlers may * hold system resources.) Normally, handlers are bound to an * execution context dynamically, when their AsyncEvent181 occurs. * This can introduce a (small) time penalty. For critical handlers * that can not afford the expense, and where this penalty is a * problem, use a BoundAsyncEventHandler. The semantics for memory * areas that were defined for realtime threads apply in the same way * to instances of AsyncEventHandler They may inherit a scope stack * when they are created, and the single parent rule applies to the * use of memory scopes for instances of AsyncEventHandler just as it * does in realtime threads. * * @author Angelo Corsaro * @author Morgan Deters * @version 1.0 */ public class AsyncEventHandler implements Schedulable { protected RawData natFireCount_; protected int executionEligibility = -1; protected SchedulingParameters scheduling; protected ReleaseParameters release; protected MemoryParameters memory; protected MemoryArea area; protected ProcessingGroupParameters group; protected boolean nonheap; protected Runnable logic; protected RealtimeThread thread; protected Scheduler scheduler; protected class HandlerLogic implements Runnable { private boolean eventNotified = false; public synchronized void waitEvent() { while(!eventNotified) { try { wait(); } catch(InterruptedException e) { e.printStackTrace(); } } eventNotified = false; } public synchronized void notifyEvent() { eventNotified = true; notify(); } public void run() { for(;;) { waitEvent(); do { handleAsyncEvent(); } while(getAndDecrementPendingFireCount() > 1); } } } protected HandlerLogic handleDispatcher = new HandlerLogic(); public AsyncEventHandler() { this(null, null, null, null, null, false, null); } public AsyncEventHandler(boolean nonheap) { this(null, null, null, null, null, nonheap, null); } public AsyncEventHandler(boolean nonheap, Runnable logic) { this(null, null, null, null, null, nonheap, logic); } public AsyncEventHandler(Runnable logic) { this(null, null, null, null, null, false, logic); } public AsyncEventHandler(SchedulingParameters scheduling, ReleaseParameters release, MemoryParameters memory, MemoryArea area, ProcessingGroupParameters group, boolean nonheap) { this(scheduling, release, memory, area, group, nonheap, null); } public AsyncEventHandler(SchedulingParameters scheduling, ReleaseParameters release, MemoryParameters memory, MemoryArea area, ProcessingGroupParameters group, Runnable logic) { this(scheduling, release, memory, area, group, false, logic); } public AsyncEventHandler(SchedulingParameters scheduling, ReleaseParameters release, MemoryParameters memory, MemoryArea area, ProcessingGroupParameters group, boolean nonheap, Runnable logic) { if(scheduling == null) { Thread t = Thread.currentThread(); if(t instanceof RealtimeThread) scheduling = (SchedulingParameters) ((RealtimeThread)t).getSchedulingParameters().clone(); else scheduling = new PriorityParameters(PriorityScheduler.NORM_PRIORITY); } if(release == null) release = new AperiodicParameters(); if(area == null) area = RealtimeThread.getCurrentMemoryArea(); if(nonheap && (RealtimeThread.getCurrentMemoryArea() instanceof HeapMemory || NoHeapRealtimeThread.heapCheck(this) || NoHeapRealtimeThread.heapCheck(scheduling) || NoHeapRealtimeThread.heapCheck(release) || NoHeapRealtimeThread.heapCheck(memory) || NoHeapRealtimeThread.heapCheck(area) || NoHeapRealtimeThread.heapCheck(group) || NoHeapRealtimeThread.heapCheck(logic))) throw new IllegalArgumentException("heap used for nonheap AEH"); this.scheduling = scheduling; this.release = release; this.memory = memory; this.area = area; this.group = group; this.nonheap = nonheap; this.logic = logic; scheduler = Scheduler.getDefaultScheduler(); init(); } /** * Atomically set to zero the number of pending executions of this * handler and returns the value from before it was cleared. This * is used in handlers that can handle multiple firings and that * want to collapse them together. The general form for using this * is: * * public void handleAsyncEvent() { * int fireCount = * getAndClearPendingFireCount(); * * } * * @return an int value representing the pending fire * count. */ protected native int getAndClearPendingFireCount(); /** * Atomically decrements the number of pending executions of this * handler (if it was non-zero) and returns the value from before * the decrement. This can be used in the * handleAsyncEvent() method in this form to handle * multiple firings: * * * public void handleAsyncEvent() { * * do { * * } while(getAndDecrementPendingFireCount()>0); * } * * * This construction is necessary only in the case where one * wishes to avoid the setup costs since the framework guarantees * that handleAsyncEvent() will be invoked the * appropriate number of times. * @return an int value representing the pending fire count. */ protected native int getAndDecrementPendingFireCount(); /** * Atomically increments the number of pending executions of this * handler and returns the value from before the increment. The * handleAsyncEvent() method does not need to do * this, since the surrounding framework guarantees that the * handler will be re-executed the appropriate number of times. It * is only of value when there is common setup code that is * expensive. * * @return an int value representing the pending fire * count. */ protected native int getAndIncrementPendingFireCount(); /** * Return the number of pending executions of this handler. * * @return an int value representing the pending fire * count. */ protected native int getPendingFireCount(); /** * If this handler was constructed using a separate Runnable logic * object, then that Runnable objects * run method is called; This method will be invoked * repeatedly while fireCount is greater than zero. */ public void handleAsyncEvent() { // spec says catch and print all throwables try { if(logic != null) logic.run(); } catch(Throwable t) { t.printStackTrace(); } } public MemoryArea getMemoryArea() { return area; } public boolean addToFeasibility() { throw new UnimplementedFeatureError(); } public boolean addIfFeasible() { throw new UnimplementedFeatureError(); } public boolean setIfFeasible(ReleaseParameters release, MemoryParameters memory) { throw new UnimplementedFeatureError(); } public boolean setIfFeasible(ReleaseParameters release, ProcessingGroupParameters group) { throw new UnimplementedFeatureError(); } public boolean setIfFeasible(SchedulingParameters scheduling, ReleaseParameters release, MemoryParameters memory) { throw new UnimplementedFeatureError(); } public boolean setIfFeasible(ReleaseParameters release, MemoryParameters memory, ProcessingGroupParameters group) { throw new UnimplementedFeatureError(); } public boolean setIfFeasible(SchedulingParameters scheduling, ReleaseParameters release, MemoryParameters memory, ProcessingGroupParameters group) { throw new UnimplementedFeatureError(); } public boolean setReleaseParametersIfFeasible(ReleaseParameters release) { throw new UnimplementedFeatureError(); } public boolean setProcessingGroupParametersIfFeasible(ProcessingGroupParameters group) { throw new UnimplementedFeatureError(); } public boolean setMemoryParametersIfFeasible(MemoryParameters memory) { throw new UnimplementedFeatureError(); } public MemoryParameters getMemoryParameters() { return memory; } public ReleaseParameters getReleaseParameters() { return release; } public Scheduler getScheduler() { throw new UnimplementedFeatureError(); } public SchedulingParameters getSchedulingParameters() { return scheduling; } public ProcessingGroupParameters getProcessingGroupParameters() { return group; } public boolean removeFromFeasibility() { throw new UnimplementedFeatureError(); } public void setMemoryParameters(MemoryParameters memory) { if(nonheap && NoHeapRealtimeThread.heapCheck(memory)) throw new IllegalArgumentException("heap params not permitted in nonheap AEH"); this.memory = memory; } public void setReleaseParameters(ReleaseParameters release) { if(nonheap && NoHeapRealtimeThread.heapCheck(release)) throw new IllegalArgumentException("heap params not permitted in nonheap AEH"); this.release = release; } public void setScheduler(Scheduler scheduler) { if(nonheap && NoHeapRealtimeThread.heapCheck(scheduler)) throw new IllegalArgumentException("heap params not permitted in nonheap AEH"); RealtimeSystem.getSecurityManager().checkSetScheduler(); throw new UnimplementedFeatureError(); } public void setScheduler(Scheduler scheduler, SchedulingParameters scheduling, ReleaseParameters release, MemoryParameters memory, ProcessingGroupParameters group) { if(nonheap && (NoHeapRealtimeThread.heapCheck(scheduler) || NoHeapRealtimeThread.heapCheck(scheduling) || NoHeapRealtimeThread.heapCheck(release) || NoHeapRealtimeThread.heapCheck(memory) || NoHeapRealtimeThread.heapCheck(group))) throw new IllegalArgumentException("heap params not permitted in nonheap AEH"); RealtimeSystem.getSecurityManager().checkSetScheduler(); throw new UnimplementedFeatureError(); } public void setSchedulingParameters(SchedulingParameters scheduling) { if(nonheap && NoHeapRealtimeThread.heapCheck(scheduling)) throw new IllegalArgumentException("heap params not permitted in nonheap AEH"); this.scheduling = scheduling; } public boolean setSchedulingParametersIfFeasible(SchedulingParameters scheduling) { if(nonheap && NoHeapRealtimeThread.heapCheck(scheduling)) throw new IllegalArgumentException("heap params not permitted in nonheap AEH"); throw new UnimplementedFeatureError(); } public void setProcessingGroupParameters(ProcessingGroupParameters group) { if(nonheap && NoHeapRealtimeThread.heapCheck(group)) throw new IllegalArgumentException("heap params not permitted in nonheap AEH"); this.group = group; } public final void setDaemon(boolean on) { throw new UnimplementedFeatureError(); } /** * Used by the asynchronous event mechanism, see {@link * AsyncEvent}. This method invokes * handleAsyncEvent() repeatedly while the fire count * is greater than zero. Applications cannot override this method * and should thus override handleAsyncEvent() in * subclasses with the logic of the handler. */ public final void run() { if(thread == null) { RealtimeThread rt = nonheap ? new NoHeapRealtimeThread(scheduling, release, memory, area, group, handleDispatcher) : new RealtimeThread(scheduling, release, memory, area, group, handleDispatcher); rt.setDaemon(true); rt.setScheduler(scheduler); handleDispatcher.notifyEvent(); rt.start(); } else { handleDispatcher.notifyEvent(); } } /* * Implementation-specific methods */ private native void init(); private native void fini(); protected void finalize() { this.fini(); } public int executionEligibility() { return executionEligibility; } }