Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI_RT / src / RTthread.c
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.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 unsigned threadCreate(dyntid_t tid);
46
47 static void (*rt_newthr_cb)(int) = NULL;
48 void setNewthrCB(void (*cb)(int)) {
49     rt_newthr_cb = cb;
50 }
51
52 /**
53  * Translate a tid given by pthread_self into an index.  Called by 
54  * basetramps everywhere.
55  **/
56
57 int DYNINSTthreadIndex()
58 {
59    dyntid_t tid;
60    unsigned curr_index;
61
62    rtdebug_printf("%s[%d]:  welcome to DYNINSTthreadIndex()\n", __FILE__, __LINE__);
63    if (!DYNINSThasInitialized) 
64    {
65       return 0;
66    }
67    
68    tid = dyn_pthread_self();
69    rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): tid = %lu\n", __FILE__, __LINE__, (unsigned long) tid);
70    if (tid == (dyntid_t) DYNINST_SINGLETHREADED) {
71       return 0;
72    }
73
74    curr_index = DYNINSTthreadIndexFAST();
75    if (curr_index < DYNINST_max_num_threads &&
76        DYNINST_getThreadFromIndex(curr_index) == tid)
77    {
78        rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): index exists already, returning %d\n", __FILE__, __LINE__, curr_index);
79        return curr_index;
80    }
81    
82    curr_index = DYNINSTthreadIndexSLOW(tid);
83    if ( curr_index == DYNINST_NOT_IN_HASHTABLE )
84    {
85        rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): doing threadCreate for %lu\n", __FILE__, __LINE__, tid);
86        curr_index = threadCreate(tid);
87        rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): returning index: %d\n",  __FILE__, __LINE__, curr_index);
88    }
89                 
90    /* While DYNINST_max_num_threads is also an error return for
91       DYNINSTthreadIndexSLOW(), there's not really anything we
92       can do about it at the moment, so just return it
93       and let the mutatee scribble into the so-allocated memory. */
94
95    rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): returning index: %d\n",  
96                   __FILE__, __LINE__, curr_index);
97    return curr_index;
98 }
99
100 extern tc_lock_t DYNINST_trace_lock;
101
102 static int asyncSendThreadEvent(int pid, rtBPatch_asyncEventType type, 
103                                 void *ev, unsigned ev_size)
104 {
105    int result;
106    rtBPatch_asyncEventRecord aev;
107    aev.pid = pid;
108    aev.type = type;
109    aev.event_fd = 0;
110    aev.size = ev_size;
111
112    result = tc_lock_lock(&DYNINST_trace_lock);
113    if (result == DYNINST_DEAD_LOCK)
114    {
115       fprintf(stderr, "[%s:%d] - Error in libdyninstAPI_RT: trace pipe deadlock in thread %lu\n",
116                     __FILE__, __LINE__, (unsigned long) dyn_pthread_self() );
117       return DYNINST_TRACEPIPE_ERRVAL;
118    }
119    
120    result = DYNINSTwriteEvent((void *) &aev, sizeof(rtBPatch_asyncEventRecord));
121    if (result == -1)
122    {
123       fprintf(stderr, "%s[%d]:  write error creating thread\n",
124               __FILE__, __LINE__);
125       goto done;
126    }
127
128    result = DYNINSTwriteEvent((void *) ev, ev_size);
129    if (result == -1)
130    {
131       fprintf(stderr, "%s[%d]:  write error creating thread\n",
132               __FILE__, __LINE__);
133       goto done;
134    }
135    
136    
137  done:
138    tc_lock_unlock(&DYNINST_trace_lock);
139    rtdebug_printf("%s[%d]:  leaving asyncSendThreadEvent: status = %s\n", 
140                   __FILE__, __LINE__, result ? "error" : "ok");
141    return result;
142 }
143
144 /**
145  * Creates a new index for a given tid.
146  **/
147 static unsigned threadCreate(dyntid_t tid)
148 {
149    int res;
150    BPatch_newThreadEventRecord ev;
151    unsigned index;
152
153    rtdebug_printf("%s[%d]:  welcome to threadCreate\n", 
154                  __FILE__, __LINE__);
155    if (!DYNINSThasInitialized && !DYNINSTstaticMode)
156    {
157       return DYNINST_max_num_threads;
158    }
159    
160    /* Get an index */
161    index = DYNINST_alloc_index(tid);
162
163    /**
164     * Trigger the mutator and mutatee side callbacks.
165     **/
166    memset(&ev, 0, sizeof(BPatch_newThreadEventRecord));
167
168    ev.ppid = dyn_pid_self();
169    ev.tid = tid;
170    ev.lwp = dyn_lwp_self();
171    ev.index = index;
172    
173    res = DYNINSTthreadInfo(&ev);
174    if (!res)
175    {
176       return DYNINST_max_num_threads;
177    }
178    
179    if (rt_newthr_cb)
180    {
181       rt_newthr_cb(index);
182    }
183
184    if (!DYNINSTstaticMode)
185    {
186       /*Only async for now.  We should parameterize this function to also 
187         have a sync option.*/
188       asyncSendThreadEvent(ev.ppid, rtBPatch_threadCreateEvent, &ev, 
189                            sizeof(BPatch_newThreadEventRecord));
190       rtdebug_printf("%s[%d]:  leaving threadCreate: index = %d\n", 
191                      __FILE__, __LINE__, index);
192    }
193    return index;
194 }
195
196 /**
197  * Called when a thread is destroyed
198  **/
199 void DYNINSTthreadDestroy()
200 {
201    dyntid_t tid = dyn_pthread_self();
202    int index = DYNINSTthreadIndex();
203    /*   int pid = dyn_pid_self();*/
204    int err;
205    /*   BPatch_deleteThreadEventRecord rec;*/
206
207   rtdebug_printf("%s[%d]: DESTROY freeing index for thread %lu, index = %d\n", 
208                  __FILE__, __LINE__, tid, index);
209    err = DYNINST_free_index(tid);
210    if (err) {
211       rtdebug_printf("%s[%d]:  DYNINST_free_index FAILED\n", __FILE__, __LINE__);
212       return;
213    }
214 #if 0
215    //  no longer do notification of exits asynchronously
216    memset(&rec, 0, sizeof(rec));
217    rec.index = index;
218 #if !defined(os_windows)
219    //Windows doesn't need to use the trace pipe for thread events, thread 
220    // creation/deletion is handled through the debugging interface.
221    asyncSendThreadEvent(pid, rtBPatch_threadDestroyEvent, &rec, 
222                         sizeof(BPatch_deleteThreadEventRecord));
223 #endif
224 #endif
225 }
226
227 /**
228  * This function's entire purpose in life is to exist in the symbol table.
229  * We modify a global variable just to ensure that no compiler ever gets
230  * rid of it.
231  **/
232 volatile int DYNINST_dummy_create_var;
233 void DYNINST_dummy_create()
234 {
235    /*   fprintf(stderr, "[%s:%u] - In DYNINST_dummy_create\n", __FILE__, __LINE__);*/
236    DYNINST_dummy_create_var++;
237 }
238
239 /**
240  * Some exported wrapper function for other runtime libraries to use tc_lock
241  **/
242
243 unsigned dyninst_threadIndex()
244 {
245    return DYNINSTthreadIndex();
246 }