gem5/base/res_list.hh
Kevin Lim f58d85128d Fixes so m5 compiles on gcc 3.4, which has much stricter syntax. Most changes come from templated code,
which is evaluated slightly differently than in previous versions of gcc.

arch/alpha/alpha_linux_process.cc:
    Alphabetize includes.
arch/alpha/vptr.hh:
    Change the constants that are being used for alpha pagebytes to come from the ISA.
base/random.hh:
cpu/static_inst.cc:
sim/param.cc:
    Fix up template syntax.
base/range.hh:
    Include iostream for << operator.
base/res_list.hh:
base/statistics.hh:
cpu/simple_cpu/simple_cpu.hh:
cpu/static_inst.hh:
sim/eventq.hh:
sim/param.hh:
    Fixup for templated code to resolve different scope lookup in gcc 3.4.  This defers the lookup of the
    function/variable until actual instantiation time by making it dependent on the templated class/function.
base/trace.cc:
    Fix call to new.
base/trace.hh:
    Fix up #define to have full path.
cpu/base_cpu.cc:
    Fix up call to new.
dev/etherlink.hh:
dev/ns_gige.hh:
dev/sinic.hh:
    Fixup for friend class/function declaration.  g++ 3.4 no longer allows typedefs to be declared as
    a friend class.
dev/pcidev.hh:
    Fix up re-definition of access level to params.
kern/linux/linux_syscalls.hh:
kern/tru64/tru64_syscalls.hh:
    Fix up header.  Fix up template syntax.
sim/serialize.cc:
    Include errno.h.
sim/startup.cc:
    Change startupq.  queue was getting destructed before all things had called ~StartupCallback(), which lead
    to a segfault.  This puts startupq in global space, and we allocate it ourselves.  Other code may be similar
    to this and may need changing in the future.
sim/syscall_emul.hh:
    Include cpu/exec_context.hh and sim/process.hh, as forward declarations are no longer sufficient.
sim/universe.cc:
    Include errno.h

--HG--
extra : convert_revision : e49d08ee89eb06a28351f02bafc028ca6652d5af
2005-01-14 18:34:56 -05:00

756 lines
17 KiB
C++

/*
* Copyright (c) 2001-2004 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __RES_LIST_HH__
#define __RES_LIST_HH__
#include "base/cprintf.hh"
#include <assert.h>
#define DEBUG_REMOVE 0
#define DEBUG_MEMORY 0
//#define DEBUG_MEMORY DEBUG
class res_list_base
{
#if DEBUG_MEMORY
protected:
static long long allocated_elements;
static long long allocated_lists;
public:
long long get_elements(void) {
return allocated_elements;
}
long long get_lists(void) {
return allocated_lists;
}
#endif
};
#if DEBUG_MEMORY
extern void what_the(void);
#endif
template<class T>
class res_list : public res_list_base
{
public:
class iterator;
class res_element
{
res_element *next;
res_element *prev;
T *data;
bool allocate_data;
public:
// always adds to the END of the list
res_element(res_element *_prev, bool allocate);
~res_element();
void dump(void);
friend class res_list<T>;
friend class res_list<T>::iterator;
};
class iterator
{
private:
res_element *p;
friend class res_list<T>;
public:
// Constructors
iterator(res_element *q) : p(q) {}
iterator(void) { p=0; };
void dump(void);
T* data_ptr(void);
res_element *res_el_ptr(void) { return p;}
void point_to(T &d) { p->data = &d; }
iterator next(void) { return iterator(p->next); }
iterator prev(void) { return iterator(p->prev); }
bool operator== (iterator x) { return (x.p == this->p); }
bool operator != (iterator x) { return (x.p != this->p); }
T &operator * (void) { return *(p->data); }
T* operator -> (void) { return p->data; }
bool isnull(void) { return (p==0); }
bool notnull(void) { return (p!=0); }
};
private:
iterator unused_elements;
iterator head_ptr;
iterator tail_ptr;
unsigned base_elements;
unsigned extra_elements;
unsigned active_elements;
bool allocate_storage;
unsigned build_size;
int remove_count;
//
// Allocate new elements, and assign them to the unused_elements
// list.
//
unsigned allocate_elements(unsigned num, bool allocate_storage);
public:
//
// List Constructor
//
res_list(unsigned size, bool alloc_storage = false,
unsigned build_sz = 5);
//
// List Destructor
//
~res_list();
iterator head(void) {return head_ptr;};
iterator tail(void) {return tail_ptr;};
unsigned num_free(void) { return size() - count(); }
unsigned size(void) { return base_elements + extra_elements; }
unsigned count(void) { return active_elements; }
bool empty(void) { return count() == 0; }
bool full(void);
//
// Insert with data copy
//
iterator insert_after(iterator prev, T *d);
iterator insert_after(iterator prev, T &d);
iterator insert_before(iterator prev, T *d);
iterator insert_before(iterator prev, T &d);
//
// Insert new list element (no data copy)
//
iterator insert_after(iterator prev);
iterator insert_before(iterator prev);
iterator add_tail(T *d) { return insert_after(tail_ptr, d); }
iterator add_tail(T &d) { return insert_after(tail_ptr, d); }
iterator add_tail(void) { return insert_after(tail_ptr); }
iterator add_head(T *d) { return insert_before(head_ptr, d); }
iterator add_head(T &d) { return insert_before(head_ptr, d); }
iterator add_head(void) { return insert_before(head_ptr); }
iterator remove(iterator q);
iterator remove_head(void) {return remove(head_ptr);}
iterator remove_tail(void) {return remove(tail_ptr);}
bool in_list(iterator j);
void free_extras(void);
void clear(void);
void dump(void);
void raw_dump(void);
};
template <class T>
inline
res_list<T>::res_element::res_element(res_element *_prev, bool allocate)
{
allocate_data = allocate;
prev = _prev;
next = 0;
if (prev)
prev->next = this;
if (allocate)
data = new T;
else
data = 0;
#if DEBUG_MEMORY
++allocated_elements;
#endif
}
template <class T>
inline
res_list<T>::res_element::~res_element(void)
{
if (prev)
prev->next = next;
if (next)
next->prev = prev;
if (allocate_data)
delete data;
#if DEBUG_MEMORY
--allocated_elements;
#endif
}
template <class T>
inline void
res_list<T>::res_element::dump(void)
{
cprintf(" prev = %#x\n", prev);
cprintf(" next = %#x\n", next);
cprintf(" data = %#x\n", data);
}
template <class T>
inline void
res_list<T>::iterator::dump(void)
{
if (p && p->data)
p->data->dump();
else {
if (!p)
cprintf(" Null Pointer\n");
else
cprintf(" Null 'data' Pointer\n");
}
}
template <class T>
inline T *
res_list<T>::iterator::data_ptr(void)
{
if (p)
return p->data;
else
return 0;
}
//
// Allocate new elements, and assign them to the unused_elements
// list.
//
template <class T>
inline unsigned
res_list<T>::allocate_elements(unsigned num, bool allocate_storage)
{
res_element *pnew, *plast = 0, *pfirst=0;
for (int i=0; i<num; ++i) {
pnew = new res_element(plast, allocate_storage);
if (i==0)
pfirst = pnew;
plast = pnew;
}
if (unused_elements.notnull()) {
// Add these new elements to the front of the list
plast->next = unused_elements.res_el_ptr();
unused_elements.res_el_ptr()->prev = plast;
}
unused_elements = iterator(pfirst);
return num;
}
template <class T>
inline
res_list<T>::res_list(unsigned size, bool alloc_storage, unsigned build_sz)
{
#if DEBUG_MEMORY
++allocated_lists;
#endif
extra_elements = 0;
active_elements = 0;
build_size = build_sz;
allocate_storage = alloc_storage;
remove_count = 0;
// Create the new elements
base_elements = allocate_elements(size, alloc_storage);
// The list of active elements
head_ptr = iterator(0);
tail_ptr = iterator(0);
}
//
// List Destructor
//
template <class T>
inline
res_list<T>::~res_list(void)
{
iterator n;
#if DEBUG_MEMORY
--allocated_lists;
#endif
// put everything into the unused list
clear();
// rudely delete all the res_elements
for (iterator p = unused_elements;
p.notnull();
p = n) {
n = p.next();
// delete the res_element
// (it will take care of deleting the data)
delete p.res_el_ptr();
}
}
template <class T>
inline bool
res_list<T>::full(void)
{
if (build_size)
return false;
else
return unused_elements.isnull();
}
//
// Insert with data copy
//
template <class T>
inline typename res_list<T>::iterator
res_list<T>::insert_after(iterator prev, T *d)
{
iterator p;
if (!allocate_storage)
this->panic("Can't copy data... not allocating storage");
p = insert_after(prev);
if (p.notnull())
*p = *d;
return p;
}
template <class T>
inline typename res_list<T>::iterator
res_list<T>::insert_after(iterator prev, T &d)
{
iterator p;
p = insert_after(prev);
if (p.notnull()) {
if (allocate_storage) {
// if we allocate storage, then copy the contents of the
// specified object to our object
*p = d;
}
else {
// if we don't allocate storage, then we just want to
// point to the specified object
p.point_to(d);
}
}
return p;
}
template <class T>
inline typename res_list<T>::iterator
res_list<T>::insert_after(iterator prev)
{
#if DEBUG_MEMORY
if (active_elements > 2*base_elements) {
what_the();
}
#endif
// If we have no unused elements, make some more
if (unused_elements.isnull()) {
if (build_size == 0) {
return 0; // No space left, and can't allocate more....
}
extra_elements += allocate_elements(build_size, allocate_storage);
}
// grab the first unused element
res_element *p = unused_elements.res_el_ptr();
unused_elements = unused_elements.next();
++active_elements;
// Insert the new element
if (head_ptr.isnull()) {
//
// Special case #1: Empty List
//
head_ptr = p;
tail_ptr = p;
p->prev = 0;
p->next = 0;
}
else if (prev.isnull()) {
//
// Special case #2: Insert at head
//
// our next ptr points to old head element
p->next = head_ptr.res_el_ptr();
// our element becomes the new head element
head_ptr = p;
// no previous element for the head
p->prev = 0;
// old head element points back to this element
p->next->prev = p;
}
else if (prev.next().isnull()) {
//
// Special case #3 Insert at tail
//
// our prev pointer points to old tail element
p->prev = tail_ptr.res_el_ptr();
// our element becomes the new tail
tail_ptr = p;
// no next element for the tail
p->next = 0;
// old tail element point to this element
p->prev->next = p;
}
else {
//
// Normal insertion (after prev)
//
p->prev = prev.res_el_ptr();
p->next = prev.next().res_el_ptr();
prev.res_el_ptr()->next = p;
p->next->prev = p;
}
return iterator(p);
}
template <class T>
inline typename res_list<T>::iterator
res_list<T>::insert_before(iterator next, T &d)
{
iterator p;
p = insert_before(next);
if (p.notnull()) {
if (allocate_storage) {
// if we allocate storage, then copy the contents of the
// specified object to our object
*p = d;
}
else {
// if we don't allocate storage, then we just want to
// point to the specified object
p.point_to(d);
}
}
return p;
}
template <class T>
inline typename res_list<T>::iterator
res_list<T>::insert_before(iterator next)
{
#if DEBUG_MEMORY
if (active_elements > 2*base_elements) {
what_the();
}
#endif
// If we have no unused elements, make some more
if (unused_elements.isnull()) {
if (build_size == 0) {
return 0; // No space left, and can't allocate more....
}
extra_elements += allocate_elements(build_size, allocate_storage);
}
// grab the first unused element
res_element *p = unused_elements.res_el_ptr();
unused_elements = unused_elements.next();
++active_elements;
// Insert the new element
if (head_ptr.isnull()) {
//
// Special case #1: Empty List
//
head_ptr = p;
tail_ptr = p;
p->prev = 0;
p->next = 0;
}
else if (next.isnull()) {
//
// Special case #2 Insert at tail
//
// our prev pointer points to old tail element
p->prev = tail_ptr.res_el_ptr();
// our element becomes the new tail
tail_ptr = p;
// no next element for the tail
p->next = 0;
// old tail element point to this element
p->prev->next = p;
}
else if (next.prev().isnull()) {
//
// Special case #3: Insert at head
//
// our next ptr points to old head element
p->next = head_ptr.res_el_ptr();
// our element becomes the new head element
head_ptr = p;
// no previous element for the head
p->prev = 0;
// old head element points back to this element
p->next->prev = p;
}
else {
//
// Normal insertion (before next)
//
p->next = next.res_el_ptr();
p->prev = next.prev().res_el_ptr();
next.res_el_ptr()->prev = p;
p->prev->next = p;
}
return iterator(p);
}
template <class T>
inline typename res_list<T>::iterator
res_list<T>::remove(iterator q)
{
res_element *p = q.res_el_ptr();
iterator n = 0;
// Handle the special cases
if (active_elements == 1) { // This is the only element
head_ptr = 0;
tail_ptr = 0;
}
else if (q == head_ptr) { // This is the head element
head_ptr = q.next();
head_ptr.res_el_ptr()->prev = 0;
n = head_ptr;
}
else if (q == tail_ptr) { // This is the tail element
tail_ptr = q.prev();
tail_ptr.res_el_ptr()->next = 0;
}
else { // This is between two elements
p->prev->next = p->next;
p->next->prev = p->prev;
// Get the "next" element for return
n = p->next;
}
--active_elements;
// Put this element back onto the unused list
p->next = unused_elements.res_el_ptr();
p->prev = 0;
if (p->next) { // NULL if unused list is empty
p->next->prev = p;
}
if (!allocate_storage) {
p->data = 0;
}
unused_elements = q;
// A little "garbage collection"
if (++remove_count > 10) {
// free_extras();
remove_count = 0;
}
#if DEBUG_REMOVE
unsigned unused_count = 0;
for (iterator i=unused_elements;
i.notnull();
i = i.next()) {
++unused_count;
}
assert((active_elements+unused_count) == (base_elements+extra_elements));
#endif
return iterator(n);
}
template <class T>
inline bool
res_list<T>::in_list(iterator j)
{
iterator i;
for (i=head(); i.notnull(); i=i.next()) {
if (j.res_el_ptr() == i.res_el_ptr()) {
return true;
}
}
return false;
}
template <class T>
inline void
res_list<T>::free_extras(void)
{
unsigned num_unused = base_elements + extra_elements - active_elements;
unsigned to_free = extra_elements;
res_element *p;
if (extra_elements != 0) {
//
// Free min(extra_elements, # unused elements)
//
if (extra_elements > num_unused) {
to_free = num_unused;
}
p = unused_elements.res_el_ptr();
for (int i=0; i<to_free; ++i) {
res_element *q = p->next;
delete p;
p = q;
}
// update the unused element pointer to point to the first
// element that wasn't deleted.
unused_elements = iterator(p);
// Update the number of extra elements
extra_elements -= to_free;
}
return;
}
template <class T>
inline void
res_list<T>::clear(void)
{
iterator i,n;
for (i=head_ptr; i.notnull(); i=n) {
n = i.next();
remove(i);
}
free_extras();
}
template <class T>
inline void
res_list<T>::dump(void)
{
for (iterator i=head(); !i.isnull(); i=i.next())
i->dump();
}
template <class T>
inline void
res_list<T>::raw_dump(void)
{
int j = 0;
res_element *p;
for (iterator i=head(); !i.isnull(); i=i.next()) {
cprintf("Element %d:\n", j);
if (i.notnull()) {
p = i.res_el_ptr();
cprintf(" points to res_element @ %#x\n", p);
p->dump();
cprintf(" Data Element:\n");
i->dump();
}
else {
cprintf(" NULL iterator!\n");
}
++j;
}
}
#endif // __RES_LIST_HH__