1 /* 2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. 4 * All rights reserved. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 #include <sys/wait.h> 9 10 #include <errno.h> 11 #include <pthread.h> 12 13 #include <syscall_utils.h> 14 15 #include <syscalls.h> 16 #include <thread_defs.h> 17 18 19 pid_t 20 wait(int* _status) 21 { 22 return waitpid(-1, _status, 0); 23 } 24 25 26 pid_t 27 waitpid(pid_t pid, int* _status, int options) 28 { 29 // wait 30 siginfo_t info; 31 pid_t child = _kern_wait_for_child(pid, options, &info); 32 33 pthread_testcancel(); 34 35 if (child < 0) { 36 // When not getting a child status when WNOHANG was specified, don't 37 // fail. 38 if (child == B_WOULD_BLOCK && (options & WNOHANG) != 0) 39 return 0; 40 RETURN_AND_SET_ERRNO(child); 41 } 42 43 // prepare the status 44 if (_status != NULL) { 45 int status; 46 switch (info.si_code) { 47 case CLD_EXITED: 48 // fill in exit status for WIFEXITED() and WEXITSTATUS() 49 status = info.si_status & 0xff; 50 break; 51 52 case CLD_KILLED: 53 case CLD_DUMPED: 54 // fill in signal for WIFSIGNALED() and WTERMSIG() 55 status = (info.si_status << 8) & 0xff00; 56 // if core dumped, set flag for WIFCORED() 57 if (info.si_code == CLD_DUMPED) 58 status |= 0x10000; 59 break; 60 61 case CLD_CONTINUED: 62 // set flag for WIFCONTINUED() 63 status = 0x20000; 64 break; 65 66 case CLD_STOPPED: 67 // fill in signal for WIFSTOPPED() and WSTOPSIG() 68 status = (info.si_status << 16) & 0xff0000; 69 break; 70 71 case CLD_TRAPPED: 72 // we don't do that 73 default: 74 // should never get here -- assume exited 75 status = 0; 76 break; 77 } 78 79 *_status = status; 80 } 81 82 return child; 83 } 84 85 86 int 87 waitid(idtype_t idType, id_t id, siginfo_t* info, int options) 88 { 89 // translate the idType, id pair to a waitpid() style ID 90 switch (idType) { 91 case P_ALL: 92 // any child 93 id = -1; 94 break; 95 96 case P_PID: 97 // the child with the given ID 98 if (id <= 0) 99 RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL); 100 break; 101 102 case P_PGID: 103 // any child in the given process group 104 if (id <= 1) 105 RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL); 106 id = -id; 107 break; 108 109 default: 110 RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL); 111 } 112 113 pid_t child = _kern_wait_for_child(id, options, info); 114 if (child >= 0 || child == B_WOULD_BLOCK) 115 return 0; 116 117 RETURN_AND_SET_ERRNO_TEST_CANCEL(child); 118 } 119