summaryrefslogtreecommitdiff
path: root/kernel/procs/:w
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-04-15 22:51:25 -0400
committerFreya Murphy <freya@freyacat.org>2025-04-15 22:51:25 -0400
commitf7382469feb83e1753e835693e892fe4dbfc6221 (patch)
tree07d69e205a01e4598b707fdc38b5a295ace68417 /kernel/procs/:w
parentfmt (diff)
downloadcomus-f7382469feb83e1753e835693e892fe4dbfc6221.tar.gz
comus-f7382469feb83e1753e835693e892fe4dbfc6221.tar.bz2
comus-f7382469feb83e1753e835693e892fe4dbfc6221.zip
update build.zig
Diffstat (limited to 'kernel/procs/:w')
-rw-r--r--kernel/procs/:w856
1 files changed, 0 insertions, 856 deletions
diff --git a/kernel/procs/:w b/kernel/procs/:w
deleted file mode 100644
index a8352b0..0000000
--- a/kernel/procs/:w
+++ /dev/null
@@ -1,856 +0,0 @@
-#include <comus/procs.h>
-#include <comus/error.h>
-#include <comus/cpu.h>
-#include <comus/memory.h>
-
-#define PCB_QUEUE_EMPTY(q) ((q)->head == NULL)
-
-struct pcb_queue_s {
- struct pcb *head;
- struct pcb *tail;
- enum pcb_queue_order order;
-};
-
-// collection of queues
-static struct pcb_queue_s pcb_freelist_queue;
-static struct pcb_queue_s ready_queue;
-static struct pcb_queue_s waiting_queue;
-static struct pcb_queue_s sleeping_queue;
-static struct pcb_queue_s zombie_queue;
-
-// public facing queue handels
-pcb_queue_t pcb_freelist;
-pcb_queue_t ready;
-pcb_queue_t waiting;
-pcb_queue_t sleeping;
-pcb_queue_t zombie;
-
-// pointer to the currently-running process
-struct pcb *current;
-
-/// pointer to the currently-running process
-struct pcb *current;
-
-/// the process table
-struct pcb ptable[N_PROCS];
-
-/// next avaliable pid
-pid_t next_pid;
-
-/// pointer to the pcb for the 'init' process
-struct pcb *init_pcb;
-
-/// table of state name strings
-const char *proc_state_str[N_PROC_STATES] = {
- [PROC_STATE_UNUSED] = "Unu", [PROC_STATE_NEW] = "New",
- [PROC_STATE_READY] = "Rdy", [PROC_STATE_RUNNING] = "Run",
- [PROC_STATE_SLEEPING] = "Slp", [PROC_STATE_BLOCKED] = "Blk",
- [PROC_STATE_WAITING] = "Wat", [PROC_STATE_KILLED] = "Kil",
- [PROC_STATE_ZOMBIE] = "Zom",
-};
-
-/// table of priority name strings
-const char *proc_prio_str[N_PROC_PRIOS] = {
- [PROC_PRIO_HIGH] = "High",
- [PROC_PRIO_STD] = "User",
- [PROC_PRIO_LOW] = "Low ",
- [PROC_PRIO_DEFERRED] = "Def ",
-};
-
-/// table of queue ordering name strings
-const char *pcb_ord_str[N_PCB_ORDERINGS] = {
- [O_PCB_FIFO] = "FIFO",
- [O_PCB_PRIO] = "PRIO",
- [O_PCB_PID] = "PID ",
- [O_PCB_WAKEUP] = "WAKE",
-};
-
-/**
- * Priority search functions. These are used to traverse a supplied
- * queue looking for the queue entry that would precede the supplied
- * PCB when that PCB is inserted into the queue.
- *
- * Variations:
- * find_prev_wakeup() compares wakeup times
- * find_prev_priority() compares process priorities
- * find_prev_pid() compares PIDs
- *
- * Each assumes the queue should be in ascending order by the specified
- * comparison value.
- *
- * @param[in] queue The queue to search
- * @param[in] pcb The PCB to look for
- *
- * @return a pointer to the predecessor in the queue, or NULL if
- * this PCB would be at the beginning of the queue.
- */
-static struct pcb *find_prev_wakeup(pcb_queue_t queue, struct pcb *pcb)
-{
- // sanity checks!
- assert(queue != NULL, "find_prev_wakeup: queue is null");
- assert(pcb != NULL, "find_prev_wakeup: pcb is null");
-
- struct pcb *prev = NULL;
- struct pcb *curr = queue->head;
-
- while (curr != NULL && curr->wakeup <= pcb->wakeup) {
- prev = curr;
- curr = curr->next;
- }
-
- return prev;
-}
-
-static struct pcb *find_prev_priority(pcb_queue_t queue, struct pcb *pcb)
-{
- // sanity checks!
- assert(queue != NULL, "find_prev_priority: queue is null");
- assert(pcb != NULL, "find_prev_priority: pcb is null");
-
- struct pcb *prev = NULL;
- struct pcb *curr = queue->head;
-
- while (curr != NULL && curr->priority <= pcb->priority) {
- prev = curr;
- curr = curr->next;
- }
-
- return prev;
-}
-
-static struct pcb *find_prev_pid(pcb_queue_t queue, struct pcb *pcb)
-{
- // sanity checks!
- assert(queue != NULL, "find_prev_pid: queue is null");
- assert(pcb != NULL, "find_prev_pid: pcb is null");
-
- struct pcb *prev = NULL;
- struct pcb *curr = queue->head;
-
- while (curr != NULL && curr->pid <= pcb->pid) {
- prev = curr;
- curr = curr->next;
- }
-
- return prev;
-}
-
-// a macro to simplify queue setup
-#define QINIT(q, s) \
- q = &q##_queue; \
- if (pcb_queue_reset(q, s) != SUCCESS) { \
- panic("pcb_init can't reset " #q); \
- }
-
-void pcb_init(void)
-{
- // there is no current process
- current = NULL;
-
- // set up the external links to the queues
- QINIT(pcb_freelist, O_PCB_FIFO);
- QINIT(ready, O_PCB_PRIO);
- QINIT(waiting, O_PCB_PID);
- QINIT(sleeping, O_PCB_WAKEUP);
- QINIT(zombie, O_PCB_PID);
-
- // We statically allocate our PCBs, so we need to add them
- // to the freelist before we can use them. If this changes
- // so that we dynamically allocate PCBs, this step either
- // won't be required, or could be used to pre-allocate some
- // number of PCB structures for future use.
-
- struct pcb *ptr = ptable;
- for (int i = 0; i < N_PROCS; ++i) {
- pcb_free(ptr);
- ++ptr;
- }
-}
-
-int pcb_alloc(struct pcb **pcb)
-{
- // sanity check!
- assert(pcb != NULL, "pcb_alloc: allocating a non free pcb pointer");
-
- // remove the first PCB from the free list
- struct pcb *tmp;
- if (pcb_queue_remove(pcb_freelist, &tmp) != SUCCESS)
- return E_NO_PCBS;
-
- *pcb = tmp;
- return SUCCESS;
-}
-
-void pcb_free(struct pcb *pcb)
-{
- if (pcb != NULL) {
- // mark the PCB as available
- pcb->state = PROC_STATE_UNUSED;
-
- // add it to the free list
- int status = pcb_queue_insert(pcb_freelist, pcb);
-
- // if that failed, we're in trouble
- if (status != SUCCESS) {
- panic("pcb_free(%16p) status %d", (void *)pcb, status);
- }
- }
-}
-
-void pcb_zombify(register struct pcb *victim)
-{
- // should this be an error?
- if (victim == NULL)
- return;
-
- // every process must have a parent, even if it's 'init'
- assert(victim->parent != NULL, "pcb_zombify: process missing a parent");
-
- // We need to locate the parent of this process. We also need
- // to reparent any children of this process. We do these in
- // a single loop.
- struct pcb *parent = victim->parent;
- struct pcb *zchild = NULL;
-
- // two PIDs we will look for
- pid_t vicpid = victim->pid;
-
- // speed up access to the process table entries
- register struct pcb *curr = ptable;
-
- for (int i = 0; i < N_PROCS; ++i, ++curr) {
- // make sure this is a valid entry
- if (curr->state == PROC_STATE_UNUSED)
- continue;
-
- // if this is our parent, just keep going - we continue
- // iterating to find all the children of this process.
- if (curr == parent)
- continue;
-
- if (curr->parent == victim) {
- // found a child - reparent it
- curr->parent = init_pcb;
-
- // see if this child is already undead
- if (curr->state == PROC_STATE_ZOMBIE) {
- // if it's already a zombie, remember it, so we
- // can pass it on to 'init'; also, if there are
- // two or more zombie children, it doesn't matter
- // which one we pick here, as the others will be
- // collected when 'init' loops
- zchild = curr;
- }
- }
- }
-
- // If we found a child that was already terminated, we need to
- // wake up the init process if it's already waiting.
- //
- // NOTE: we only need to do this for one Zombie child process -
- // init will loop and collect the others after it finishes with
- // this one.
- //
- // Also note: it's possible that the exiting process' parent is
- // also init, which means we're letting one of zombie children
- // of the exiting process be cleaned up by init before the
- // existing process itself is cleaned up by init. This will work,
- // because after init cleans up the zombie, it will loop and
- // call waitpid() again, by which time this exiting process will
- // be marked as a zombie.
-
- if (zchild != NULL && init_pcb->state == PROC_STATE_WAITING) {
- // dequeue the zombie
- assert(pcb_queue_remove_this(zombie, zchild) == SUCCESS,
- "pcb_zombify: cannot remove zombie process from queue");
-
- assert(pcb_queue_remove_this(waiting, init_pcb) == SUCCESS,
- "pcb_zombify: cannot remove waiting process from queue");
-
- // intrinsic return value is the PID
- PCB_RET(init_pcb) = zchild->pid;
-
- // may also want to return the exit status
- int64_t *ptr = (int64_t *)PCB_ARG(init_pcb, 2);
-
- if (ptr != NULL) {
- // BUG:
- // ********************************************************
- // ** Potential VM issue here! This code assigns the exit
- // ** status into a variable in the parent's address space.
- // ** This works in the baseline because we aren't using
- // ** any type of memory protection. If address space
- // ** separation is implemented, this code will very likely
- // ** STOP WORKING, and will need to be fixed.
- // ********************************************************
- *ptr = zchild->exit_status;
- }
-
- // all done - schedule 'init', and clean up the zombie
- schedule(init_pcb);
- pcb_cleanup(zchild);
- }
-
- // Now, deal with the parent of this process. If the parent is
- // already waiting, just wake it up and clean up this process.
- // Otherwise, this process becomes a zombie.
- //
- // NOTE: if the exiting process' parent is init and we just woke
- // init up to deal with a zombie child of the exiting process,
- // init's status won't be Waiting any more, so we don't have to
- // worry about it being scheduled twice.
-
- if (parent->state == PROC_STATE_WAITING) {
- // verify that the parent is either waiting for this process
- // or is waiting for any of its children
- uint64_t target = PCB_ARG(parent, 1);
-
- if (target == 0 || target == vicpid) {
- // the parent is waiting for this child or is waiting
- // for any of its children, so we can wake it up.
-
- // intrinsic return value is the PID
- PCB_RET(parent) = vicpid;
-
- // may also want to return the exit status
- int64_t *ptr = (int64_t *)PCB_ARG(parent, 2);
-
- if (ptr != NULL) {
- // ********************************************************
- // ** Potential VM issue here! This code assigns the exit
- // ** status into a variable in the parent's address space.
- // ** This works in the baseline because we aren't using
- // ** any type of memory protection. If address space
- // ** separation is implemented, this code will very likely
- // ** STOP WORKING, and will need to be fixed.
- // ********************************************************
- *ptr = victim->exit_status;
- }
-
- // all done - schedule the parent, and clean up the zombie
- schedule(parent);
- pcb_cleanup(victim);
-
- return;
- }
- }
-
- // The parent isn't waiting OR is waiting for a specific child
- // that isn't this exiting process, so we become a Zombie.
- //
- // This code assumes that Zombie processes are *not* in
- // a queue, but instead are just in the process table with
- // a state of 'Zombie'. This simplifies life immensely,
- // because we won't need to dequeue it when it is collected
- // by its parent.
-
- victim->state = PROC_STATE_ZOMBIE;
- assert(pcb_queue_insert(zombie, victim) == SUCCESS,
- "cannot insert victim process into zombie queue");
-
- // Note: we don't call _dispatch() here - we leave that for
- // the calling routine, as it's possible we don't need to
- // choose a new current process.
-}
-
-void pcb_cleanup(struct pcb *pcb)
-{
- // avoid deallocating a NULL pointer
- if (pcb == NULL) {
- // should this be an error?
- return;
- }
-
- // we need to release all the VM data structures and frames
- mem_ctx_free(pcb->memctx);
- // TODO: close open files
-
- // release the PCB itself
- pcb_free(pcb);
-}
-
-struct pcb *pcb_find_pid(pid_t pid)
-{
- // must be a valid PID
- if (pid < 1) {
- return NULL;
- }
-
- // scan the process table
- struct pcb *p = ptable;
-
- for (int i = 0; i < N_PROCS; ++i, ++p) {
- if (p->pid == pid && p->state != PROC_STATE_UNUSED) {
- return p;
- }
- }
-
- // didn't find it!
- return NULL;
-}
-
-struct pcb *pcb_find_ppid(pid_t pid)
-{
- // must be a valid PID
- if (pid < 1) {
- return NULL;
- }
-
- // scan the process table
- struct pcb *p = ptable;
-
- for (int i = 0; i < N_PROCS; ++i, ++p) {
- assert(p->parent != NULL,
- "pcb_find_ppid: process does not have a parent");
- if (p->parent->pid == pid && p->parent->state != PROC_STATE_UNUSED) {
- return p;
- }
- }
-
- // didn't find it!
- return NULL;
-}
-
-int pcb_queue_reset(pcb_queue_t queue, enum pcb_queue_order style)
-{
- // sanity check
- assert(queue != NULL, "pcb_queue_reset: queue is null");
-
- // make sure the style is valid
- if (style < 0 || style >= N_PCB_ORDERINGS) {
- return E_BAD_PARAM;
- }
-
- // reset the queue
- queue->head = queue->tail = NULL;
- queue->order = style;
-
- return SUCCESS;
-}
-
-bool pcb_queue_empty(pcb_queue_t queue)
-{
- // if there is no queue, blow up
- assert(queue != NULL, "pcb_queue_empty: queue is empty");
-
- return PCB_QUEUE_EMPTY(queue);
-}
-
-/**
- * Return the count of elements in the specified queue.
- *
- * @param[in] queue The queue to check
- * @return the count (0 if the queue is empty)
- */
-size_t pcb_queue_length(const pcb_queue_t queue)
-{
- // sanity check
- assert(queue != NULL, "pcb_queue_length: queue is null");
-
- // this is pretty simple
- register struct pcb *tmp = queue->head;
- register size_t num = 0;
-
- while (tmp != NULL) {
- ++num;
- tmp = tmp->next;
- }
-
- return num;
-}
-
-int pcb_queue_insert(pcb_queue_t queue, struct pcb *pcb)
-{
- // sanity checks
- assert(queue != NULL, "pcb_queue_insert: queue is null");
- assert(pcb != NULL, "pcb_queue_insert: pcb is null");
-
- // if this PCB is already in a queue, we won't touch it
- if (pcb->next != NULL) {
- // what to do? we let the caller decide
- return E_BAD_PARAM;
- }
-
- // is the queue empty?
- if (queue->head == NULL) {
- queue->head = queue->tail = pcb;
- return SUCCESS;
- }
- assert(queue->tail != NULL, "pcb_queue_insert: queue tail is null");
-
- // no, so we need to search it
- struct pcb *prev = NULL;
-
- // find the predecessor node
- switch (queue->order) {
- case O_PCB_FIFO:
- prev = queue->tail;
- break;
- case O_PCB_PRIO:
- prev = find_prev_priority(queue, pcb);
- break;
- case O_PCB_PID:
- prev = find_prev_pid(queue, pcb);
- break;
- case O_PCB_WAKEUP:
- prev = find_prev_wakeup(queue, pcb);
- break;
- default:
- // do we need something more specific here?
- return E_BAD_PARAM;
- }
-
- // OK, we found the predecessor node; time to do the insertion
-
- if (prev == NULL) {
- // there is no predecessor, so we're
- // inserting at the front of the queue
- pcb->next = queue->head;
- if (queue->head == NULL) {
- // empty queue!?! - should we panic?
- queue->tail = pcb;
- }
- queue->head = pcb;
-
- } else if (prev->next == NULL) {
- // append at end
- prev->next = pcb;
- queue->tail = pcb;
-
- } else {
- // insert between prev & prev->next
- pcb->next = prev->next;
- prev->next = pcb;
- }
-
- return SUCCESS;
-}
-
-int pcb_queue_remove(pcb_queue_t queue, struct pcb **pcb)
-{
- //sanity checks
- assert(queue != NULL, "pcb_queue_remove: queue is null");
- assert(pcb != NULL, "pcb_queue_remove: pcb is null");
-
- // can't get anything if there's nothing to get!
- if (PCB_QUEUE_EMPTY(queue)) {
- return E_EMPTY_QUEUE;
- }
-
- // take the first entry from the queue
- struct pcb *tmp = queue->head;
- queue->head = tmp->next;
-
- // disconnect it completely
- tmp->next = NULL;
-
- // was this the last thing in the queue?
- if (queue->head == NULL) {
- // yes, so clear the tail pointer for consistency
- queue->tail = NULL;
- }
-
- // save the pointer
- *pcb = tmp;
-
- return SUCCESS;
-}
-
-int pcb_queue_remove_this(pcb_queue_t queue, struct pcb *pcb)
-{
- //sanity checks
- assert(queue != NULL, "pcb_queue_remove_this: queue is null");
- assert(pcb != NULL, "pcb_queue_remove_this: pcb is null");
-
- // can't get anything if there's nothing to get!
- if (PCB_QUEUE_EMPTY(queue)) {
- return E_EMPTY_QUEUE;
- }
-
- // iterate through the queue until we find the desired PCB
- struct pcb *prev = NULL;
- struct pcb *curr = queue->head;
-
- while (curr != NULL && curr != pcb) {
- prev = curr;
- curr = curr->next;
- }
-
- // case prev curr next interpretation
- // ==== ==== ==== ==== ============================
- // 1. 0 0 -- *** CANNOT HAPPEN ***
- // 2. 0 !0 0 removing only element
- // 3. 0 !0 !0 removing first element
- // 4. !0 0 -- *** NOT FOUND ***
- // 5. !0 !0 0 removing from end
- // 6. !0 !0 !0 removing from middle
-
- if (curr == NULL) {
- // case 1
- assert(prev != NULL,
- "pcb_queue_remove_this: prev element in queue is null");
- // case 4
- return E_NOT_FOUND;
- }
-
- // connect predecessor to successor
- if (prev != NULL) {
- // not the first element
- // cases 5 and 6
- prev->next = curr->next;
- } else {
- // removing first element
- // cases 2 and 3
- queue->head = curr->next;
- }
-
- // if this was the last node (cases 2 and 5),
- // also need to reset the tail pointer
- if (curr->next == NULL) {
- // if this was the only entry (2), prev is NULL,
- // so this works for that case, too
- queue->tail = prev;
- }
-
- // unlink current from queue
- curr->next = NULL;
-
- // there's a possible consistancy problem here if somehow
- // one of the queue pointers is NULL and the other one
- // is not NULL
-
- assert((queue->head == NULL && queue->tail == NULL) ||
- (queue->head != NULL && queue->tail != NULL),
- "pcb_queue_remove_this: queue consistancy problem");
-
- return SUCCESS;
-}
-
-struct pcb *pcb_queue_peek(const pcb_queue_t queue)
-{
- //sanity check
- assert(queue != NULL, "pcb_queue_peek: queue is null");
-
- // can't get anything if there's nothing to get!
- if (PCB_QUEUE_EMPTY(queue)) {
- return NULL;
- }
-
- // just return the first entry from the queue
- return queue->head;
-}
-
-void schedule(struct pcb *pcb)
-{
- // sanity check
- assert(pcb != NULL, "schedule: pcb is null");
-
- // check for a killed process
- if (pcb->state == PROC_STATE_KILLED)
- panic("attempted to schedule killed process %d", pcb->pid);
-
- // mark it as ready
- pcb->state = PROC_STATE_READY;
-
- // add it to the ready queue
- if (pcb_queue_insert(ready, pcb) != SUCCESS)
- panic("schedule insert fail");
-}
-
-void dispatch(void)
-{
- // verify that there is no current process
- assert(current == NULL, "dispatch: current process is not null");
-
- // grab whoever is at the head of the queue
- int status = pcb_queue_remove(ready, &current);
- if (status != SUCCESS) {
- panic("dispatch queue remove failed, code %d", status);
- }
-
- // set the process up for success
- current->state = PROC_STATE_RUNNING;
- current->ticks = PROC_QUANTUM_STANDARD;
-}
-
-void ctx_dump(const char *msg, register struct cpu_regs *regs)
-{
- // first, the message (if there is one)
- if (msg)
- kputs(msg);
-
- // the pointer
- kprintf(" @ %16p: ", (void *)regs);
-
- // if it's NULL, why did you bother calling me?
- if (regs == NULL) {
- kprintf(" NULL???\n");
- return;
- }
-
- // now, the contents
- kputc('\n');
- cpu_print_regs(regs);
-}
-
-void ctx_dump_all(const char *msg)
-{
- // first, the message (if there is one)
- if (msg)
- kputs(msg);
-
- int n = 0;
- register struct pcb *pcb = ptable;
- for (int i = 0; i < N_PROCS; ++i, ++pcb) {
- if (pcb->state != PROC_STATE_UNUSED) {
- ++n;
- kprintf("%2d(%d): ", n, pcb->pid);
- ctx_dump(NULL, pcb->regs);
- }
- }
-}
-
-void pcb_dump(const char *msg, register struct pcb *pcb, bool all)
-{
- // first, the message (if there is one)
- if (msg)
- kputs(msg);
-
- // the pointer
- kprintf(" @ %16px:", (void *)pcb);
-
- // if it's NULL, why did you bother calling me?
- if (pcb == NULL) {
- kputs(" NULL???\n");
- return;
- }
-
- kprintf(" %d", pcb->pid);
- kprintf(" %s",
- pcb->state >= N_PROC_STATES ? "???" : proc_state_str[pcb->state]);
-
- if (!all) {
- // just printing IDs and states on one line
- return;
- }
-
- // now, the rest of the contents
- kprintf(" %s", pcb->priority >= N_PROC_PRIOS ?
- "???" :
- proc_prio_str[pcb->priority]);
-
- kprintf(" ticks %zu xit %d wake %16lx\n", pcb->ticks, pcb->exit_status,
- pcb->wakeup);
-
- kprintf(" parent %16p", (void *)pcb->regs);
- if (pcb->parent != NULL) {
- kprintf(" (%u)", pcb->parent->pid);
- }
-
- kprintf(" next %16p context %16p memctx %16p", (void *)pcb->next,
- (void *)pcb->regs, (void *)pcb->memctx);
-
- kputc('\n');
-}
-
-void pcb_queue_dump(const char *msg, pcb_queue_t queue, bool contents)
-{
- // report on this queue
- kprintf("%s: ", msg);
- if (queue == NULL) {
- kputs("NULL???\n");
- return;
- }
-
- // first, the basic data
- kprintf("head %16p tail %16p", (void *)queue->head, (void *)queue->tail);
-
- // next, how the queue is ordered
- kprintf(" order %s\n", queue->order >= N_PCB_ORDERINGS ?
- "????" :
- pcb_ord_str[queue->order]);
-
- // if there are members in the queue, dump the first few PIDs
- if (contents && queue->head != NULL) {
- kputs(" PIDs: ");
- struct pcb *tmp = queue->head;
- for (int i = 0; i < 5 && tmp != NULL; ++i, tmp = tmp->next) {
- kprintf(" [%u]", tmp->pid);
- }
-
- if (tmp != NULL) {
- kputs(" ...");
- }
-
- kputc('\n');
- }
-}
-
-void ptable_dump(const char *msg, bool all)
-{
- if (msg)
- kputs(msg);
- kputc(' ');
-
- int used = 0;
- int empty = 0;
-
- register struct pcb *pcb = ptable;
- for (int i = 0; i < N_PROCS; ++i) {
- if (pcb->state == PROC_STATE_UNUSED) {
- // an empty slot
- ++empty;
-
- } else {
- // a non-empty slot
- ++used;
-
- // if not dumping everything, add commas if needed
- if (!all && used) {
- kputc(',');
- }
-
- // report the table slot #
- kprintf(" #%d:", i);
-
- // and dump the contents
- pcb_dump(NULL, pcb, all);
- }
- }
-
- // only need this if we're doing one-line output
- if (!all) {
- kputc('\n');
- }
-
- // sanity check - make sure we saw the correct number of table slots
- if ((used + empty) != N_PROCS) {
- kprintf("Table size %d, used %d + empty %d = %d???\n", N_PROCS, used,
- empty, used + empty);
- }
-}
-
-void ptable_dump_counts(void)
-{
- size_t nstate[N_PROC_STATES] = { 0 };
- size_t unknown = 0;
-
- int n = 0;
- struct pcb *ptr = ptable;
- while (n < N_PROCS) {
- if (ptr->state < 0 || ptr->state >= N_PROC_STATES) {
- ++unknown;
- } else {
- ++nstate[ptr->state];
- }
- ++n;
- ++ptr;
- }
-
- kprintf("Ptable: %zu ***", unknown);
- for (n = 0; n < N_PROC_STATES; ++n) {
- kprintf(" %zu %s", nstate[n],
- proc_state_str[n] != NULL ? proc_state_str[n] : "???");
- }
- kputc('\n');
-}