proc_syscalls.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #include <types.h>
  2. #include <kern/errno.h>
  3. #include <kern/unistd.h>
  4. #include <kern/wait.h>
  5. #include <mips/trapframe.h>
  6. #include <lib.h>
  7. #include <vfs.h>
  8. #include <vnode.h>
  9. #include <syscall.h>
  10. #include <current.h>
  11. #include <proc.h>
  12. #include <thread.h>
  13. #include <addrspace.h>
  14. #include <copyinout.h>
  15. #include <synch.h>
  16. #include <kern/fcntl.h>
  17. void sys__exit(int exitcode)
  18. {
  19. struct addrspace * as;
  20. struct proc * p = curproc;
  21. p->exitcode = exitcode;
  22. DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode);
  23. KASSERT(curproc->p_addrspace != NULL);
  24. lock_acquire(proclock);
  25. int x = listpop(p->kids);
  26. while (x)
  27. {
  28. if(processes->pids[x])
  29. {
  30. processes->pids[x]->parent = NULL;
  31. if (processes->pids[x]->exitcode >= 0)
  32. {
  33. lock_release(proclock);
  34. proc_destroy(processes->pids[x]);
  35. lock_acquire(proclock);
  36. }
  37. }
  38. x = listpop(p->kids);
  39. }
  40. lock_release(proclock);
  41. listelete(p->kids);
  42. // VFS fields
  43. if (p->p_cwd)
  44. {
  45. VOP_DECREF(p->p_cwd);
  46. p->p_cwd = NULL;
  47. }
  48. as_deactivate();
  49. as = curproc_setas(NULL);
  50. as_destroy(as);
  51. /* detach this thread from its process */
  52. /* note: curproc cannot be used after this call */
  53. proc_remthread(curthread);
  54. threadarray_cleanup(&p->p_threads);
  55. spinlock_cleanup(&p->p_lock);
  56. lock_acquire(p->waitlock);
  57. cv_broadcast(p->waiting, p->waitlock);
  58. lock_release(p->waitlock);
  59. if (!(p->parent) || p->parent->exitcode >= 0 || p->parent == kproc) proc_destroy(p);
  60. thread_exit();
  61. /* thread_exit() does not return, so we should never get here */
  62. panic("return from thread_exit in sys_exit\n");
  63. }
  64. // basically, return an error code, and put the actual result in retval
  65. int sys_getpid(pid_t * retval)
  66. {
  67. if (!(curproc)) return 1;
  68. *retval = curproc->pid;
  69. return(0);
  70. }
  71. int sys_waitpid(pid_t pid, userptr_t status, int options, pid_t * retval)
  72. {
  73. (void)status;
  74. if (options != 0)
  75. {
  76. return(EINVAL);
  77. }
  78. if (pid < PID_MIN || pid > PID_MAX) return ESRCH;
  79. struct proc * target = getChild(curproc, pid);
  80. if (!(target)) return ECHILD;
  81. if (target->exitcode >= 0)
  82. {
  83. *retval = target->exitcode;
  84. return 0;
  85. }
  86. lock_acquire(target->waitlock);
  87. cv_wait(target->waiting, target->waitlock);
  88. lock_release(target->waitlock);
  89. *retval = target->exitcode;
  90. proc_destroy(target);
  91. return 0;
  92. }
  93. int sys_fork(struct trapframe * tf, int * retval)
  94. {
  95. // create new process' memory space
  96. struct proc * child = proc_create_runprogram("childproc");
  97. if ((!child)) return ENOMEM;
  98. struct trapframe * new_tf = kmalloc(sizeof(*tf));
  99. struct addrspace * new_as;
  100. as_copy(curproc_getas(), &new_as);
  101. if (!(new_as) || !(new_tf))
  102. {
  103. proc_destroy(child);
  104. kfree(new_as);
  105. kfree(new_tf);
  106. return ENOMEM;
  107. }
  108. // set PIDs, etc. copy data in to the new space
  109. child->p_addrspace = new_as;
  110. child->parent = curproc;
  111. add_child(curproc, child->pid);
  112. *new_tf = *tf;
  113. // start new thread
  114. thread_fork("childproc", child, enter_forked_process, new_tf, 0);
  115. // return correct values
  116. if (curproc->pid == child->pid) *retval = 0;
  117. else *retval = child->pid;
  118. return 0;
  119. }
  120. // args is an array of null terminated strings, with the last element being a null pointer so we don't overflow if iterating
  121. // since this is a userptr type, we need to use copyin and copyout to get data properly
  122. // hopefully the path in program is actually a full filepath
  123. int sys_execv(const char * program, userptr_t args)
  124. {
  125. userptr_t temp = args;
  126. int argcount = 0;
  127. char ** argv;
  128. int errcode; // why don't we have errno!!! my beautful one-liners!!!
  129. // see how long args is
  130. while (1)
  131. {
  132. char * temp2;
  133. errcode = copyin((const userptr_t)temp, temp2, sizeof(char *));
  134. if (errcode) return errcode;
  135. if (!(temp2)) break;
  136. temp += sizeof(char *);
  137. ++argcount;
  138. }
  139. // allocate space for argv
  140. argv = kmalloc(argcount * sizeof(char *));
  141. if (!argv) return ENOMEM;
  142. // get kernel copy of args in argv
  143. temp = args;
  144. for (int i = 0; i < argcount; ++i)
  145. {
  146. errcode = copyin(temp, argv[i], sizeof(char *));
  147. if (errcode)
  148. {
  149. kfree(argv);
  150. return errcode;
  151. }
  152. temp += sizeof(char *);
  153. }
  154. // allocate space for filepath
  155. char * filepath = kmalloc(sizeof(program));
  156. if (!(filepath))
  157. {
  158. kfree(argv);
  159. return ENOMEM;
  160. }
  161. // get kernel copy of filepath
  162. size_t useless;
  163. errcode = copyinstr((const_userptr_t)program, filepath, strlen(program) + 1, &useless);
  164. if (errcode)
  165. {
  166. kfree(argv);
  167. kfree(filepath);
  168. return errcode;
  169. }
  170. // open program file
  171. struct vnode * v;
  172. errcode = vfs_open(filepath, O_RDONLY, 0, &v);
  173. if (errcode)
  174. {
  175. kfree(argv);
  176. kfree(filepath);
  177. return errcode;
  178. }
  179. // create new address space
  180. struct addrspace * as = as_create();
  181. if (!(as))
  182. {
  183. vfs_close(v);
  184. kfree(argv);
  185. kfree(filepath);
  186. return ENOMEM;
  187. }
  188. // Switch to the new as and activate. keep old in case we fail later
  189. struct addrspace * oldas = curproc_getas();
  190. curproc_setas(as);
  191. as_activate();
  192. vaddr_t entrypoint;
  193. // Load santa's favourite slave
  194. errcode = load_elf(v, &entrypoint);
  195. if (errcode)
  196. {
  197. vfs_close(v);
  198. kfree(argv);
  199. kfree(filepath);
  200. curproc_setas(oldas);
  201. as_destroy(as);
  202. return errcode;
  203. }
  204. // close the file now that we're done
  205. vfs_close(v);
  206. // create the new stack
  207. vaddr_t newstack;
  208. errcode = as_define_stack(as, &newstack);
  209. if (errcode)
  210. {
  211. kfree(argv);
  212. kfree(filepath);
  213. curproc_setas(oldas);
  214. as_destroy(as);
  215. return errcode;
  216. }
  217. userptr_t userArgv;
  218. // need to copy data over into the new address space, as rn it is all in kernel heap
  219. // delete old addrspace, enter new process
  220. as_destroy(oldas);
  221. enter_new_process(argcount, userArgv, newstack, entrypoint);
  222. panic("Enter new process returned!\n");
  223. return EINVAL;
  224. }