// Copyright © 2020 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
//
using System;
using System.Text;
using System.Threading;
namespace CefSharp.Internals
{
///
/// Tracks the number of browser instances currently open
/// The cound will be incrmented and decremented each time a CefBrowser is created/closed.
/// This includes CefBrowser popup instances.
///
///
/// Roughtly based on , unforeunately
/// doesn't reset the internal when Count is aleady 0.
/// In our case it's valid to increase the number of browsers and reset the event.
///
public sealed class BrowserRefCounter : IBrowserRefCounter
{
private volatile int count = 0;
private ManualResetEventSlim manualResetEvent = new ManualResetEventSlim();
private bool loggingEnabled = false;
private StringBuilder logger = new StringBuilder();
/// TODO: Refactor this so it's not static.
public static IBrowserRefCounter Instance = new NoOpBrowserRefCounter();
///
/// If logging is enabled the will be appended to
/// the internal log.
///
/// text to append to log if logging enabled.
public void AppendLineToLog(string line)
{
if(loggingEnabled)
{
logger.AppendLine(line);
}
}
///
void IBrowserRefCounter.Increment(Type type)
{
var newCount = Interlocked.Increment(ref count);
if (newCount > 0)
{
manualResetEvent.Reset();
AppendLineToLog($"{type} - Incremented (ManualResetEvent was reset)");
}
else if(loggingEnabled)
{
logger.AppendLine($"New Count <= 0 - {newCount} ");
}
}
///
bool IBrowserRefCounter.Decrement(Type type)
{
var newCount = Interlocked.Decrement(ref count);
AppendLineToLog($"{type} - Decremented (Current Count {newCount})");
if (newCount == 0)
{
manualResetEvent.Set();
return true;
}
if (newCount < 0)
{
AppendLineToLog($"{type} - Decremented (Less than 0 : Current Count {newCount})");
//If we went below 0 then reset to 0
// TODO: something went wrong with our tracking
Interlocked.Exchange(ref count, 0);
manualResetEvent.Set();
}
return false;
}
///
int IBrowserRefCounter.Count
{
get
{
int observedCount = count;
return observedCount < 0 ? 0 : observedCount;
}
}
///
void IBrowserRefCounter.WaitForBrowsersToClose(int timeoutInMiliseconds)
{
AppendLineToLog($"WaitForBrowsersToClose - Current Count {count}");
if (!manualResetEvent.IsSet)
{
manualResetEvent.Wait(timeoutInMiliseconds);
}
AppendLineToLog($"WaitForBrowsersToClose - Updated Count {count}");
}
///
void IBrowserRefCounter.WaitForBrowsersToClose(int timeoutInMiliseconds, CancellationToken cancellationToken)
{
AppendLineToLog($"WaitForBrowsersToClose - Current Count {count}");
if (!manualResetEvent.IsSet)
{
manualResetEvent.Wait(timeoutInMiliseconds, cancellationToken);
}
AppendLineToLog($"WaitForBrowsersToClose - Updated Count {count}");
}
///
void IBrowserRefCounter.EnableLogging()
{
loggingEnabled = true;
}
///
string IBrowserRefCounter.GetLog()
{
return logger.ToString();
}
public void Dispose()
{
manualResetEvent.Dispose();
}
}
}