Merge branch 'jistone/coverity'
[dyninst.git] / dyninstAPI_RT / src / RTthread.c
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <assert.h>
35
36 #include "RTthread.h"
37 #include "RTcommon.h"
38 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
39 #include "dyninstAPI_RT/h/dyninstRTExport.h"
40
41 extern unsigned DYNINST_max_num_threads;
42 int DYNINST_multithread_capable;
43 extern unsigned int DYNINSThasInitialized;
44
45 static void (*rt_newthr_cb)(int) = NULL;
46 void setNewthrCB(void (*cb)(int)) {
47     rt_newthr_cb = cb;
48 }
49
50 #define IDX_NONE -1
51
52 /* I split these in half to make mutator-side updates easier */
53 dyntid_t *DYNINST_thread_hash_tids;
54 long *DYNINST_thread_hash_indices;
55 unsigned DYNINST_thread_hash_size;
56
57 static DECLARE_TC_LOCK(DYNINST_index_lock);
58
59 static int num_free;
60
61 static dyntid_t default_thread_hash_tids[THREADS_HASH_SIZE];
62 static long default_thread_hash_indices[THREADS_HASH_SIZE];
63
64 DLLEXPORT int DYNINSTthreadCount() { return (DYNINST_max_num_threads - num_free); }
65
66 void DYNINST_initialize_index_list()
67 {
68   static int init_index_done;
69   unsigned i;
70
71   if (init_index_done) return;
72   init_index_done = 1;
73
74   if (DYNINST_max_num_threads == MAX_THREADS) {
75      DYNINST_thread_hash_size = THREADS_HASH_SIZE;
76      DYNINST_thread_hash_indices = default_thread_hash_indices;
77      DYNINST_thread_hash_tids = default_thread_hash_tids;
78   }
79   else {
80      DYNINST_thread_hash_size = (int) (DYNINST_max_num_threads * 1.25);
81      DYNINST_thread_hash_indices =  
82          malloc(DYNINST_thread_hash_size * sizeof(long));
83         DYNINST_thread_hash_tids = 
84                 malloc(DYNINST_thread_hash_size * sizeof(dyntid_t));
85   }
86   assert( DYNINST_thread_hash_tids != NULL );
87   assert( DYNINST_thread_hash_indices != NULL );
88
89   for (i=0; i < DYNINST_thread_hash_size; i++)
90       DYNINST_thread_hash_indices[i] = IDX_NONE;
91
92   num_free = DYNINST_max_num_threads;
93 }
94
95 /**
96  * A guaranteed-if-there index lookup 
97  **/
98 unsigned DYNINSTthreadIndexSLOW(dyntid_t tid) {
99     unsigned hash_id, orig;
100     unsigned retval = DYNINST_NOT_IN_HASHTABLE;
101     int index, result;
102     unsigned long tid_val = (unsigned long) tid;
103     rtdebug_printf("%s[%d]: getting dyninst index lock\n", __FILE__, __LINE__);
104     result = tc_lock_lock(&DYNINST_index_lock);
105     if (result == DYNINST_DEAD_LOCK) {
106         rtdebug_printf("%s[%d]:  DEADLOCK HERE tid %lu \n", __FILE__, __LINE__,
107                        dyn_pthread_self());
108         /* We specifically return DYNINST_max_num_threads so that instrumentation
109          * has someplace safe to scribble in case of an error. */
110
111         /* DO NOT USE print statements here. That's horribly unsafe if we've instrumented
112            the output functions, as we'll infinite recurse and die */
113         return DYNINST_max_num_threads;
114     }
115     rtdebug_printf("%s[%d]: got dyninst index lock\n", __FILE__, __LINE__);
116
117     /**
118      * Search the hash table
119      **/
120     if (!DYNINST_thread_hash_size) {
121         //Uninitialized tramp guard.
122         tc_lock_unlock(&DYNINST_index_lock);
123         return DYNINST_max_num_threads;
124     }
125
126     hash_id = tid_val % DYNINST_thread_hash_size;
127     orig = hash_id;
128     for (;;) {
129         index = DYNINST_thread_hash_indices[hash_id];
130         if (index != IDX_NONE && DYNINST_thread_hash_tids[hash_id] == tid) {
131             retval = index;
132             break;
133         }
134
135         hash_id++;
136         if (hash_id == DYNINST_thread_hash_size)
137             hash_id = 0;
138         if (orig == hash_id)
139             break;
140     }
141
142     tc_lock_unlock(&DYNINST_index_lock);
143     return retval;
144 }
145
146 /*
147  * Invoked by the mutator on thread creation
148  */
149 unsigned long DYNINSTregisterThread(dyntid_t tid, unsigned index) {
150     unsigned hash_id, orig;
151     unsigned long tid_val = (unsigned long) tid;
152
153     unsigned long retval = (unsigned long)dyn_pthread_self();
154     assert(retval != 0 );
155     rtdebug_printf("%s[%d]: Begin DYNINSTregisterThread, tid %lu\n", __FILE__, __LINE__,
156             dyn_pthread_self());
157
158     if( tid_val != retval ) {
159         tid_val = retval;
160     }
161
162     if( tc_lock_lock(&DYNINST_index_lock) == DYNINST_DEAD_LOCK ) {
163        rtdebug_printf("%s[%d]:  DEADLOCK HERE tid %lu \n", __FILE__, __LINE__, 
164                dyn_pthread_self());
165         return 0;
166     }
167
168     hash_id = tid_val % DYNINST_thread_hash_size;
169     orig = hash_id;
170     while(DYNINST_thread_hash_indices[hash_id] != IDX_NONE) {
171         hash_id++;
172         if( hash_id == DYNINST_thread_hash_size ) hash_id = 0;
173         if( orig == hash_id ) {
174             retval = 0;
175             break;
176         }
177     }
178
179     if( retval ) {
180         DYNINST_thread_hash_indices[hash_id] = index;
181         DYNINST_thread_hash_tids[hash_id] = tid;
182         num_free--;
183         rtdebug_printf("%s[%d]: created mapping for thread (index = %lu, tid = 0x%lx)\n",
184                 __FILE__, __LINE__, index, tid);
185     }
186
187     tc_lock_unlock(&DYNINST_index_lock);
188     return retval;
189 }
190
191 /*
192  * Invoked by the mutator on thread exit
193  */
194 int DYNINSTunregisterThread(dyntid_t tid) {
195     unsigned hash_id, orig;
196     unsigned tid_val = (unsigned long) tid;
197
198     int retval = 1;
199     rtdebug_printf("%s[%d]: Begin DYNINSTunregisterThread, tid %lu\n", __FILE__, __LINE__,
200             dyn_pthread_self());
201
202     if( tc_lock_lock(&DYNINST_index_lock) == DYNINST_DEAD_LOCK ) {
203         rtdebug_printf("%s[%d]: DEADLOCK HERE tid %lu\n", __FILE__, __LINE__,
204                 dyn_pthread_self());
205         return 0;
206     }
207
208     hash_id = tid_val % DYNINST_thread_hash_size;
209     orig = hash_id;
210     while(DYNINST_thread_hash_tids[hash_id] != tid) {
211         hash_id++;
212         if( hash_id == DYNINST_thread_hash_size ) hash_id = 0;
213         if( orig == hash_id ) {
214             retval = 0;
215             break;
216         }
217     }
218
219     if( retval ) {
220         rtdebug_printf("%s[%d]: removed mapping for thread (index = %lu, tid = 0x%lx)\n",
221                 __FILE__, __LINE__, DYNINST_thread_hash_indices[hash_id], tid);
222         DYNINST_thread_hash_indices[hash_id] = IDX_NONE;
223         num_free++;
224     }
225
226     tc_lock_unlock(&DYNINST_index_lock);
227     return retval;
228 }
229
230 int global = 1;
231
232 /**
233  * Translate a tid given by pthread_self into an index.  Called by 
234  * basetramps everywhere.
235  **/
236 int DYNINSTthreadIndex() {
237     dyntid_t tid;
238     unsigned curr_index;
239
240     rtdebug_printf("%s[%d]:  welcome to DYNINSTthreadIndex()\n", __FILE__, __LINE__);
241     if (!DYNINSThasInitialized) {
242       rtdebug_printf("%s[%d]: dyninst not initialized, ret false\n", __FILE__, __LINE__);
243       return 0;
244     }
245
246     tid = (dyntid_t) ((unsigned long)dyn_pthread_self());
247     rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): tid = %lu\n", __FILE__, __LINE__,
248                    (unsigned long) tid);
249     if (tid == (dyntid_t) DYNINST_SINGLETHREADED) return 0;
250     rtdebug_printf("%s[%d]: calling thread index slow (modified)\n", __FILE__, __LINE__);
251     curr_index = DYNINSTthreadIndexSLOW(tid);
252     rtdebug_printf("%s[%d]: back from thread index slow\n", __FILE__, __LINE__);
253     /* While DYNINST_max_num_threads is an error return for
254        DYNINSTthreadIndexSLOW(), there's not really anything we
255        can do about it at the moment, so just return it
256        and let the mutatee scribble into the so-allocated memory. */
257     if ( curr_index == DYNINST_NOT_IN_HASHTABLE ) {
258         rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): failed to find index for %lu\n",
259                 __FILE__, __LINE__, tid);
260         curr_index = DYNINST_max_num_threads;
261     }
262
263     rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): returning index: %d\n",
264                    __FILE__, __LINE__, curr_index);
265     return curr_index;
266 }
267
268 /**
269  * Some exported wrapper function for other runtime libraries to use tc_lock
270  **/
271 unsigned dyninst_threadIndex() {
272    return DYNINSTthreadIndex();
273 }