1/* Copyright (C) 2021 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 <stdlib.h>
30#include <string.h>
31#include <sys/param.h>
32#include <pthread.h>
33
34#include "gp-defs.h"
35#include "collector_module.h"
36#include "gp-experiment.h"
37#include "data_pckts.h"
38#include "i18n.h"
39#include "tsd.h"
40#include "cc_libcollector.h"
41
42/* TprintfT(<level>,...) definitions.  Adjust per module as needed */
43#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
44#define DBG_LTT 0 // for interposition on GLIBC functions
45#define DBG_LT1 1 // for configuration details, warnings
46#define DBG_LT2 2
47#define DBG_LT3 3
48
49/* define the packet that will be written out */
50typedef struct Sync_packet
51{ /* Synchronization delay tracing packet */
52  Common_packet comm;
53  hrtime_t requested;       /* time of synchronization request */
54  Vaddr_type objp;          /* vaddr of synchronization object */
55} Sync_packet;
56
57static int open_experiment (const char *);
58static int start_data_collection (void);
59static int stop_data_collection (void);
60static int close_experiment (void);
61static int detach_experiment (void);
62static int init_thread_intf ();
63static int sync_calibrate ();
64
65static ModuleInterface module_interface ={
66  SP_SYNCTRACE_FILE,        /* description */
67  NULL,                     /* initInterface */
68  open_experiment,          /* openExperiment */
69  start_data_collection,    /* startDataCollection */
70  stop_data_collection,     /* stopDataCollection */
71  close_experiment,         /* closeExperiment */
72  detach_experiment         /* detachExperiment (fork child) */
73};
74
75static CollectorInterface *collector_interface = NULL;
76static int sync_mode = 0;
77static long sync_scope = 0;
78static int sync_native = 0;
79static int sync_java = 0;
80static CollectorModule sync_hndl = COLLECTOR_MODULE_ERR;
81static unsigned sync_key = COLLECTOR_TSD_INVALID_KEY;
82static long sync_threshold = -1; /* calibrate the value */
83static int init_thread_intf_started = 0;
84static int init_thread_intf_finished = 0;
85
86#define CHCK_NREENTRANCE(x)     (!sync_native || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) != 0))
87#define RECHCK_NREENTRANCE(x)   (!sync_native || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) == 0))
88#define CHCK_JREENTRANCE(x)     (!sync_java || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) != 0))
89#define RECHCK_JREENTRANCE(x)   (!sync_java || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) == 0))
90#define PUSH_REENTRANCE(x)      ((*(x))++)
91#define POP_REENTRANCE(x)       ((*(x))--)
92
93#define CALL_REAL(x)            (*(int(*)())__real_##x)
94#define NULL_PTR(x)             ( __real_##x == NULL )
95#define gethrtime	collector_interface->getHiResTime
96
97#ifdef DEBUG
98#define Tprintf(...)   if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
99#define TprintfT(...)  if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
100#else
101#define Tprintf(...)
102#define TprintfT(...)
103#endif
104
105/*
106 * In most cases, the functions which require interposition are implemented as
107 * weak symbols corresponding to an associated internal function named with a
108 * leading underscore: e.g., mutex_lock() is simply an alias for _mutex_lock().
109 * For the wait functions, however, the published version (used by applications)
110 * is distinct from the internal version (used by system libraries), i.e.,
111 * cond_wait() is an alias for _cond_wait_cancel() rather than _cond_wait().
112 */
113static void *__real_strtol = NULL;
114static void *__real_fprintf = NULL;
115static void *__real___collector_jprofile_enable_synctrace = NULL;
116static void *__real_pthread_mutex_lock = NULL;
117static void *__real_pthread_mutex_unlock = NULL; /* not interposed, used in calibrate */
118static void *__real_pthread_cond_wait = NULL;
119static void *__real_pthread_cond_timedwait = NULL;
120static void *__real_pthread_join = NULL;
121static void *__real_sem_wait = NULL;
122static void *__real_pthread_cond_wait_2_3_2 = NULL;
123static void *__real_pthread_cond_timedwait_2_3_2 = NULL;
124
125#if WSIZE(32)
126static void *__real_sem_wait_2_1 = NULL;
127static void *__real_sem_wait_2_0 = NULL;
128static void *__real_pthread_cond_wait_2_0 = NULL;
129static void *__real_pthread_cond_timedwait_2_0 = NULL;
130#elif WSIZE(64)
131#if ARCH(Intel)
132static void *__real_pthread_cond_wait_2_2_5 = NULL;
133static void *__real_pthread_cond_timedwait_2_2_5 = NULL;
134#elif ARCH(SPARC)
135static void *__real_pthread_cond_wait_2_2 = NULL;
136static void *__real_pthread_cond_timedwait_2_2 = NULL;
137#endif  /* ARCH() */
138#endif /* WSIZE() */
139
140static void
141collector_memset (void *s, int c, size_t n)
142{
143  unsigned char *s1 = s;
144  while (n--)
145    *s1++ = (unsigned char) c;
146}
147
148void
149__collector_module_init (CollectorInterface *_collector_interface)
150{
151  if (_collector_interface == NULL)
152    return;
153  collector_interface = _collector_interface;
154  TprintfT (0, "synctrace: __collector_module_init\n");
155  sync_hndl = collector_interface->registerModule (&module_interface);
156
157  /* Initialize next module */
158  ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init");
159  if (next_init != NULL)
160    next_init (_collector_interface);
161}
162
163static int
164open_experiment (const char *exp)
165{
166  long thresh = 0;
167  if (init_thread_intf_finished == 0)
168    init_thread_intf ();
169  if (collector_interface == NULL)
170    {
171      Tprintf (0, "synctrace: collector_interface is null.\n");
172      return COL_ERROR_SYNCINIT;
173    }
174  if (sync_hndl == COLLECTOR_MODULE_ERR)
175    {
176      Tprintf (0, "synctrace: handle create failed.\n");
177      collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
178				     SP_JCMD_CERROR, COL_ERROR_SYNCINIT);
179      return COL_ERROR_SYNCINIT;
180    }
181  TprintfT (0, "synctrace: open_experiment %s\n", exp);
182
183  char *params = (char *) collector_interface->getParams ();
184  while (params)
185    {
186      if ((params[0] == 's') && (params[1] == ':'))
187	{
188	  char *ptr = params + 2;
189	  Tprintf (DBG_LT1, "synctrace: open_experiment s: parameter = %s\n", ptr);
190	  while (*ptr != ',' && *ptr != ';')
191	    ptr++;
192	  sync_scope = 0;
193	  if (*ptr == ',')
194	    {
195	      sync_scope = CALL_REAL (strtol) (ptr + 1, NULL, 0);
196	      switch (sync_scope)
197		{
198		case 1:
199		  sync_java = 0;
200		  sync_native = 1;
201		  break;
202		case 2:
203		  sync_java = 1;
204		  sync_native = 0;
205		  break;
206		default:
207		case 3:
208		  sync_native = 1;
209		  sync_java = 1;
210		  break;
211		}
212	      Tprintf (0, "\tsynctrace: sync_scope found as %ld\n", sync_scope);
213	    }
214	  else
215	    {
216	      /* the old-style descriptor, without scope */
217	      /* if there was no comma, use the old default */
218	      sync_scope = 3;
219	      sync_java = 1;
220	      sync_native = 1;
221	      Tprintf (0, "\tsynctrace: sync_scope not found set to %ld\n", sync_scope);
222	    }
223	  if (__real___collector_jprofile_enable_synctrace == NULL)
224	    sync_java = 0;
225	  thresh = CALL_REAL (strtol)(params + 2, NULL, 0);
226	  break; /* from the loop to find the "s:thresh,scope" entry */
227	}
228      else
229	params++;
230    }
231  if (params == NULL)  /* Sync data collection not specified */
232    return COL_ERROR_SYNCINIT;
233  if (thresh < 0)  /* calibrate the threshold, keep it as a negative number */
234    thresh = -sync_calibrate ();
235
236  sync_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
237  if (sync_key == (unsigned) - 1)
238    {
239      Tprintf (0, "synctrace: TSD key create failed.\n");
240      collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
241				     SP_JCMD_CERROR, COL_ERROR_SYNCINIT);
242      return COL_ERROR_SYNCINIT;
243    }
244  /* if Java synctrace was requested, tell the jprofile module */
245  if (sync_java)
246    {
247      TprintfT (0, "synctrace: enabling Java synctrace\n");
248      CALL_REAL (__collector_jprofile_enable_synctrace)();
249    }
250  collector_interface->writeLog ("<profile name=\"%s\" threshold=\"%ld\" scope=\"%ld\">\n",
251				 SP_JCMD_SYNCTRACE, thresh, sync_scope);
252  collector_interface->writeLog ("  <profdata fname=\"%s\"/>\n",
253				 module_interface.description);
254  /* Record Sync_packet description */
255  Sync_packet *pp = NULL;
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				 &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64");
259  collector_interface->writeLog ("    <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n",
260				 &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64");
261  collector_interface->writeLog ("    <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n",
262				 &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64");
263  collector_interface->writeLog ("    <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n",
264				 &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64");
265  collector_interface->writeLog ("    <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
266				 &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64");
267  collector_interface->writeLog ("    <field name=\"SRQST\" uname=\"Synchronization start time\" offset=\"%d\" type=\"%s\"/>\n",
268				 &pp->requested, sizeof (pp->requested) == 4 ? "INT32" : "INT64");
269  collector_interface->writeLog ("    <field name=\"SOBJ\" uname=\"Synchronization object address\" offset=\"%d\" type=\"%s\"/>\n",
270				 &pp->objp, sizeof (pp->objp) == 4 ? "INT32" : "INT64");
271  collector_interface->writeLog ("  </profpckt>\n");
272  collector_interface->writeLog ("</profile>\n");
273
274  /* Convert threshold from microsec to nanosec */
275  sync_threshold = (thresh > 0 ? thresh : -thresh) * 1000;
276  TprintfT (0, "synctrace: open_experiment complete %ld\n", sync_threshold);
277  return COL_ERROR_NONE;
278}
279
280static int
281start_data_collection (void)
282{
283  sync_mode = 1;
284  TprintfT (0, "synctrace: start_data_collection\n");
285  return 0;
286}
287
288static int
289stop_data_collection (void)
290{
291  sync_mode = 0;
292  TprintfT (0, "synctrace: stop_data_collection\n");
293  return 0;
294}
295
296static int
297close_experiment (void)
298{
299  sync_mode = 0;
300  sync_threshold = -1;
301  sync_key = COLLECTOR_TSD_INVALID_KEY;
302  TprintfT (0, "synctrace: close_experiment\n");
303  return 0;
304}
305
306/* fork child.  Clean up state but don't write to experiment */
307static int
308detach_experiment (void)
309{
310  sync_mode = 0;
311  sync_threshold = -1;
312  sync_key = COLLECTOR_TSD_INVALID_KEY;
313  TprintfT (0, "synctrace: detach_experiment\n");
314  return 0;
315}
316
317#define NUM_ITER    100     /* number of iterations in calibration */
318#define NUM_WARMUP    3     /* number of warm up iterations */
319
320static int
321sync_calibrate ()
322{
323  pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
324  hrtime_t bt, at, delta;
325  hrtime_t avg, max, min;
326  int i;
327  int ret;
328  avg = (hrtime_t) 0;
329  min = max = (hrtime_t) 0;
330  for (i = 0; i < NUM_ITER + NUM_WARMUP; i++)
331    {
332      /* Here we simulate a real call */
333      bt = gethrtime ();
334      ret = CALL_REAL (pthread_mutex_lock)(&mt);
335      at = gethrtime ();
336      CALL_REAL (pthread_mutex_unlock)(&mt);
337      if (i < NUM_WARMUP)   /* skip these iterations */
338	continue;
339      /* add the time of this one */
340      delta = at - bt;
341      avg += delta;
342      if (min == 0)
343	min = delta;
344      if (delta < min)
345	min = delta;
346      if (delta > max)
347	max = delta;
348    }
349  /* compute average time */
350  avg = avg / NUM_ITER;
351
352  /* pretty simple, let's see how it works */
353  if (max < 6 * avg)
354    max = 6 * avg;
355  /* round up to the nearest microsecond */
356  ret = (int) ((max + 999) / 1000);
357  return ret;
358}
359
360static int
361init_thread_intf ()
362{
363  void *dlflag = RTLD_NEXT;
364  int err = 0;
365  /* if we detect recursion/reentrance, SEGV so we can get a stack */
366  init_thread_intf_started++;
367  if (!init_thread_intf_finished && init_thread_intf_started >= 3)
368    {
369      /* pull the plug if recursion occurs... */
370      abort ();
371    }
372  /* lookup fprint to print fatal error message */
373  void *ptr = dlsym (RTLD_DEFAULT, "fprintf");
374  if (ptr)
375    {
376      __real_fprintf = (void *) ptr;
377    }
378  else
379    {
380      abort ();
381    }
382
383  /* find the __collector_jprofile_enable_synctrace routine in jprofile module */
384  ptr = dlsym (RTLD_DEFAULT, "__collector_jprofile_enable_synctrace");
385  if (ptr)
386    __real___collector_jprofile_enable_synctrace = (void *) ptr;
387  else
388    {
389#if defined(GPROFNG_JAVA_PROFILING)
390      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT __collector_jprofile_enable_synctrace\n");
391      err = COL_ERROR_SYNCINIT;
392#endif
393      sync_java = 0;
394    }
395
396#if WSIZE(32)
397  /* ########################################## begin WSIZE(32) */
398  /* IMPORTANT!!  The GLIBC_* versions below must match those in the er_sync.*.mapfile ! */
399  dlflag = RTLD_NEXT;
400  ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.0");
401  if (ptr == NULL)
402    {
403      /* We are probably dlopened after libthread/libc,
404       * try to search in the previously loaded objects
405       */
406      dlflag = RTLD_DEFAULT;
407      ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.0");
408      if (ptr != NULL)
409	{
410	  __real_pthread_mutex_lock = ptr;
411	  Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for OS sync routines\n");
412	}
413      else
414	{
415	  CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_lock\n");
416	  err = COL_ERROR_SYNCINIT;
417	}
418    }
419  else
420    __real_pthread_mutex_lock = ptr;
421
422  ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.0");
423  if (ptr)
424    __real_pthread_mutex_unlock = (void *) ptr;
425  else
426    {
427      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n");
428      err = COL_ERROR_SYNCINIT;
429    }
430  ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2");
431  if (ptr)
432    __real_pthread_cond_wait = (void *) ptr;
433  else
434    {
435      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n");
436      err = COL_ERROR_SYNCINIT;
437    }
438  ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2");
439  if (ptr)
440    __real_pthread_cond_timedwait = (void *) ptr;
441  else
442    {
443      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n");
444      err = COL_ERROR_SYNCINIT;
445    }
446  ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.0");
447  if (ptr)
448    __real_pthread_join = (void *) ptr;
449  else
450    {
451      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n");
452      err = COL_ERROR_SYNCINIT;
453    }
454  ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.1");
455  if (ptr)
456    __real_sem_wait = (void *) ptr;
457  else
458    {
459      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n");
460      err = COL_ERROR_SYNCINIT;
461    }
462
463#if ARCH(Intel)
464  /* ############## Intel specific additional pointers for 32-bits */
465  ptr = __real_sem_wait_2_1 = __real_sem_wait;
466  ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.0");
467  if (ptr)
468    __real_sem_wait_2_0 = (void *) ptr;
469  else
470    {
471      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait_2_0\n");
472      err = COL_ERROR_SYNCINIT;
473    }
474  ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.0");
475  if (ptr)
476    __real_pthread_cond_wait_2_0 = (void *) ptr;
477  else
478    {
479      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_0\n");
480      err = COL_ERROR_SYNCINIT;
481    }
482  ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.0");
483  if (ptr)
484    __real_pthread_cond_timedwait_2_0 = (void *) ptr;
485  else
486    {
487      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT __real_pthread_cond_timedwait_2_0\n");
488      err = COL_ERROR_SYNCINIT;
489    }
490#endif /* ARCH(Intel) */
491
492#else /* WSIZE(64) */
493  /* # most versions are different between platforms	*/
494  /* # the few that are common are set after the ARCH ifdef */
495#if ARCH(Aarch64)
496  dlflag = RTLD_NEXT;
497#define GLIBC_N    "GLIBC_2.17"
498  __real_pthread_mutex_lock = dlvsym(dlflag, "pthread_mutex_lock", GLIBC_N);
499  __real_pthread_mutex_unlock = dlvsym(dlflag, "pthread_mutex_unlock", GLIBC_N);
500  __real_pthread_cond_wait = dlvsym(dlflag, "pthread_cond_wait", GLIBC_N);
501  __real_pthread_cond_timedwait = dlvsym(dlflag, "pthread_cond_timedwait", GLIBC_N);
502  __real_pthread_join = dlvsym(dlflag, "pthread_join", GLIBC_N);
503  __real_sem_wait = dlvsym(dlflag, "sem_wait", GLIBC_N);
504
505#elif ARCH(Intel)
506  dlflag = RTLD_NEXT;
507  ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2.5");
508  if (ptr == NULL)
509    {
510      /* We are probably dlopened after libthread/libc,
511       * try to search in the previously loaded objects
512       */
513      dlflag = RTLD_DEFAULT;
514      ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2.5");
515      if (ptr != NULL)
516	{
517	  __real_pthread_mutex_lock = ptr;
518	  Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for Solaris sync routines\n");
519	}
520      else
521	{
522	  CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_lock\n");
523	  err = COL_ERROR_SYNCINIT;
524	}
525    }
526  else
527    __real_pthread_mutex_lock = ptr;
528  ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.2.5");
529  if (ptr)
530    __real_pthread_mutex_unlock = (void *) ptr;
531  else
532    {
533      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n");
534      err = COL_ERROR_SYNCINIT;
535    }
536  ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2");
537  if (ptr)
538    __real_pthread_cond_wait = (void *) ptr;
539  else
540    {
541      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n");
542      err = COL_ERROR_SYNCINIT;
543    }
544  ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2");
545  if (ptr)
546    __real_pthread_cond_timedwait = (void *) ptr;
547  else
548    {
549      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n");
550      err = COL_ERROR_SYNCINIT;
551    }
552  ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.2.5");
553  if (ptr)
554    __real_pthread_join = (void *) ptr;
555  else
556    {
557      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n");
558      err = COL_ERROR_SYNCINIT;
559    }
560  ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.2.5");
561  if (ptr)
562    __real_sem_wait = (void *) ptr;
563  else
564    {
565      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n");
566      err = COL_ERROR_SYNCINIT;
567    }
568  ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.2.5");
569  if (ptr)
570    __real_pthread_cond_wait_2_2_5 = (void *) ptr;
571  else
572    {
573      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_2_5\n");
574      err = COL_ERROR_SYNCINIT;
575    }
576  ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.2.5");
577  if (ptr)
578    __real_pthread_cond_timedwait_2_2_5 = (void *) ptr;
579  else
580    {
581      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait_2_2_5\n");
582      err = COL_ERROR_SYNCINIT;
583    }
584
585#elif ARCH(SPARC)
586  dlflag = RTLD_NEXT;
587  ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2");
588  if (ptr == NULL)
589    {
590      /* We are probably dlopened after libthread/libc,
591       * try to search in the previously loaded objects
592       */
593      dlflag = RTLD_DEFAULT;
594      ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2");
595      if (ptr != NULL)
596	{
597	  __real_pthread_mutex_lock = ptr;
598	  Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for Solaris sync routines\n");
599	}
600      else
601	{
602	  CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT mutex_lock\n");
603	  err = COL_ERROR_SYNCINIT;
604	}
605    }
606  else
607    __real_pthread_mutex_lock = ptr;
608  ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.2");
609  if (ptr)
610    __real_pthread_mutex_unlock = (void *) ptr;
611  else
612    {
613      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n");
614      err = COL_ERROR_SYNCINIT;
615    }
616  ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2");
617  if (ptr)
618    __real_pthread_cond_wait = (void *) ptr;
619  else
620    {
621      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n");
622      err = COL_ERROR_SYNCINIT;
623    }
624  ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2");
625  if (ptr)
626    __real_pthread_cond_timedwait = (void *) ptr;
627  else
628    {
629      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n");
630      err = COL_ERROR_SYNCINIT;
631    }
632  ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.2");
633  if (ptr)
634    __real_pthread_join = (void *) ptr;
635  else
636    {
637      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n");
638      err = COL_ERROR_SYNCINIT;
639    }
640  ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.2");
641  if (ptr)
642    __real_sem_wait = (void *) ptr;
643  else
644    {
645      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n");
646      err = COL_ERROR_SYNCINIT;
647    }
648  ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.2");
649  if (ptr)
650    __real_pthread_cond_wait_2_2 = (void *) ptr;
651  else
652    {
653      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_2_5\n");
654      err = COL_ERROR_SYNCINIT;
655    }
656  ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.2");
657  if (ptr)
658    __real_pthread_cond_timedwait_2_2 = (void *) ptr;
659  else
660    {
661      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait_2_2\n");
662      err = COL_ERROR_SYNCINIT;
663    }
664#endif /* ARCH() */
665#endif /* WSIZE(64) */
666  /*  the pointers that are common to 32- and 64-bits, and to SPARC and Intel */
667
668  __real_pthread_cond_wait_2_3_2 = __real_pthread_cond_wait;
669  __real_pthread_cond_timedwait_2_3_2 = __real_pthread_cond_timedwait;
670  ptr = dlsym (dlflag, "strtol");
671  if (ptr)
672    __real_strtol = (void *) ptr;
673  else
674    {
675      CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT strtol\n");
676      err = COL_ERROR_SYNCINIT;
677    }
678  init_thread_intf_finished++;
679  TprintfT (0, "synctrace init_thread_intf complete\n");
680  return err;
681}
682
683/* These next two routines are used from jprofile to record Java synctrace data */
684void
685__collector_jsync_begin ()
686{
687  int *guard;
688  if (CHCK_JREENTRANCE (guard))
689    {
690      Tprintf (DBG_LT1, "__collector_jsync_begin: skipped\n");
691      return;
692    }
693  Tprintf (DBG_LT1, "__collector_jsync_begin: start event\n");
694  PUSH_REENTRANCE (guard);
695}
696
697void
698__collector_jsync_end (hrtime_t reqt, void *object)
699{
700  int *guard;
701  if (RECHCK_JREENTRANCE (guard))
702    {
703      Tprintf (DBG_LT1, "__collector_jsync_end: skipped\n");
704      return;
705    }
706  hrtime_t grnt = gethrtime ();
707  if (grnt - reqt >= sync_threshold)
708    {
709      Sync_packet spacket;
710      collector_memset (&spacket, 0, sizeof (Sync_packet));
711      spacket.comm.tsize = sizeof (Sync_packet);
712      spacket.comm.tstamp = grnt;
713      spacket.requested = reqt;
714      spacket.objp = (intptr_t) object;
715      spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
716      collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
717    }
718  Tprintf (DBG_LT1, "__collector_jsync_begin: end event\n");
719  POP_REENTRANCE (guard);
720}
721
722/*-------------------------------------------------------- pthread_mutex_lock */
723int
724pthread_mutex_lock (pthread_mutex_t *mp)
725{
726  int *guard;
727  if (NULL_PTR (pthread_mutex_lock))
728    init_thread_intf ();
729  if (CHCK_NREENTRANCE (guard))
730    return CALL_REAL (pthread_mutex_lock)(mp);
731  PUSH_REENTRANCE (guard);
732  hrtime_t reqt = gethrtime ();
733  int ret = CALL_REAL (pthread_mutex_lock)(mp);
734  if (RECHCK_NREENTRANCE (guard))
735    {
736      POP_REENTRANCE (guard);
737      return ret;
738    }
739  hrtime_t grnt = gethrtime ();
740  if (grnt - reqt >= sync_threshold)
741    {
742      Sync_packet spacket;
743      collector_memset (&spacket, 0, sizeof (Sync_packet));
744      spacket.comm.tsize = sizeof (Sync_packet);
745      spacket.comm.tstamp = grnt;
746      spacket.requested = reqt;
747      spacket.objp = (intptr_t) mp;
748      spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket);
749      collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
750    }
751  POP_REENTRANCE (guard);
752  return ret;
753}
754
755
756/*------------------------------------------------------------- pthread_cond_wait */
757// map interposed symbol versions
758static int
759__collector_pthread_cond_wait_symver (int(real_pthread_cond_wait) (), pthread_cond_t *cond, pthread_mutex_t *mutex);
760
761#if ARCH(Intel) || ARCH(SPARC)
762SYMVER_ATTRIBUTE (__collector_pthread_cond_wait_2_3_2,
763		  pthread_cond_wait@@GLIBC_2.3.2)
764#endif
765int
766__collector_pthread_cond_wait_2_3_2 (pthread_cond_t *cond, pthread_mutex_t *mutex)
767{
768  if (NULL_PTR (pthread_cond_wait))
769    init_thread_intf ();
770  TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_3_2@%p\n", CALL_REAL (pthread_cond_wait_2_3_2));
771  return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_3_2), cond, mutex);
772}
773
774#if WSIZE(32)
775
776SYMVER_ATTRIBUTE (__collector_pthread_cond_wait_2_0,
777		  pthread_cond_wait@GLIBC_2.0)
778int
779__collector_pthread_cond_wait_2_0 (pthread_cond_t *cond, pthread_mutex_t *mutex)
780{
781  if (NULL_PTR (pthread_cond_wait))
782    init_thread_intf ();
783  TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_0@%p\n", CALL_REAL (pthread_cond_wait_2_0));
784  return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_0), cond, mutex);
785}
786#else // WSIZE(64)
787#if ARCH(Intel)
788SYMVER_ATTRIBUTE (__collector_pthread_cond_wait_2_2_5,
789		  pthread_cond_wait@GLIBC_2.2.5)
790int
791__collector_pthread_cond_wait_2_2_5 (pthread_cond_t *cond, pthread_mutex_t *mutex)
792{
793  if (NULL_PTR (pthread_cond_wait))
794    init_thread_intf ();
795  TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_2_5@%p\n", CALL_REAL (pthread_cond_wait_2_2_5));
796  return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_2_5), cond, mutex);
797}
798#elif ARCH(SPARC)
799
800SYMVER_ATTRIBUTE (__collector_pthread_cond_wait_2_2,
801		  pthread_cond_wait@GLIBC_2.2)
802int
803__collector_pthread_cond_wait_2_2 (pthread_cond_t *cond, pthread_mutex_t *mutex)
804{
805  if (NULL_PTR (pthread_cond_wait))
806    init_thread_intf ();
807  TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_2@%p\n", CALL_REAL (pthread_cond_wait_2_2));
808  return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_2), cond, mutex);
809}
810#endif  // ARCH()
811#endif  // WSIZE()
812
813static int
814__collector_pthread_cond_wait_symver (int(real_pthread_cond_wait) (), pthread_cond_t *cond, pthread_mutex_t *mutex)
815{
816  int *guard;
817  if (NULL_PTR (pthread_cond_wait))
818    init_thread_intf ();
819  if (CHCK_NREENTRANCE (guard))
820    return (real_pthread_cond_wait) (cond, mutex);
821  PUSH_REENTRANCE (guard);
822  hrtime_t reqt = gethrtime ();
823  int ret = -1;
824  ret = (real_pthread_cond_wait) (cond, mutex);
825  if (RECHCK_NREENTRANCE (guard))
826    {
827      POP_REENTRANCE (guard);
828      return ret;
829    }
830  hrtime_t grnt = gethrtime ();
831  if (grnt - reqt >= sync_threshold)
832    {
833      Sync_packet spacket;
834      collector_memset (&spacket, 0, sizeof (Sync_packet));
835      spacket.comm.tsize = sizeof (Sync_packet);
836      spacket.comm.tstamp = grnt;
837      spacket.requested = reqt;
838      spacket.objp = (intptr_t) mutex;
839      spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
840      collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
841    }
842  POP_REENTRANCE (guard);
843  return ret;
844}
845
846/*---------------------------------------------------- pthread_cond_timedwait */
847// map interposed symbol versions
848static int
849__collector_pthread_cond_timedwait_symver (int(real_pthread_cond_timedwait) (),
850					   pthread_cond_t *cond,
851					   pthread_mutex_t *mutex,
852					   const struct timespec *abstime);
853
854#if ARCH(Intel) || ARCH(SPARC)
855SYMVER_ATTRIBUTE (__collector_pthread_cond_timedwait_2_3_2,
856		  pthread_cond_timedwait@@GLIBC_2.3.2)
857#endif  // ARCH()
858int
859__collector_pthread_cond_timedwait_2_3_2 (pthread_cond_t *cond,
860					  pthread_mutex_t *mutex,
861					  const struct timespec *abstime)
862{
863  if (NULL_PTR (pthread_cond_timedwait))
864    init_thread_intf ();
865  TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_3_2@%p\n", CALL_REAL (pthread_cond_timedwait_2_3_2));
866  return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_3_2), cond, mutex, abstime);
867}
868
869#if WSIZE(32)
870SYMVER_ATTRIBUTE (__collector_pthread_cond_timedwait_2_0,
871		  pthread_cond_timedwait@GLIBC_2.0)
872int
873__collector_pthread_cond_timedwait_2_0 (pthread_cond_t *cond,
874					pthread_mutex_t *mutex,
875					const struct timespec *abstime)
876{
877  if (NULL_PTR (pthread_cond_timedwait))
878    init_thread_intf ();
879  TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_0@%p\n", CALL_REAL (pthread_cond_timedwait_2_0));
880  return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_0), cond, mutex, abstime);
881}
882#else // WSIZE(64)
883#if ARCH(Intel)
884SYMVER_ATTRIBUTE (__collector_pthread_cond_timedwait_2_2_5,
885		  pthread_cond_timedwait@GLIBC_2.2.5)
886int
887__collector_pthread_cond_timedwait_2_2_5 (pthread_cond_t *cond,
888					  pthread_mutex_t *mutex,
889					  const struct timespec *abstime)
890{
891  if (NULL_PTR (pthread_cond_timedwait))
892    init_thread_intf ();
893  TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_2_5@%p\n", CALL_REAL (pthread_cond_timedwait_2_2_5));
894  return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_2_5), cond, mutex, abstime);
895}
896#elif ARCH(SPARC)
897
898SYMVER_ATTRIBUTE (__collector_pthread_cond_timedwait_2_2,
899		  pthread_cond_timedwait@GLIBC_2.2)
900int
901__collector_pthread_cond_timedwait_2_2 (pthread_cond_t *cond,
902					pthread_mutex_t *mutex,
903					const struct timespec *abstime)
904{
905  if (NULL_PTR (pthread_cond_timedwait))
906    init_thread_intf ();
907  TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_2@%p\n", CALL_REAL (pthread_cond_timedwait_2_2));
908  return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_2), cond, mutex, abstime);
909}
910#endif  // ARCH()
911#endif  // WSIZE()
912
913static int
914__collector_pthread_cond_timedwait_symver (int(real_pthread_cond_timedwait) (),
915					   pthread_cond_t *cond,
916					   pthread_mutex_t *mutex,
917					   const struct timespec *abstime)
918{
919  int *guard;
920  if (NULL_PTR (pthread_cond_timedwait))
921    init_thread_intf ();
922  if (CHCK_NREENTRANCE (guard))
923    return (real_pthread_cond_timedwait) (cond, mutex, abstime);
924  PUSH_REENTRANCE (guard);
925  hrtime_t reqt = gethrtime ();
926  int ret = -1;
927  ret = (real_pthread_cond_timedwait) (cond, mutex, abstime);
928  if (RECHCK_NREENTRANCE (guard))
929    {
930      POP_REENTRANCE (guard);
931      return ret;
932    }
933  hrtime_t grnt = gethrtime ();
934  if (grnt - reqt >= sync_threshold)
935    {
936      Sync_packet spacket;
937      collector_memset (&spacket, 0, sizeof ( Sync_packet));
938      spacket.comm.tsize = sizeof ( Sync_packet);
939      spacket.comm.tstamp = grnt;
940      spacket.requested = reqt;
941      spacket.objp = (intptr_t) mutex;
942      spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
943      collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
944    }
945  POP_REENTRANCE (guard);
946  return ret;
947}
948
949/*------------------------------------------------------------- pthread_join */
950int
951pthread_join (pthread_t target_thread, void **status)
952{
953  int *guard;
954  if (NULL_PTR (pthread_join))
955    init_thread_intf ();
956  if (CHCK_NREENTRANCE (guard))
957    return CALL_REAL (pthread_join)(target_thread, status);
958  PUSH_REENTRANCE (guard);
959  hrtime_t reqt = gethrtime ();
960  int ret = CALL_REAL (pthread_join)(target_thread, status);
961  if (RECHCK_NREENTRANCE (guard))
962    {
963      POP_REENTRANCE (guard);
964      return ret;
965    }
966  hrtime_t grnt = gethrtime ();
967  if (grnt - reqt >= sync_threshold)
968    {
969      Sync_packet spacket;
970      collector_memset (&spacket, 0, sizeof ( Sync_packet));
971      spacket.comm.tsize = sizeof ( Sync_packet);
972      spacket.comm.tstamp = grnt;
973      spacket.requested = reqt;
974      spacket.objp = (Vaddr_type) target_thread;
975      spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket);
976      collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
977    }
978  POP_REENTRANCE (guard);
979  return ret;
980}
981
982/*------------------------------------------------------------- sem_wait */
983// map interposed symbol versions
984#if ARCH(Intel) && WSIZE(32)
985static int
986__collector_sem_wait_symver (int(real_sem_wait) (), sem_t *sp);
987
988SYMVER_ATTRIBUTE (__collector_sem_wait_2_1, sem_wait@@GLIBC_2.1)
989int
990__collector_sem_wait_2_1 (sem_t *sp)
991{
992  if (NULL_PTR (sem_wait))
993    init_thread_intf ();
994  TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_sem_wait_2_1@%p\n", CALL_REAL (sem_wait_2_1));
995  return __collector_sem_wait_symver (CALL_REAL (sem_wait_2_1), sp);
996}
997
998SYMVER_ATTRIBUTE (__collector_sem_wait_2_0, sem_wait@GLIBC_2.0)
999int
1000__collector_sem_wait_2_0 (sem_t *sp)
1001{
1002  if (NULL_PTR (sem_wait))
1003    init_thread_intf ();
1004  TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_sem_wait_2_0@%p\n", CALL_REAL (sem_wait_2_0));
1005  return __collector_sem_wait_symver (CALL_REAL (sem_wait_2_0), sp);
1006}
1007#endif
1008
1009#if ARCH(Intel) && WSIZE(32)
1010static int
1011__collector_sem_wait_symver (int(real_sem_wait) (), sem_t *sp)
1012{
1013#else
1014int
1015sem_wait (sem_t *sp)
1016{
1017#endif
1018  int *guard;
1019  if (NULL_PTR (sem_wait))
1020    init_thread_intf ();
1021  if (CHCK_NREENTRANCE (guard))
1022    {
1023#if ARCH(Intel) && WSIZE(32)
1024      return (real_sem_wait) (sp);
1025#else
1026      return CALL_REAL (sem_wait)(sp);
1027#endif
1028    }
1029  PUSH_REENTRANCE (guard);
1030  hrtime_t reqt = gethrtime ();
1031  int ret = -1;
1032#if ARCH(Intel) && WSIZE(32)
1033  ret = (real_sem_wait) (sp);
1034#else
1035  ret = CALL_REAL (sem_wait)(sp);
1036#endif
1037  if (RECHCK_NREENTRANCE (guard))
1038    {
1039      POP_REENTRANCE (guard);
1040      return ret;
1041    }
1042  hrtime_t grnt = gethrtime ();
1043  if (grnt - reqt >= sync_threshold)
1044    {
1045      Sync_packet spacket;
1046      collector_memset (&spacket, 0, sizeof ( Sync_packet));
1047      spacket.comm.tsize = sizeof ( Sync_packet);
1048      spacket.comm.tstamp = grnt;
1049      spacket.requested = reqt;
1050      spacket.objp = (intptr_t) sp;
1051
1052#if ARCH(Intel) && WSIZE(32)
1053      spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
1054#else
1055      spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket);
1056#endif
1057      collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
1058    }
1059  POP_REENTRANCE (guard);
1060  return ret;
1061}
1062