feat: add PollFd, PrioQNode and PrioQueue
This commit is contained in:
1 parent
25f50f156a
commit
8af9a09f89
4 files changed
+198
No files matched your search
@@ -0,0 +1,62 @@
|
||||
#ifndef FROSTBYTE_PRIOQ_H
|
||||
#define FROSTBYTE_PRIOQ_H
|
||||
|
||||
#include "types.h"
|
||||
#include "rbt.h"
|
||||
|
||||
/*
|
||||
* Prioq: an ephemeral min-vruntime priority queue built on top of the
|
||||
* intrusive red-black tree (rbt.h) -- the "run queue" half of a CFS-lite
|
||||
* (Completely Fair Scheduler, weighted-fair) scheduler. The caller owns the
|
||||
* PrioQNode storage (typically embedded in a scheduler's thread struct,
|
||||
* next to the vruntime counter it mirrors) and is expected to rebuild the
|
||||
* queue from scratch every time a scheduling decision is needed: insert
|
||||
* every currently-eligible candidate, pop the minimum, discard the rest.
|
||||
* That "ephemeral" usage pattern (rather than a queue that persists node
|
||||
* membership across calls) sidesteps a real hazard for a preemptive kernel
|
||||
* scheduler: a thread can become eligible again from code paths other than
|
||||
* the scheduler itself (e.g. a wait-queue wakeup), and keeping a
|
||||
* long-lived queue in sync with every one of those paths is exactly the
|
||||
* kind of dual-source-of-truth bug this design avoids by never trying.
|
||||
*
|
||||
* Ordering key is (vruntime, id): id is a mandatory, unique tiebreaker
|
||||
* because rbtInsert silently rejects a node whose key compares equal to one
|
||||
* already present (no duplicates in the underlying tree) -- two candidates
|
||||
* that happen to share a vruntime would otherwise cause one of them to be
|
||||
* dropped from the queue entirely rather than merely deprioritised.
|
||||
*/
|
||||
|
||||
typedef struct PrioQNode {
|
||||
RbtNode node;
|
||||
uint64 vruntime;
|
||||
uint32 id;
|
||||
} PrioQNode;
|
||||
|
||||
typedef struct PrioQueue {
|
||||
RbTree tree;
|
||||
} PrioQueue;
|
||||
|
||||
void prioqInit(PrioQueue* q);
|
||||
|
||||
/* (Re)inserts n into the queue, keyed by (vruntime, id). n's storage is
|
||||
owned by the caller and may be reused across unrelated queue lifetimes --
|
||||
every field the tree needs is reset unconditionally by the underlying
|
||||
rbtInsert. id must be unique among nodes simultaneously in the same
|
||||
queue. */
|
||||
void prioqInsert(PrioQueue* q, PrioQNode* n, uint64 vruntime, uint32 id);
|
||||
|
||||
/* Returns the minimum-vruntime node without removing it, or nullptr if the
|
||||
queue is empty. */
|
||||
PrioQNode* prioqPeekMin(const PrioQueue* q);
|
||||
|
||||
/* Removes and returns the minimum-vruntime node, or nullptr if the queue is
|
||||
empty. */
|
||||
PrioQNode* prioqPopMin(PrioQueue* q);
|
||||
|
||||
/* Removes an arbitrary node that is currently a member of q. */
|
||||
void prioqRemove(PrioQueue* q, PrioQNode* n);
|
||||
|
||||
usize prioqCount(const PrioQueue* q);
|
||||
bool prioqIsEmpty(const PrioQueue* q);
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user