Home | History | Annotate | Line # | Download | only in libcollector
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