1061 lines
35 KiB
C
1061 lines
35 KiB
C
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
/*
|
|
* Synchronization events
|
|
*/
|
|
#include "config.h"
|
|
#include <alloca.h>
|
|
#include <dlfcn.h>
|
|
#include <unistd.h>
|
|
#include <semaphore.h> /* sem_wait() */
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/param.h>
|
|
#include <pthread.h>
|
|
|
|
#include "gp-defs.h"
|
|
#include "collector_module.h"
|
|
#include "gp-experiment.h"
|
|
#include "data_pckts.h"
|
|
#include "i18n.h"
|
|
#include "tsd.h"
|
|
#include "cc_libcollector.h"
|
|
|
|
/* TprintfT(<level>,...) definitions. Adjust per module as needed */
|
|
#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
|
|
#define DBG_LTT 0 // for interposition on GLIBC functions
|
|
#define DBG_LT1 1 // for configuration details, warnings
|
|
#define DBG_LT2 2
|
|
#define DBG_LT3 3
|
|
|
|
/* define the packet that will be written out */
|
|
typedef struct Sync_packet
|
|
{ /* Synchronization delay tracing packet */
|
|
Common_packet comm;
|
|
hrtime_t requested; /* time of synchronization request */
|
|
Vaddr_type objp; /* vaddr of synchronization object */
|
|
} Sync_packet;
|
|
|
|
static int open_experiment (const char *);
|
|
static int start_data_collection (void);
|
|
static int stop_data_collection (void);
|
|
static int close_experiment (void);
|
|
static int detach_experiment (void);
|
|
static int init_thread_intf ();
|
|
static int sync_calibrate ();
|
|
|
|
static ModuleInterface module_interface ={
|
|
SP_SYNCTRACE_FILE, /* description */
|
|
NULL, /* initInterface */
|
|
open_experiment, /* openExperiment */
|
|
start_data_collection, /* startDataCollection */
|
|
stop_data_collection, /* stopDataCollection */
|
|
close_experiment, /* closeExperiment */
|
|
detach_experiment /* detachExperiment (fork child) */
|
|
};
|
|
|
|
static CollectorInterface *collector_interface = NULL;
|
|
static int sync_mode = 0;
|
|
static long sync_scope = 0;
|
|
static int sync_native = 0;
|
|
static int sync_java = 0;
|
|
static CollectorModule sync_hndl = COLLECTOR_MODULE_ERR;
|
|
static unsigned sync_key = COLLECTOR_TSD_INVALID_KEY;
|
|
static long sync_threshold = -1; /* calibrate the value */
|
|
static int init_thread_intf_started = 0;
|
|
static int init_thread_intf_finished = 0;
|
|
|
|
#define CHCK_NREENTRANCE(x) (!sync_native || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) != 0))
|
|
#define RECHCK_NREENTRANCE(x) (!sync_native || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) == 0))
|
|
#define CHCK_JREENTRANCE(x) (!sync_java || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) != 0))
|
|
#define RECHCK_JREENTRANCE(x) (!sync_java || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) == 0))
|
|
#define PUSH_REENTRANCE(x) ((*(x))++)
|
|
#define POP_REENTRANCE(x) ((*(x))--)
|
|
|
|
#define CALL_REAL(x) (*(int(*)())__real_##x)
|
|
#define NULL_PTR(x) ( __real_##x == NULL )
|
|
#define gethrtime collector_interface->getHiResTime
|
|
|
|
#ifdef DEBUG
|
|
#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
|
|
#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
|
|
#else
|
|
#define Tprintf(...)
|
|
#define TprintfT(...)
|
|
#endif
|
|
|
|
/*
|
|
* In most cases, the functions which require interposition are implemented as
|
|
* weak symbols corresponding to an associated internal function named with a
|
|
* leading underscore: e.g., mutex_lock() is simply an alias for _mutex_lock().
|
|
* For the wait functions, however, the published version (used by applications)
|
|
* is distinct from the internal version (used by system libraries), i.e.,
|
|
* cond_wait() is an alias for _cond_wait_cancel() rather than _cond_wait().
|
|
*/
|
|
static void *__real_strtol = NULL;
|
|
static void *__real_fprintf = NULL;
|
|
static void *__real___collector_jprofile_enable_synctrace = NULL;
|
|
static void *__real_pthread_mutex_lock = NULL;
|
|
static void *__real_pthread_mutex_unlock = NULL; /* not interposed, used in calibrate */
|
|
static void *__real_pthread_cond_wait = NULL;
|
|
static void *__real_pthread_cond_timedwait = NULL;
|
|
static void *__real_pthread_join = NULL;
|
|
static void *__real_sem_wait = NULL;
|
|
static void *__real_pthread_cond_wait_2_3_2 = NULL;
|
|
static void *__real_pthread_cond_timedwait_2_3_2 = NULL;
|
|
|
|
#if WSIZE(32)
|
|
static void *__real_sem_wait_2_1 = NULL;
|
|
static void *__real_sem_wait_2_0 = NULL;
|
|
static void *__real_pthread_cond_wait_2_0 = NULL;
|
|
static void *__real_pthread_cond_timedwait_2_0 = NULL;
|
|
#elif WSIZE(64)
|
|
#if ARCH(Intel)
|
|
static void *__real_pthread_cond_wait_2_2_5 = NULL;
|
|
static void *__real_pthread_cond_timedwait_2_2_5 = NULL;
|
|
#elif ARCH(SPARC)
|
|
static void *__real_pthread_cond_wait_2_2 = NULL;
|
|
static void *__real_pthread_cond_timedwait_2_2 = NULL;
|
|
#endif /* ARCH() */
|
|
#endif /* WSIZE() */
|
|
|
|
static void
|
|
collector_memset (void *s, int c, size_t n)
|
|
{
|
|
unsigned char *s1 = s;
|
|
while (n--)
|
|
*s1++ = (unsigned char) c;
|
|
}
|
|
|
|
void
|
|
__collector_module_init (CollectorInterface *_collector_interface)
|
|
{
|
|
if (_collector_interface == NULL)
|
|
return;
|
|
collector_interface = _collector_interface;
|
|
TprintfT (0, "synctrace: __collector_module_init\n");
|
|
sync_hndl = collector_interface->registerModule (&module_interface);
|
|
|
|
/* Initialize next module */
|
|
ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init");
|
|
if (next_init != NULL)
|
|
next_init (_collector_interface);
|
|
}
|
|
|
|
static int
|
|
open_experiment (const char *exp)
|
|
{
|
|
long thresh = 0;
|
|
if (init_thread_intf_finished == 0)
|
|
init_thread_intf ();
|
|
if (collector_interface == NULL)
|
|
{
|
|
Tprintf (0, "synctrace: collector_interface is null.\n");
|
|
return COL_ERROR_SYNCINIT;
|
|
}
|
|
if (sync_hndl == COLLECTOR_MODULE_ERR)
|
|
{
|
|
Tprintf (0, "synctrace: handle create failed.\n");
|
|
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
|
|
SP_JCMD_CERROR, COL_ERROR_SYNCINIT);
|
|
return COL_ERROR_SYNCINIT;
|
|
}
|
|
TprintfT (0, "synctrace: open_experiment %s\n", exp);
|
|
|
|
char *params = (char *) collector_interface->getParams ();
|
|
while (params)
|
|
{
|
|
if ((params[0] == 's') && (params[1] == ':'))
|
|
{
|
|
char *ptr = params + 2;
|
|
Tprintf (DBG_LT1, "synctrace: open_experiment s: parameter = %s\n", ptr);
|
|
while (*ptr != ',' && *ptr != ';')
|
|
ptr++;
|
|
sync_scope = 0;
|
|
if (*ptr == ',')
|
|
{
|
|
sync_scope = CALL_REAL (strtol) (ptr + 1, NULL, 0);
|
|
switch (sync_scope)
|
|
{
|
|
case 1:
|
|
sync_java = 0;
|
|
sync_native = 1;
|
|
break;
|
|
case 2:
|
|
sync_java = 1;
|
|
sync_native = 0;
|
|
break;
|
|
default:
|
|
case 3:
|
|
sync_native = 1;
|
|
sync_java = 1;
|
|
break;
|
|
}
|
|
Tprintf (0, "\tsynctrace: sync_scope found as %ld\n", sync_scope);
|
|
}
|
|
else
|
|
{
|
|
/* the old-style descriptor, without scope */
|
|
/* if there was no comma, use the old default */
|
|
sync_scope = 3;
|
|
sync_java = 1;
|
|
sync_native = 1;
|
|
Tprintf (0, "\tsynctrace: sync_scope not found set to %ld\n", sync_scope);
|
|
}
|
|
if (__real___collector_jprofile_enable_synctrace == NULL)
|
|
sync_java = 0;
|
|
thresh = CALL_REAL (strtol)(params + 2, NULL, 0);
|
|
break; /* from the loop to find the "s:thresh,scope" entry */
|
|
}
|
|
else
|
|
params++;
|
|
}
|
|
if (params == NULL) /* Sync data collection not specified */
|
|
return COL_ERROR_SYNCINIT;
|
|
if (thresh < 0) /* calibrate the threshold, keep it as a negative number */
|
|
thresh = -sync_calibrate ();
|
|
|
|
sync_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
|
|
if (sync_key == (unsigned) - 1)
|
|
{
|
|
Tprintf (0, "synctrace: TSD key create failed.\n");
|
|
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
|
|
SP_JCMD_CERROR, COL_ERROR_SYNCINIT);
|
|
return COL_ERROR_SYNCINIT;
|
|
}
|
|
/* if Java synctrace was requested, tell the jprofile module */
|
|
if (sync_java)
|
|
{
|
|
TprintfT (0, "synctrace: enabling Java synctrace\n");
|
|
CALL_REAL (__collector_jprofile_enable_synctrace)();
|
|
}
|
|
collector_interface->writeLog ("<profile name=\"%s\" threshold=\"%ld\" scope=\"%ld\">\n",
|
|
SP_JCMD_SYNCTRACE, thresh, sync_scope);
|
|
collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
|
|
module_interface.description);
|
|
/* Record Sync_packet description */
|
|
Sync_packet *pp = NULL;
|
|
collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"Synchronization tracing data\">\n", SYNC_PCKT);
|
|
collector_interface->writeLog (" <field name=\"LWPID\" uname=\"Lightweight process id\" offset=\"%d\" type=\"%s\"/>\n",
|
|
&pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64");
|
|
collector_interface->writeLog (" <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n",
|
|
&pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64");
|
|
collector_interface->writeLog (" <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n",
|
|
&pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64");
|
|
collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n",
|
|
&pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64");
|
|
collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
|
|
&pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64");
|
|
collector_interface->writeLog (" <field name=\"SRQST\" uname=\"Synchronization start time\" offset=\"%d\" type=\"%s\"/>\n",
|
|
&pp->requested, sizeof (pp->requested) == 4 ? "INT32" : "INT64");
|
|
collector_interface->writeLog (" <field name=\"SOBJ\" uname=\"Synchronization object address\" offset=\"%d\" type=\"%s\"/>\n",
|
|
&pp->objp, sizeof (pp->objp) == 4 ? "INT32" : "INT64");
|
|
collector_interface->writeLog (" </profpckt>\n");
|
|
collector_interface->writeLog ("</profile>\n");
|
|
|
|
/* Convert threshold from microsec to nanosec */
|
|
sync_threshold = (thresh > 0 ? thresh : -thresh) * 1000;
|
|
TprintfT (0, "synctrace: open_experiment complete %ld\n", sync_threshold);
|
|
return COL_ERROR_NONE;
|
|
}
|
|
|
|
static int
|
|
start_data_collection (void)
|
|
{
|
|
sync_mode = 1;
|
|
TprintfT (0, "synctrace: start_data_collection\n");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
stop_data_collection (void)
|
|
{
|
|
sync_mode = 0;
|
|
TprintfT (0, "synctrace: stop_data_collection\n");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
close_experiment (void)
|
|
{
|
|
sync_mode = 0;
|
|
sync_threshold = -1;
|
|
sync_key = COLLECTOR_TSD_INVALID_KEY;
|
|
TprintfT (0, "synctrace: close_experiment\n");
|
|
return 0;
|
|
}
|
|
|
|
/* fork child. Clean up state but don't write to experiment */
|
|
static int
|
|
detach_experiment (void)
|
|
{
|
|
sync_mode = 0;
|
|
sync_threshold = -1;
|
|
sync_key = COLLECTOR_TSD_INVALID_KEY;
|
|
TprintfT (0, "synctrace: detach_experiment\n");
|
|
return 0;
|
|
}
|
|
|
|
#define NUM_ITER 100 /* number of iterations in calibration */
|
|
#define NUM_WARMUP 3 /* number of warm up iterations */
|
|
|
|
static int
|
|
sync_calibrate ()
|
|
{
|
|
pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
|
|
hrtime_t bt, at, delta;
|
|
hrtime_t avg, max, min;
|
|
int i;
|
|
int ret;
|
|
avg = (hrtime_t) 0;
|
|
min = max = (hrtime_t) 0;
|
|
for (i = 0; i < NUM_ITER + NUM_WARMUP; i++)
|
|
{
|
|
/* Here we simulate a real call */
|
|
bt = gethrtime ();
|
|
ret = CALL_REAL (pthread_mutex_lock)(&mt);
|
|
at = gethrtime ();
|
|
CALL_REAL (pthread_mutex_unlock)(&mt);
|
|
if (i < NUM_WARMUP) /* skip these iterations */
|
|
continue;
|
|
/* add the time of this one */
|
|
delta = at - bt;
|
|
avg += delta;
|
|
if (min == 0)
|
|
min = delta;
|
|
if (delta < min)
|
|
min = delta;
|
|
if (delta > max)
|
|
max = delta;
|
|
}
|
|
/* compute average time */
|
|
avg = avg / NUM_ITER;
|
|
|
|
/* pretty simple, let's see how it works */
|
|
if (max < 6 * avg)
|
|
max = 6 * avg;
|
|
/* round up to the nearest microsecond */
|
|
ret = (int) ((max + 999) / 1000);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
init_thread_intf ()
|
|
{
|
|
void *dlflag = RTLD_NEXT;
|
|
int err = 0;
|
|
/* if we detect recursion/reentrance, SEGV so we can get a stack */
|
|
init_thread_intf_started++;
|
|
if (!init_thread_intf_finished && init_thread_intf_started >= 3)
|
|
{
|
|
/* pull the plug if recursion occurs... */
|
|
abort ();
|
|
}
|
|
/* lookup fprint to print fatal error message */
|
|
void *ptr = dlsym (RTLD_DEFAULT, "fprintf");
|
|
if (ptr)
|
|
{
|
|
__real_fprintf = (void *) ptr;
|
|
}
|
|
else
|
|
{
|
|
abort ();
|
|
}
|
|
|
|
/* find the __collector_jprofile_enable_synctrace routine in jprofile module */
|
|
ptr = dlsym (RTLD_DEFAULT, "__collector_jprofile_enable_synctrace");
|
|
if (ptr)
|
|
__real___collector_jprofile_enable_synctrace = (void *) ptr;
|
|
else
|
|
{
|
|
#if defined(GPROFNG_JAVA_PROFILING)
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT __collector_jprofile_enable_synctrace\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
#endif
|
|
sync_java = 0;
|
|
}
|
|
|
|
#if WSIZE(32)
|
|
/* ########################################## begin WSIZE(32) */
|
|
/* IMPORTANT!! The GLIBC_* versions below must match those in the er_sync.*.mapfile ! */
|
|
dlflag = RTLD_NEXT;
|
|
ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.0");
|
|
if (ptr == NULL)
|
|
{
|
|
/* We are probably dlopened after libthread/libc,
|
|
* try to search in the previously loaded objects
|
|
*/
|
|
dlflag = RTLD_DEFAULT;
|
|
ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.0");
|
|
if (ptr != NULL)
|
|
{
|
|
__real_pthread_mutex_lock = ptr;
|
|
Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for OS sync routines\n");
|
|
}
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_lock\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
}
|
|
else
|
|
__real_pthread_mutex_lock = ptr;
|
|
|
|
ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.0");
|
|
if (ptr)
|
|
__real_pthread_mutex_unlock = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2");
|
|
if (ptr)
|
|
__real_pthread_cond_wait = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2");
|
|
if (ptr)
|
|
__real_pthread_cond_timedwait = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.0");
|
|
if (ptr)
|
|
__real_pthread_join = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.1");
|
|
if (ptr)
|
|
__real_sem_wait = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
|
|
#if ARCH(Intel)
|
|
/* ############## Intel specific additional pointers for 32-bits */
|
|
ptr = __real_sem_wait_2_1 = __real_sem_wait;
|
|
ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.0");
|
|
if (ptr)
|
|
__real_sem_wait_2_0 = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait_2_0\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.0");
|
|
if (ptr)
|
|
__real_pthread_cond_wait_2_0 = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_0\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.0");
|
|
if (ptr)
|
|
__real_pthread_cond_timedwait_2_0 = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT __real_pthread_cond_timedwait_2_0\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
#endif /* ARCH(Intel) */
|
|
|
|
#else /* WSIZE(64) */
|
|
/* # most versions are different between platforms */
|
|
/* # the few that are common are set after the ARCH ifdef */
|
|
#if ARCH(Aarch64)
|
|
dlflag = RTLD_NEXT;
|
|
#define GLIBC_N "GLIBC_2.17"
|
|
__real_pthread_mutex_lock = dlvsym(dlflag, "pthread_mutex_lock", GLIBC_N);
|
|
__real_pthread_mutex_unlock = dlvsym(dlflag, "pthread_mutex_unlock", GLIBC_N);
|
|
__real_pthread_cond_wait = dlvsym(dlflag, "pthread_cond_wait", GLIBC_N);
|
|
__real_pthread_cond_timedwait = dlvsym(dlflag, "pthread_cond_timedwait", GLIBC_N);
|
|
__real_pthread_join = dlvsym(dlflag, "pthread_join", GLIBC_N);
|
|
__real_sem_wait = dlvsym(dlflag, "sem_wait", GLIBC_N);
|
|
|
|
#elif ARCH(Intel)
|
|
dlflag = RTLD_NEXT;
|
|
ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2.5");
|
|
if (ptr == NULL)
|
|
{
|
|
/* We are probably dlopened after libthread/libc,
|
|
* try to search in the previously loaded objects
|
|
*/
|
|
dlflag = RTLD_DEFAULT;
|
|
ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2.5");
|
|
if (ptr != NULL)
|
|
{
|
|
__real_pthread_mutex_lock = ptr;
|
|
Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for Solaris sync routines\n");
|
|
}
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_lock\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
}
|
|
else
|
|
__real_pthread_mutex_lock = ptr;
|
|
ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.2.5");
|
|
if (ptr)
|
|
__real_pthread_mutex_unlock = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2");
|
|
if (ptr)
|
|
__real_pthread_cond_wait = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2");
|
|
if (ptr)
|
|
__real_pthread_cond_timedwait = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.2.5");
|
|
if (ptr)
|
|
__real_pthread_join = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.2.5");
|
|
if (ptr)
|
|
__real_sem_wait = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.2.5");
|
|
if (ptr)
|
|
__real_pthread_cond_wait_2_2_5 = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_2_5\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.2.5");
|
|
if (ptr)
|
|
__real_pthread_cond_timedwait_2_2_5 = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait_2_2_5\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
|
|
#elif ARCH(SPARC)
|
|
dlflag = RTLD_NEXT;
|
|
ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2");
|
|
if (ptr == NULL)
|
|
{
|
|
/* We are probably dlopened after libthread/libc,
|
|
* try to search in the previously loaded objects
|
|
*/
|
|
dlflag = RTLD_DEFAULT;
|
|
ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2");
|
|
if (ptr != NULL)
|
|
{
|
|
__real_pthread_mutex_lock = ptr;
|
|
Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for Solaris sync routines\n");
|
|
}
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT mutex_lock\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
}
|
|
else
|
|
__real_pthread_mutex_lock = ptr;
|
|
ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.2");
|
|
if (ptr)
|
|
__real_pthread_mutex_unlock = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2");
|
|
if (ptr)
|
|
__real_pthread_cond_wait = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2");
|
|
if (ptr)
|
|
__real_pthread_cond_timedwait = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.2");
|
|
if (ptr)
|
|
__real_pthread_join = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.2");
|
|
if (ptr)
|
|
__real_sem_wait = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.2");
|
|
if (ptr)
|
|
__real_pthread_cond_wait_2_2 = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_2_5\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.2");
|
|
if (ptr)
|
|
__real_pthread_cond_timedwait_2_2 = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait_2_2\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
#endif /* ARCH() */
|
|
#endif /* WSIZE(64) */
|
|
/* the pointers that are common to 32- and 64-bits, and to SPARC and Intel */
|
|
|
|
__real_pthread_cond_wait_2_3_2 = __real_pthread_cond_wait;
|
|
__real_pthread_cond_timedwait_2_3_2 = __real_pthread_cond_timedwait;
|
|
ptr = dlsym (dlflag, "strtol");
|
|
if (ptr)
|
|
__real_strtol = (void *) ptr;
|
|
else
|
|
{
|
|
CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT strtol\n");
|
|
err = COL_ERROR_SYNCINIT;
|
|
}
|
|
init_thread_intf_finished++;
|
|
TprintfT (0, "synctrace init_thread_intf complete\n");
|
|
return err;
|
|
}
|
|
|
|
/* These next two routines are used from jprofile to record Java synctrace data */
|
|
void
|
|
__collector_jsync_begin ()
|
|
{
|
|
int *guard;
|
|
if (CHCK_JREENTRANCE (guard))
|
|
{
|
|
Tprintf (DBG_LT1, "__collector_jsync_begin: skipped\n");
|
|
return;
|
|
}
|
|
Tprintf (DBG_LT1, "__collector_jsync_begin: start event\n");
|
|
PUSH_REENTRANCE (guard);
|
|
}
|
|
|
|
void
|
|
__collector_jsync_end (hrtime_t reqt, void *object)
|
|
{
|
|
int *guard;
|
|
if (RECHCK_JREENTRANCE (guard))
|
|
{
|
|
Tprintf (DBG_LT1, "__collector_jsync_end: skipped\n");
|
|
return;
|
|
}
|
|
hrtime_t grnt = gethrtime ();
|
|
if (grnt - reqt >= sync_threshold)
|
|
{
|
|
Sync_packet spacket;
|
|
collector_memset (&spacket, 0, sizeof ( Sync_packet));
|
|
spacket.comm.tsize = sizeof ( Sync_packet);
|
|
spacket.comm.tstamp = grnt;
|
|
spacket.requested = reqt;
|
|
spacket.objp = (Vaddr_type) object;
|
|
spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
|
|
collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
|
|
}
|
|
Tprintf (DBG_LT1, "__collector_jsync_begin: end event\n");
|
|
POP_REENTRANCE (guard);
|
|
}
|
|
|
|
/*-------------------------------------------------------- pthread_mutex_lock */
|
|
int
|
|
pthread_mutex_lock (pthread_mutex_t *mp)
|
|
{
|
|
int *guard;
|
|
if (NULL_PTR (pthread_mutex_lock))
|
|
init_thread_intf ();
|
|
if (CHCK_NREENTRANCE (guard))
|
|
return CALL_REAL (pthread_mutex_lock)(mp);
|
|
PUSH_REENTRANCE (guard);
|
|
hrtime_t reqt = gethrtime ();
|
|
int ret = CALL_REAL (pthread_mutex_lock)(mp);
|
|
if (RECHCK_NREENTRANCE (guard))
|
|
{
|
|
POP_REENTRANCE (guard);
|
|
return ret;
|
|
}
|
|
hrtime_t grnt = gethrtime ();
|
|
if (grnt - reqt >= sync_threshold)
|
|
{
|
|
Sync_packet spacket;
|
|
collector_memset (&spacket, 0, sizeof ( Sync_packet));
|
|
spacket.comm.tsize = sizeof ( Sync_packet);
|
|
spacket.comm.tstamp = grnt;
|
|
spacket.requested = reqt;
|
|
spacket.objp = (Vaddr_type) mp;
|
|
spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket);
|
|
collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
|
|
}
|
|
POP_REENTRANCE (guard);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------- pthread_cond_wait */
|
|
// map interposed symbol versions
|
|
static int
|
|
__collector_pthread_cond_wait_symver (int(real_pthread_cond_wait) (), pthread_cond_t *cond, pthread_mutex_t *mutex);
|
|
|
|
#if ARCH(Intel) || ARCH(SPARC)
|
|
SYMVER_ATTRIBUTE (__collector_pthread_cond_wait_2_3_2,
|
|
pthread_cond_wait@@GLIBC_2.3.2)
|
|
#endif
|
|
int
|
|
__collector_pthread_cond_wait_2_3_2 (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
|
{
|
|
if (NULL_PTR (pthread_cond_wait))
|
|
init_thread_intf ();
|
|
TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_3_2@%p\n", CALL_REAL (pthread_cond_wait_2_3_2));
|
|
return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_3_2), cond, mutex);
|
|
}
|
|
|
|
#if WSIZE(32)
|
|
|
|
SYMVER_ATTRIBUTE (__collector_pthread_cond_wait_2_0,
|
|
pthread_cond_wait@GLIBC_2.0)
|
|
int
|
|
__collector_pthread_cond_wait_2_0 (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
|
{
|
|
if (NULL_PTR (pthread_cond_wait))
|
|
init_thread_intf ();
|
|
TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_0@%p\n", CALL_REAL (pthread_cond_wait_2_0));
|
|
return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_0), cond, mutex);
|
|
}
|
|
#else // WSIZE(64)
|
|
#if ARCH(Intel)
|
|
SYMVER_ATTRIBUTE (__collector_pthread_cond_wait_2_2_5,
|
|
pthread_cond_wait@GLIBC_2.2.5)
|
|
int
|
|
__collector_pthread_cond_wait_2_2_5 (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
|
{
|
|
if (NULL_PTR (pthread_cond_wait))
|
|
init_thread_intf ();
|
|
TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_2_5@%p\n", CALL_REAL (pthread_cond_wait_2_2_5));
|
|
return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_2_5), cond, mutex);
|
|
}
|
|
#elif ARCH(SPARC)
|
|
|
|
SYMVER_ATTRIBUTE (__collector_pthread_cond_wait_2_2,
|
|
pthread_cond_wait@GLIBC_2.2)
|
|
int
|
|
__collector_pthread_cond_wait_2_2 (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
|
{
|
|
if (NULL_PTR (pthread_cond_wait))
|
|
init_thread_intf ();
|
|
TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_2@%p\n", CALL_REAL (pthread_cond_wait_2_2));
|
|
return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_2), cond, mutex);
|
|
}
|
|
#endif // ARCH()
|
|
#endif // WSIZE()
|
|
|
|
static int
|
|
__collector_pthread_cond_wait_symver (int(real_pthread_cond_wait) (), pthread_cond_t *cond, pthread_mutex_t *mutex)
|
|
{
|
|
int *guard;
|
|
if (NULL_PTR (pthread_cond_wait))
|
|
init_thread_intf ();
|
|
if (CHCK_NREENTRANCE (guard))
|
|
return (real_pthread_cond_wait) (cond, mutex);
|
|
PUSH_REENTRANCE (guard);
|
|
hrtime_t reqt = gethrtime ();
|
|
int ret = -1;
|
|
ret = (real_pthread_cond_wait) (cond, mutex);
|
|
if (RECHCK_NREENTRANCE (guard))
|
|
{
|
|
POP_REENTRANCE (guard);
|
|
return ret;
|
|
}
|
|
hrtime_t grnt = gethrtime ();
|
|
if (grnt - reqt >= sync_threshold)
|
|
{
|
|
Sync_packet spacket;
|
|
collector_memset (&spacket, 0, sizeof ( Sync_packet));
|
|
spacket.comm.tsize = sizeof ( Sync_packet);
|
|
spacket.comm.tstamp = grnt;
|
|
spacket.requested = reqt;
|
|
spacket.objp = (Vaddr_type) mutex;
|
|
spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
|
|
collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
|
|
}
|
|
POP_REENTRANCE (guard);
|
|
return ret;
|
|
}
|
|
|
|
/*---------------------------------------------------- pthread_cond_timedwait */
|
|
// map interposed symbol versions
|
|
static int
|
|
__collector_pthread_cond_timedwait_symver (int(real_pthread_cond_timedwait) (),
|
|
pthread_cond_t *cond,
|
|
pthread_mutex_t *mutex,
|
|
const struct timespec *abstime);
|
|
|
|
#if ARCH(Intel) || ARCH(SPARC)
|
|
SYMVER_ATTRIBUTE (__collector_pthread_cond_timedwait_2_3_2,
|
|
pthread_cond_timedwait@@GLIBC_2.3.2)
|
|
#endif // ARCH()
|
|
int
|
|
__collector_pthread_cond_timedwait_2_3_2 (pthread_cond_t *cond,
|
|
pthread_mutex_t *mutex,
|
|
const struct timespec *abstime)
|
|
{
|
|
if (NULL_PTR (pthread_cond_timedwait))
|
|
init_thread_intf ();
|
|
TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_3_2@%p\n", CALL_REAL (pthread_cond_timedwait_2_3_2));
|
|
return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_3_2), cond, mutex, abstime);
|
|
}
|
|
|
|
#if WSIZE(32)
|
|
SYMVER_ATTRIBUTE (__collector_pthread_cond_timedwait_2_0,
|
|
pthread_cond_timedwait@GLIBC_2.0)
|
|
int
|
|
__collector_pthread_cond_timedwait_2_0 (pthread_cond_t *cond,
|
|
pthread_mutex_t *mutex,
|
|
const struct timespec *abstime)
|
|
{
|
|
if (NULL_PTR (pthread_cond_timedwait))
|
|
init_thread_intf ();
|
|
TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_0@%p\n", CALL_REAL (pthread_cond_timedwait_2_0));
|
|
return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_0), cond, mutex, abstime);
|
|
}
|
|
#else // WSIZE(64)
|
|
#if ARCH(Intel)
|
|
SYMVER_ATTRIBUTE (__collector_pthread_cond_timedwait_2_2_5,
|
|
pthread_cond_timedwait@GLIBC_2.2.5)
|
|
int
|
|
__collector_pthread_cond_timedwait_2_2_5 (pthread_cond_t *cond,
|
|
pthread_mutex_t *mutex,
|
|
const struct timespec *abstime)
|
|
{
|
|
if (NULL_PTR (pthread_cond_timedwait))
|
|
init_thread_intf ();
|
|
TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_2_5@%p\n", CALL_REAL (pthread_cond_timedwait_2_2_5));
|
|
return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_2_5), cond, mutex, abstime);
|
|
}
|
|
#elif ARCH(SPARC)
|
|
|
|
SYMVER_ATTRIBUTE (__collector_pthread_cond_timedwait_2_2,
|
|
pthread_cond_timedwait@GLIBC_2.2)
|
|
int
|
|
__collector_pthread_cond_timedwait_2_2 (pthread_cond_t *cond,
|
|
pthread_mutex_t *mutex,
|
|
const struct timespec *abstime)
|
|
{
|
|
if (NULL_PTR (pthread_cond_timedwait))
|
|
init_thread_intf ();
|
|
TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_2@%p\n", CALL_REAL (pthread_cond_timedwait_2_2));
|
|
return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_2), cond, mutex, abstime);
|
|
}
|
|
#endif // ARCH()
|
|
#endif // WSIZE()
|
|
|
|
static int
|
|
__collector_pthread_cond_timedwait_symver (int(real_pthread_cond_timedwait) (),
|
|
pthread_cond_t *cond,
|
|
pthread_mutex_t *mutex,
|
|
const struct timespec *abstime)
|
|
{
|
|
int *guard;
|
|
if (NULL_PTR (pthread_cond_timedwait))
|
|
init_thread_intf ();
|
|
if (CHCK_NREENTRANCE (guard))
|
|
return (real_pthread_cond_timedwait) (cond, mutex, abstime);
|
|
PUSH_REENTRANCE (guard);
|
|
hrtime_t reqt = gethrtime ();
|
|
int ret = -1;
|
|
ret = (real_pthread_cond_timedwait) (cond, mutex, abstime);
|
|
if (RECHCK_NREENTRANCE (guard))
|
|
{
|
|
POP_REENTRANCE (guard);
|
|
return ret;
|
|
}
|
|
hrtime_t grnt = gethrtime ();
|
|
if (grnt - reqt >= sync_threshold)
|
|
{
|
|
Sync_packet spacket;
|
|
collector_memset (&spacket, 0, sizeof ( Sync_packet));
|
|
spacket.comm.tsize = sizeof ( Sync_packet);
|
|
spacket.comm.tstamp = grnt;
|
|
spacket.requested = reqt;
|
|
spacket.objp = (Vaddr_type) mutex;
|
|
spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
|
|
collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
|
|
}
|
|
POP_REENTRANCE (guard);
|
|
return ret;
|
|
}
|
|
|
|
/*------------------------------------------------------------- pthread_join */
|
|
int
|
|
pthread_join (pthread_t target_thread, void **status)
|
|
{
|
|
int *guard;
|
|
if (NULL_PTR (pthread_join))
|
|
init_thread_intf ();
|
|
if (CHCK_NREENTRANCE (guard))
|
|
return CALL_REAL (pthread_join)(target_thread, status);
|
|
PUSH_REENTRANCE (guard);
|
|
hrtime_t reqt = gethrtime ();
|
|
int ret = CALL_REAL (pthread_join)(target_thread, status);
|
|
if (RECHCK_NREENTRANCE (guard))
|
|
{
|
|
POP_REENTRANCE (guard);
|
|
return ret;
|
|
}
|
|
hrtime_t grnt = gethrtime ();
|
|
if (grnt - reqt >= sync_threshold)
|
|
{
|
|
Sync_packet spacket;
|
|
collector_memset (&spacket, 0, sizeof ( Sync_packet));
|
|
spacket.comm.tsize = sizeof ( Sync_packet);
|
|
spacket.comm.tstamp = grnt;
|
|
spacket.requested = reqt;
|
|
spacket.objp = (Vaddr_type) target_thread;
|
|
spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket);
|
|
collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
|
|
}
|
|
POP_REENTRANCE (guard);
|
|
return ret;
|
|
}
|
|
|
|
/*------------------------------------------------------------- sem_wait */
|
|
// map interposed symbol versions
|
|
#if ARCH(Intel) && WSIZE(32)
|
|
static int
|
|
__collector_sem_wait_symver (int(real_sem_wait) (), sem_t *sp);
|
|
|
|
SYMVER_ATTRIBUTE (__collector_sem_wait_2_1, sem_wait@@GLIBC_2.1)
|
|
int
|
|
__collector_sem_wait_2_1 (sem_t *sp)
|
|
{
|
|
if (NULL_PTR (sem_wait))
|
|
init_thread_intf ();
|
|
TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_sem_wait_2_1@%p\n", CALL_REAL (sem_wait_2_1));
|
|
return __collector_sem_wait_symver (CALL_REAL (sem_wait_2_1), sp);
|
|
}
|
|
|
|
SYMVER_ATTRIBUTE (__collector_sem_wait_2_0, sem_wait@GLIBC_2.0)
|
|
int
|
|
__collector_sem_wait_2_0 (sem_t *sp)
|
|
{
|
|
if (NULL_PTR (sem_wait))
|
|
init_thread_intf ();
|
|
TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_sem_wait_2_0@%p\n", CALL_REAL (sem_wait_2_0));
|
|
return __collector_sem_wait_symver (CALL_REAL (sem_wait_2_0), sp);
|
|
}
|
|
#endif
|
|
|
|
#if ARCH(Intel) && WSIZE(32)
|
|
static int
|
|
__collector_sem_wait_symver (int(real_sem_wait) (), sem_t *sp)
|
|
{
|
|
#else
|
|
int
|
|
sem_wait (sem_t *sp)
|
|
{
|
|
#endif
|
|
int *guard;
|
|
if (NULL_PTR (sem_wait))
|
|
init_thread_intf ();
|
|
if (CHCK_NREENTRANCE (guard))
|
|
{
|
|
#if ARCH(Intel) && WSIZE(32)
|
|
return (real_sem_wait) (sp);
|
|
#else
|
|
return CALL_REAL (sem_wait)(sp);
|
|
#endif
|
|
}
|
|
PUSH_REENTRANCE (guard);
|
|
hrtime_t reqt = gethrtime ();
|
|
int ret = -1;
|
|
#if ARCH(Intel) && WSIZE(32)
|
|
ret = (real_sem_wait) (sp);
|
|
#else
|
|
ret = CALL_REAL (sem_wait)(sp);
|
|
#endif
|
|
if (RECHCK_NREENTRANCE (guard))
|
|
{
|
|
POP_REENTRANCE (guard);
|
|
return ret;
|
|
}
|
|
hrtime_t grnt = gethrtime ();
|
|
if (grnt - reqt >= sync_threshold)
|
|
{
|
|
Sync_packet spacket;
|
|
collector_memset (&spacket, 0, sizeof ( Sync_packet));
|
|
spacket.comm.tsize = sizeof ( Sync_packet);
|
|
spacket.comm.tstamp = grnt;
|
|
spacket.requested = reqt;
|
|
spacket.objp = (Vaddr_type) sp;
|
|
|
|
#if ARCH(Intel) && WSIZE(32)
|
|
spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
|
|
#else
|
|
spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket);
|
|
#endif
|
|
collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
|
|
}
|
|
POP_REENTRANCE (guard);
|
|
return ret;
|
|
}
|