Back to index

glibc  2.9
waitid.c
Go to the documentation of this file.
00001 /* Pseudo implementation of waitid.
00002    Copyright (C) 1997, 1998, 2002, 2003, 2004 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1997.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <assert.h>
00022 #include <errno.h>
00023 #include <signal.h>
00024 #define __need_NULL
00025 #include <stddef.h>
00026 #include <sys/wait.h>
00027 #include <sys/types.h>
00028 #include <sysdep-cancel.h>
00029 
00030 
00031 #ifdef DO_WAITID
00032 # define OUR_WAITID DO_WAITID
00033 #elif !defined NO_DO_WAITID
00034 # define OUR_WAITID do_waitid
00035 #endif
00036 
00037 #ifdef OUR_WAITID
00038 static int
00039 OUR_WAITID (idtype_t idtype, id_t id, siginfo_t *infop, int options)
00040 {
00041   pid_t pid, child;
00042   int status;
00043 
00044   switch (idtype)
00045     {
00046     case P_PID:
00047       if(id <= 0)
00048        goto invalid;
00049       pid = (pid_t) id;
00050       break;
00051     case P_PGID:
00052       if (id < 0 || id == 1)
00053        goto invalid;
00054       pid = (pid_t) -id;
00055       break;
00056     case P_ALL:
00057       pid = -1;
00058       break;
00059     default:
00060     invalid:
00061       __set_errno (EINVAL);
00062       return -1;
00063     }
00064 
00065   /* Technically we're supposed to return EFAULT if infop is bogus,
00066      but that would involve mucking with signals, which is
00067      too much hassle.  User will have to deal with SIGSEGV/SIGBUS.
00068      We just check for a null pointer. */
00069 
00070   if (infop == NULL)
00071     {
00072       __set_errno (EFAULT);
00073       return -1;
00074     }
00075 
00076   /* This emulation using waitpid cannot support the waitid modes in which
00077      we do not reap the child, or match only stopped and not dead children.  */
00078   if (0
00079 #ifdef WNOWAIT
00080       || (options & WNOWAIT)
00081 #endif
00082 #ifdef WEXITED
00083       || ((options & (WEXITED|WSTOPPED|WCONTINUED))
00084          != (WEXITED | (options & WUNTRACED)))
00085 #endif
00086       )
00087     {
00088       __set_errno (ENOTSUP);
00089       return -1;
00090     }
00091 
00092   /* Note the waitid() is a cancellation point.  But since we call
00093      waitpid() which itself is a cancellation point we do not have
00094      to do anything here.  */
00095   child = __waitpid (pid, &status,
00096                    options
00097 #ifdef WEXITED
00098                    &~ WEXITED
00099 #endif
00100                    );
00101 
00102   if (child == -1)
00103     /* `waitpid' set `errno' for us.  */
00104     return -1;
00105 
00106   if (child == 0)
00107     {
00108       /* The WHOHANG bit in OPTIONS is set and there are children available
00109         but none has a status for us.  The XPG docs do not mention this
00110         case so we clear the `siginfo_t' struct and return successfully.  */
00111       infop->si_signo = 0;
00112       infop->si_code = 0;
00113       return 0;
00114     }
00115 
00116   /* Decode the status field and set infop members... */
00117   infop->si_signo = SIGCHLD;
00118   infop->si_pid = child;
00119   infop->si_errno = 0;
00120 
00121   if (WIFEXITED (status))
00122     {
00123       infop->si_code = CLD_EXITED;
00124       infop->si_status = WEXITSTATUS (status);
00125     }
00126   else if (WIFSIGNALED (status))
00127     {
00128       infop->si_code = WCOREDUMP (status) ? CLD_DUMPED : CLD_KILLED;
00129       infop->si_status = WTERMSIG (status);
00130     }
00131   else if (WIFSTOPPED (status))
00132     {
00133       infop->si_code = CLD_STOPPED;
00134       infop->si_status = WSTOPSIG (status);
00135     }
00136 #ifdef WIFCONTINUED
00137   else if (WIFCONTINUED (status))
00138     {
00139       infop->si_code = CLD_CONTINUED;
00140       infop->si_status = SIGCONT;
00141     }
00142 #endif
00143   else
00144     /* Can't happen. */
00145     assert (! "What?");
00146 
00147   return 0;
00148 }
00149 #endif
00150 
00151 
00152 int
00153 __waitid (idtype, id, infop, options)
00154      idtype_t idtype;
00155      id_t id;
00156      siginfo_t *infop;
00157      int options;
00158 {
00159   if (SINGLE_THREAD_P)
00160     return do_waitid (idtype, id, infop, options);
00161 
00162   int oldtype = LIBC_CANCEL_ASYNC ();
00163 
00164   int result = do_waitid (idtype, id, infop, options);
00165 
00166   LIBC_CANCEL_RESET (oldtype);
00167 
00168   return result;
00169 }
00170 weak_alias (__waitid, waitid)
00171 strong_alias (__waitid, __libc_waitid)