140 likes | 159 Views
Processes and Process Control. Anand Sivasubramaniam Dept. of Computer Science & Eng. Pennsylvania State University. Process States. Creation. Stopped. Signal. Signal. Preempt. Ready. Zombie. Executing. Terminate. Schedule. I/O. I/O Done. Suspended. Task Structure (PCB).
E N D
Processes and Process Control Anand Sivasubramaniam Dept. of Computer Science & Eng. Pennsylvania State University
Process States Creation Stopped Signal Signal Preempt Ready Zombie Executing Terminate Schedule I/O I/O Done Suspended
Task Structure (PCB) Task_struct { // in linux/sched.h Volatile long state; Long counter; Long priority Unsigned long signals; // pending sigs Unsigned long blocked; //masked sigs Int pid, pgrp, uid, euid, gid, egid; Struct linux_binfmt; Struct task_struct p_opptr; // ptr to original parent Struct task_struct p_pptr; // ptr to immediate parent Struct task_struct p_cptr; // ptr to most recent child Struct task_struct p_ysptr; // ptr to following sibling Struct task_struct p_osptr; // ptr to previous sibling Struct task_struct *next_task; // in process list Struct task_struct *prev_task; // in process list Struct task_struct *next_run; // in ready queue Struct task_struct *prev_run; //in ready queue
Struct mm_struct mm[1]; • Unsigned long kernel_stack_page; • Unsigned long saved_kernel_stack; • Struct fs_struct fs[1]; • Long utime, stime, cutime, cstime, start_time; • Struct sem_queue *semsleeping; • Struct wait_queue *wait_chldexit; • Struct sigaction sigaction[32]; • Struct rlimit rlim[RLIM_NLIMITS]; • Struct thread_struct tss; // includes saved registers • Unsigned long policy; // SCHED_FIFO,SCHED_RR,SCHED_OTHER • Unsigned long rt_priority; • // for SMPs • Int processor, last processor; • Int lock_depth; • … • }
Struct task_struct init_task; // Task structure for init • The list of tasks is a doubly-linked circular list. • Struct task_struct current; // current task • In SMPs, there is task_struct *current_set[NR_CPUS]; • Earlier versions used a simple task[] table, and task[0] is INIT_TASK
Queues and Semaphores • Circular list Struct wait_queue { Struct task_struct * task; Struct wait_queue * nest; } • Access only using Void add_wait_queue(struct wait_queue **, struct wait_queue *) Void remove_wait_queue(struct wait_queue **, struct wait_queue *)
Sleep and wakeup implementation using wait queues void sleep_on(struct wait_queue **queue) { add_wait_queue(queue, ¤t); schedule(); remove_wait_queue(queue, ¤t); } void wake_up(struct wait_queue **queue) { struct wait_queue *p; do { P->task->state = TASK_RUNNING; P = p-> next; } while (p!=queue); } Exercise: Implement Semaphores
Process Creation Using fork() • Clone flags = CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_PID do_fork(clone_flags, unsigned long usp, struct pt_regs *regs) { unsigned long new_stack; struct task_struct *p; p = (struct task_struct *) kmalloc(sizeof(*p), GFP_KERNEL); new_stack = alloc_kernel_stack(); nr = find_empty_process(); task[nr] = p; *p = *current; // inherit parent’s task struct
P->did_exec = 0; P->swappable = 0; P->pid = get_pid(clone_flags); P->next_run = p->prev_run = NULL; … P->start_time = jiffies; P->swappable = 1; P->exit_signal = clone_flags & CSIGNAL; P->counter = current->counter >> 1; Init_waitqueue(&p->wait_chldexit); Init_timer(&p->real_timer); Copy_files(clone_flags,p); Copy_fs(clone_flags,p) Copy_sighand(clone_flags,p); Copy_mm(clone_flags,p); Copy_thread(nr,clone_flags,usp,p,regs); // sets regs, and p->tss.eip is set to ret_from_sys_call for return address Wake_up_process(p); // puts in ready queue Return p->pid; }
execve() Static int do_execve(char *filename, char **argv, char **envp, struct pt_regs *regs) { …. for (fmt = formats; ; fmt = fmt-> next) { fmt->load_binary(….) // find out if this is the loader else go to the next } } Load_binary_format(…) { … check magic number, format etc. flush_old_exec(bprm); // releases old memory
current->mm->start_code = N_TXT_ADDR(ex); current->mm->end_code = current->mm->start_code + ex.a_text; current->mm->end_data = current->mm->end_code + ex.a_data; current->mm->start_brk = current->mm->end_data; current->mm->brk = ex.a_bss + current->mm->start_brk; current->suid = bprm->e_uid; current->euid = bprm->e_uid; … fd = open(bprm->inode,O_RDONLY); file = current->files->fd[fd]; do_mmap(file,N_TEXTADDR(ex),ex.a_text,PROT_READ|PROT_EXEC,| MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset); do_mmap(file,N_TXTADDR(ex) + ex.a_text, ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); sys_close(fd); set_brk(current->mm->start_brk,current->mm->brk); current->mm->start_stack = ….. start_thread(regs, ex.a_entry, p); }
Linux Scheduling • 3 scheduling classes set by sched_setscheduler() • SCHED_FIFO and SCHED_RR are real-time classes • SCHED_OTHER is for the rest • When a process with higher real-time priority (rt_priority) wishes to run, all other processes with lower real-time priority are thrust aside. • In SCHED_FIFO, a process runs unil I reliquishes control or another with higher real-time priority wishes to run. • SCHED_RR process, in addition to this, is also interrupted when its time slice explires or there are processes of same real-time priority (RR between processes of this class) • Schedule() in kernel/sched.c implements the scheduler. • It is called when • Blocking call (sleep) • After every ret_from_sys_call if need_resched is on • After every slow interrupt if need_resched is on
schedule(void) { struct task_struct *p, *prev, *next; prev = current; next = &init_task; if (bh_active & bh_mask) { intr_count = 1; do_bottom_half(); intr_count = 0; } run_task_queue(&tq_scheduler); if (prev->state != TASK_RUNNING) del_from_runqueue(prev); else if (prev->policy == SCHED_RR && prev->counter == 0) { Prev->counter = prev->priority; Move_last_runqueue(prev); }
Restart_reschedule: // goodness calculation next = &init_task; next_p = 1000; for (p=init_task->next_run; p!=&init_task; p=p->next_run) { if (p->policy != SCHED_OTHER) weight = 1000 + p->rt_priority; else weight = p->counter; if (weight > next_p) { next_p = weight; next = p; } if (next_p == 0) { for_each_task(p) // not just in Ready Queue !!! p->counter = (p->counter/2) + p->priority; goto restart_reschedule; } if (prev != next) switch_to(prev,next); }