kernel: Add O(1) lookup and insertion priority queue
This commit is contained in:
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Paweł Dziepak, [email protected]
|
||||||
|
*/
|
||||||
|
#ifndef RUN_QUEUE_LINK_H
|
||||||
|
#define RUN_QUEUE_LINK_H
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Element>
|
||||||
|
struct RunQueueLink {
|
||||||
|
RunQueueLink();
|
||||||
|
|
||||||
|
unsigned int fPriority;
|
||||||
|
Element* fPrevious;
|
||||||
|
Element* fNext;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Element>
|
||||||
|
class RunQueueLinkImpl {
|
||||||
|
public:
|
||||||
|
inline RunQueueLink<Element>* GetRunQueueLink();
|
||||||
|
|
||||||
|
private:
|
||||||
|
RunQueueLink<Element> fRunQueueLink;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if KDEBUG
|
||||||
|
template<typename Element>
|
||||||
|
RunQueueLink<Element>::RunQueueLink()
|
||||||
|
:
|
||||||
|
fPrevious(NULL),
|
||||||
|
fNext(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template<typename Element>
|
||||||
|
RunQueueLink<Element>::RunQueueLink()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Element>
|
||||||
|
RunQueueLink<Element>*
|
||||||
|
RunQueueLinkImpl<Element>::GetRunQueueLink()
|
||||||
|
{
|
||||||
|
return &fRunQueueLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // RUN_QUEUE_LINK_H
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <heap.h>
|
#include <heap.h>
|
||||||
#include <ksignal.h>
|
#include <ksignal.h>
|
||||||
#include <lock.h>
|
#include <lock.h>
|
||||||
|
#include <RunQueueLink.h>
|
||||||
#include <smp.h>
|
#include <smp.h>
|
||||||
#include <thread_defs.h>
|
#include <thread_defs.h>
|
||||||
#include <timer.h>
|
#include <timer.h>
|
||||||
@@ -409,7 +410,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Thread : TeamThreadIteratorEntry<thread_id>, KernelReferenceable {
|
struct Thread : TeamThreadIteratorEntry<thread_id>, KernelReferenceable,
|
||||||
|
RunQueueLinkImpl<Thread> {
|
||||||
int32 flags; // summary of events relevant in interrupt
|
int32 flags; // summary of events relevant in interrupt
|
||||||
// handlers (signals pending, user debugging
|
// handlers (signals pending, user debugging
|
||||||
// enabled, etc.)
|
// enabled, etc.)
|
||||||
|
|||||||
@@ -0,0 +1,353 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Paweł Dziepak, [email protected]
|
||||||
|
*/
|
||||||
|
#ifndef RUN_QUEUE_H
|
||||||
|
#define RUN_QUEUE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <RunQueueLink.h>
|
||||||
|
#include <util/Bitmap.h>
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Element>
|
||||||
|
class RunQueueStandardGetLink {
|
||||||
|
private:
|
||||||
|
typedef RunQueueLink<Element> Link;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline Link* operator()(Element* element) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Element, RunQueueLink<Element> Element::*LinkMember>
|
||||||
|
class RunQueueMemberGetLink {
|
||||||
|
private:
|
||||||
|
typedef RunQueueLink<Element> Link;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline Link* operator()(Element* element) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RUN_QUEUE_TEMPLATE_LIST \
|
||||||
|
template<typename Element, unsigned int MaxPriority, typename GetLink>
|
||||||
|
#define RUN_QUEUE_CLASS_NAME RunQueue<Element, MaxPriority, GetLink>
|
||||||
|
|
||||||
|
template<typename Element, unsigned int MaxPriority,
|
||||||
|
typename GetLink = RunQueueStandardGetLink<Element> >
|
||||||
|
class RunQueue {
|
||||||
|
public:
|
||||||
|
class ConstIterator {
|
||||||
|
public:
|
||||||
|
ConstIterator();
|
||||||
|
ConstIterator(const RunQueue<Element,
|
||||||
|
MaxPriority, GetLink>* list);
|
||||||
|
|
||||||
|
inline ConstIterator& operator=(const ConstIterator& other);
|
||||||
|
|
||||||
|
bool HasNext() const;
|
||||||
|
Element* Next();
|
||||||
|
|
||||||
|
void Rewind();
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void _FindNextPriority();
|
||||||
|
|
||||||
|
const RUN_QUEUE_CLASS_NAME* fList;
|
||||||
|
unsigned int fPriority;
|
||||||
|
Element* fNext;
|
||||||
|
|
||||||
|
static GetLink sGetLink;
|
||||||
|
};
|
||||||
|
|
||||||
|
RunQueue();
|
||||||
|
|
||||||
|
inline status_t GetInitStatus();
|
||||||
|
|
||||||
|
inline Element* PeekMaximum();
|
||||||
|
inline Element* PeekSecondMaximum();
|
||||||
|
|
||||||
|
inline void PushFront(Element* element, unsigned int priority);
|
||||||
|
inline void PushBack(Element* elementt, unsigned int priority);
|
||||||
|
|
||||||
|
inline void Remove(Element* element);
|
||||||
|
|
||||||
|
inline Element* GetHead(unsigned int priority) const;
|
||||||
|
|
||||||
|
inline ConstIterator GetConstIterator() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t fInitStatus;
|
||||||
|
|
||||||
|
Bitmap fBitmap;
|
||||||
|
|
||||||
|
Element* fHeads[MaxPriority + 1];
|
||||||
|
Element* fTails[MaxPriority + 1];
|
||||||
|
|
||||||
|
static GetLink sGetLink;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Element>
|
||||||
|
RunQueueLink<Element>*
|
||||||
|
RunQueueStandardGetLink<Element>::operator()(Element* element) const
|
||||||
|
{
|
||||||
|
return element->GetRunQueueLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Element, RunQueueLink<Element> Element::*LinkMember>
|
||||||
|
RunQueueLink<Element>*
|
||||||
|
RunQueueMemberGetLink<Element, LinkMember>::operator()(Element* element) const
|
||||||
|
{
|
||||||
|
return &(element->*LinkMember);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
RUN_QUEUE_CLASS_NAME::ConstIterator::ConstIterator()
|
||||||
|
:
|
||||||
|
fList(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
RUN_QUEUE_CLASS_NAME::ConstIterator::ConstIterator(const RunQueue<Element,
|
||||||
|
MaxPriority, GetLink>* list)
|
||||||
|
:
|
||||||
|
fList(list)
|
||||||
|
{
|
||||||
|
Rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
typename RUN_QUEUE_CLASS_NAME::ConstIterator&
|
||||||
|
RUN_QUEUE_CLASS_NAME::ConstIterator::operator=(const ConstIterator& other)
|
||||||
|
{
|
||||||
|
fList = other.fList;
|
||||||
|
fPriority = other.fPriority;
|
||||||
|
fNext = other.fNext;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
bool
|
||||||
|
RUN_QUEUE_CLASS_NAME::ConstIterator::HasNext() const
|
||||||
|
{
|
||||||
|
return fNext != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
Element*
|
||||||
|
RUN_QUEUE_CLASS_NAME::ConstIterator::Next()
|
||||||
|
{
|
||||||
|
ASSERT(HasNext());
|
||||||
|
|
||||||
|
Element* current = fNext;
|
||||||
|
RunQueueLink<Element>* link = sGetLink(fNext);
|
||||||
|
|
||||||
|
fNext = link->fNext;
|
||||||
|
if (fNext == NULL)
|
||||||
|
_FindNextPriority();
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
void
|
||||||
|
RUN_QUEUE_CLASS_NAME::ConstIterator::Rewind()
|
||||||
|
{
|
||||||
|
ASSERT(fList != NULL);
|
||||||
|
|
||||||
|
fPriority = MaxPriority;
|
||||||
|
fNext = fList->GetHead(fPriority);
|
||||||
|
if (fNext == NULL)
|
||||||
|
_FindNextPriority();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
void
|
||||||
|
RUN_QUEUE_CLASS_NAME::ConstIterator::_FindNextPriority()
|
||||||
|
{
|
||||||
|
ASSERT(fList != NULL);
|
||||||
|
|
||||||
|
while (fPriority-- > 0) {
|
||||||
|
fNext = fList->GetHead(fPriority);
|
||||||
|
if (fNext != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
RUN_QUEUE_CLASS_NAME::RunQueue()
|
||||||
|
:
|
||||||
|
fBitmap(MaxPriority + 1)
|
||||||
|
{
|
||||||
|
fInitStatus = fBitmap.GetInitStatus();
|
||||||
|
|
||||||
|
memset(fHeads, 0, sizeof(fHeads));
|
||||||
|
memset(fTails, 0, sizeof(fTails));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
status_t
|
||||||
|
RUN_QUEUE_CLASS_NAME::GetInitStatus()
|
||||||
|
{
|
||||||
|
return fInitStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
Element*
|
||||||
|
RUN_QUEUE_CLASS_NAME::PeekMaximum()
|
||||||
|
{
|
||||||
|
int priority = fBitmap.GetHighestSet();
|
||||||
|
if (priority < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ASSERT((unsigned int)priority <= MaxPriority);
|
||||||
|
ASSERT(fHeads[priority] != NULL);
|
||||||
|
|
||||||
|
Element* element = fHeads[priority];
|
||||||
|
RunQueueLink<Element>* elementLink = sGetLink(element);
|
||||||
|
|
||||||
|
ASSERT(elementLink->fPriority == (unsigned int)priority);
|
||||||
|
ASSERT(fTails[priority] != NULL);
|
||||||
|
ASSERT(elementLink->fPrevious == NULL);
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
Element*
|
||||||
|
RUN_QUEUE_CLASS_NAME::PeekSecondMaximum()
|
||||||
|
{
|
||||||
|
int priority = fBitmap.GetHighestSet();
|
||||||
|
if (priority < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
fBitmap.Clear(priority);
|
||||||
|
Element* element = PeekMaximum();
|
||||||
|
fBitmap.Set(priority);
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
void
|
||||||
|
RUN_QUEUE_CLASS_NAME::PushFront(Element* element,
|
||||||
|
unsigned int priority)
|
||||||
|
{
|
||||||
|
ASSERT(priority <= MaxPriority);
|
||||||
|
|
||||||
|
RunQueueLink<Element>* elementLink = sGetLink(element);
|
||||||
|
|
||||||
|
ASSERT(elementLink->fPrevious == NULL);
|
||||||
|
ASSERT(elementLink->fNext == NULL);
|
||||||
|
|
||||||
|
ASSERT((fHeads[priority] == NULL && fTails[priority] == NULL)
|
||||||
|
|| (fHeads[priority] != NULL && fTails[priority] != NULL));
|
||||||
|
|
||||||
|
elementLink->fPriority = priority;
|
||||||
|
elementLink->fNext = fHeads[priority];
|
||||||
|
if (fHeads[priority])
|
||||||
|
sGetLink(fHeads[priority])->fPrevious = element;
|
||||||
|
else
|
||||||
|
fTails[priority] = element;
|
||||||
|
fHeads[priority] = element;
|
||||||
|
|
||||||
|
fBitmap.Set(priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
void
|
||||||
|
RUN_QUEUE_CLASS_NAME::PushBack(Element* element,
|
||||||
|
unsigned int priority)
|
||||||
|
{
|
||||||
|
ASSERT(priority <= MaxPriority);
|
||||||
|
|
||||||
|
RunQueueLink<Element>* elementLink = sGetLink(element);
|
||||||
|
|
||||||
|
ASSERT(elementLink->fPrevious == NULL);
|
||||||
|
ASSERT(elementLink->fNext == NULL);
|
||||||
|
|
||||||
|
ASSERT((fHeads[priority] == NULL && fTails[priority] == NULL)
|
||||||
|
|| (fHeads[priority] != NULL && fTails[priority] != NULL));
|
||||||
|
|
||||||
|
elementLink->fPriority = priority;
|
||||||
|
elementLink->fPrevious = fTails[priority];
|
||||||
|
if (fTails[priority])
|
||||||
|
sGetLink(fTails[priority])->fNext = element;
|
||||||
|
else
|
||||||
|
fHeads[priority] = element;
|
||||||
|
fTails[priority] = element;
|
||||||
|
|
||||||
|
fBitmap.Set(priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
void
|
||||||
|
RUN_QUEUE_CLASS_NAME::Remove(Element* element)
|
||||||
|
{
|
||||||
|
RunQueueLink<Element>* elementLink = sGetLink(element);
|
||||||
|
unsigned int priority = elementLink->fPriority;
|
||||||
|
|
||||||
|
ASSERT(elementLink->fPrevious != NULL || fHeads[priority] == element);
|
||||||
|
ASSERT(elementLink->fNext != NULL || fTails[priority] == element);
|
||||||
|
|
||||||
|
if (elementLink->fPrevious != NULL)
|
||||||
|
sGetLink(elementLink->fPrevious)->fNext = elementLink->fNext;
|
||||||
|
else
|
||||||
|
fHeads[priority] = elementLink->fNext;
|
||||||
|
if (elementLink->fNext != NULL)
|
||||||
|
sGetLink(elementLink->fNext)->fPrevious = elementLink->fPrevious;
|
||||||
|
else
|
||||||
|
fTails[priority] = elementLink->fPrevious;
|
||||||
|
|
||||||
|
ASSERT((fHeads[priority] == NULL && fTails[priority] == NULL)
|
||||||
|
|| (fHeads[priority] != NULL && fTails[priority] != NULL));
|
||||||
|
|
||||||
|
if (fHeads[priority] == NULL)
|
||||||
|
fBitmap.Clear(priority);
|
||||||
|
|
||||||
|
#if KDEBUG
|
||||||
|
elementLink->fPrevious = NULL;
|
||||||
|
elementLink->fNext = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
Element*
|
||||||
|
RUN_QUEUE_CLASS_NAME::GetHead(unsigned int priority) const
|
||||||
|
{
|
||||||
|
ASSERT(priority <= MaxPriority);
|
||||||
|
return fHeads[priority];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUN_QUEUE_TEMPLATE_LIST
|
||||||
|
typename RUN_QUEUE_CLASS_NAME::ConstIterator
|
||||||
|
RUN_QUEUE_CLASS_NAME::GetConstIterator() const
|
||||||
|
{
|
||||||
|
return ConstIterator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // RUN_QUEUE_H
|
||||||
|
|
||||||
Reference in New Issue
Block a user