/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see proj13.1/kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see proj13.1/libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: YOUR CODE */ #if USE_SKEW_HEAP if (rq->lab6_run_pool == NULL) return NULL; struct proc_struct *p = le2proc(rq->lab6_run_pool, lab6_run_pool); #else list_entry_t *le = list_next(&(rq->run_list)); if (le == &rq->run_list) return NULL; struct proc_struct *p = le2proc(le, run_link); le = list_next(le); while (le != &rq->run_list) { struct proc_struct *q = le2proc(le, run_link); if ((int32_t)(p->lab6_stride - q->lab6_stride) > 0) p = q; le = list_next(le); } #endif if (p->lab6_priority == 0) p->lab6_stride += BIG_STRIDE; else p->lab6_stride += BIG_STRIDE / p->lab6_priority; cprintf("%d is picked by pick_next proc_prioperty:%d proc_stride:%u \n",p->pid,p->lab6_priority,p->lab6_stride); return p; }
/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: YOUR CODE * (1) get a proc_struct pointer p with the minimum value of stride (1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_poll (1.2) If using list, we have to search list to find the p with minimum stride value * (2) update p;s stride value: p->lab6_stride * (3) return p */ struct proc_struct *p; if (USE_SKEW_HEAP) { if (rq->lab6_run_pool == NULL) return NULL; p = le2proc(rq->lab6_run_pool,lab6_run_pool); } else { list_entry_t *le = list_next(&(rq->run_list)); if (le == &rq->run_list) return NULL; p = le2proc(le,run_link); le = list_next(le); while (le != &rq->run_list) { struct proc_struct *q = le2proc(le,run_link); if (p->lab6_stride > q->lab6_stride) p = q; le = list_next(le); } } if (p->lab6_priority == 0) { p->lab6_stride += BIG_STRIDE; } else { p->lab6_stride += BIG_STRIDE / p->lab6_priority; } return p; }
/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see proj13.1/kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see proj13.1/libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { // rq代表就绪队列,这个函数主要用于挑选下一个要运行的进程 /* LAB6: YOUR CODE * (1) get a proc_struct pointer p with the minimum value of stride (1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_poll (1.2) If using list, we have to search list to find the p with minimum stride value * (2) update p;s stride value: p->lab6_stride * (3) return p */ #if USE_SKEW_HEAP if (rq->lab6_run_pool == NULL) return NULL; struct proc_struct *p = le2proc(rq->lab6_run_pool, lab6_run_pool); // 如果使用了优先队列的话,只需要队列的第一个就可以了 #else list_entry_t *le = list_next(&(rq->run_list)); if (le == &rq->run_list) return NULL; struct proc_struct *p = le2proc(le, run_link); le = list_next(le); while (le != &rq->run_list) { struct proc_struct *q = le2proc(le, run_link); if ((int32_t)(p->lab6_stride - q->lab6_stride) > 0) p = q; le = list_next(le); } #endif if (p->lab6_priority == 0) p->lab6_stride += BIG_STRIDE; // 将优先级提升至最高? else p->lab6_stride += BIG_STRIDE / p->lab6_priority; return p; }
/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: 2014210912 * (1) get a proc_struct pointer p with the minimum value of stride (1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_poll (1.2) If using list, we have to search list to find the p with minimum stride value * (2) update p;s stride value: p->lab6_stride * (3) return p */ struct proc_struct *tmp; struct list_entry* le=list_next(&(rq->run_list)); if(le==&rq->run_list) return NULL; struct proc_struct *p=le2proc(le,run_link); while(le->next!=&rq->run_list){ le=le->next; tmp=le2proc(le,run_link); if((int32_t)(p->lab6_stride-tmp->lab6_stride)>0) p=tmp; } if(p->lab6_priority==0) p->lab6_stride+=BIG_STRIDE; else p->lab6_stride+=BIG_STRIDE/p->lab6_priority; return p; }
/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: 2013011377 * (1) get a proc_struct pointer p with the minimum value of stride (1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_poll (1.2) If using list, we have to search list to find the p with minimum stride value * (2) update p;s stride value: p->lab6_stride * (3) return p */ struct proc_struct *p = NULL; #if USE_SKEW_HEAP if(!rq->lab6_run_pool) return NULL; p = le2proc(rq->lab6_run_pool, lab6_run_pool); #else list_entry_t *le = list_next(&rq->run_list); while ((le = list_next(le)) != &rq->run_list) { struct proc_struct *cnt = le2proc(le, run_link); if (!p || proc_stride_comp_f(&p->lab6_run_pool, &cur->lab6_run_pool)) p = cur; } #endif if (p) p->lab6_stride += BIG_STRIDE / (p->lab6_priority == 0? 1: p->lab6_priority); return p; }
/* The compare function for two skew_heap_node_t's and the * corresponding procs*/ static int proc_stride_comp_f(void *a, void *b) { struct proc_struct *p = le2proc(a, lab6_run_pool); struct proc_struct *q = le2proc(b, lab6_run_pool); int32_t c = p->lab6_stride - q->lab6_stride; if (c > 0) return 1; else if (c == 0) return 0; else return -1; }
void schedule(void) { bool intr_flag; list_entry_t *le, *last; struct proc_struct *next = NULL; local_intr_save(intr_flag); { current->need_resched = 0; last = (current == idleproc) ? &proc_list : &(current->list_link); le = last; do { if ((le = list_next(le)) != &proc_list) { next = le2proc(le, list_link); if (next->state == PROC_RUNNABLE) { break; } } } while (le != last); if (next == NULL || next->state != PROC_RUNNABLE) { next = idleproc; } next->runs ++; if (next != current) { //proc_print(next); cprintf("sche! proc %d, pc=%08x\n\n",next->pid,next->context.pc); //cprintf("sp=%08x\n\n",read_sp()); proc_run(next); } } local_intr_restore(intr_flag); }
// get_pid - alloc a unique pid for process static int get_pid(void) { static_assert(MAX_PID > MAX_PROCESS); struct proc_struct *proc; list_entry_t *list = &proc_list, *le; static int next_safe = MAX_PID, last_pid = MAX_PID; if (++ last_pid >= MAX_PID) { last_pid = pls_read(lcpu_count); goto inside; } if (last_pid >= next_safe) { inside: next_safe = MAX_PID; repeat: le = list; while ((le = list_next(le)) != list) { proc = le2proc(le, list_link); if (proc->pid == last_pid) { if (++ last_pid >= next_safe) { if (last_pid >= MAX_PID) { last_pid = 1; } next_safe = MAX_PID; goto repeat; } } else if (proc->pid > last_pid && next_safe > proc->pid) { next_safe = proc->pid; } } } return last_pid; }
void schedule(void) { bool intr_flag; list_entry_t *le, *last; struct proc_struct *next = NULL; local_intr_save(intr_flag); { current->need_resched = 0; last = (current == idleproc) ? &proc_list : &(current->list_link); le = last; do { if ((le = list_next(le)) != &proc_list) { next = le2proc(le, list_link); if (next->state == PROC_RUNNABLE) { break; } } } while (le != last); if (next == NULL || next->state != PROC_RUNNABLE) { next = idleproc; } next->runs ++; if (next != current) { proc_run(next); } } local_intr_restore(intr_flag); }
static struct proc_struct * RR_pick_next(struct run_queue *rq) { list_entry_t *le = list_next(&(rq->run_list)); if (le != &(rq->run_list)) { return le2proc(le, run_link); } return NULL; }
// find_proc - find proc frome proc hash_list according to pid struct proc_struct * find_proc(int pid) { if (0 < pid && pid < MAX_PID) { list_entry_t *list = hash_list + pid_hashfn(pid), *le = list; while ((le = list_next(le)) != list) { struct proc_struct *proc = le2proc(le, hash_link); if (proc->pid == pid) { return proc; } } } return NULL; }
// check if there is a RT process in run queue with earlier deadline // necessary on each tick, because at any time a new process may have joined // combine with tick_decrease_RT_pt eventually bool rq_exist_earlier_deadline(struct run_queue *rq, int deadline) { struct proc_struct *proc; // proc iterator list_entry_t *le; // list iterator list_entry_t *start = list_next(&(rq->run_list)); // temporary use for(le = list_next(&(rq->run_list)); le->next != start; le = list_next(le)) { proc = le2proc(le, run_link); if (proc->isRT) { if (proc->pt < deadline) return TRUE; } } return FALSE; }
/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: 2013011400 * (1) get a proc_struct pointer p with the minimum value of stride (1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_poll (1.2) If using list, we have to search list to find the p with minimum stride value * (2) update p;s stride value: p->lab6_stride * (3) return p */ list_entry_t *le = list_next(&rq->run_list); if (le == &rq->run_list) return NULL; struct proc_struct *p = le2proc(le, run_link); for (le = list_next(le); le != &rq->run_list; le = list_next(le)) { struct proc_struct *q = le2proc(le, run_link); if ((int32_t)(p->lab6_stride - q->lab6_stride) > 0) p = q; } p->lab6_stride += BIG_STRIDE / (p->lab6_priority ? p->lab6_priority : 1); return p; }
// do_exit - kill a thread group, called by syscall or trap handler int do_exit(int error_code) { bool intr_flag; local_intr_save(intr_flag); { list_entry_t *list = &(current->thread_group), *le = list; while ((le = list_next(le)) != list) { struct proc_struct *proc = le2proc(le, thread_group); __do_kill(proc, error_code); } } local_intr_restore(intr_flag); return do_exit_thread(error_code); }
/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: 2012012017 * (1) get a proc_struct pointer p with the minimum value of stride (1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_poll (1.2) If using list, we have to search list to find the p with minimum stride value * (2) update p;s stride value: p->lab6_stride * (3) return p */ #if USE_SKEW_HEAP if (!rq->lab6_run_pool) return NULL; struct proc_struct *p = le2proc(rq->lab6_run_pool, lab6_run_pool); #else list_entry_t *le; struct proc_struct *p = 0; for (le = list_next(&rq->run_list); le != &rq->run_list; le = list_next(le)) { struct proc_struct *q = le2proc(le, run_link); if (!p || proc_stride_comp_f(&p->lab6_run_pool, &q->lab6_run_pool) == 1) p = q; } #endif if (p) p->lab6_stride += BIG_STRIDE / p->lab6_priority; return p; }
/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: 2012011383 * (1) get a proc_struct pointer p with the minimum value of stride (1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_poll (1.2) If using list, we have to search list to find the p with minimum stride value * (2) update p;s stride value: p->lab6_stride * (3) return p */ if (rq->lab6_run_pool == NULL) return NULL; struct proc_struct *p = le2proc(rq->lab6_run_pool, lab6_run_pool); return p; }
/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: YOUR CODE * (1) get a proc_struct pointer p with the minimum value of stride (1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_poll (1.2) If using list, we have to search list to find the p with minimum stride value * (2) update p;s stride value: p->lab6_stride * (3) return p */ if (rq->lab6_run_pool == NULL) return NULL; skew_heap_entry_t *s = rq->lab6_run_pool; struct proc_struct *proc = le2proc(s,lab6_run_pool); proc->lab6_stride += BIG_STRIDE / proc->lab6_priority; return proc; }
// do_wait - wait one OR any children with PROC_ZOMBIE state, and free memory space of kernel stack // - proc struct of this child. // NOTE: only after do_wait function, all resources of the child proces are free. int do_wait(int pid, int *code_store) { struct proc_struct *proc; bool intr_flag, haskid; repeat: cprintf("do_wait: begin\n"); haskid = 0; list_entry_t *list = &proc_list, *le = list; while ((le = list_next(le)) != list) { proc = le2proc(le, list_link); if (proc != NULL) { haskid = 1; if (proc->state == PROC_ZOMBIE) { goto found; } } } if (haskid) { cprintf("do_wait: has kid begin\n"); cprintf("proc_wait:: pid: %d, name: %s from PROC_RUNABLE to PROC_SLEEPING\n",current->pid, current->name); current->state = PROC_SLEEPING; current->wait_state = WT_CHILD; schedule(); goto repeat; } return -E_BAD_PROC; found: cprintf("do_wait: has kid find child pid%d\n",proc->pid); cprintf("proc_exit:: pid: %d, name: %s from PROC_ZOMBIE to exit\n",proc->pid, proc->name); if (proc == idleproc ) { panic("wait idleproc \n"); } local_intr_save(intr_flag); { remove_links(proc); } local_intr_restore(intr_flag); put_kstack(proc); kfree(proc); return 0; }
// decrease the pt of all RT procs in runqueue // assume all process are RT void tick_decrease_RT_pt(struct run_queue *rq, struct proc_struct *currentproc) { struct proc_struct *proc; // proc iterator list_entry_t *le; // list iterator list_entry_t *start = list_next(&(rq->run_list)); // temporary use bool noRTprocs = TRUE; // see if there are still RT procs in the run queue. Otherwise exist. Helps debugging for(le = list_next(&(rq->run_list)); le->next != start; le = list_next(le)) { proc = le2proc(le, run_link); if (proc->isRT) { noRTprocs = FALSE; proc->pt--; // for all RT procs the pt has decreased one! if (proc->pt == 0 && proc->ct < proc->compute_time) panic("pt of proc %d == 0 but ct == %d (process in run queue)", proc->pid, proc->ct); if (proc->pt < 0) panic("pt of RT proc %d < 0! RT schedule failure!", proc->pid); } } //if (noRTprocs && currentproc->isRT == FALSE) // init proc // panic("no RT procs left. Exiting"); }
/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: 2009011419 * (1) get a proc_struct pointer p with the minimum value of stride (1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_poll (1.2) If using list, we have to search list to find the p with minimum stride value * (2) update p;s stride value: p->lab6_stride * (3) return p */ if (!rq->lab6_run_pool) { return NULL ; } struct proc_struct *p = le2proc((rq->lab6_run_pool), lab6_run_pool); p->lab6_stride += (BIG_STRIDE / p->lab6_priority); return p; }
/* * stride_pick_next pick the element from the ``run-queue'', with the * minimum value of stride, and returns the corresponding process * pointer. The process pointer would be calculated by macro le2proc, * see kern/process/proc.h for definition. Return NULL if * there is no process in the queue. * * When one proc structure is selected, remember to update the stride * property of the proc. (stride += BIG_STRIDE / priority) * * hint: see libs/skew_heap.h for routines of the priority * queue structures. */ static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: 2013011356 * (1) get a proc_struct pointer p with the minimum value of stride (1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_pool (1.2) If using list, we have to search list to find the p with minimum stride value * (2) update p;s stride value: p->lab6_stride * (3) return p */ // assert(rq != NULL); if (rq->lab6_run_pool == NULL) { return NULL; } else { struct proc_struct *proc = le2proc(rq->lab6_run_pool, lab6_run_pool); assert (proc->lab6_priority > 0); proc->lab6_stride += BIG_STRIDE / proc->lab6_priority; // cprintf("next is pid %d, stride is %d, priority is %d\n", proc->pid, proc->lab6_stride, proc->lab6_priority); return proc; } }
/** * Find a proc_struct whose mm->pgdir is @pgdir. * Note that if multiple proc_structs have the same pgdir, then they must be threads of the same group, * and thus are in the same container process. * @param pgdir the 'hint' page table for finding the target proc_struct * @return the pointer to the proc_struct found, * or NULL if the map/uemap should be done in the main process */ static struct proc_struct* find_proc_by_pgdir (pde_t *pgdir) { /* Some special occasions: * 1. current == NULL means we're work in test functions. * Then the map/unmap belongs to the main process (we only have it at that time). * 2. current->mm == NULL means current is a kernel thread. * The only kernel thread which needs to modify user address space is kswapd * for it should invalidate the page which has been swapped out. * The others should be only occured when creating a user process by 'do_execve' * and the work belongs to the host process. * 3. if current->mm->pgdir = @pgdir, which is commonly the case, * 'current' is obviously what we are looking for. * This is just for speeding up. */ if (current != kswapd) { if (current == NULL || current->mm == NULL) return NULL; if (pgdir == current->mm->pgdir) return current; } /* Search for a proc_sturct by brute force, * iterating the proc list and ask everyone. */ list_entry_t *le = &proc_list; if (list_next(le) == 0) /* not initialized. this happens when kswapd is initializing */ return NULL; struct proc_struct *proc; while (( le = list_next(le) ) != &proc_list) { proc = le2proc(le, list_link); if (proc->mm != NULL && proc->mm->pgdir == pgdir) { return proc; } } return NULL; }
// next_thread - get the next thread "proc" from thread_group list static struct proc_struct * next_thread(struct proc_struct *proc) { return le2proc(list_next(&(proc->thread_group)), thread_group); }
void schedule(void) { /* schedule in irq ctx is not allowed */ assert(!ucore_in_interrupt()); bool intr_flag; struct proc_struct *next; #ifndef MT_SUPPORT list_entry_t head; int lapic_id = pls_read(lapic_id); #endif local_intr_save(intr_flag); int lcpu_count = pls_read(lcpu_count); { current->need_resched = 0; #ifndef MT_SUPPORT if (current->mm) { assert(current->mm->lapic == lapic_id); current->mm->lapic = -1; } #endif if (current->state == PROC_RUNNABLE && current->pid >= lcpu_count) { sched_class_enqueue(current); } #ifndef MT_SUPPORT list_init(&head); while (1) { next = sched_class_pick_next(); if (next != NULL) sched_class_dequeue(next); if (next && next->mm && next->mm->lapic != -1) { list_add(&head, &(next->run_link)); } else { list_entry_t *cur; while ((cur = list_next(&head)) != &head) { list_del_init(cur); sched_class_enqueue(le2proc(cur, run_link)); } break; } } #else next = sched_class_pick_next(); if (next != NULL) sched_class_dequeue(next); #endif /* !MT_SUPPORT */ if (next == NULL) { next = idleproc; } next->runs ++; /* Collect information here*/ if (sched_collect_info) { int lcpu_count = pls_read(lcpu_count); int lcpu_idx = pls_read(lcpu_idx); int loc = sched_info_head[lcpu_idx]; int prev = sched_info_pid[loc*lcpu_count + lcpu_idx]; if (next->pid == prev) sched_info_times[loc*lcpu_count + lcpu_idx] ++; else { sched_info_head[lcpu_idx] ++; if (sched_info_head[lcpu_idx] >= PGSIZE / sizeof(uint16_t) / lcpu_count) sched_info_head[lcpu_idx] = 0; loc = sched_info_head[lcpu_idx]; uint16_t prev_pid = sched_info_pid[loc*lcpu_count + lcpu_idx]; uint16_t prev_times = sched_info_times[loc*lcpu_count + lcpu_idx]; if (prev_times > 0 && prev_pid >= lcpu_count + 2) sched_slices[lcpu_idx][prev_pid % SLICEPOOL_SIZE] += prev_times; sched_info_pid[loc*lcpu_count + lcpu_idx] = next->pid; sched_info_times[loc*lcpu_count + lcpu_idx] = 1; } } #ifndef MT_SUPPORT assert(!next->mm || next->mm->lapic == -1); if (next->mm) next->mm->lapic = lapic_id; #endif if (next != current) { #if 0 kprintf("N %d to %d\n", current->pid, next->pid); #endif proc_run(next); } } local_intr_restore(intr_flag); }