Back to index

glibc  2.9
td_ta_thr_iter.c
Go to the documentation of this file.
00001 /* Iterate over a process's threads.
00002    Copyright (C) 1999,2000,2001,2002,2003,2004,2007,2008
00003        Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
00006 
00007    The GNU C Library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public
00009    License as published by the Free Software Foundation; either
00010    version 2.1 of the License, or (at your option) any later version.
00011 
00012    The GNU C Library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with the GNU C Library; if not, write to the Free
00019    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00020    02111-1307 USA.  */
00021 
00022 #include "thread_dbP.h"
00023 
00024 
00025 static td_err_e
00026 iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
00027                    void *cbdata_p, td_thr_state_e state, int ti_pri,
00028                    psaddr_t head, bool fake_empty, pid_t match_pid)
00029 {
00030   td_err_e err;
00031   psaddr_t next, ofs;
00032   void *copy;
00033 
00034   /* Test the state.
00035      XXX This is incomplete.  Normally this test should be in the loop.  */
00036   if (state != TD_THR_ANY_STATE)
00037     return TD_OK;
00038 
00039   err = DB_GET_FIELD (next, ta, head, list_t, next, 0);
00040   if (err != TD_OK)
00041     return err;
00042 
00043   if (next == 0 && fake_empty)
00044     {
00045       /* __pthread_initialize_minimal has not run.  There is just the main
00046         thread to return.  We cannot rely on its thread register.  They
00047         sometimes contain garbage that would confuse us, left by the
00048         kernel at exec.  So if it looks like initialization is incomplete,
00049         we only fake a special descriptor for the initial thread.  */
00050       td_thrhandle_t th = { ta, 0 };
00051       return callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK;
00052     }
00053 
00054   /* Cache the offset from struct pthread to its list_t member.  */
00055   err = DB_GET_FIELD_ADDRESS (ofs, ta, 0, pthread, list, 0);
00056   if (err != TD_OK)
00057     return err;
00058 
00059   if (ta->ta_sizeof_pthread == 0)
00060     {
00061       err = _td_check_sizeof (ta, &ta->ta_sizeof_pthread, SYM_SIZEOF_pthread);
00062       if (err != TD_OK)
00063        return err;
00064     }
00065   copy = __alloca (ta->ta_sizeof_pthread);
00066 
00067   while (next != head)
00068     {
00069       psaddr_t addr, schedpolicy, schedprio;
00070 
00071       addr = next - (ofs - (psaddr_t) 0);
00072       if (next == 0 || addr == 0) /* Sanity check.  */
00073        return TD_DBERR;
00074 
00075       /* Copy the whole descriptor in once so we can access the several
00076         fields locally.  Excess copying in one go is much better than
00077         multiple ps_pdread calls.  */
00078       if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK)
00079        return TD_ERR;
00080 
00081       /* Verify that this thread's pid field matches the child PID.
00082         If its pid field is negative, it's about to do a fork or it
00083         is the sole thread in a fork child.  */
00084       psaddr_t pid;
00085       err = DB_GET_FIELD_LOCAL (pid, ta, copy, pthread, pid, 0);
00086       if (err == TD_OK && (pid_t) (uintptr_t) pid < 0)
00087        {
00088          if (-(pid_t) (uintptr_t) pid == match_pid)
00089            /* It is about to do a fork, but is really still the parent PID.  */
00090            pid = (psaddr_t) (uintptr_t) match_pid;
00091          else
00092            /* It must be a fork child, whose new PID is in the tid field.  */
00093            err = DB_GET_FIELD_LOCAL (pid, ta, copy, pthread, tid, 0);
00094        }
00095       if (err != TD_OK)
00096        break;
00097 
00098       if ((pid_t) (uintptr_t) pid == match_pid)
00099        {
00100          err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread,
00101                                 schedpolicy, 0);
00102          if (err != TD_OK)
00103            break;
00104          err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread,
00105                                 schedparam_sched_priority, 0);
00106          if (err != TD_OK)
00107            break;
00108 
00109          /* Now test whether this thread matches the specified conditions.  */
00110 
00111          /* Only if the priority level is as high or higher.  */
00112          int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
00113                         ? 0 : (uintptr_t) schedprio);
00114          if (descr_pri >= ti_pri)
00115            {
00116              /* Yep, it matches.  Call the callback function.  */
00117              td_thrhandle_t th;
00118              th.th_ta_p = (td_thragent_t *) ta;
00119              th.th_unique = addr;
00120              if (callback (&th, cbdata_p) != 0)
00121               return TD_DBERR;
00122            }
00123        }
00124 
00125       /* Get the pointer to the next element.  */
00126       err = DB_GET_FIELD_LOCAL (next, ta, copy + (ofs - (psaddr_t) 0), list_t,
00127                             next, 0);
00128       if (err != TD_OK)
00129        break;
00130     }
00131 
00132   return err;
00133 }
00134 
00135 
00136 td_err_e
00137 td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
00138               void *cbdata_p, td_thr_state_e state, int ti_pri,
00139               sigset_t *ti_sigmask_p, unsigned int ti_user_flags)
00140 {
00141   td_thragent_t *const ta = (td_thragent_t *) ta_arg;
00142   td_err_e err;
00143   psaddr_t list = 0;
00144 
00145   LOG ("td_ta_thr_iter");
00146 
00147   /* Test whether the TA parameter is ok.  */
00148   if (! ta_ok (ta))
00149     return TD_BADTA;
00150 
00151   /* The thread library keeps two lists for the running threads.  One
00152      list contains the thread which are using user-provided stacks
00153      (this includes the main thread) and the other includes the
00154      threads for which the thread library allocated the stacks.  We
00155      have to iterate over both lists separately.  We start with the
00156      list of threads with user-defined stacks.  */
00157 
00158   pid_t pid = ps_getpid (ta->ph);
00159   err = DB_GET_SYMBOL (list, ta, __stack_user);
00160   if (err == TD_OK)
00161     err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
00162                             list, true, pid);
00163 
00164   /* And the threads with stacks allocated by the implementation.  */
00165   if (err == TD_OK)
00166     err = DB_GET_SYMBOL (list, ta, stack_used);
00167   if (err == TD_OK)
00168     err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
00169                             list, false, pid);
00170 
00171   return err;
00172 }