kernel: Add O(1) lookup and insertion priority queue

This commit is contained in:
Pawel Dziepak
2013-10-05 20:16:06 +02:00
parent 7039b950fb
commit b8c1df9b00
3 changed files with 412 additions and 1 deletions
+56
View File
@@ -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
+3 -1
View File
@@ -17,6 +17,7 @@
#include <heap.h>
#include <ksignal.h>
#include <lock.h>
#include <RunQueueLink.h>
#include <smp.h>
#include <thread_defs.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
// handlers (signals pending, user debugging
// enabled, etc.)
+353
View File
@@ -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