Blame nptl_db/td_ta_thr_iter.c

Packit 6c4009
/* Iterate over a process's threads.
Packit 6c4009
   Copyright (C) 1999-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include "thread_dbP.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
static td_err_e
Packit 6c4009
iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
Packit 6c4009
		     void *cbdata_p, td_thr_state_e state, int ti_pri,
Packit 6c4009
		     psaddr_t head, bool fake_empty)
Packit 6c4009
{
Packit 6c4009
  td_err_e err;
Packit 6c4009
  psaddr_t next, ofs;
Packit 6c4009
  void *copy;
Packit 6c4009
Packit 6c4009
  /* Test the state.
Packit 6c4009
     XXX This is incomplete.  Normally this test should be in the loop.  */
Packit 6c4009
  if (state != TD_THR_ANY_STATE)
Packit 6c4009
    return TD_OK;
Packit 6c4009
Packit 6c4009
  err = DB_GET_FIELD (next, ta, head, list_t, next, 0);
Packit 6c4009
  if (err != TD_OK)
Packit 6c4009
    return err;
Packit 6c4009
Packit 6c4009
  if (next == 0 && fake_empty)
Packit 6c4009
    {
Packit 6c4009
      /* __pthread_initialize_minimal has not run.  There is just the main
Packit 6c4009
	 thread to return.  We cannot rely on its thread register.  They
Packit 6c4009
	 sometimes contain garbage that would confuse us, left by the
Packit 6c4009
	 kernel at exec.  So if it looks like initialization is incomplete,
Packit 6c4009
	 we only fake a special descriptor for the initial thread.  */
Packit 6c4009
      td_thrhandle_t th = { ta, 0 };
Packit 6c4009
      return callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Cache the offset from struct pthread to its list_t member.  */
Packit 6c4009
  err = DB_GET_FIELD_ADDRESS (ofs, ta, 0, pthread, list, 0);
Packit 6c4009
  if (err != TD_OK)
Packit 6c4009
    return err;
Packit 6c4009
Packit 6c4009
  if (ta->ta_sizeof_pthread == 0)
Packit 6c4009
    {
Packit 6c4009
      err = _td_check_sizeof (ta, &ta->ta_sizeof_pthread, SYM_SIZEOF_pthread);
Packit 6c4009
      if (err != TD_OK)
Packit 6c4009
	return err;
Packit 6c4009
    }
Packit 6c4009
  copy = __alloca (ta->ta_sizeof_pthread);
Packit 6c4009
Packit 6c4009
  while (next != head)
Packit 6c4009
    {
Packit 6c4009
      psaddr_t addr, schedpolicy, schedprio;
Packit 6c4009
Packit 6c4009
      addr = next - (ofs - (psaddr_t) 0);
Packit 6c4009
      if (next == 0 || addr == 0) /* Sanity check.  */
Packit 6c4009
	return TD_DBERR;
Packit 6c4009
Packit 6c4009
      /* Copy the whole descriptor in once so we can access the several
Packit 6c4009
	 fields locally.  Excess copying in one go is much better than
Packit 6c4009
	 multiple ps_pdread calls.  */
Packit 6c4009
      if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK)
Packit 6c4009
	return TD_ERR;
Packit 6c4009
Packit 6c4009
      err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread,
Packit 6c4009
				schedpolicy, 0);
Packit 6c4009
      if (err != TD_OK)
Packit 6c4009
	break;
Packit 6c4009
      err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread,
Packit 6c4009
				schedparam_sched_priority, 0);
Packit 6c4009
      if (err != TD_OK)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      /* Now test whether this thread matches the specified conditions.  */
Packit 6c4009
Packit 6c4009
      /* Only if the priority level is as high or higher.  */
Packit 6c4009
      int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
Packit 6c4009
		       ? 0 : (uintptr_t) schedprio);
Packit 6c4009
      if (descr_pri >= ti_pri)
Packit 6c4009
	{
Packit 6c4009
	  /* Yep, it matches.  Call the callback function.  */
Packit 6c4009
	  td_thrhandle_t th;
Packit 6c4009
	  th.th_ta_p = (td_thragent_t *) ta;
Packit 6c4009
	  th.th_unique = addr;
Packit 6c4009
	  if (callback (&th, cbdata_p) != 0)
Packit 6c4009
	    return TD_DBERR;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Get the pointer to the next element.  */
Packit 6c4009
      err = DB_GET_FIELD_LOCAL (next, ta, copy + (ofs - (psaddr_t) 0), list_t,
Packit 6c4009
				next, 0);
Packit 6c4009
      if (err != TD_OK)
Packit 6c4009
	break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return err;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
td_err_e
Packit 6c4009
td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
Packit 6c4009
		void *cbdata_p, td_thr_state_e state, int ti_pri,
Packit 6c4009
		sigset_t *ti_sigmask_p, unsigned int ti_user_flags)
Packit 6c4009
{
Packit 6c4009
  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
Packit 6c4009
  td_err_e err;
Packit 6c4009
  psaddr_t list = 0;
Packit 6c4009
Packit 6c4009
  LOG ("td_ta_thr_iter");
Packit 6c4009
Packit 6c4009
  /* Test whether the TA parameter is ok.  */
Packit 6c4009
  if (! ta_ok (ta))
Packit 6c4009
    return TD_BADTA;
Packit 6c4009
Packit 6c4009
  /* The thread library keeps two lists for the running threads.  One
Packit 6c4009
     list contains the thread which are using user-provided stacks
Packit 6c4009
     (this includes the main thread) and the other includes the
Packit 6c4009
     threads for which the thread library allocated the stacks.  We
Packit 6c4009
     have to iterate over both lists separately.  We start with the
Packit 6c4009
     list of threads with user-defined stacks.  */
Packit 6c4009
Packit 6c4009
  err = DB_GET_SYMBOL (list, ta, __stack_user);
Packit 6c4009
  if (err == TD_OK)
Packit 6c4009
    err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
Packit 6c4009
			       list, true);
Packit 6c4009
Packit 6c4009
  /* And the threads with stacks allocated by the implementation.  */
Packit 6c4009
  if (err == TD_OK)
Packit 6c4009
    err = DB_GET_SYMBOL (list, ta, stack_used);
Packit 6c4009
  if (err == TD_OK)
Packit 6c4009
    err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
Packit 6c4009
			       list, false);
Packit 6c4009
Packit 6c4009
  return err;
Packit 6c4009
}