001/* Attribute that regulates the passage of time to wait for real time to catch up. 002 003 Copyright (c) 2007-2015 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.actor.lib; 028 029import ptolemy.actor.AbstractInitializableAttribute; 030import ptolemy.actor.Actor; 031import ptolemy.actor.Director; 032import ptolemy.actor.TimeRegulator; 033import ptolemy.actor.util.Time; 034import ptolemy.data.DoubleToken; 035import ptolemy.data.expr.Parameter; 036import ptolemy.data.type.BaseType; 037import ptolemy.kernel.CompositeEntity; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.NameDuplicationException; 040import ptolemy.kernel.util.NamedObj; 041 042/////////////////////////////////////////////////////////////////// 043//// SynchronizeToRealTime 044 045/** 046 * Attribute that regulates the passage of time to wait for real time to catch up. 047 * 048 * <p>The scaleFactor parameter is here to set up how many seconds in wallclock 049 * time should pass for a single second in model time. So a scale factor of 0.5 050 * will make the model time passes twice as fast as real time, while make it 051 * equals 2 means that 2 seconds in wallclock are needed for a single unit 052 * of time in the model.</p> 053 * 054 * <p>The default value is 1.</p> 055 * 056 @author Edward A. Lee, Gilles Lasnier, Patricia Derler 057 @version $Id$ 058 @since Ptolemy II 10.0 059 @Pt.ProposedRating Yellow (eal) 060 @Pt.AcceptedRating Red (cxh) 061 */ 062public class SynchronizeToRealTime extends AbstractInitializableAttribute 063 implements TimeRegulator { 064 065 /** Construct an instance of the attribute. 066 * @param container The container. 067 * @param name The name. 068 * @exception IllegalActionException If the superclass throws it. 069 * @exception NameDuplicationException If the superclass throws it. 070 */ 071 public SynchronizeToRealTime(CompositeEntity container, String name) 072 throws IllegalActionException, NameDuplicationException { 073 super(container, name); 074 075 scaleFactor = new Parameter(this, "scaleFactor"); 076 scaleFactor.setDisplayName("Time scale factor"); 077 scaleFactor.setTypeEquals(BaseType.DOUBLE); 078 scaleFactor.setExpression("1.0"); 079 attributeChanged(scaleFactor); 080 } 081 082 /////////////////////////////////////////////////////////////////// 083 //// public methods //// 084 085 /** 086 * This class does not create change request for new actor in proposeTime. 087 * Always return true then. 088 */ 089 @Override 090 public boolean noNewActors() { 091 return true; 092 } 093 094 /** Propose a time to advance to. 095 * @param proposedTime The proposed time. 096 * @return The proposed time or a smaller time. 097 * @exception IllegalActionException If this attribute is not 098 * contained by an Actor. 099 */ 100 @Override 101 public Time proposeTime(Time proposedTime) throws IllegalActionException { 102 NamedObj container = getContainer(); 103 if (!(container instanceof Actor)) { 104 throw new IllegalActionException(this, 105 "SynchronizeToRealTime has to be contained by an Actor"); 106 } 107 108 Director director = ((Actor) container).getDirector(); 109 Object mutexLockObject = director.mutexLockObject(); 110 111 int depth = 0; 112 try { 113 synchronized (mutexLockObject) { 114 while (true) { 115 116 // NOTE: We assume that the elapsed time can be 117 // safely cast to a double. This means that 118 // the SR domain has an upper limit on running 119 // time of Double.MAX_VALUE milliseconds. 120 double elapsedTime_s = director.elapsedTimeSinceStart() 121 / 1000.0; 122 double currentTime_s = director.getModelTime() 123 .getDoubleValue(); 124 125 double scale = ((DoubleToken) scaleFactor.getToken()) 126 .doubleValue(); 127 if (currentTime_s * scale <= elapsedTime_s) { 128 break; 129 } 130 131 long timeToWait_ms = (long) ((currentTime_s * scale 132 - elapsedTime_s) * 1000.0); 133 134 if (_debugging) { 135 _debug("Waiting for real time to pass: " + timeToWait_ms 136 + " before " + proposedTime.getDoubleValue()); 137 } 138 139 try { 140 // NOTE: The built-in Java wait() method 141 // does not release the 142 // locks on the workspace, which would block 143 // UI interactions and may cause deadlocks. 144 // SOLUTION: explicitly release read permissions. 145 if (timeToWait_ms > 0) { 146 // Bug fix from J. S. Senecal: 147 // 148 // The problem was that sometimes, the 149 // method Object.wait(timeout) was called 150 // with timeout = 0. According to java 151 // documentation: 152 // 153 // " If timeout is zero, however, then 154 // real time is not taken into 155 // consideration and the thread simply 156 // waits until notified." 157 depth = _workspace.releaseReadPermission(); 158 mutexLockObject.wait(timeToWait_ms); 159 } 160 } catch (InterruptedException ex) { 161 // Continue executing. 162 } 163 } 164 } 165 } finally { 166 if (depth > 0) { 167 _workspace.reacquireReadPermission(depth); 168 } 169 } 170 return proposedTime; 171 } 172 173 /////////////////////////////////////////////////////////////////// 174 //// public members //// 175 176 /** How many seconds in wallclock time should pass for a single 177 * second in model time. So a scaleFactor of 0.5 will make the 178 * model time passes twice as fast as real time, while make it 179 * equals 2 means that 2 seconds in wallclock are needed for a 180 * single unit of time in the model. The default value is 1.0. 181 */ 182 public Parameter scaleFactor; 183}