// $Id$ // // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // using System; using System.Runtime.CompilerServices; using System.Threading; namespace Org.Apache.Etch.Bindings.Csharp.Util { /// /// A class which we can use to monitor conditions. /// /// Type of object that can be stored in the monitor public class Monitor { /// /// Constructs the Monitor. /// /// a description of this monitor /// the initial value of this monitor public Monitor( String description, T initialValue ) { this.description = description; this.value = initialValue; } /// /// Constructs the Monitor with null initial value /// /// a description of this monitor public Monitor( String description ) : this( description, default( T ) ) { } /// /// Get the description of the Monitor /// /// return the description of this monitor public String GetDescription() { return description; } private String description; private T value; public override string ToString() { return "Monitor "+description+": "+value; } /// /// /// /// The current value of the monitor public T Get() { return value; } /// /// Sets the current value. /// /// the value to be set /// the old value. [MethodImpl(MethodImplOptions.Synchronized)] public T Set( T newValue ) { T oldValue = value; value = newValue; System.Threading.Monitor.PulseAll(this); return oldValue; } /// /// Waits until monitor value is set /// the value. Will wait forever /// /// the max amount of time in ms to wait. /// If 0 is specified, we will wait forever. /// the current value of the monitor. /// Exception: /// throws ThreadInterruptedException if we waited too long. [MethodImpl( MethodImplOptions.Synchronized )] private T WaitUntilSet( long maxDelay ) { System.Threading.Monitor.Wait( this, (int) maxDelay ); return value; } /// /// Waits until value equals the desired value and /// then sets the value. Will wait forever. /// /// the value we want /// the value to be set /// The old value /// Exception: /// throws Exception public T WaitUntilEqAndSet( T desiredValue, T newValue ) { return WaitUntilEqAndSet( desiredValue, 0, newValue ); } /// /// Waits until value equals the desired value and /// then sets the value /// /// the value we want. /// the max amount of time in ms to wait /// If 0 is specified, we will wait forever. /// /// the value to be set /// Old Value /// Exception: /// throws ThreadInterruptedException [MethodImpl( MethodImplOptions.Synchronized )] public T WaitUntilEqAndSet( T desiredValue, int maxDelay, T newValue ) { WaitUntilEq(desiredValue, maxDelay); return Set(newValue); } /// /// Waits forever until the value is set to the specified value. /// /// The value we are waiting for. /// Exception: /// throws ThreadInterruptedException public void WaitUntilEq( T desiredValue ) { WaitUntilEq( desiredValue, 0 ); } /// /// Waits until the value equals the desired value /// /// The value we want /// the max amount of time in ms to wait. /// If 0 is specified, we will wait forever. /// Exception: /// throws ThreadInterruptedException if we waited too long. [MethodImpl(MethodImplOptions.Synchronized)] public void WaitUntilEq(T desiredValue, int maxDelay) { CheckDelay(maxDelay); long now = HPTimer.Now(); long end = EndTime(now, maxDelay); int d; while (!Eq(value, desiredValue) && (d = RemTime(end, now)) > 0) { System.Threading.Monitor.Wait(this, d); now = HPTimer.Now(); } if (!Eq(value, desiredValue)) throw new ThreadInterruptedException("timeout"); } /// /// Waits until value does not equal the undesired value and then /// sets the value. Will wait forever /// /// the value we do not want /// the value to be set /// Old value /// Exception: /// throws ThreadInterruptedException public T WaitUntilNotEqAndSet( T undesiredValue, T newValue ) { return WaitUntilNotEqAndSet( undesiredValue, 0, newValue ); } /// /// Waits until value does not equal the undesired value and then /// sets the value. /// /// the value we do not want /// the max amount of time in ms to wait. /// If 0 is specified, we will wait forever. /// New value /// The old value /// Exception: /// throws ThreadInterrupedException [MethodImpl( MethodImplOptions.Synchronized )] public T WaitUntilNotEqAndSet( T undesiredValue, int maxDelay, T newValue ) { WaitUntilNotEq( undesiredValue, maxDelay ); return Set( newValue ); } /// /// Waits until value does not equal the undesired value. Will /// wait forever /// /// The value we do not want /// Curretn value of the monitor /// Exception: /// throws ThreadInterruptedException if we waited too long. public T WaitUntilNotEq( T undesiredValue ) { return WaitUntilNotEq( undesiredValue, 0 ); } /// /// Waits until the value is not the specified value. /// /// the value we do not want. /// the max amount of time in ms to wait. /// If 0 is specified, we will wait forever. /// the current value of the monitor /// Exception: /// throws ThreadInterruptedException if we waited too long. [MethodImpl(MethodImplOptions.Synchronized)] public T WaitUntilNotEq(T undesiredValue, int maxDelay) { CheckDelay(maxDelay); long now = HPTimer.Now(); long end = EndTime(now, maxDelay); int d; while (Eq(value, undesiredValue) && (d = RemTime(end, now)) > 0) { System.Threading.Monitor.Wait(this, d); now = HPTimer.Now(); } if (Eq(value, undesiredValue)) throw new ThreadInterruptedException("timeout"); return value; } private void CheckDelay(int maxDelay) { if (maxDelay < 0) throw new ArgumentException("maxDelay < 0"); } private long EndTime(long now, int maxDelay) { if (maxDelay == 0 || maxDelay == int.MaxValue) return long.MaxValue; return now + maxDelay * HPTimer.NS_PER_MILLISECOND; } private int RemTime(long end, long now) { if (end == long.MaxValue) return int.MaxValue; long ms = (end - now) / HPTimer.NS_PER_MILLISECOND; if (ms > int.MaxValue) return int.MaxValue; return (int) ms; } /// /// Compares the specified values. /// /// a value to compare, which may be null. /// another value to compare, which may be null. /// true if the values are equal, false otherwise. If both /// values are null, they are considered equal. private bool Eq( T v1, T v2 ) { if ( v1 != null && v2 != null ) return v1.Equals(v2); if ( v1 == null && v2 == null ) return true; return false; } } }