/* $Id: objectslist.h 69500 2017-10-28 15:14:05Z vboxsync $ */ /** @file * * List of COM objects */ /* * Copyright (C) 2009-2017 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. */ #ifndef ____H_OBJECTSLIST #define ____H_OBJECTSLIST #include #include /** * Implements a "flat" objects list with a lock. Since each such list * has its own lock it is not a good idea to implement trees with this. * * ObjectList is designed to behave as if it were a std::list of * COM pointers of class T; in other words, * ObjectList behaves like std::list< ComObjPtr > but * it's less typing. Iterators, front(), size(), begin() and end() * are implemented. * * In addition it automatically includes an RWLockHandle which can be * accessed with getLockHandle(). * * If you need the raw std::list for some reason you can access it with * getList(). * * The destructor automatically calls uninit() on every contained * COM object. If this is not desired, clear the member list before * deleting the list object. */ template class ObjectsList { public: typedef ComObjPtr MyType; typedef std::list MyList; typedef typename MyList::iterator iterator; typedef typename MyList::const_iterator const_iterator; // typename is necessary to disambiguate "::iterator" in templates; see // the "this might hurt your head" part in // http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18 ObjectsList(RWLockHandle &lockHandle) : m_lock(lockHandle) { } ~ObjectsList() { uninitAll(); } private: // prohibit copying and assignment ObjectsList(const ObjectsList &d); ObjectsList& operator=(const ObjectsList &d); public: /** * Returns the lock handle which protects this list, for use with * AutoReadLock or AutoWriteLock. */ RWLockHandle& getLockHandle() { return m_lock; } /** * Calls m_ll.push_back(p) with locking. * @param p */ void addChild(MyType p) { AutoWriteLock al(m_lock COMMA_LOCKVAL_SRC_POS); m_ll.push_back(p); } /** * Calls m_ll.remove(p) with locking. Does NOT call uninit() * on the contained object. * @param p */ void removeChild(MyType p) { AutoWriteLock al(m_lock COMMA_LOCKVAL_SRC_POS); m_ll.remove(p); } /** * Appends all objects from another list to the member list. * Locks the other list for reading but does not lock "this" * (because it might be on the caller's stack and needs no * locking). * @param ll */ void appendOtherList(ObjectsList &ll) { AutoReadLock alr(ll.getLockHandle() COMMA_LOCKVAL_SRC_POS); for (const_iterator it = ll.begin(); it != ll.end(); ++it) { m_ll.push_back(*it); } } /** * Calls uninit() on every COM object on the list and then * clears the list, with locking. */ void uninitAll() { /* The implementation differs from the high level description, because * it isn't safe to hold any locks when invoking uninit() methods. It * leads to incorrect lock order (first lock, then the Caller related * event semaphore) and thus deadlocks. Dropping the lock is vital, * and means we can't rely on iterators while not holding the lock. */ AutoWriteLock al(m_lock COMMA_LOCKVAL_SRC_POS); while (!m_ll.empty()) { /* Need a copy of the element, have to delete the entry before * dropping the lock, otherwise someone else might mess with the * list in the mean time, leading to erratic behavior. */ MyType q = m_ll.front(); m_ll.pop_front(); al.release(); q->uninit(); al.acquire(); } } /** * Returns the no. of objects on the list (std::list compatibility) * with locking. */ size_t size() { AutoReadLock al(m_lock COMMA_LOCKVAL_SRC_POS); return m_ll.size(); } /** * Returns a raw pointer to the member list of objects. * Does not lock! * @return */ MyList& getList() { return m_ll; } /** * Returns the first object on the list (std::list compatibility) * with locking. */ MyType front() { AutoReadLock al(m_lock COMMA_LOCKVAL_SRC_POS); return m_ll.front(); } /** * Returns the begin iterator from the list (std::list compatibility). * Does not lock! * @return */ iterator begin() { return m_ll.begin(); } /** * Returns the end iterator from the list (std::list compatibility). * Does not lock! */ iterator end() { return m_ll.end(); } void insert(iterator it, MyType &p) { m_ll.insert(it, p); } void erase(iterator it) { m_ll.erase(it); } private: MyList m_ll; RWLockHandle &m_lock; }; #endif