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