.
[kopensolaris-gnu/glibc.git] / nptl_db / td_thr_validate.c
1 /* Validate a thread handle.
2    Copyright (C) 1999,2001,2002,2003,2004,2007,2008
3         Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, write to the Free
19    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20    02111-1307 USA.  */
21
22 #include "thread_dbP.h"
23 #include <stdbool.h>
24
25 static td_err_e
26 check_thread_list (const td_thrhandle_t *th, psaddr_t head, bool *uninit)
27 {
28   td_err_e err;
29   psaddr_t next, ofs;
30
31   err = DB_GET_FIELD (next, th->th_ta_p, head, list_t, next, 0);
32   if (err == TD_OK)
33     {
34       if (next == 0)
35         {
36           *uninit = true;
37           return TD_NOTHR;
38         }
39       err = DB_GET_FIELD_ADDRESS (ofs, th->th_ta_p, 0, pthread, list, 0);
40     }
41
42   while (err == TD_OK)
43     {
44       if (next == head)
45         return TD_NOTHR;
46
47       if (next - (ofs - (psaddr_t) 0) == th->th_unique)
48         return TD_OK;
49
50       err = DB_GET_FIELD (next, th->th_ta_p, next, list_t, next, 0);
51     }
52
53   return err;
54 }
55
56
57 td_err_e
58 td_thr_validate (const td_thrhandle_t *th)
59 {
60   td_err_e err;
61   psaddr_t list;
62
63   LOG ("td_thr_validate");
64
65   /* First check the list with threads using user allocated stacks.  */
66   bool uninit = false;
67   err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_user);
68   if (err == TD_OK)
69     err = check_thread_list (th, list, &uninit);
70
71   /* If our thread is not on this list search the list with stack
72      using implementation allocated stacks.  */
73   if (err == TD_NOTHR)
74     {
75       err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used);
76       if (err == TD_OK)
77         err = check_thread_list (th, list, &uninit);
78
79       if (err == TD_NOTHR && uninit && th->th_unique == 0)
80         /* __pthread_initialize_minimal has not run yet.
81            There is only the special case thread handle.  */
82         err = TD_OK;
83     }
84
85   if (err == TD_OK)
86     {
87       /* Verify that this is not a stale element in a fork child.  */
88       pid_t match_pid = ps_getpid (th->th_ta_p->ph);
89       psaddr_t pid;
90       err = DB_GET_FIELD (pid, th->th_ta_p, th->th_unique, pthread, pid, 0);
91       if (err == TD_OK && (pid_t) (uintptr_t) pid < 0)
92         {
93           /* This was a thread that was about to fork, or it is the new sole
94              thread in a fork child.  In the latter case, its tid was stored
95              via CLONE_CHILD_SETTID and so is already the proper child PID.  */
96           if (-(pid_t) (uintptr_t) pid == match_pid)
97             /* It is about to do a fork, but is really still the parent PID.  */
98             pid = (psaddr_t) (uintptr_t) match_pid;
99           else
100             /* It must be a fork child, whose new PID is in the tid field.  */
101             err = DB_GET_FIELD (pid, th->th_ta_p, th->th_unique,
102                                 pthread, tid, 0);
103         }
104       if (err == TD_OK && (pid_t) (uintptr_t) pid != match_pid)
105         err = TD_NOTHR;
106     }
107
108   return err;
109 }