xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/libcollector/synctrace.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 /*
22  *	Synchronization events
23  */
24 #include "config.h"
25 #include <alloca.h>
26 #include <dlfcn.h>
27 #include <unistd.h>
28 #include <semaphore.h>		/* sem_wait() */
29 #include <stddef.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/param.h>
33 #include <pthread.h>
34 
35 #include "gp-defs.h"
36 #include "collector.h"
37 #include "gp-experiment.h"
38 #include "data_pckts.h"
39 #include "tsd.h"
40 #include "cc_libcollector.h"
41 
42 /* define the packet that will be written out */
43 typedef struct Sync_packet
44 { /* Synchronization delay tracing packet */
45   Common_packet comm;
46   hrtime_t requested;       /* time of synchronization request */
47   Vaddr_type objp;          /* vaddr of synchronization object */
48 } Sync_packet;
49 
50 static int open_experiment (const char *);
51 static int start_data_collection (void);
52 static int stop_data_collection (void);
53 static int close_experiment (void);
54 static int detach_experiment (void);
55 static int init_thread_intf ();
56 static int sync_calibrate ();
57 
58 static ModuleInterface module_interface ={
59   SP_SYNCTRACE_FILE,        /* description */
60   NULL,                     /* initInterface */
61   open_experiment,          /* openExperiment */
62   start_data_collection,    /* startDataCollection */
63   stop_data_collection,     /* stopDataCollection */
64   close_experiment,         /* closeExperiment */
65   detach_experiment         /* detachExperiment (fork child) */
66 };
67 
68 static CollectorInterface *collector_interface = NULL;
69 static int sync_mode = 0;
70 static long sync_scope = 0;
71 static int sync_native = 0;
72 static int sync_java = 0;
73 static CollectorModule sync_hndl = COLLECTOR_MODULE_ERR;
74 static unsigned sync_key = COLLECTOR_TSD_INVALID_KEY;
75 static long sync_threshold = -1; /* calibrate the value */
76 static int init_thread_intf_started = 0;
77 static int init_thread_intf_finished = 0;
78 
79 #define CHCK_NREENTRANCE(x)     (!sync_native || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) != 0))
80 #define RECHCK_NREENTRANCE(x)   (!sync_native || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) == 0))
81 #define CHCK_JREENTRANCE(x)     (!sync_java || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) != 0))
82 #define RECHCK_JREENTRANCE(x)   (!sync_java || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) == 0))
83 #define PUSH_REENTRANCE(x)      ((*(x))++)
84 #define POP_REENTRANCE(x)       ((*(x))--)
85 #define gethrtime	collector_interface->getHiResTime
86 
87 /*
88  * In most cases, the functions which require interposition are implemented as
89  * weak symbols corresponding to an associated internal function named with a
90  * leading underscore: e.g., mutex_lock() is simply an alias for _mutex_lock().
91  * For the wait functions, however, the published version (used by applications)
92  * is distinct from the internal version (used by system libraries), i.e.,
93  * cond_wait() is an alias for _cond_wait_cancel() rather than _cond_wait().
94  */
95 static long int (*__real_strtol)(const char *nptr, char **endptr, int base) = NULL;
96 static int (*__real_fprintf) (FILE *stream, const char *format, ...) = NULL;
97 static void (*__real___collector_jprofile_enable_synctrace) (void) = NULL;
98 static int (*__real_pthread_mutex_lock) (pthread_mutex_t *mutex) = NULL;
99 static int (*__real_pthread_mutex_lock_2_17) (pthread_mutex_t *mutex) = NULL;
100 static int (*__real_pthread_mutex_lock_2_2_5) (pthread_mutex_t *mutex) = NULL;
101 static int (*__real_pthread_mutex_lock_2_0) (pthread_mutex_t *mutex) = NULL;
102 static int (*__real_pthread_mutex_unlock) (pthread_mutex_t *mutex) = NULL;
103 static int (*__real_pthread_cond_wait) (pthread_cond_t *restrict cond,
104 				pthread_mutex_t *restrict mutex) = NULL;
105 static int (*__real_pthread_cond_timedwait) (pthread_cond_t *restrict cond,
106 			pthread_mutex_t *restrict mutex,
107 			const struct timespec *restrict abstime) = NULL;
108 static int (*__real_pthread_join) (pthread_t thread, void **retval) = NULL;
109 static int (*__real_pthread_join_2_34) (pthread_t thread, void **retval) = NULL;
110 static int (*__real_pthread_join_2_17) (pthread_t thread, void **retval) = NULL;
111 static int (*__real_pthread_join_2_2_5) (pthread_t thread, void **retval) = NULL;
112 static int (*__real_pthread_join_2_0) (pthread_t thread, void **retval) = NULL;
113 static int (*__real_sem_wait) (sem_t *sem) = NULL;
114 static int (*__real_sem_wait_2_34) (sem_t *sem) = NULL;
115 static int (*__real_sem_wait_2_17) (sem_t *sem) = NULL;
116 static int (*__real_sem_wait_2_2_5) (sem_t *sem) = NULL;
117 static int (*__real_sem_wait_2_1) (sem_t *sem) = NULL;
118 static int (*__real_sem_wait_2_0) (sem_t *sem) = NULL;
119 static int (*__real_pthread_cond_wait_2_17) (pthread_cond_t *restrict cond,
120 				pthread_mutex_t *restrict mutex) = NULL;
121 static int (*__real_pthread_cond_wait_2_3_2) (pthread_cond_t *restrict cond,
122 				pthread_mutex_t *restrict mutex) = NULL;
123 static int (*__real_pthread_cond_wait_2_2_5) (pthread_cond_t *restrict cond,
124 				pthread_mutex_t *restrict mutex) = NULL;
125 static int (*__real_pthread_cond_wait_2_0) (pthread_cond_t *restrict cond,
126 				pthread_mutex_t *restrict mutex) = NULL;
127 static int (*__real_pthread_cond_timedwait_2_17) (pthread_cond_t *restrict cond,
128 			pthread_mutex_t *restrict mutex,
129 			const struct timespec *restrict abstime) = NULL;
130 static int (*__real_pthread_cond_timedwait_2_3_2) (pthread_cond_t *restrict cond,
131 			pthread_mutex_t *restrict mutex,
132 			const struct timespec *restrict abstime) = NULL;
133 static int (*__real_pthread_cond_timedwait_2_2_5) (pthread_cond_t *restrict cond,
134 			pthread_mutex_t *restrict mutex,
135 			const struct timespec *restrict abstime) = NULL;
136 static int (*__real_pthread_cond_timedwait_2_0) (pthread_cond_t *restrict cond,
137 			pthread_mutex_t *restrict mutex,
138 			const struct timespec *restrict abstime) = NULL;
139 
140 
141 static void
collector_memset(void * s,int c,size_t n)142 collector_memset (void *s, int c, size_t n)
143 {
144   unsigned char *s1 = s;
145   while (n--)
146     *s1++ = (unsigned char) c;
147 }
148 
149 void
__collector_module_init(CollectorInterface * _collector_interface)150 __collector_module_init (CollectorInterface *_collector_interface)
151 {
152   if (_collector_interface == NULL)
153     return;
154   collector_interface = _collector_interface;
155   TprintfT (0, "synctrace: __collector_module_init\n");
156   sync_hndl = collector_interface->registerModule (&module_interface);
157 
158   /* Initialize next module */
159   ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init");
160   if (next_init != NULL)
161     next_init (_collector_interface);
162 }
163 
164 static int
open_experiment(const char * exp)165 open_experiment (const char *exp)
166 {
167   long thresh = 0;
168   if (init_thread_intf_finished == 0)
169     init_thread_intf ();
170   if (collector_interface == NULL)
171     {
172       Tprintf (0, "synctrace: collector_interface is null.\n");
173       return COL_ERROR_SYNCINIT;
174     }
175   if (sync_hndl == COLLECTOR_MODULE_ERR)
176     {
177       Tprintf (0, "synctrace: handle create failed.\n");
178       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
179 				     SP_JCMD_CERROR, COL_ERROR_SYNCINIT);
180       return COL_ERROR_SYNCINIT;
181     }
182   TprintfT (0, "synctrace: open_experiment %s\n", exp);
183 
184   char *params = (char *) collector_interface->getParams ();
185   while (params)
186     {
187       if ((params[0] == 's') && (params[1] == ':'))
188 	{
189 	  char *ptr = params + 2;
190 	  Tprintf (DBG_LT1, "synctrace: open_experiment s: parameter = %s\n", ptr);
191 	  while (*ptr != ',' && *ptr != ';')
192 	    ptr++;
193 	  sync_scope = 0;
194 	  if (*ptr == ',')
195 	    {
196 	      sync_scope = CALL_REAL (strtol) (ptr + 1, NULL, 0);
197 	      switch (sync_scope)
198 		{
199 		case 1:
200 		  sync_java = 0;
201 		  sync_native = 1;
202 		  break;
203 		case 2:
204 		  sync_java = 1;
205 		  sync_native = 0;
206 		  break;
207 		default:
208 		case 3:
209 		  sync_native = 1;
210 		  sync_java = 1;
211 		  break;
212 		}
213 	      Tprintf (0, "\tsynctrace: sync_scope found as %ld\n", sync_scope);
214 	    }
215 	  else
216 	    {
217 	      /* the old-style descriptor, without scope */
218 	      /* if there was no comma, use the old default */
219 	      sync_scope = 3;
220 	      sync_java = 1;
221 	      sync_native = 1;
222 	      Tprintf (0, "\tsynctrace: sync_scope not found set to %ld\n", sync_scope);
223 	    }
224 	  if (__real___collector_jprofile_enable_synctrace == NULL)
225 	    sync_java = 0;
226 	  thresh = CALL_REAL (strtol)(params + 2, NULL, 0);
227 	  break; /* from the loop to find the "s:thresh,scope" entry */
228 	}
229       else
230 	params++;
231     }
232   if (params == NULL)  /* Sync data collection not specified */
233     return COL_ERROR_SYNCINIT;
234   if (thresh < 0)  /* calibrate the threshold, keep it as a negative number */
235     thresh = -sync_calibrate ();
236 
237   sync_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
238   if (sync_key == (unsigned) - 1)
239     {
240       Tprintf (0, "synctrace: TSD key create failed.\n");
241       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
242 				     SP_JCMD_CERROR, COL_ERROR_SYNCINIT);
243       return COL_ERROR_SYNCINIT;
244     }
245   /* if Java synctrace was requested, tell the jprofile module */
246   if (sync_java)
247     {
248       TprintfT (0, "synctrace: enabling Java synctrace\n");
249       CALL_REAL (__collector_jprofile_enable_synctrace)();
250     }
251   collector_interface->writeLog ("<profile name=\"%s\" threshold=\"%ld\" scope=\"%ld\">\n",
252 				 SP_JCMD_SYNCTRACE, thresh, sync_scope);
253   collector_interface->writeLog ("  <profdata fname=\"%s\"/>\n",
254 				 module_interface.description);
255   /* Record Sync_packet description */
256   collector_interface->writeLog ("  <profpckt kind=\"%d\" uname=\"Synchronization tracing data\">\n", SYNC_PCKT);
257   collector_interface->writeLog ("    <field name=\"LWPID\" uname=\"Lightweight process id\" offset=\"%d\" type=\"%s\"/>\n",
258 		(int) offsetof (Sync_packet, comm.lwp_id),
259 		fld_sizeof (Sync_packet, comm.lwp_id) == 4 ? "INT32" : "INT64");
260   collector_interface->writeLog ("    <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n",
261 		(int) offsetof (Sync_packet, comm.thr_id),
262 		fld_sizeof (Sync_packet, comm.thr_id) == 4 ? "INT32" : "INT64");
263   collector_interface->writeLog ("    <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n",
264 		(int) offsetof (Sync_packet, comm.cpu_id),
265 		fld_sizeof (Sync_packet, comm.cpu_id) == 4 ? "INT32" : "INT64");
266   collector_interface->writeLog ("    <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n",
267 		(int) offsetof (Sync_packet, comm.tstamp),
268 		fld_sizeof (Sync_packet, comm.tstamp) == 4 ? "INT32" : "INT64");
269   collector_interface->writeLog ("    <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
270 		(int) offsetof (Sync_packet, comm.frinfo),
271 		fld_sizeof (Sync_packet, comm.frinfo) == 4 ? "INT32" : "INT64");
272   collector_interface->writeLog ("    <field name=\"SRQST\" uname=\"Synchronization start time\" offset=\"%d\" type=\"%s\"/>\n",
273 		(int) offsetof (Sync_packet, requested),
274 		fld_sizeof (Sync_packet, requested) == 4 ? "INT32" : "INT64");
275   collector_interface->writeLog ("    <field name=\"SOBJ\" uname=\"Synchronization object address\" offset=\"%d\" type=\"%s\"/>\n",
276 		(int) offsetof (Sync_packet, objp),
277 		fld_sizeof (Sync_packet, objp) == 4 ? "INT32" : "INT64");
278   collector_interface->writeLog ("  </profpckt>\n");
279   collector_interface->writeLog ("</profile>\n");
280 
281   /* Convert threshold from microsec to nanosec */
282   sync_threshold = (thresh > 0 ? thresh : -thresh) * 1000;
283   TprintfT (0, "synctrace: open_experiment complete %ld\n", sync_threshold);
284   return COL_ERROR_NONE;
285 }
286 
287 static int
start_data_collection(void)288 start_data_collection (void)
289 {
290   sync_mode = 1;
291   TprintfT (0, "synctrace: start_data_collection\n");
292   return 0;
293 }
294 
295 static int
stop_data_collection(void)296 stop_data_collection (void)
297 {
298   sync_mode = 0;
299   TprintfT (0, "synctrace: stop_data_collection\n");
300   return 0;
301 }
302 
303 static int
close_experiment(void)304 close_experiment (void)
305 {
306   sync_mode = 0;
307   sync_threshold = -1;
308   sync_key = COLLECTOR_TSD_INVALID_KEY;
309   TprintfT (0, "synctrace: close_experiment\n");
310   return 0;
311 }
312 
313 /* fork child.  Clean up state but don't write to experiment */
314 static int
detach_experiment(void)315 detach_experiment (void)
316 {
317   sync_mode = 0;
318   sync_threshold = -1;
319   sync_key = COLLECTOR_TSD_INVALID_KEY;
320   TprintfT (0, "synctrace: detach_experiment\n");
321   return 0;
322 }
323 
324 #define NUM_ITER    100     /* number of iterations in calibration */
325 #define NUM_WARMUP    3     /* number of warm up iterations */
326 
327 static int
sync_calibrate()328 sync_calibrate ()
329 {
330   pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
331   hrtime_t bt, at, delta;
332   hrtime_t avg, max, min;
333   int i;
334   int ret;
335   avg = (hrtime_t) 0;
336   min = max = (hrtime_t) 0;
337   for (i = 0; i < NUM_ITER + NUM_WARMUP; i++)
338     {
339       /* Here we simulate a real call */
340       bt = gethrtime ();
341       ret = CALL_REAL (pthread_mutex_lock)(&mt);
342       at = gethrtime ();
343       CALL_REAL (pthread_mutex_unlock)(&mt);
344       if (i < NUM_WARMUP)   /* skip these iterations */
345 	continue;
346       /* add the time of this one */
347       delta = at - bt;
348       avg += delta;
349       if (min == 0)
350 	min = delta;
351       if (delta < min)
352 	min = delta;
353       if (delta > max)
354 	max = delta;
355     }
356   /* compute average time */
357   avg = avg / NUM_ITER;
358 
359   /* pretty simple, let's see how it works */
360   if (max < 6 * avg)
361     max = 6 * avg;
362   /* round up to the nearest microsecond */
363   ret = (int) ((max + 999) / 1000);
364   return ret;
365 }
366 
367 static int
init_pthread_mutex_lock(void * dlflag)368 init_pthread_mutex_lock (void *dlflag)
369 {
370   __real_pthread_mutex_lock_2_17 = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.17");
371   __real_pthread_mutex_lock_2_2_5 = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2.5");
372   __real_pthread_mutex_lock_2_0 = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.0");
373   if (__real_pthread_mutex_lock_2_17)
374     __real_pthread_mutex_lock = __real_pthread_mutex_lock_2_17;
375   else if (__real_pthread_mutex_lock_2_2_5)
376     __real_pthread_mutex_lock = __real_pthread_mutex_lock_2_2_5;
377   else if (__real_pthread_mutex_lock_2_0)
378     __real_pthread_mutex_lock = __real_pthread_mutex_lock_2_0;
379   else
380     __real_pthread_mutex_lock = dlsym (dlflag, "pthread_mutex_lock");
381   return __real_pthread_mutex_lock ? 1 : 0;
382 }
383 
384 static int
init_thread_intf()385 init_thread_intf ()
386 {
387   void *dlflag = RTLD_NEXT;
388   int err = 0;
389   /* if we detect recursion/reentrance, SEGV so we can get a stack */
390   init_thread_intf_started++;
391   if (!init_thread_intf_finished && init_thread_intf_started >= 3)
392     {
393       /* pull the plug if recursion occurs... */
394       abort ();
395     }
396   /* lookup fprint to print fatal error message */
397   void *ptr = dlsym (RTLD_DEFAULT, "fprintf");
398   if (ptr)
399     {
400       __real_fprintf = (void *) ptr;
401     }
402   else
403     {
404       abort ();
405     }
406 
407   /* find the __collector_jprofile_enable_synctrace routine in jprofile module */
408   ptr = dlsym (RTLD_DEFAULT, "__collector_jprofile_enable_synctrace");
409   if (ptr)
410     __real___collector_jprofile_enable_synctrace = (void *) ptr;
411   else
412     {
413 #if defined(GPROFNG_JAVA_PROFILING)
414       CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT __collector_jprofile_enable_synctrace\n");
415       err = COL_ERROR_SYNCINIT;
416 #endif
417       sync_java = 0;
418     }
419 
420   dlflag = RTLD_NEXT;
421   if (init_pthread_mutex_lock (dlflag) == 0)
422     {
423       /* We are probably dlopened after libthread/libc,
424        * try to search in the previously loaded objects
425        */
426       dlflag = RTLD_DEFAULT;
427       if (init_pthread_mutex_lock (dlflag) == 0)
428 	{
429 	  CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_lock\n");
430 	  err = COL_ERROR_SYNCINIT;
431 	}
432     }
433 
434   if ((ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.17")) != NULL)
435     __real_pthread_mutex_unlock = ptr;
436   else if ((ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.2.5")) != NULL)
437     __real_pthread_mutex_unlock = ptr;
438   else if ((ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.0")) != NULL)
439     __real_pthread_mutex_unlock = ptr;
440   else
441     __real_pthread_mutex_unlock = dlsym (dlflag, "pthread_mutex_unlock");
442   if (__real_pthread_mutex_unlock == NULL)
443     {
444       CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n");
445       err = COL_ERROR_SYNCINIT;
446     }
447 
448   __real_pthread_cond_wait_2_17 = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.17");
449   __real_pthread_cond_wait_2_3_2 = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2");
450   __real_pthread_cond_wait_2_2_5 = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.2.5");
451   __real_pthread_cond_wait_2_0 = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.0");
452   if (__real_pthread_cond_wait_2_17)
453     __real_pthread_cond_wait = __real_pthread_cond_wait_2_17;
454   else if (__real_pthread_cond_wait_2_3_2)
455     __real_pthread_cond_wait = __real_pthread_cond_wait_2_3_2;
456   else if (__real_pthread_cond_wait_2_2_5)
457     __real_pthread_cond_wait = __real_pthread_cond_wait_2_2_5;
458   else if (__real_pthread_cond_wait_2_0)
459     __real_pthread_cond_wait = __real_pthread_cond_wait_2_0;
460   else
461     __real_pthread_cond_wait = dlsym (dlflag, "pthread_cond_wait");
462   if (__real_pthread_cond_wait == NULL)
463     {
464       CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n");
465       err = COL_ERROR_SYNCINIT;
466     }
467 
468   __real_pthread_cond_timedwait_2_17 = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.17");
469   __real_pthread_cond_timedwait_2_3_2 = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2");
470   __real_pthread_cond_timedwait_2_2_5 = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.2.5");
471   __real_pthread_cond_timedwait_2_0 = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.0");
472   if (__real_pthread_cond_timedwait_2_17)
473     __real_pthread_cond_timedwait = __real_pthread_cond_timedwait_2_17;
474   else if (__real_pthread_cond_timedwait_2_3_2)
475     __real_pthread_cond_timedwait = __real_pthread_cond_timedwait_2_3_2;
476   else if (__real_pthread_cond_timedwait_2_2_5)
477     __real_pthread_cond_timedwait = __real_pthread_cond_timedwait_2_2_5;
478   else if (__real_pthread_cond_timedwait_2_0)
479     __real_pthread_cond_timedwait = __real_pthread_cond_timedwait_2_0;
480   else
481     __real_pthread_cond_timedwait = dlsym (dlflag, "pthread_cond_timedwait");
482   if (__real_pthread_cond_timedwait == NULL)
483     {
484       CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n");
485       err = COL_ERROR_SYNCINIT;
486     }
487 
488   __real_pthread_join_2_34 = dlvsym (dlflag, "pthread_join", "GLIBC_2.34");
489   __real_pthread_join_2_17 = dlvsym (dlflag, "pthread_join", "GLIBC_2.17");
490   __real_pthread_join_2_2_5 = dlvsym (dlflag, "pthread_join", "GLIBC_2.2.5");
491   __real_pthread_join_2_0 = dlvsym (dlflag, "pthread_join", "GLIBC_2.0");
492   if (__real_pthread_join_2_34)
493     __real_pthread_join = __real_pthread_join_2_34;
494   else if (__real_pthread_join_2_17)
495     __real_pthread_join = __real_pthread_join_2_17;
496   else if (__real_pthread_join_2_2_5)
497     __real_pthread_join = __real_pthread_join_2_2_5;
498   else if (__real_pthread_join_2_0)
499     __real_pthread_join = __real_pthread_join_2_0;
500   else
501     __real_pthread_join = dlsym (dlflag, "pthread_join");
502   if (__real_pthread_join == NULL)
503     {
504       CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n");
505       err = COL_ERROR_SYNCINIT;
506     }
507 
508   __real_sem_wait_2_34 = dlvsym (dlflag, "sem_wait", "GLIBC_2.34");
509   __real_sem_wait_2_17 = dlvsym (dlflag, "sem_wait", "GLIBC_2.17");
510   __real_sem_wait_2_2_5 = dlvsym (dlflag, "sem_wait", "GLIBC_2.2.5");
511   __real_sem_wait_2_1 = dlvsym (dlflag, "sem_wait", "GLIBC_2.1");
512   __real_sem_wait_2_0 = dlvsym (dlflag, "sem_wait", "GLIBC_2.0");
513   if (__real_sem_wait_2_34)
514     __real_sem_wait = __real_sem_wait_2_34;
515   else if (__real_sem_wait_2_17)
516     __real_sem_wait = __real_sem_wait_2_17;
517   else if (__real_sem_wait_2_2_5)
518     __real_sem_wait = __real_sem_wait_2_2_5;
519   else if (__real_sem_wait_2_1)
520     __real_sem_wait = __real_sem_wait_2_1;
521   else if (__real_sem_wait_2_0)
522     __real_sem_wait = __real_sem_wait_2_0;
523   else
524     __real_sem_wait = dlsym (dlflag, "sem_wait");
525   if (__real_sem_wait == NULL)
526     {
527       CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n");
528       err = COL_ERROR_SYNCINIT;
529     }
530 
531 
532   ptr = dlsym (dlflag, "strtol");
533   if (ptr)
534     __real_strtol = (void *) ptr;
535   else
536     {
537       CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT strtol\n");
538       err = COL_ERROR_SYNCINIT;
539     }
540   init_thread_intf_finished++;
541   TprintfT (0, "synctrace init_thread_intf complete\n");
542   return err;
543 }
544 
545 /* These next two routines are used from jprofile to record Java synctrace data */
546 void
__collector_jsync_begin()547 __collector_jsync_begin ()
548 {
549   int *guard;
550   if (CHCK_JREENTRANCE (guard))
551     {
552       Tprintf (DBG_LT1, "__collector_jsync_begin: skipped\n");
553       return;
554     }
555   Tprintf (DBG_LT1, "__collector_jsync_begin: start event\n");
556   PUSH_REENTRANCE (guard);
557 }
558 
559 void
__collector_jsync_end(hrtime_t reqt,void * object)560 __collector_jsync_end (hrtime_t reqt, void *object)
561 {
562   int *guard;
563   if (RECHCK_JREENTRANCE (guard))
564     {
565       Tprintf (DBG_LT1, "__collector_jsync_end: skipped\n");
566       return;
567     }
568   hrtime_t grnt = gethrtime ();
569   if (grnt - reqt >= sync_threshold)
570     {
571       Sync_packet spacket;
572       collector_memset (&spacket, 0, sizeof (Sync_packet));
573       spacket.comm.tsize = sizeof (Sync_packet);
574       spacket.comm.tstamp = grnt;
575       spacket.requested = reqt;
576       spacket.objp = (intptr_t) object;
577       spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl,
578 			spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
579       collector_interface->writeDataRecord (sync_hndl, (Common_packet*) &spacket);
580     }
581   Tprintf (DBG_LT1, "__collector_jsync_begin: end event\n");
582   POP_REENTRANCE (guard);
583 }
584 /*-------------------------------------------------------- pthread_mutex_lock */
585 static int
gprofng_pthread_mutex_lock(int (real_func)(pthread_mutex_t *),pthread_mutex_t * mp)586 gprofng_pthread_mutex_lock (int (real_func) (pthread_mutex_t *),
587 			    pthread_mutex_t *mp)
588 {
589   int *guard;
590   if (CHCK_NREENTRANCE (guard))
591     return (real_func) (mp);
592   PUSH_REENTRANCE (guard);
593   hrtime_t reqt = gethrtime ();
594   int ret = (real_func) (mp);
595   if (RECHCK_NREENTRANCE (guard))
596     {
597       POP_REENTRANCE (guard);
598       return ret;
599     }
600   hrtime_t grnt = gethrtime ();
601   if (grnt - reqt >= sync_threshold)
602     {
603       Sync_packet spacket;
604       collector_memset (&spacket, 0, sizeof (Sync_packet));
605       spacket.comm.tsize = sizeof (Sync_packet);
606       spacket.comm.tstamp = grnt;
607       spacket.requested = reqt;
608       spacket.objp = (intptr_t) mp;
609       spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl,
610 			spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
611       collector_interface->writeDataRecord (sync_hndl, (Common_packet*) &spacket);
612     }
613   POP_REENTRANCE (guard);
614   return ret;
615 }
616 
617 #define DCL_PTHREAD_MUTEX_LOCK(dcl_f) \
618   int dcl_f (pthread_mutex_t *mp) \
619   { \
620     if (__real_pthread_mutex_lock == NULL) \
621       init_thread_intf (); \
622     return gprofng_pthread_mutex_lock (__real_pthread_mutex_lock, mp); \
623   }
624 
625 DCL_FUNC_VER (DCL_PTHREAD_MUTEX_LOCK, pthread_mutex_lock_2_17, pthread_mutex_lock@GLIBC_2.17)
626 DCL_FUNC_VER (DCL_PTHREAD_MUTEX_LOCK, pthread_mutex_lock_2_2_5, pthread_mutex_lock@GLIBC_2.2.5)
627 DCL_FUNC_VER (DCL_PTHREAD_MUTEX_LOCK, pthread_mutex_lock_2_0, pthread_mutex_lock@GLIBC_2.0)
DCL_PTHREAD_MUTEX_LOCK(pthread_mutex_lock)628 DCL_PTHREAD_MUTEX_LOCK (pthread_mutex_lock)
629 
630 /*------------------------------------------------------------- pthread_cond_wait */
631 static int
632 gprofng_pthread_cond_wait (int(real_func) (pthread_cond_t *, pthread_mutex_t *),
633 			   pthread_cond_t *cond, pthread_mutex_t *mutex)
634 {
635   int *guard;
636   if (CHCK_NREENTRANCE (guard))
637     return (real_func) (cond, mutex);
638   PUSH_REENTRANCE (guard);
639   hrtime_t reqt = gethrtime ();
640   int ret = -1;
641   ret = (real_func) (cond, mutex);
642   if (RECHCK_NREENTRANCE (guard))
643     {
644       POP_REENTRANCE (guard);
645       return ret;
646     }
647   hrtime_t grnt = gethrtime ();
648   if (grnt - reqt >= sync_threshold)
649     {
650       Sync_packet spacket;
651       collector_memset (&spacket, 0, sizeof (Sync_packet));
652       spacket.comm.tsize = sizeof (Sync_packet);
653       spacket.comm.tstamp = grnt;
654       spacket.requested = reqt;
655       spacket.objp = (intptr_t) mutex;
656       spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl,
657 			spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
658       collector_interface->writeDataRecord (sync_hndl, (Common_packet*) &spacket);
659     }
660   POP_REENTRANCE (guard);
661   return ret;
662 }
663 
664 #define DCL_PTHREAD_COND_WAIT(dcl_f) \
665   int dcl_f (pthread_cond_t *cond, pthread_mutex_t *mutex) \
666   { \
667     if (__real_pthread_cond_wait == NULL) \
668       init_thread_intf (); \
669     return gprofng_pthread_cond_wait (__real_pthread_cond_wait, cond, mutex); \
670   }
671 
672 DCL_FUNC_VER (DCL_PTHREAD_COND_WAIT, pthread_cond_wait_2_17, pthread_cond_wait@GLIBC_2.17)
673 DCL_FUNC_VER (DCL_PTHREAD_COND_WAIT, pthread_cond_wait_2_3_2, pthread_cond_wait@GLIBC_2.3.2)
674 DCL_FUNC_VER (DCL_PTHREAD_COND_WAIT, pthread_cond_wait_2_2_5, pthread_cond_wait@GLIBC_2.2.5)
675 DCL_FUNC_VER (DCL_PTHREAD_COND_WAIT, pthread_cond_wait_2_0, pthread_cond_wait@GLIBC_2.0)
DCL_PTHREAD_COND_WAIT(pthread_cond_wait)676 DCL_PTHREAD_COND_WAIT (pthread_cond_wait)
677 
678 /*---------------------------------------------------- pthread_cond_timedwait */
679 static int
680 gprofng_pthread_cond_timedwait (int(real_func) (pthread_cond_t *,
681 				    pthread_mutex_t*, const struct timespec *),
682 				pthread_cond_t *cond, pthread_mutex_t *mutex,
683 				const struct timespec *abstime)
684 {
685   int *guard;
686   if (CHCK_NREENTRANCE (guard))
687     return (real_func) (cond, mutex, abstime);
688   PUSH_REENTRANCE (guard);
689   hrtime_t reqt = gethrtime ();
690   int ret = -1;
691   ret = (real_func) (cond, mutex, abstime);
692   if (RECHCK_NREENTRANCE (guard))
693     {
694       POP_REENTRANCE (guard);
695       return ret;
696     }
697   hrtime_t grnt = gethrtime ();
698   if (grnt - reqt >= sync_threshold)
699     {
700       Sync_packet spacket;
701       collector_memset (&spacket, 0, sizeof (Sync_packet));
702       spacket.comm.tsize = sizeof (Sync_packet);
703       spacket.comm.tstamp = grnt;
704       spacket.requested = reqt;
705       spacket.objp = (intptr_t) mutex;
706       spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl,
707 			spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
708       collector_interface->writeDataRecord (sync_hndl, (Common_packet*) &spacket);
709     }
710   POP_REENTRANCE (guard);
711   return ret;
712 }
713 
714 #define DCL_PTHREAD_COND_TIMEDWAIT(dcl_f) \
715   int dcl_f (pthread_cond_t *cond, pthread_mutex_t *mutex, \
716 	     const struct timespec *abstime) \
717   { \
718     if (__real_pthread_cond_timedwait == NULL) \
719       init_thread_intf (); \
720     return gprofng_pthread_cond_timedwait (__real_pthread_cond_timedwait, cond, mutex, abstime); \
721   }
722 
723 DCL_FUNC_VER (DCL_PTHREAD_COND_TIMEDWAIT, pthread_cond_timedwait_2_17, pthread_cond_timedwait@GLIBC_2.17)
724 DCL_FUNC_VER (DCL_PTHREAD_COND_TIMEDWAIT, pthread_cond_timedwait_2_3_2, pthread_cond_timedwait@GLIBC_2.3.2)
725 DCL_FUNC_VER (DCL_PTHREAD_COND_TIMEDWAIT, pthread_cond_timedwait_2_2_5, pthread_cond_timedwait@GLIBC_2.2.5)
726 DCL_FUNC_VER (DCL_PTHREAD_COND_TIMEDWAIT, pthread_cond_timedwait_2_0, pthread_cond_timedwait@GLIBC_2.0)
DCL_PTHREAD_COND_TIMEDWAIT(pthread_cond_timedwait)727 DCL_PTHREAD_COND_TIMEDWAIT (pthread_cond_timedwait)
728 
729 
730 /*------------------------------------------------------------- pthread_join */
731 static int
732 gprofng_pthread_join (int(real_func) (pthread_t, void **),
733 		      pthread_t target_thread, void **status)
734 {
735   int *guard;
736   if (CHCK_NREENTRANCE (guard))
737     return real_func (target_thread, status);
738   PUSH_REENTRANCE (guard);
739   hrtime_t reqt = gethrtime ();
740   int ret = real_func(target_thread, status);
741   if (RECHCK_NREENTRANCE (guard))
742     {
743       POP_REENTRANCE (guard);
744       return ret;
745     }
746   hrtime_t grnt = gethrtime ();
747   if (grnt - reqt >= sync_threshold)
748     {
749       Sync_packet spacket;
750       collector_memset (&spacket, 0, sizeof (Sync_packet));
751       spacket.comm.tsize = sizeof (Sync_packet);
752       spacket.comm.tstamp = grnt;
753       spacket.requested = reqt;
754       spacket.objp = (Vaddr_type) target_thread;
755       spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl,
756 			spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
757       collector_interface->writeDataRecord (sync_hndl, (Common_packet*) &spacket);
758     }
759   POP_REENTRANCE (guard);
760   return ret;
761 }
762 
763 #define DCL_PTHREAD_JOIN(dcl_f) \
764   int dcl_f (pthread_t target_thread, void **status) \
765   { \
766     if (__real_pthread_join == NULL) \
767       init_thread_intf (); \
768     return gprofng_pthread_join (__real_pthread_join, target_thread, status); \
769   }
770 
771 DCL_FUNC_VER (DCL_PTHREAD_JOIN, pthread_join_2_34, pthread_join@GLIBC_2.34)
772 DCL_FUNC_VER (DCL_PTHREAD_JOIN, pthread_join_2_17, pthread_join@GLIBC_2.17)
773 DCL_FUNC_VER (DCL_PTHREAD_JOIN, pthread_join_2_2_5, pthread_join@GLIBC_2.2.5)
774 DCL_FUNC_VER (DCL_PTHREAD_JOIN, pthread_join_2_0, pthread_join@GLIBC_2.0)
DCL_PTHREAD_JOIN(pthread_join)775 DCL_PTHREAD_JOIN (pthread_join)
776 
777 /*------------------------------------------------------------- sem_wait */
778 static int
779 gprofng_sem_wait (int (real_func) (sem_t *), sem_t *sp)
780 {
781   int *guard;
782   if (CHCK_NREENTRANCE (guard))
783     return real_func (sp);
784   PUSH_REENTRANCE (guard);
785   hrtime_t reqt = gethrtime ();
786   int ret = -1;
787   ret = real_func (sp);
788   if (RECHCK_NREENTRANCE (guard))
789     {
790       POP_REENTRANCE (guard);
791       return ret;
792     }
793   hrtime_t grnt = gethrtime ();
794   if (grnt - reqt >= sync_threshold)
795     {
796       Sync_packet spacket;
797       collector_memset (&spacket, 0, sizeof (Sync_packet));
798       spacket.comm.tsize = sizeof (Sync_packet);
799       spacket.comm.tstamp = grnt;
800       spacket.requested = reqt;
801       spacket.objp = (intptr_t) sp;
802       spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl,
803 			spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
804       collector_interface->writeDataRecord (sync_hndl, (Common_packet*) &spacket);
805     }
806   POP_REENTRANCE (guard);
807   return ret;
808 }
809 
810 #define DCL_SEM_WAIT(dcl_f) \
811   int dcl_f (sem_t *sp) \
812   { \
813     if (__real_sem_wait == NULL) \
814       init_thread_intf (); \
815     return gprofng_sem_wait (__real_sem_wait, sp); \
816   }
817 
818 DCL_FUNC_VER (DCL_SEM_WAIT, sem_wait_2_34, sem_wait@GLIBC_2.34)
819 DCL_FUNC_VER (DCL_SEM_WAIT, sem_wait_2_17, sem_wait@GLIBC_2.17)
820 DCL_FUNC_VER (DCL_SEM_WAIT, sem_wait_2_2_5, sem_wait@GLIBC_2.2.5)
821 DCL_FUNC_VER (DCL_SEM_WAIT, sem_wait_2_0, sem_wait@GLIBC_2.0)
822 DCL_FUNC_VER (DCL_SEM_WAIT, sem_wait_2_1, sem_wait@GLIBC_2.1)
823 DCL_SEM_WAIT (sem_wait)
824