// $Id$
//
// Copyright 2007-2008 Cisco Systems Inc.
//
// Licensed 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 Etch.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;
}
}
}