//
// BwgBurn - CD-R/CD-RW/DVD-R/DVD-RW burning program for Windows XP
//
// Copyright (C) 2006 by Jack W. Griffin (butchg@comcast.net)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330,
// Boston, MA 02111-1307 USA
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace Bwg.Scsi
{
///
/// This class manages a series of buffers that are used to provide data
/// for the burning process.
///
public class WriteBufferPool
{
#region private data members
int m_count ;
private Object m_buffer_list_lock;
private IList m_buffer_list;
private Object m_free_list_lock;
private IList m_free_list;
private bool m_end_of_data;
private int m_produced;
private int m_consumed;
private int m_pagesize;
private int m_mult;
private bool m_padded;
#endregion
#region public properties
///
/// If this property is true, all data has been pushed into the
/// buffer stream.
///
public bool EndOfData
{
get
{
return m_end_of_data;
}
set
{
m_end_of_data = value;
}
}
///
/// This property returns the number of 2k pages that have been produced by
/// the generator thread.
///
public int Produced
{
get
{
return m_produced;
}
}
///
/// This property returns the number of 2k pages that have been consumed
/// by the writer thread.
///
public int Consumed
{
get
{
return m_consumed;
}
}
///
/// This is the size of the pages stored in this buffer pool, in bytes.
///
public int PageSize
{
get
{
return m_pagesize;
}
}
///
/// Return the percent of the buffers used
///
public double PercentUsed
{
get
{
double v;
lock (m_buffer_list_lock)
{
v = (double)m_buffer_list.Count / (double)m_count * 100.0;
}
return v;
}
}
#endregion
#region constructors
///
/// Initialize the buffer stream by creating the buffers
///
/// the number of buffers to create
/// the size of each buffer
/// the multiple that each buffer must meet for the device
/// the size of the sectors in the buffer in bytes
public WriteBufferPool(int cnt, int size, int mult, int secsize)
{
m_count = cnt ;
m_end_of_data = false;
m_pagesize = size;
m_mult = mult;
//
// If the multiple setting is non-zero, we may have to adjust the page size
//
if (m_mult != 0)
{
int blocks = size / (mult * secsize);
m_pagesize = blocks * mult * secsize;
}
// Used to lock the data buffer list
m_buffer_list_lock = new Object();
// Used to lock the free buffer list
m_free_list_lock = new Object();
// The data buffer list
m_buffer_list = new List();
// THe free buffer list
m_free_list = new List() ;
// Create the buffers and place them all in the
// free list.
for(int i = 0 ; i < cnt ; i++)
m_free_list.Add(new WriteBuffer(size)) ;
m_produced = 0;
m_consumed = 0;
//
// This starts out false and is only set to true if we have to pad
// a buffer to reach an appropriate multiple of the multiple count
// for this device. We should only have to pad the last buffer sent
// to the device. This value is used to detect data being supplied
// after having to pad a data buffer, implying that the data put into
// the queue did not full the buffer and was not at the end of the
// queue.
//
m_padded = false;
}
#endregion
#region public methods
///
/// Get a free write buffer to fill with data
///
/// a write buffer
public WriteBuffer GetFreeBuffer()
{
while (true)
{
lock (m_free_list_lock)
{
if (m_free_list.Count > 0)
{
Debug.Assert(m_padded == false);
WriteBuffer buf = m_free_list[0] ;
m_free_list.RemoveAt(0) ;
return buf;
}
if (m_end_of_data == true)
return null;
}
// Sleep for 10 msec while we wait for buffers to become
// availsble.
Thread.Sleep(1) ;
}
}
///
/// Add a buffer to the list
///
///
public void SendBufferToDevice(WriteBuffer buf)
{
lock (m_buffer_list_lock)
{
if (m_mult != 0 && ((buf.DataSize % m_mult) != 0))
System.Diagnostics.Debug.WriteLine("Added a block of " + buf.DataSize.ToString() + " blocks, not an event multiple") ;
m_buffer_list.Add(buf);
m_produced += (int)buf.DataSize;
}
}
///
/// Get the next buffer of data from the steam
///
/// the next buffer stream, or null if all data has been processed
public WriteBuffer GetNextDataBuffer()
{
while (true)
{
lock (m_buffer_list_lock)
{
if (m_buffer_list.Count > 0)
{
WriteBuffer buf = m_buffer_list[0];
m_buffer_list.RemoveAt(0);
m_consumed += (int)buf.DataSize;
if (m_mult != 0 && (buf.DataSize % m_mult) != 0)
{
//
// The buffer is not an even multiple of the
//
m_padded = true;
buf.DataSize = ((buf.DataSize / m_mult) + 1) * m_mult;
}
return buf;
}
if (m_end_of_data)
return null;
}
// Wait for the reader thread to put data into the buffer
// stream
// Thread.Sleep(1);
}
}
///
/// Add a buffer back to the free list to be used again
///
/// the buffer to add to the list
public void FreeWriteBuffer(WriteBuffer buf)
{
lock (m_free_list_lock)
{
m_free_list.Add(buf);
}
}
#endregion
}
}