Index: trunk/include/iprt/cpp/list.h
===================================================================
--- trunk/include/iprt/cpp/list.h	(revision 36523)
+++ trunk/include/iprt/cpp/list.h	(revision 36524)
@@ -78,4 +78,18 @@
  * they are save to use.
  *
+ * Please note that the return type of some of the getter methods are slightly
+ * different depending on the list type. Native types return the item by value,
+ * items with a size greater than sizeof(void*) by reference. As native types
+ * saved directly in the internal array, returning a reference to them (and
+ * saving them in a reference as well) would make them invalid (or pointing to
+ * a wrong item) when the list is changed in the meanwhile. Returning a
+ * reference for bigger types isn't problematic and makes sure we get out the
+ * best speed of the list. The one exception to this rule is the index
+ * operator[]. This operator always return a reference to make it possible to
+ * use it as a lvalue. Its your responsibility to make sure the list isn't
+ * changed when using the value as reference returned by this operator.
+ *
+ * The list class is reentrant. For a thread-safe variant see mtlist.
+ *
  * Implementation details:
  * It is possible to specialize any type. This might be necessary to get the
@@ -90,4 +104,23 @@
  * @{
  */
+
+/**
+ * The guard definition.
+ */
+template <bool G>
+class ListGuard;
+
+/**
+ * The default guard which does nothing.
+ */
+template <>
+class ListGuard<false>
+{
+public:
+    inline void enterRead() const {}
+    inline void leaveRead() const {}
+    inline void enterWrite() {}
+    inline void leaveWrite() {}
+};
 
 /**
@@ -136,7 +169,14 @@
  * list interface to the user.
  */
-template <class T, typename TYPE>
+template <class T, typename ITYPE, bool MT>
 class ListBase
 {
+    /**
+     * Defines the return type of most of the getter methods. If the internal
+     * used type is a pointer, we return a reference. If not we return by
+     * value.
+     */
+    typedef typename if_ptr<ITYPE, T&, T>::result GET_RTYPE;
+
 public:
     /**
@@ -165,5 +205,5 @@
      * @throws  std::bad_alloc
      */
-    ListBase(const ListBase<T, TYPE>& other)
+    ListBase(const ListBase<T, ITYPE, MT>& other)
       : m_pArray(0)
       , m_cSize(0)
@@ -171,5 +211,5 @@
     {
         realloc_grow(other.m_cSize);
-        ListHelper<T, list_type>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize);
+        ListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize);
         m_cSize = other.m_cSize;
     }
@@ -180,5 +220,5 @@
     ~ListBase()
     {
-        ListHelper<T, list_type>::eraseRange(m_pArray, 0, m_cSize);
+        ListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize);
         if (m_pArray)
             RTMemFree(m_pArray);
@@ -196,5 +236,10 @@
      * @throws  std::bad_alloc
      */
-    void setCapacity(size_t cCapacity) { realloc(cCapacity); }
+    void setCapacity(size_t cCapacity)
+    {
+        m_guard.enterWrite();
+        realloc(cCapacity);
+        m_guard.leaveWrite();
+    }
 
     /**
@@ -227,11 +272,13 @@
      * @throws  std::bad_alloc
      */
-    ListBase<T, TYPE> &insert(size_t i, const T &val)
-    {
+    ListBase<T, ITYPE, MT> &insert(size_t i, const T &val)
+    {
+        m_guard.enterWrite();
         if (m_cSize == m_cCapacity)
             realloc_grow(m_cCapacity + DefaultCapacity);
-        memmove(&m_pArray[i + 1], &m_pArray[i], (m_cSize - i) * sizeof(list_type));
-        ListHelper<T, list_type>::set(m_pArray, i, val);
+        memmove(&m_pArray[i + 1], &m_pArray[i], (m_cSize - i) * sizeof(ITYPE));
+        ListHelper<T, ITYPE>::set(m_pArray, i, val);
         ++m_cSize;
+        m_guard.leaveWrite();
 
         return *this;
@@ -245,5 +292,5 @@
      * @throws  std::bad_alloc
      */
-    ListBase<T, TYPE> &prepend(const T &val)
+    ListBase<T, ITYPE, MT> &prepend(const T &val)
     {
         return insert(0, val);
@@ -257,11 +304,13 @@
      * @throws  std::bad_alloc
      */
-    ListBase<T, TYPE> &prepend(const ListBase<T, TYPE> &other)
-    {
+    ListBase<T, ITYPE, MT> &prepend(const ListBase<T, ITYPE, MT> &other)
+    {
+        m_guard.enterWrite();
         if (m_cCapacity - m_cSize < other.m_cSize)
             realloc_grow(m_cCapacity + (other.m_cSize - (m_cCapacity - m_cSize)));
-        memmove(&m_pArray[other.m_cSize], &m_pArray[0], m_cSize * sizeof(list_type));
-        ListHelper<T, list_type>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize);
+        memmove(&m_pArray[other.m_cSize], &m_pArray[0], m_cSize * sizeof(ITYPE));
+        ListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize);
         m_cSize += other.m_cSize;
+        m_guard.leaveWrite();
 
         return *this;
@@ -275,10 +324,12 @@
      * @throws  std::bad_alloc
      */
-    ListBase<T, TYPE> &append(const T &val)
-    {
+    ListBase<T, ITYPE, MT> &append(const T &val)
+    {
+        m_guard.enterWrite();
         if (m_cSize == m_cCapacity)
             realloc_grow(m_cCapacity + DefaultCapacity);
-        ListHelper<T, list_type>::set(m_pArray, m_cSize, val);
+        ListHelper<T, ITYPE>::set(m_pArray, m_cSize, val);
         ++m_cSize;
+        m_guard.leaveWrite();
 
         return *this;
@@ -292,10 +343,12 @@
      * @throws  std::bad_alloc
      */
-    ListBase<T, TYPE> &append(const ListBase<T, TYPE> &other)
-    {
+    ListBase<T, ITYPE, MT> &append(const ListBase<T, ITYPE, MT> &other)
+    {
+        m_guard.enterWrite();
         if (m_cCapacity - m_cSize < other.m_cSize)
             realloc_grow(m_cCapacity + (other.m_cSize - (m_cCapacity - m_cSize)));
-        ListHelper<T, list_type>::copyTo(m_pArray, other.m_pArray, m_cSize, other.m_cSize);
+        ListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, m_cSize, other.m_cSize);
         m_cSize += other.m_cSize;
+        m_guard.leaveWrite();
 
         return *this;
@@ -309,5 +362,5 @@
      * @return  a reference to this list.
      */
-    ListBase<T, TYPE> &operator=(const ListBase<T, TYPE>& other)
+    ListBase<T, ITYPE, MT> &operator=(const ListBase<T, ITYPE, MT>& other)
     {
         /* Prevent self assignment */
@@ -315,6 +368,7 @@
             return *this;
 
+        m_guard.enterWrite();
         /* Values cleanup */
-        ListHelper<T, list_type>::eraseRange(m_pArray, 0, m_cSize);
+        ListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize);
 
         /* Copy */
@@ -322,5 +376,6 @@
             realloc_grow(other.m_cSize);
         m_cSize = other.m_cSize;
-        ListHelper<T, list_type>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize);
+        ListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize);
+        m_guard.leaveWrite();
 
         return *this;
@@ -337,8 +392,10 @@
      * @return  a reference to this list.
      */
-    ListBase<T, TYPE> &replace(size_t i, const T &val)
-    {
-        ListHelper<T, list_type>::erase(m_pArray, i);
-        ListHelper<T, list_type>::set(m_pArray, i, val);
+    ListBase<T, ITYPE, MT> &replace(size_t i, const T &val)
+    {
+        m_guard.enterWrite();
+        ListHelper<T, ITYPE>::erase(m_pArray, i);
+        ListHelper<T, ITYPE>::set(m_pArray, i, val);
+        m_guard.leaveWrite();
 
         return *this;
@@ -346,5 +403,5 @@
 
     /**
-     * Return the first item as constant reference.
+     * Return the first item as constant object.
      *
      * @note No boundary checks are done. Make sure @a i is equal or greater zero
@@ -353,11 +410,14 @@
      * @return   The first item.
      */
-    const T &first() const
-    {
-        return ListHelper<T, list_type>::at(m_pArray, 0);
-    }
-
-    /**
-     * Return the first item as mutable reference.
+    const GET_RTYPE first() const
+    {
+        m_guard.enterRead();
+        const GET_RTYPE res = ListHelper<T, ITYPE>::at(m_pArray, 0);
+        m_guard.leaveRead();
+        return res;
+    }
+
+    /**
+     * Return the first item.
      *
      * @note No boundary checks are done. Make sure @a i is equal or greater zero
@@ -366,11 +426,14 @@
      * @return   The first item.
      */
-    T &first()
-    {
-        return ListHelper<T, list_type>::at(m_pArray, 0);
-    }
-
-    /**
-     * Return the last item as constant reference.
+    GET_RTYPE first()
+    {
+        m_guard.enterRead();
+        GET_RTYPE res = ListHelper<T, ITYPE>::at(m_pArray, 0);
+        m_guard.leaveRead();
+        return res;
+    }
+
+    /**
+     * Return the last item as constant object.
      *
      * @note No boundary checks are done. Make sure @a i is equal or greater zero
@@ -379,11 +442,14 @@
      * @return   The last item.
      */
-    const T &last() const
-    {
-        return ListHelper<T, list_type>::at(m_pArray, m_cSize - 1);
-    }
-
-    /**
-     * Return the last item as mutable reference.
+    const GET_RTYPE last() const
+    {
+        m_guard.enterRead();
+        const GET_RTYPE res = ListHelper<T, ITYPE>::at(m_pArray, m_cSize - 1);
+        m_guard.leaveRead();
+        return res;
+    }
+
+    /**
+     * Return the last item.
      *
      * @note No boundary checks are done. Make sure @a i is equal or greater zero
@@ -392,11 +458,14 @@
      * @return   The last item.
      */
-    T &last()
-    {
-        return ListHelper<T, list_type>::at(m_pArray, m_cSize - 1);
-    }
-
-    /**
-     * Return the item at position @a i as constant reference.
+    GET_RTYPE last()
+    {
+        m_guard.enterRead();
+        GET_RTYPE res = ListHelper<T, ITYPE>::at(m_pArray, m_cSize - 1);
+        m_guard.leaveRead();
+        return res;
+    }
+
+    /**
+     * Return the item at position @a i as constant object.
      *
      * @note No boundary checks are done. Make sure @a i is equal or greater zero
@@ -406,11 +475,14 @@
      * @return  The item at position @a i.
      */
-    const T &at(size_t i) const
-    {
-        return ListHelper<T, list_type>::at(m_pArray, i);
-    }
-
-    /**
-     * Return the item at position @a i as mutable reference.
+    const GET_RTYPE at(size_t i) const
+    {
+        m_guard.enterRead();
+        const GET_RTYPE res = ListHelper<T, ITYPE>::at(m_pArray, i);
+        m_guard.leaveRead();
+        return res;
+    }
+
+    /**
+     * Return the item at position @a i.
      *
      * @note No boundary checks are done. Make sure @a i is equal or greater zero
@@ -420,7 +492,10 @@
      * @return   The item at position @a i.
      */
-    T &at(size_t i)
-    {
-        return ListHelper<T, list_type>::at(m_pArray, i);
+    GET_RTYPE at(size_t i)
+    {
+        m_guard.enterRead();
+        GET_RTYPE res = ListHelper<T, ITYPE>::at(m_pArray, i);
+        m_guard.leaveRead();
+        return res;
     }
 
@@ -436,5 +511,8 @@
     T &operator[](size_t i)
     {
-        return ListHelper<T, list_type>::at(m_pArray, i);
+        m_guard.enterRead();
+        T &res = ListHelper<T, ITYPE>::at(m_pArray, i);
+        m_guard.leaveRead();
+        return res;
     }
 
@@ -448,7 +526,13 @@
     T value(size_t i) const
     {
+        m_guard.enterRead();
         if (i >= m_cSize)
+        {
+            m_guard.leaveRead();
             return T();
-        return ListHelper<T, list_type>::at(m_pArray, i);
+        }
+        T res = ListHelper<T, ITYPE>::at(m_pArray, i);
+        m_guard.leaveRead();
+        return res;
     }
 
@@ -463,7 +547,13 @@
     T value(size_t i, const T &defaultVal) const
     {
+        m_guard.enterRead();
         if (i >= m_cSize)
+        {
+            m_guard.leaveRead();
             return defaultVal;
-        return ListHelper<T, list_type>::at(m_pArray, i);
+        }
+        T res = ListHelper<T, ITYPE>::at(m_pArray, i);
+        m_guard.leaveRead();
+        return res;
     }
 
@@ -478,9 +568,11 @@
     void removeAt(size_t i)
     {
-        ListHelper<T, list_type>::erase(m_pArray, i);
+        m_guard.enterWrite();
+        ListHelper<T, ITYPE>::erase(m_pArray, i);
         /* Not last element? */
         if (i < m_cSize - 1)
-            memmove(&m_pArray[i], &m_pArray[i + 1], (m_cSize - i - 1) * sizeof(list_type));
+            memmove(&m_pArray[i], &m_pArray[i + 1], (m_cSize - i - 1) * sizeof(ITYPE));
         --m_cSize;
+        m_guard.leaveWrite();
     }
 
@@ -497,9 +589,11 @@
     void removeRange(size_t iFrom, size_t iTo)
     {
-        ListHelper<T, list_type>::eraseRange(m_pArray, iFrom, iTo - iFrom);
+        m_guard.enterWrite();
+        ListHelper<T, ITYPE>::eraseRange(m_pArray, iFrom, iTo - iFrom);
         /* Not last elements? */
         if (m_cSize - iTo > 0)
-            memmove(&m_pArray[iFrom], &m_pArray[iTo], (m_cSize - iTo) * sizeof(list_type));
+            memmove(&m_pArray[iFrom], &m_pArray[iTo], (m_cSize - iTo) * sizeof(ITYPE));
         m_cSize -= iTo - iFrom;
+        m_guard.leaveWrite();
     }
 
@@ -509,9 +603,11 @@
     void clear()
     {
+        m_guard.enterWrite();
         /* Values cleanup */
-        ListHelper<T, list_type>::eraseRange(m_pArray, 0, m_cSize);
+        ListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize);
         if (m_cSize != DefaultCapacity)
             realloc_grow(DefaultCapacity);
         m_cSize = 0;
+        m_guard.leaveWrite();
     }
 
@@ -536,5 +632,5 @@
             && m_pArray)
         {
-            ListHelper<T, list_type>::eraseRange(m_pArray, cNewSize, m_cSize - cNewSize);
+            ListHelper<T, ITYPE>::eraseRange(m_pArray, cNewSize, m_cSize - cNewSize);
             m_cSize -= m_cSize - cNewSize;
         }
@@ -552,5 +648,5 @@
         if (cNewSize > 0)
         {
-            m_pArray = static_cast<list_type*>(RTMemRealloc(m_pArray, sizeof(list_type) * cNewSize));
+            m_pArray = static_cast<ITYPE*>(RTMemRealloc(m_pArray, sizeof(ITYPE) * cNewSize));
             if (!m_pArray)
             {
@@ -574,5 +670,5 @@
         /* Resize the array. */
         m_cCapacity = cNewSize;
-        m_pArray = static_cast<list_type*>(RTMemRealloc(m_pArray, sizeof(list_type) * cNewSize));
+        m_pArray = static_cast<ITYPE*>(RTMemRealloc(m_pArray, sizeof(ITYPE) * cNewSize));
         if (!m_pArray)
         {
@@ -586,23 +682,16 @@
     }
 
-    /**
-     * Which type of list should be created. This depends on the size of T. If
-     * T is a native type (int, bool, ptr, ...), the list will contain the
-     * values itself. If the size is bigger than the size of a void*, the list
-     * contains pointers to the values. This could be specialized like for the
-     * 64-bit integer types.
-     */
-    typedef TYPE list_type;
-
     /** The internal list array. */
-    list_type *m_pArray;
+    ITYPE *m_pArray;
     /** The current count of items in use. */
     size_t m_cSize;
     /** The current capacity of the internal array. */
     size_t m_cCapacity;
+    /** The guard used to serialize the access to the items. */
+    ListGuard<MT> m_guard;
 };
 
-template <class T, typename TYPE>
-const size_t ListBase<T, TYPE>::DefaultCapacity = 10;
+template <class T, typename ITYPE, bool MT>
+const size_t ListBase<T, ITYPE, MT>::DefaultCapacity = 10;
 
 /**
@@ -611,9 +700,9 @@
  * @see ListBase
  */
-template <class T, typename TYPE = typename if_<(sizeof(T) > sizeof(void*)), T*, T>::result>
-class list : public ListBase<T, TYPE> {};
+template <class T, typename ITYPE = typename if_<(sizeof(T) > sizeof(void*)), T*, T>::result>
+class list : public ListBase<T, ITYPE, false> {};
 
 /**
- * Specialization class for using the native type list for unsigned 64-bit
+ * Specialized class for using the native type list for unsigned 64-bit
  * values even on a 32-bit host.
  *
@@ -621,8 +710,8 @@
  */
 template <>
-class list<uint64_t>: public ListBase<uint64_t, uint64_t> {};
+class list<uint64_t>: public ListBase<uint64_t, uint64_t, false> {};
 
 /**
- * Specialization class for using the native type list for signed 64-bit
+ * Specialized class for using the native type list for signed 64-bit
  * values even on a 32-bit host.
  *
@@ -630,5 +719,5 @@
  */
 template <>
-class list<int64_t>: public ListBase<int64_t, int64_t> {};
+class list<int64_t>: public ListBase<int64_t, int64_t, false> {};
 
 /** @} */
Index: trunk/include/iprt/cpp/meta.h
===================================================================
--- trunk/include/iprt/cpp/meta.h	(revision 36523)
+++ trunk/include/iprt/cpp/meta.h	(revision 36524)
@@ -70,4 +70,36 @@
 };
 
+/**
+ * Check if @a T is a pointer or not at compile time and dependent of the
+ * result TrueResult or FalseResult will be defined.
+ *
+ * False version of if_ptr.
+ *
+ * @param   Condition     Condition to check.
+ * @param   TrueResult    Result when condition is true.
+ * @param   FalseResult   Result when condition is false
+ */
+template <class T, typename TrueResult, typename FalseResult>
+struct if_ptr
+{
+    typedef FalseResult result;
+};
+
+/**
+ * Check if @a T is a pointer or not at compile time and dependent of the
+ * result TrueResult or FalseResult will be defined.
+ *
+ * True specialization of of_ptr.
+ *
+ * @param   Condition     Condition to check.
+ * @param   TrueResult    Result when condition is true.
+ * @param   FalseResult   Result when condition is false
+ */
+template <class T, typename TrueResult, typename FalseResult>
+struct if_ptr<T*, TrueResult, FalseResult>
+{
+    typedef TrueResult result;
+};
+
 /** @} */
 
Index: trunk/include/iprt/cpp/mtlist.h
===================================================================
--- trunk/include/iprt/cpp/mtlist.h	(revision 36524)
+++ trunk/include/iprt/cpp/mtlist.h	(revision 36524)
@@ -0,0 +1,100 @@
+/** @file
+ * IPRT - Generic thread-safe list Class.
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_cpp_mtlist_h
+#define ___iprt_cpp_mtlist_h
+
+#include <iprt/cpp/list.h>
+
+#include <iprt/semaphore.h>
+
+namespace iprt
+{
+
+/** @addtogroup grp_rt_cpp_list
+ * @{
+ */
+
+/**
+ * A guard class for thread-safe read/write access.
+ */
+template <>
+class ListGuard<true>
+{
+public:
+    ListGuard() { int rc = RTSemRWCreate(&m_hRWSem); AssertRC(rc); }
+    ~ListGuard() { RTSemRWDestroy(m_hRWSem); }
+    inline void enterRead() const { int rc = RTSemRWRequestRead(m_hRWSem, RT_INDEFINITE_WAIT); AssertRC(rc); }
+    inline void leaveRead() const { int rc = RTSemRWReleaseRead(m_hRWSem); AssertRC(rc); }
+    inline void enterWrite()      { int rc = RTSemRWRequestWrite(m_hRWSem, RT_INDEFINITE_WAIT); AssertRC(rc); }
+    inline void leaveWrite()      { int rc = RTSemRWReleaseWrite(m_hRWSem); AssertRC(rc); }
+
+private:
+    mutable RTSEMRW m_hRWSem;
+};
+
+/**
+ * @brief Generic thread-safe list class.
+ *
+ * mtlist is a thread-safe implementation of the list class. It uses a
+ * read/write semaphore to serialize the access to the items. Several readers
+ * can simultaneous access different or the same item. If one thread is writing
+ * to an item, the other accessors are blocked until the write has finished.
+ *
+ * Although the access is guarded, the user has to make sure the list content
+ * is consistent when iterating over the list or doing any other kind of access
+ * which makes assumptions about the list content. For a finer control of access
+ * restrictions, use your own locking mechanism and the standard list
+ * implementation.
+ *
+ * @see ListBase
+ */
+template <class T, typename ITYPE = typename if_<(sizeof(T) > sizeof(void*)), T*, T>::result>
+class mtlist : public ListBase<T, ITYPE, true> {};
+
+/**
+ * Specialized thread-safe list class for using the native type list for
+ * unsigned 64-bit values even on a 32-bit host.
+ *
+ * @see ListBase
+ */
+template <>
+class mtlist<uint64_t>: public ListBase<uint64_t, uint64_t, true> {};
+
+/**
+ * Specialized thread-safe list class for using the native type list for
+ * signed 64-bit values even on a 32-bit host.
+ *
+ * @see ListBase
+ */
+template <>
+class mtlist<int64_t>: public ListBase<int64_t, uint64_t, true> {};
+
+/** @} */
+
+} /* namespace iprt */
+
+#endif /* !___iprt_cpp_mtlist_h */
+
Index: trunk/include/iprt/semaphore.h
===================================================================
--- trunk/include/iprt/semaphore.h	(revision 36523)
+++ trunk/include/iprt/semaphore.h	(revision 36524)
@@ -40,5 +40,5 @@
  * This module implements all kinds of event and mutex semaphores; in addition
  * to these, IPRT implements "critical sections", which are fast recursive
- * mutexes (see @ref grp_rt_critsect ).  C++ users may find @ref grp_rt_lock
+ * mutexes (see @ref grp_rt_critsect ).  C++ users may find @ref grp_rt_cpp_lock
  * interesting.
  *
