#include "process.h" #include "api/error.h" #include "api/process.h" #include "hal/smp.h" #include "proc/ipc.h" #include "proc/scheduler.h" #include "sys/objdir.h" #include "lib/string.h" struct rbtree_node *pcb_tree; pid_t __next_pid = 1; int pcb_new(jove_owned_obj_t *pcb_obj, size_t size, jove_owned_obj_t *rootdir_obj) { struct pcb_header *pcb_header = obj_deref(pcb_obj); memset(pcb_header, 0, size); pcb_header->size = size; pcb_header->pid = __next_pid++; pcb_header->rootdir = obj_release(rootdir_obj); pcb_header->tree_node.get_key = (void*)pcb_getpid; pcb_tree = rbtree_insert(pcb_tree, &pcb_header->tree_node); pcb_header->mailbox.owner = pcb_header->pid; pcb_header->state = PCB_STATE_EMBRYO; pcb_header->ksp = (void*)(__syscall_stack + 0x1000 - sizeof(void*)); return _pcb_new_arch((pcb_t*)pcb_header); } int pcb_send(pcb_t *pcb, pid_t target, jove_owned_obj_t *subject, size_t timeout) { //Validate that the target PCB has a valid port. pcb_t *target_pcb = (pcb_t*)rbtree_search(pcb_tree, target); if(target_pcb == 0) { return -EBADPROC; } struct port *pcb_port = pcb_getport(pcb); struct port *target_port = pcb_getport(target_pcb); //Try to send to either the send buffer or the target recv buffer. int port_send_result = port_send(pcb_port, target_port, subject); if(port_send_result < 0) { //Port send buffer was full. Wait for it to clear, or timeout. if(timeout == 0) return -EFULL; scheduler_block_for_mail((struct pcb_header*)pcb, timeout, target); if((port_send_result = port_send(pcb_port, target_port, subject)) < 0) { //If the send buffer is still full, then we timed out. return -ETIMEOUT; } } if(port_send_result == 1) { //We sent to the port, but it's stuck in the send buffer. scheduler_block_for_mail((struct pcb_header*)pcb, timeout, target); if(port_poll_send(pcb_port)) { //If the send buffer is still full, then we timed out. port_take_send(pcb_port, subject); return -ETIMEOUT; } } return 0; } int pcb_recv(pcb_t *pcb, pid_t target, jove_owned_obj_t *dest_obj, size_t timeout) { struct port *target_port = NULL; if(target == 0) { //If the target is zero, we're accepting from all send targets. pcb_t *target_pcb = (pcb_t*)rbtree_search(pcb_tree, target); if(target_pcb == 0) { return -EBADPROC; } target_port = pcb_getport(target_pcb); } struct port *pcb_port = pcb_getport(pcb); //Block PCB port from recieving from anything other than the target. port_set_recv_target(pcb_port, target_port); struct port *recv_from = port_take_recv(pcb_port, dest_obj); if(recv_from == 0) { if(timeout == 0) { //If non-blocking, leave immediately. return -EEMPTY; } scheduler_block_for_mail((struct pcb_header*)pcb, timeout, target); recv_from = port_take_recv(pcb_port, dest_obj); if(recv_from == 0) { //If blocking, and timeout expired, then we timed out. return -ETIMEOUT; } } return port_get_owner(recv_from); } pcb_t *pcb_frompid(pid_t pid) { return (pcb_t*)rbtree_search((struct rbtree_node*)pcb_tree, pid); } jove_owned_obj_t* process_current(void) { return processor_getpcb(((processor_t*)processor_current())); } inline pid_t pcb_getpid(pcb_t *pcb) { return ((struct pcb_header*)pcb)->pid; } inline jove_obj_t* pcb_getrootdir(pcb_t *pcb) { return ((struct pcb_header*)pcb)->rootdir; } inline jove_owned_obj_t* pcb_getpagedir(jove_obj_t *rootdir_obj) { return objdir_getlocal(rootdir_obj, PCB_ROOTDIR_PAGEDIR_I); } inline jove_owned_obj_t* pcb_getself(jove_obj_t *rootdir_obj) { return objdir_getlocal(rootdir_obj, PCB_ROOTDIR_SELF_I); } inline struct port* pcb_getport(pcb_t *pcb) { return &((struct pcb_header*)pcb)->mailbox; } inline enum pcb_state pcb_getstate(pcb_t *pcb) { return ((struct pcb_header*)pcb)->state; } inline intmax_t pcb_getstatecode(pcb_t *pcb) { return ((struct pcb_header*)pcb)->state_code; } inline void* pcb_getksp(pcb_t *pcb) { return ((struct pcb_header*)pcb)->ksp; } inline void** pcb_getksp_ref(pcb_t *pcb) { return &((struct pcb_header*)pcb)->ksp; }