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 <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.)
|
||||
|
||||
@@ -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