proc.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*****************************************************************
  2. * proc.c
  3. * adapted from MIT xv6 by Zhiyi Huang, [email protected]
  4. * University of Otago
  5. *
  6. ********************************************************************/
  7. #include "types.h"
  8. #include "defs.h"
  9. #include "param.h"
  10. #include "memlayout.h"
  11. #include "mmu.h"
  12. #include "arm.h"
  13. #include "proc.h"
  14. #include "spinlock.h"
  15. struct {
  16. struct spinlock lock;
  17. struct proc proc[NPROC];
  18. } ptable;
  19. static struct proc *initproc;
  20. int first_sched = 1;
  21. int nextpid = 1;
  22. extern void forkret(void);
  23. extern void trapret(void);
  24. static void wakeup1(void *chan);
  25. void
  26. pinit(void)
  27. {
  28. memset(&ptable, 0, sizeof(ptable));
  29. initlock(&ptable.lock, "ptable");
  30. }
  31. //PAGEBREAK: 32
  32. // Look in the process table for an UNUSED proc.
  33. // If found, change state to EMBRYO and initialize
  34. // state required to run in the kernel.
  35. // Otherwise return 0.
  36. static struct proc*
  37. allocproc(void)
  38. {
  39. struct proc *p;
  40. char *sp;
  41. acquire(&ptable.lock);
  42. for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
  43. if(p->state == UNUSED)
  44. goto found;
  45. release(&ptable.lock);
  46. return 0;
  47. found:
  48. p->state = EMBRYO;
  49. p->pid = nextpid++;
  50. release(&ptable.lock);
  51. // Allocate kernel stack.
  52. if((p->kstack = kalloc()) == 0){
  53. p->state = UNUSED;
  54. return 0;
  55. }
  56. memset(p->kstack, 0, PGSIZE);
  57. sp = p->kstack + KSTACKSIZE;
  58. // Leave room for trap frame.
  59. sp -= sizeof *p->tf;
  60. p->tf = (struct trapframe*)sp;
  61. // Set up new context to start executing at forkret,
  62. // which returns to trapret.
  63. sp -= sizeof *p->context;
  64. p->context = (struct context*)sp;
  65. memset(p->context, 0, sizeof *p->context);
  66. p->context->pc = (uint)forkret;
  67. p->context->lr = (uint)trapret;
  68. return p;
  69. }
  70. //PAGEBREAK: 32
  71. // Set up first user process.
  72. void
  73. userinit(void)
  74. {
  75. struct proc *p;
  76. extern char _binary_initcode_start[], _binary_initcode_end[];
  77. uint _binary_initcode_size;
  78. _binary_initcode_size = (uint)_binary_initcode_end - (uint)_binary_initcode_start;
  79. p = allocproc();
  80. //cprintf("after allocproc: initcode start: %x end %x\n", _binary_initcode_start, _binary_initcode_end);
  81. initproc = p;
  82. //cprintf("initproc is %x\n", initproc);
  83. if((p->pgdir = setupkvm()) == 0)
  84. panic("userinit: out of memory?");
  85. //cprintf("after setupkvm\n");
  86. inituvm(p->pgdir, _binary_initcode_start, _binary_initcode_size);
  87. //cprintf("after initkvm\n");
  88. p->sz = PGSIZE;
  89. memset(p->tf, 0, sizeof(*p->tf));
  90. p->tf->spsr = 0x10;
  91. p->tf->sp = PGSIZE;
  92. p->tf->pc = 0; // beginning of initcode.S
  93. safestrcpy(p->name, "initcode", sizeof(p->name));
  94. p->cwd = namei("/");
  95. p->state = RUNNABLE;
  96. }
  97. // Grow current process's memory by n bytes.
  98. // Return 0 on success, -1 on failure.
  99. int
  100. growproc(int n)
  101. {
  102. uint sz;
  103. sz = curr_proc->sz;
  104. if(n > 0){
  105. if((sz = allocuvm(curr_proc->pgdir, sz, sz + n)) == 0)
  106. return -1;
  107. } else if(n < 0){
  108. if((sz = deallocuvm(curr_proc->pgdir, sz, sz + n)) == 0)
  109. return -1;
  110. }
  111. curr_proc->sz = sz;
  112. switchuvm(curr_proc);
  113. return 0;
  114. }
  115. // Create a new process copying p as the parent.
  116. // Sets up stack to return as if from system call.
  117. // Caller must set state of returned proc to RUNNABLE.
  118. int
  119. fork(void)
  120. {
  121. int i, pid;
  122. struct proc *np;
  123. // Allocate process.
  124. if((np = allocproc()) == 0)
  125. return -1;
  126. // Copy process state from p.
  127. if((np->pgdir = copyuvm(curr_proc->pgdir, curr_proc->sz)) == 0){
  128. kfree(np->kstack);
  129. np->kstack = 0;
  130. np->state = UNUSED;
  131. return -1;
  132. }
  133. np->sz = curr_proc->sz;
  134. np->parent = curr_proc;
  135. *np->tf = *curr_proc->tf;
  136. // Clear r0 so that fork returns 0 in the child.
  137. np->tf->r0 = 0;
  138. for(i = 0; i < NOFILE; i++)
  139. if(curr_proc->ofile[i])
  140. np->ofile[i] = filedup(curr_proc->ofile[i]);
  141. np->cwd = idup(curr_proc->cwd);
  142. pid = np->pid;
  143. np->state = RUNNABLE;
  144. safestrcpy(np->name, curr_proc->name, sizeof(curr_proc->name));
  145. return pid;
  146. }
  147. // Exit the current process. Does not return.
  148. // An exited process remains in the zombie state
  149. // until its parent calls wait() to find out it exited.
  150. void
  151. exit(void)
  152. {
  153. struct proc *p;
  154. int fd;
  155. if(curr_proc == initproc)
  156. panic("init exiting");
  157. // Close all open files.
  158. for(fd = 0; fd < NOFILE; fd++){
  159. if(curr_proc->ofile[fd]){
  160. fileclose(curr_proc->ofile[fd]);
  161. curr_proc->ofile[fd] = 0;
  162. }
  163. }
  164. iput(curr_proc->cwd);
  165. curr_proc->cwd = 0;
  166. acquire(&ptable.lock);
  167. // Parent might be sleeping in wait().
  168. wakeup1(curr_proc->parent);
  169. // Pass abandoned children to init.
  170. for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
  171. if(p->parent == curr_proc){
  172. p->parent = initproc;
  173. if(p->state == ZOMBIE)
  174. wakeup1(initproc);
  175. }
  176. }
  177. // Jump into the scheduler, never to return.
  178. curr_proc->state = ZOMBIE;
  179. sched();
  180. panic("zombie exit");
  181. }
  182. // Wait for a child process to exit and return its pid.
  183. // Return -1 if this process has no children.
  184. int
  185. wait(void)
  186. {
  187. struct proc *p;
  188. int havekids, pid;
  189. acquire(&ptable.lock);
  190. for(;;){
  191. // Scan through table looking for zombie children.
  192. havekids = 0;
  193. for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
  194. if(p->parent != curr_proc)
  195. continue;
  196. havekids = 1;
  197. if(p->state == ZOMBIE){
  198. // Found one.
  199. pid = p->pid;
  200. kfree(p->kstack);
  201. p->kstack = 0;
  202. freevm(p->pgdir);
  203. p->state = UNUSED;
  204. p->pid = 0;
  205. p->parent = 0;
  206. p->name[0] = 0;
  207. p->killed = 0;
  208. release(&ptable.lock);
  209. return pid;
  210. }
  211. }
  212. // No point waiting if we don't have any children.
  213. if(!havekids || curr_proc->killed){
  214. release(&ptable.lock);
  215. return -1;
  216. }
  217. //cprintf("inside wait before calling sleep\n");
  218. // Wait for children to exit. (See wakeup1 call in proc_exit.)
  219. sleep(curr_proc, &ptable.lock); //DOC: wait-sleep
  220. }
  221. }
  222. //PAGEBREAK: 42
  223. // Per-CPU process scheduler.
  224. // Each CPU calls scheduler() after setting itself up.
  225. // Scheduler never returns. It loops, doing:
  226. // - choose a process to run
  227. // - swtch to start running that process
  228. // - eventually that process transfers control
  229. // via swtch back to the scheduler.
  230. void
  231. scheduler(void)
  232. {
  233. struct proc *p;
  234. for(;;){
  235. // Enable interrupts on this processor.
  236. //cprintf("before enabling interrupts\n");
  237. if(first_sched) first_sched = 0;
  238. else sti();
  239. // Loop over process table looking for process to run.
  240. acquire(&ptable.lock);
  241. for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
  242. if(p->state != RUNNABLE)
  243. continue;
  244. // Switch to chosen process. It is the process's job
  245. // to release ptable.lock and then reacquire it
  246. // before jumping back to us.
  247. curr_proc = p;
  248. //cprintf("before switching page table\n");
  249. switchuvm(p);
  250. p->state = RUNNING;
  251. //cprintf("after switching page table\n");
  252. swtch(&curr_cpu->scheduler, curr_proc->context);
  253. switchkvm();
  254. // Process is done running for now.
  255. // It should have changed its p->state before coming back.
  256. curr_proc = 0;
  257. }
  258. release(&ptable.lock);
  259. }
  260. }
  261. // Enter scheduler. Must hold only ptable.lock
  262. // and have changed proc->state.
  263. void
  264. sched(void)
  265. {
  266. int intena;
  267. if(!holding(&ptable.lock))
  268. panic("sched ptable.lock");
  269. if(curr_cpu->ncli != 1)
  270. panic("sched locks");
  271. if(curr_proc->state == RUNNING)
  272. panic("sched running");
  273. if(!(readcpsr()&PSR_DISABLE_IRQ))
  274. panic("sched interruptible");
  275. intena = curr_cpu->intena;
  276. swtch(&curr_proc->context, curr_cpu->scheduler);
  277. curr_cpu->intena = intena;
  278. }
  279. // Give up the CPU for one scheduling round.
  280. void
  281. yield(void)
  282. {
  283. acquire(&ptable.lock); //DOC: yieldlock
  284. curr_proc->state = RUNNABLE;
  285. sched();
  286. release(&ptable.lock);
  287. }
  288. // A fork child's very first scheduling by scheduler()
  289. // will swtch here. "Return" to user space.
  290. void
  291. forkret(void)
  292. {
  293. static int first = 1;
  294. // Still holding ptable.lock from scheduler.
  295. release(&ptable.lock);
  296. if (first) {
  297. // Some initialization functions must be run in the context
  298. // of a regular process (e.g., they call sleep), and thus cannot
  299. // be run from main().
  300. first = 0;
  301. initlog();
  302. }
  303. //cprintf("inside forkret\n");
  304. // Return to "caller", actually trapret (see allocproc).
  305. }
  306. // Atomically release lock and sleep on chan.
  307. // Reacquires lock when awakened.
  308. void
  309. sleep(void *chan, struct spinlock *lk)
  310. {
  311. if(curr_proc == 0)
  312. panic("sleep");
  313. if(lk == 0)
  314. panic("sleep without lk");
  315. // Must acquire ptable.lock in order to
  316. // change p->state and then call sched.
  317. // Once we hold ptable.lock, we can be
  318. // guaranteed that we won't miss any wakeup
  319. // (wakeup runs with ptable.lock locked),
  320. // so it's okay to release lk.
  321. if(lk != &ptable.lock){ //DOC: sleeplock0
  322. acquire(&ptable.lock); //DOC: sleeplock1
  323. release(lk);
  324. }
  325. // Go to sleep.
  326. curr_proc->chan = chan;
  327. curr_proc->state = SLEEPING;
  328. //cprintf("inside sleep before calling sched\n");
  329. sched();
  330. // Tidy up.
  331. curr_proc->chan = 0;
  332. // Reacquire original lock.
  333. if(lk != &ptable.lock){ //DOC: sleeplock2
  334. release(&ptable.lock);
  335. acquire(lk);
  336. }
  337. }
  338. //PAGEBREAK!
  339. // Wake up all processes sleeping on chan.
  340. // The ptable lock must be held.
  341. static void
  342. wakeup1(void *chan)
  343. {
  344. struct proc *p;
  345. for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
  346. if(p->state == SLEEPING && p->chan == chan)
  347. p->state = RUNNABLE;
  348. }
  349. // Wake up all processes sleeping on chan.
  350. void
  351. wakeup(void *chan)
  352. {
  353. acquire(&ptable.lock);
  354. wakeup1(chan);
  355. release(&ptable.lock);
  356. }
  357. // Kill the process with the given pid.
  358. // Process won't exit until it returns
  359. // to user space (see trap in trap.c).
  360. int
  361. kill(int pid)
  362. {
  363. struct proc *p;
  364. acquire(&ptable.lock);
  365. for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
  366. if(p->pid == pid){
  367. p->killed = 1;
  368. // Wake process from sleep if necessary.
  369. if(p->state == SLEEPING)
  370. p->state = RUNNABLE;
  371. release(&ptable.lock);
  372. return 0;
  373. }
  374. }
  375. release(&ptable.lock);
  376. return -1;
  377. }
  378. //PAGEBREAK: 36
  379. // Print a process listing to console. For debugging.
  380. // Runs when user types ^P on console.
  381. // No lock to avoid wedging a stuck machine further.
  382. void
  383. procdump(void)
  384. {
  385. }