(1) Fix test5_5 failure on Solaris Native Compiler (bug 933).
[dyninst.git] / dyninstAPI_RT / src / RTthread.c
1 /*
2  * Copyright (c) 1996-2004 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  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45
46 #include "RTthread.h"
47 #include "RTcommon.h"
48 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
49 #include "dyninstAPI_RT/h/dyninstRTExport.h"
50
51 extern unsigned DYNINST_max_num_threads;
52 int DYNINST_multithread_capable;
53 extern unsigned int DYNINSThasInitialized;
54
55 static unsigned threadCreate(dyntid_t tid);
56
57 static void (*rt_newthr_cb)(int) = NULL;
58 void setNewthrCB(void (*cb)(int)) {
59     rt_newthr_cb = cb;
60 }
61
62 /**
63  * Translate a tid given by pthread_self into an index.  Called by 
64  * basetramps everywhere.
65  **/
66
67 int DYNINSTthreadIndex()
68 {
69    dyntid_t tid;
70    unsigned curr_index;
71
72    rtdebug_printf("%s[%d]:  welcome to DYNINSTthreadIndex()\n", __FILE__, __LINE__);
73    if (!DYNINSThasInitialized) 
74    {
75        return 0;
76    }
77    
78    tid = dyn_pthread_self();
79    rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): tid = %lu\n", __FILE__, __LINE__, (unsigned long) tid);
80    if (tid == (dyntid_t) DYNINST_SINGLETHREADED) {
81        return 0;
82    }
83
84    curr_index = DYNINSTthreadIndexFAST();
85    if (curr_index < DYNINST_max_num_threads &&
86        DYNINST_getThreadFromIndex(curr_index) == tid)
87    {
88        rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): index exists already, returning %d\n", __FILE__, __LINE__, curr_index);
89        return curr_index;
90    }
91    
92    curr_index = DYNINSTthreadIndexSLOW(tid);
93    if ( curr_index == DYNINST_NOT_IN_HASHTABLE )
94    {
95        rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): doing threadCreate for %lu\n", __FILE__, __LINE__, tid);
96        curr_index = threadCreate(tid);
97        rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): returning index: %d\n",  __FILE__, __LINE__, curr_index);
98    }
99                 
100    /* While DYNINST_max_num_threads is also an error return for
101       DYNINSTthreadIndexSLOW(), there's not really anything we
102       can do about it at the moment, so just return it
103       and let the mutatee scribble into the so-allocated memory. */
104
105    rtdebug_printf("%s[%d]:  DYNINSTthreadIndex(): returning index: %d\n",  __FILE__, __LINE__, curr_index);
106    return curr_index;
107 }
108
109 extern tc_lock_t DYNINST_trace_lock;
110
111 static int asyncSendThreadEvent(int pid, rtBPatch_asyncEventType type, 
112                                 void *ev, unsigned ev_size)
113 {
114    int result;
115    rtBPatch_asyncEventRecord aev;
116    aev.pid = pid;
117    aev.type = type;
118    aev.event_fd = 0;
119    aev.size = ev_size;
120
121    result = tc_lock_lock(&DYNINST_trace_lock);
122    if (result == DYNINST_DEAD_LOCK)
123    {
124       fprintf(stderr, "[%s:%d] - Error in libdyninstAPI_RT: trace pipe deadlock in thread %lu \n",
125                     __FILE__, __LINE__,dyn_pthread_self() );
126       return DYNINST_TRACEPIPE_ERRVAL;
127    }
128    
129    result = DYNINSTwriteEvent((void *) &aev, sizeof(rtBPatch_asyncEventRecord));
130    if (result == -1)
131    {
132       fprintf(stderr, "%s[%d]:  write error creating thread\n",
133               __FILE__, __LINE__);
134       goto done;
135    }
136
137    result = DYNINSTwriteEvent((void *) ev, ev_size);
138    if (result == -1)
139    {
140       fprintf(stderr, "%s[%d]:  write error creating thread\n",
141               __FILE__, __LINE__);
142       goto done;
143    }
144    
145    
146  done:
147    tc_lock_unlock(&DYNINST_trace_lock);
148   rtdebug_printf("%s[%d]:  leaving asyncSendThreadEvent: status = %s\n", 
149                  __FILE__, __LINE__, result ? "error" : "ok");
150    return result;
151 }
152
153 /**
154  * Creates a new index for a given tid.
155  **/
156 static unsigned threadCreate(dyntid_t tid)
157 {
158    int res;
159    BPatch_newThreadEventRecord ev;
160    unsigned index;
161
162    rtdebug_printf("%s[%d]:  welcome to threadCreate\n", 
163                  __FILE__, __LINE__);
164    if (!DYNINSThasInitialized)
165    {
166       return DYNINST_max_num_threads;
167    }
168    
169    /* Get an index */
170    index = DYNINST_alloc_index(tid);
171
172    /**
173     * Trigger the mutator and mutatee side callbacks.
174     **/
175    memset(&ev, 0, sizeof(BPatch_newThreadEventRecord));
176
177    ev.ppid = dyn_pid_self();
178    ev.tid = tid;
179    ev.lwp = dyn_lwp_self();
180    ev.index = index;
181    
182    res = DYNINSTthreadInfo(&ev);
183    if (!res)
184    {
185       return DYNINST_max_num_threads;
186    }
187    
188    if (rt_newthr_cb)
189    {
190       rt_newthr_cb(index);
191    }
192
193    /*Only async for now.  We should parameterize this function to also have a*/
194    /* sync option.*/
195    asyncSendThreadEvent(ev.ppid, rtBPatch_threadCreateEvent, &ev, 
196                         sizeof(BPatch_newThreadEventRecord));
197    rtdebug_printf("%s[%d]:  leaving threadCreate: index = %d\n", 
198                  __FILE__, __LINE__, index);
199
200    return index;
201 }
202
203 /**
204  * Called when a thread is destroyed
205  **/
206 void DYNINSTthreadDestroy()
207 {
208    dyntid_t tid = dyn_pthread_self();
209    int index = DYNINSTthreadIndex();
210    /*   int pid = dyn_pid_self();*/
211    int err;
212    /*   BPatch_deleteThreadEventRecord rec;*/
213
214   rtdebug_printf("%s[%d]: DESTROY freeing index for thread %lu, index = %d\n", 
215                  __FILE__, __LINE__, tid, index);
216    err = DYNINST_free_index(tid);
217    if (err) {
218       rtdebug_printf("%s[%d]:  DYNINST_free_index FAILED\n", __FILE__, __LINE__);
219       return;
220    }
221 #if 0
222    //  no longer do notification of exits asynchronously
223    memset(&rec, 0, sizeof(rec));
224    rec.index = index;
225 #if !defined(os_windows)
226    //Windows doesn't need to use the trace pipe for thread events, thread 
227    // creation/deletion is handled through the debugging interface.
228    asyncSendThreadEvent(pid, rtBPatch_threadDestroyEvent, &rec, 
229                         sizeof(BPatch_deleteThreadEventRecord));
230 #endif
231 #endif
232 }
233
234 /**
235  * This function's entire purpose in life is to exist in the symbol table.
236  * We modify a global variable just to ensure that no compiler ever gets
237  * rid of it.
238  **/
239 volatile int DYNINST_dummy_create_var;
240 void DYNINST_dummy_create()
241 {
242    /*   fprintf(stderr, "[%s:%u] - In DYNINST_dummy_create\n", __FILE__, __LINE__);*/
243    /*DYNINST_dummy_create_var++;*/
244 }
245
246 /**
247  * Some exported wrapper function for other runtime libraries to use tc_lock
248  **/
249
250 unsigned dyninst_threadIndex()
251 {
252    return DYNINSTthreadIndex();
253 }