/* * Copyright 2013 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Paweł Dziepak, pdziepak@quarnos.org */ #ifndef RUN_QUEUE_H #define RUN_QUEUE_H #include #include "scheduler_profiler.h" template struct RunQueueLink { RunQueueLink(); unsigned int fPriority; Element* fPrevious; Element* fNext; }; template class RunQueueLinkImpl { public: inline RunQueueLink* GetRunQueueLink(); private: RunQueueLink fRunQueueLink; }; template class RunQueueStandardGetLink { private: typedef RunQueueLink Link; public: inline Link* operator()(Element* element) const; }; template Element::*LinkMember> class RunQueueMemberGetLink { private: typedef RunQueueLink Link; public: inline Link* operator()(Element* element) const; }; #define RUN_QUEUE_TEMPLATE_LIST \ template #define RUN_QUEUE_CLASS_NAME RunQueue template > class RunQueue { public: class ConstIterator { public: ConstIterator(); ConstIterator(const RunQueue* 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() const; 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: struct PriorityEntry : public HeapLinkImpl { }; typedef Heap > PriorityHeap; status_t fInitStatus; PriorityEntry fPriorityEntries[MaxPriority + 1]; PriorityHeap fPriorityHeap; Element* fHeads[MaxPriority + 1]; Element* fTails[MaxPriority + 1]; static GetLink sGetLink; }; template RunQueueLink::RunQueueLink() : fPrevious(NULL), fNext(NULL) { } template RunQueueLink* RunQueueLinkImpl::GetRunQueueLink() { return &fRunQueueLink; } template RunQueueLink* RunQueueStandardGetLink::operator()(Element* element) const { return element->GetRunQueueLink(); } template Element::*LinkMember> RunQueueLink* RunQueueMemberGetLink::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* 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* 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() : fInitStatus(B_OK), fPriorityHeap(MaxPriority + 1) { 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() const { SCHEDULER_ENTER_FUNCTION(); PriorityEntry* maxPriority = fPriorityHeap.PeekRoot(); if (maxPriority == NULL) return NULL; unsigned int priority = PriorityHeap::GetKey(maxPriority); ASSERT(priority <= MaxPriority); ASSERT(fHeads[priority] != NULL); Element* element = fHeads[priority]; ASSERT(sGetLink(element)->fPriority == priority); ASSERT(fTails[priority] != NULL); ASSERT(sGetLink(element)->fPrevious == NULL); return element; } RUN_QUEUE_TEMPLATE_LIST void RUN_QUEUE_CLASS_NAME::PushFront(Element* element, unsigned int priority) { SCHEDULER_ENTER_FUNCTION(); ASSERT(priority <= MaxPriority); RunQueueLink* 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] != NULL) sGetLink(fHeads[priority])->fPrevious = element; else { fTails[priority] = element; fPriorityHeap.Insert(&fPriorityEntries[priority], priority); } fHeads[priority] = element; } RUN_QUEUE_TEMPLATE_LIST void RUN_QUEUE_CLASS_NAME::PushBack(Element* element, unsigned int priority) { SCHEDULER_ENTER_FUNCTION(); ASSERT(priority <= MaxPriority); RunQueueLink* 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] != NULL) sGetLink(fTails[priority])->fNext = element; else { fHeads[priority] = element; fPriorityHeap.Insert(&fPriorityEntries[priority], priority); } fTails[priority] = element; } RUN_QUEUE_TEMPLATE_LIST void RUN_QUEUE_CLASS_NAME::Remove(Element* element) { SCHEDULER_ENTER_FUNCTION(); RunQueueLink* 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) { fPriorityHeap.ModifyKey(&fPriorityEntries[priority], MaxPriority + 1); ASSERT(fPriorityHeap.PeekRoot() == &fPriorityEntries[priority]); fPriorityHeap.RemoveRoot(); } elementLink->fPrevious = NULL; elementLink->fNext = NULL; } RUN_QUEUE_TEMPLATE_LIST Element* RUN_QUEUE_CLASS_NAME::GetHead(unsigned int priority) const { SCHEDULER_ENTER_FUNCTION(); 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); } RUN_QUEUE_TEMPLATE_LIST GetLink RUN_QUEUE_CLASS_NAME::sGetLink; RUN_QUEUE_TEMPLATE_LIST GetLink RUN_QUEUE_CLASS_NAME::ConstIterator::sGetLink; #endif // RUN_QUEUE_H