// ************************************************************************ // $Id: AsyncEvent.java 603 2005-07-23 20:59:47Z 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; /** * An asynchronous event represents something that can happen, like a * light turning red. It can have a set of handlers associated with * it, and when the event occurs, the handler is scheduled by the * scheduler to which it holds a reference (see AsyncEventHandler * and Scheduler ). A major motivator for this style of building * events is that we expect to have lots of events and lots of event * handlers. An event handler is logically very similar to a thread, * but it is intended to have a much lower cost (in both time and * space) -assuming that a relatively small number of events are fired * and in the process of being handled at once. AsyncEvent.fire() * differs from a method call because the handler (a) has scheduling * parameters and (b) is executed asynchronously. * * @author Angelo Corsaro * @author Morgan Deters * @version 1.0 */ public class AsyncEvent { // The data structure used to keep track of the handlers have to // be allocated in the same memory area as the AsyncEvent. protected PriorityQueue handlerList = new PriorityQueue(); /** * Construct a new {@link AsyncEvent}. */ public AsyncEvent() {} /** * Add a handler to the set of handlers associated with this * event. An {@link AsyncEvent} may have more than one associated * handler. Adding a handler to an {@link AsyncEvent} to which it * is already attached has no effect. This method is atomic with * respect to the execution of the {@link #fire()} method. * *

Since this affects the constraints expressed in the release * parameters of the existing schedulable objects, this may change * the feasibility of the current schedule; however, this method * does not cause any feasibility test to be performed, nor is any * scheduler's feasibility set updated. * *

An assignment from this to the handler must be * valid in accordance with RTSJ memory assignment rules. * * @param handler the new handler to add to the list of handlers * already associated with this * @throws IllegalArgumentException if handler is null */ public void addHandler(AsyncEventHandler handler) { if(handler == null) throw new IllegalArgumentException("null handler not permitted"); int eligibility = handler.executionEligibility(); handlerList.add(handler, eligibility); } /** * Remove a handler from the set associated with this event. This * method is atomic with respect to the execution of the {@link * #fire()} method. * *

A removed handler continues to execute until its fireCount * becomes zero and it completes. * * @param handler the handler to be dissociated from this; if * null, nothing happens; if not already associated with * this, nothing happens. */ public void removeHandler(AsyncEventHandler handler) { if(handler == null) return; handlerList.remove(handler); } /** * Returns true if and only if this event is handled by the passed * handler. * * @param handler an AsyncEventHandler for which to * test * @return true if this event is handled by the given * handler */ public boolean handledBy(AsyncEventHandler handler) { return handlerList.contains(handler); } /** * Associate a new handler with this event, removing all existing * handlers. This method is atomic with respect to the execution * of the {@link #fire()} method. * *

Since this affects the constraints expressed in the release * parameters of the existing {@link Schedulable} objects, this * may change the feasibility of the current schedule. This * method does not cause any feasibility test to be performed, nor * is any scheduler's feasibility set updated. * * @param handler The new and only handler to be associated with * this. If handler is null then no handler will be associated * with this (i.e., remove all handlers). */ public void setHandler(AsyncEventHandler handler) { PriorityQueue newHandlerList = new PriorityQueue(); int eligibility = handler.executionEligibility(); newHandlerList.add(handler, eligibility); handlerList = newHandlerList; } /** * Create a {@link ReleaseParameters} block appropriate to the * release characteristics of this event. The default is the most * pessimistic: {@link AperiodicParameters}. This is typically * called by code that is setting up a handler for this event that * will fill in the parts of the {@link ReleaseParameters} for * which it knows values, like cost. The returned {@link * ReleaseParameters} object is not bound to the event. Any * changes in the event's {@link ReleaseParameters} are not * reflected in previously returned objects. * * @return a ReleaseParameters value */ public ReleaseParameters createReleaseParameters() { return new AperiodicParameters(); } /** * Binds this to an external event (a * happening). The meaningful values of happening are * implementation dependent. This {@link AsyncEvent} is considered * to have occurred whenever the external event occurs. More than * one happening can be bound to the same {@link AsyncEvent}. If * a happening is already bound to an event, binding it again has * no effect. * *

When an event allocated in a {@link ScopedMemory} area is * bound to an external happening, the reference count of that * memory area is incremented. The reference count is decremented * when the event is unbound from the happening. * * @param happening an implementation-dependent value that binds * this {@link AsyncEvent} to some external event * @exception UnknownHappeningException the happening string is * not supported by the system * @exception IllegalArgumentException happening is null */ public void bindTo(String happening) throws UnknownHappeningException { if(happening == null) throw new IllegalArgumentException(); throw new UnknownHappeningException("No happenings implemented yet!"); } /** * Removes a binding to an external event (a * happening). The meaningful values of happening are * implementation dependent. If the associated event is declared * in a scoped memory area, the memory area's reference count is * decremented. * * @param happening an implementation-dependent value representing * some external event to which this {@link AsyncEvent} is to be * unbound * @exception UnknownHappeningException this {@link AsyncEvent} is * not bound to the given happening, or the happening string is * not supported by the system * @exception IllegalArgumentException happening is null */ public void unbindTo(String happening) throws UnknownHappeningException { if(happening == null) throw new IllegalArgumentException(); throw new UnknownHappeningException("No happenings implemented yet!"); } /** * Fire this event. If no handlers are attached, nothing happens. * *

If this method could throw both types of exceptions, * it will throw an {@link MITViolationException}. * *

Implementation Detail: As currently implemented this * method has linear time complexity in the number of registered * handlers. * * @throws MITViolationException there is a handler associated * with this event that has its MIT violated (and it has * MITViolationExcept behavior); handlers which cause this * exception to be thrown are not released, but all others are * @throws ArrivalTimeQueueOverflowException if the queue of * arrival time information overflows; handlers which cause this * exception to be thrown are not released, but all others are */ public void fire() { PriorityQueue.ForwardIterator listIterator = handlerList.iterator(); AsyncEventHandler handler = null; while ((handler = (AsyncEventHandler)listIterator.next()) != null) { if(handler.getAndIncrementPendingFireCount() == 0) handler.run(); } } }