/** Function Name : process_sched_add_module_write Function Type : Kernel Callback Method Description : Method is invoked whenever the process_sched_add file is written. This callback method is triggered when a write operation performed on the above mentioned file which is registered to the file operation object. /proc/process_sched_add is a write only file. */ static ssize_t process_sched_add_module_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { int ret; long int new_proc_id; printk(KERN_INFO "Process Scheduler Add Module write.\n"); printk(KERN_INFO "Registered Process ID: %s\n", buf); ret = kstrtol(buf,BASE_10,&new_proc_id); if(ret < 0) { /** Invalid argument in conversion error.*/ return -EINVAL; } /** Add process to the process queue.*/ ret = add_process_to_queue(new_proc_id); /**Check if the add process to queue method was successful or not.*/ if(ret != eExecSuccess) { printk(KERN_ALERT "Process Set ERROR:add_process_to_queue function failed from sched set write method"); /** Add process to queue error.*/ return -ENOMEM; } /** Successful execution of write call back.*/ return count; }
int32_t switch_process_queue(process_t *proc, QueueType to_q) { process_t *proc_to_switch = pop_process_from_queue(proc); if (!proc_to_switch) return -1; if (curr_running_proc == proc_to_switch) { curr_running_proc = NULL; } add_process_to_queue(proc_to_switch, to_q); return 0; }
//Initializes a process with its binary its argument process_t* create_process_new(void* binary, pid_t ppid, int new_pid, const char *proc_name, char * const argv[], size_t argv_count, char * const envp[], size_t envp_count) { uint64_t old_cr3 = 0; int32_t rc = 0; process_t *proc = allocate_process(new_pid); if (!proc) { #ifdef LOG printf("Failed to allocate memory for process\n"); #endif return NULL; } // First process will be foreground... Need to change this logic // May be this will work fine when we will be running just shell if (foreground_proc == NULL) { proc->flags |= FOREGROUND_PROCESS; foreground_proc = proc; } strncpy(proc->name, proc_name, sizeof(proc->name)); proc->kernel_stack = kmalloc(USER_KERNEL_STACK_SIZE); if(proc->kernel_stack == NULL) { reclaim_process_resources(proc); kfree(proc); #if LOG printf("failed to allocate memory for user-kern stack\n"); #endif return NULL; } rc = setup_pagetable_proc(proc); if (rc) { reclaim_process_resources(proc); kfree(proc); #ifdef LOG printf("setup_pagetable_proc failed\n"); #endif return NULL; } if (binary != NULL) { //If the process is child of some parent //So we don't need any binary rc = init_vmas_proc(proc, binary, argv_count, envp_count); } if (rc) { reclaim_process_resources(proc); kfree(proc); #ifdef LOG printf("init_vmas_proc failed\n"); #endif return NULL; } //Setup registers for the process setup_registers_proc(proc); // Allocate a page for stack // Why we are not going for demand paging? // We need to push env variables' addresses on stack while we are in kernel // and it's not a good idea to have a page fault in kernel if (binary != NULL) { //Don't allocate page for stack because it's a child. allocate_memory((uint64_t)proc->page_table_base, USER_STACK_TOP - PGSIZE, PGSIZE, PTE_P | PTE_U | PTE_W); } // This function should be last in this sequence since it uses rsp // which we set in setup_registers_proc if (binary != NULL) { if (argv_count > 0) { allocate_memory((uint64_t)proc->page_table_base, USER_ARGV_START, argv_count * sizeof(execve_argv[0]), PTE_P | PTE_U | PTE_W); old_cr3 = getcr3(); setcr3((uint64_t)proc->page_table_base); memcpy((void *)USER_ARGV_START, argv, argv_count * sizeof(execve_argv[0])); setcr3(old_cr3); } if (envp_count > 0) { allocate_memory((uint64_t)proc->page_table_base, USER_ENV_VARIABLE_START, envp_count * sizeof(execve_envp[0]), PTE_P | PTE_U | PTE_W); old_cr3 = getcr3(); setcr3((uint64_t)proc->page_table_base); memcpy((void *)USER_ENV_VARIABLE_START, envp, envp_count * sizeof(execve_envp[0])); setcr3(old_cr3); } setup_stack(proc, argv_count, envp_count); } add_process_to_queue(proc, PROCESS_RUNNABLE_QUEUE); proc->ppid = ppid; //printf("New process PID = %d\n", proc->pid); return proc; }
int terminate_process(process_t *proc, int return_value) { if (!proc) return -1; reparent_children(proc); //printf("Killing process [%d]:%s \n", proc->pid, proc->name); if (proc == foreground_proc) { // Make parent of current process as foreground process_t *parent_proc = get_proc_from_pid(proc->ppid); if (parent_proc) { /* No point in making init the foreground proc. Make root * shell the BOSS */ if ( parent_proc->pid == 1 ) { parent_proc = get_proc_from_pid(2); } parent_proc->flags |= FOREGROUND_PROCESS; proc->flags &= ~FOREGROUND_PROCESS; foreground_proc = parent_proc; } else { /* Set it to root shell */ foreground_proc = get_proc_from_pid(2); } } // Just deallocate resources but keep the process structure // and move process to TERMINATED QUEUE proc = pop_process_from_queue(proc); if (curr_running_proc == proc) { curr_running_proc = NULL; } reclaim_process_resources(proc); kfree(delete_prev_stack); delete_prev_stack = proc->kernel_stack; proc->kernel_stack = NULL; add_process_to_queue(proc, PROCESS_TERMINATED_QUEUE); proc->exit_status = (return_value & 0xff); // If I am being waited upon by my parent, wake them up if (proc->flags & PAPA_WAITING) { process_t *parent_proc = get_proc_from_pid(proc->ppid); if (!parent_proc) { #ifdef LOG printf("Failed to get parent process during termination\n"); #endif return -1; } switch_process_queue(parent_proc, PROCESS_RUNNABLE_QUEUE); } return 0; }