/* ** @file procs.h ** ** @author CSCI-452 class of 20245 ** ** @brief Process-related declarations */ #ifndef PROCS_H_ #define PROCS_H_ #include <common.h> /* ** General (C and/or assembly) definitions */ #ifndef ASM_SRC /* ** Start of C-only definitions */ /* ** Types */ /* ** Process states */ enum state_e { // pre-viable STATE_UNUSED = 0, STATE_NEW, // runnable STATE_READY, STATE_RUNNING, // runnable, but waiting for some event STATE_SLEEPING, STATE_BLOCKED, STATE_WAITING, // no longer runnable STATE_KILLED, STATE_ZOMBIE // sentinel value , N_STATES }; // these may be handy for checking general conditions of processes // they depend on the order of the state names in the enum! #define FIRST_VIABLE STATE_READY #define FIRST_BLOCKED STATE_SLEEPING #define LAST_VIABLE STATE_WAITING /* ** Process priorities are defined in <defs.h> */ /* ** Quantum lengths - values are number of clock ticks */ enum quantum_e { QUANTUM_SHORT = 1, QUANTUM_STANDARD = 3, QUANTUM_LONG = 5 }; /* ** PID-related definitions */ #define PID_INIT 1 #define FIRST_USER_PID 2 /* ** Process context structure ** ** NOTE: the order of data members here depends on the ** register save code in isr_stubs.S!!!! ** ** This will be at the top of the user stack when we enter ** an ISR. In the case of a system call, it will be followed ** by the return address and the system call parameters. */ typedef struct context_s { uint32_t ss; // pushed by isr_save uint32_t gs; uint32_t fs; uint32_t es; uint32_t ds; uint32_t edi; uint32_t esi; uint32_t ebp; uint32_t esp; uint32_t ebx; uint32_t edx; uint32_t ecx; uint32_t eax; uint32_t vector; uint32_t code; // pushed by isr_save or the hardware uint32_t eip; // pushed by the hardware uint32_t cs; uint32_t eflags; } context_t; #define SZ_CONTEXT sizeof(context_t) /* ** program section information for user processes */ typedef struct section_s { uint_t length; // length, in some units uint_t addr; // location, in some units } section_t; // note: these correspond to the PT_LOAD sections found in // an ELF file, not necessarily to text/data/bss #define SECT_L1 0 #define SECT_L2 1 #define SECT_L3 2 #define SECT_STACK 3 // total number of section table entries in our PCB #define N_SECTS 4 // number of those that can be loaded from an ELF module #define N_LOADABLE 3 /* ** The process control block ** ** Fields are ordered by size to avoid padding ** ** Currently, this is 72 bytes long. It could be reduced to 64 (2^6) ** bytes by making the last four fields uint16_t types; that would ** divide nicely into 1024 bytes, giving 16 PCBs per 1/4 page of memory. */ typedef struct pcb_s { // four-byte fields // start with these four bytes, for easy access in assembly context_t *context; // pointer to context save area on stack // VM information pde_t *pdir; // page directory for this process section_t sects[N_SECTS]; // per-section memory information // queue linkage struct pcb_s *next; // next PCB in queue // process state information struct pcb_s *parent; // pointer to PCB of our parent process uint32_t wakeup; // wakeup time, for sleeping processes int32_t exit_status; // termination status, for parent's use // these things may not need to be four bytes uint_t pid; // PID of this process enum state_e state; // process' current state enum priority_e priority; // process priority level uint_t ticks; // remaining ticks in this time slice } pcb_t; #define SZ_PCB sizeof(pcb_t) /* ** PCB queue structure (opaque to the rest of the kernel) */ typedef struct pcb_queue_s *pcb_queue_t; /* ** Queue ordering methods */ enum pcb_queue_order_e { O_FIFO, O_PRIO, O_PID, O_WAKEUP // sentinel , N_ORDERINGS }; #define O_FIRST_STYLE O_FIFO #define O_LAST_STYLE O_WAKEUP /* ** Globals */ // public-facing queue handles extern pcb_queue_t pcb_freelist; extern pcb_queue_t ready; extern pcb_queue_t waiting; extern pcb_queue_t sleeping; extern pcb_queue_t zombie; extern pcb_queue_t sioread; // pointer to the currently-running process extern pcb_t *current; // the process table extern pcb_t ptable[N_PROCS]; // next available PID extern uint_t next_pid; // pointer to the PCB for the 'init' process extern pcb_t *init_pcb; // table of state name strings extern const char state_str[N_STATES][4]; // table of priority name strings extern const char prio_str[N_PRIOS][5]; // table of queue ordering name strings extern const char ord_str[N_ORDERINGS][5]; /* ** Prototypes */ /** ** Name: pcb_init ** ** Initialization for the Process module. */ void pcb_init(void); /** ** Name: pcb_alloc ** ** Allocate a PCB from the list of free PCBs. ** ** @param pcb Pointer to a pcb_t * where the PCB pointer will be returned. ** ** @return status of the allocation attempt */ int pcb_alloc(pcb_t **pcb); /** ** Name: pcb_free ** ** Return a PCB to the list of free PCBs. ** ** @param pcb Pointer to the PCB to be deallocated. */ void pcb_free(pcb_t *pcb); /** ** Name: pcb_zombify ** ** Turn the indicated process into a Zombie. This function ** does most of the real work for exit() and kill() calls. ** Is also called from the scheduler and dispatcher. ** ** @param pcb Pointer to the newly-undead PCB */ void pcb_zombify(register pcb_t *victim); /** ** Name: pcb_cleanup ** ** Reclaim a process' data structures ** ** @param pcb The PCB to reclaim */ void pcb_cleanup(pcb_t *pcb); /** ** Name: pcb_find_pid ** ** Locate the PCB for the process with the specified PID ** ** @param pid The PID to be located ** ** @return Pointer to the PCB, or NULL */ pcb_t *pcb_find_pid(uint_t pid); /** ** Name: pcb_find_ppid ** ** Locate the PCB for the process with the specified parent ** ** @param pid The PID to be located ** ** @return Pointer to the PCB, or NULL */ pcb_t *pcb_find_ppid(uint_t pid); /** ** Name: pcb_queue_reset ** ** Initialize a PCB queue. ** ** @param queue[out] The queue to be initialized ** @param order[in] The desired ordering for the queue ** ** @return status of the init request */ int pcb_queue_reset(pcb_queue_t queue, enum pcb_queue_order_e style); /** ** Name: pcb_queue_empty ** ** Determine whether a queue is empty. Essentially just a wrapper ** for the PCB_QUEUE_EMPTY() macro, for use outside this module. ** ** @param[in] queue The queue to check ** ** @return true if the queue is empty, else false */ bool_t pcb_queue_empty(pcb_queue_t queue); /** ** Name: pcb_queue_length ** ** 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) */ uint_t pcb_queue_length(const pcb_queue_t queue); /** ** Name: pcb_queue_insert ** ** Inserts a PCB into the indicated queue. ** ** @param queue[in,out] The queue to be used ** @param pcb[in] The PCB to be inserted ** ** @return status of the insertion request */ int pcb_queue_insert(pcb_queue_t queue, pcb_t *pcb); /** ** Name: pcb_queue_peek ** ** Return the first PCB from the indicated queue, but don't ** remove it from the queue ** ** @param queue[in] The queue to be used ** ** @return the PCB pointer, or NULL if the queue is empty */ pcb_t *pcb_queue_peek(const pcb_queue_t queue); /** ** Name: pcb_queue_remove ** ** Remove the first PCB from the indicated queue. ** ** @param queue[in,out] The queue to be used ** @param pcb[out] Pointer to where the PCB pointer will be saved ** ** @return status of the removal request */ int pcb_queue_remove(pcb_queue_t queue, pcb_t **pcb); /** ** Name: pcb_queue_remove_this ** ** Remove the specified PCB from the indicated queue. ** ** @param queue[in,out] The queue to be used ** @param pcb[in] Pointer to the PCB to be removed ** ** @return status of the removal request */ int pcb_queue_remove_this(pcb_queue_t queue, pcb_t *pcb); /* ** Scheduler routines */ /** ** schedule(pcb) ** ** Schedule the supplied process ** ** @param pcb Pointer to the PCB of the process to be scheduled */ void schedule(pcb_t *pcb); /** ** dispatch() ** ** Select the next process to receive the CPU */ void dispatch(void); /* ** Debugging/tracing routines */ /** ** Name: ctx_dump ** ** Dumps the contents of this process context to the console ** ** @param msg[in] An optional message to print before the dump ** @param c[in] The context to dump out */ void ctx_dump(const char *msg, register context_t *c); /** ** Name: ctx_dump_all ** ** dump the process context for all active processes ** ** @param msg[in] Optional message to print */ void ctx_dump_all(const char *msg); /** ** Name: pcb_dump ** ** Dumps the contents of this PCB to the console ** ** @param msg[in] An optional message to print before the dump ** @param p[in] The PCB to dump ** @param all[in] Dump all the contents? */ void pcb_dump(const char *msg, register pcb_t *p, bool_t all); /** ** Name: pcb_queue_dump ** ** Dump the contents of the specified queue to the console ** ** @param msg[in] An optional message to print before the dump ** @param queue[in] The queue to dump ** @param contents[in] Also dump (some) contents? */ void pcb_queue_dump(const char *msg, pcb_queue_t queue, bool_t contents); /** ** Name: ptable_dump ** ** dump the contents of the "active processes" table ** ** @param msg[in] Optional message to print ** @param all[in] Dump all or only part of the relevant data */ void ptable_dump(const char *msg, bool_t all); /** ** Name: ptable_dump_counts ** ** Prints basic information about the process table (number of ** entries, number with each process state, etc.). */ void ptable_dump_counts(void); #endif /* !ASM_SRC */ #endif