/* Copyright (C) 2021-2023 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 #include #include #include /* sem_wait() */ #include #include #include #include #include "gp-defs.h" #include "collector.h" #include "gp-experiment.h" #include "data_pckts.h" #include "tsd.h" #include "cc_libcollector.h" /* TprintfT(,...) 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 ("data handle not created\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 ("TSD key not created\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 ("\n", SP_JCMD_SYNCTRACE, thresh, sync_scope); collector_interface->writeLog (" \n", module_interface.description); /* Record Sync_packet description */ Sync_packet *pp = NULL; collector_interface->writeLog (" \n", SYNC_PCKT); collector_interface->writeLog (" \n", &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64"); collector_interface->writeLog (" \n", &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64"); collector_interface->writeLog (" \n", &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64"); collector_interface->writeLog (" \n", &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64"); collector_interface->writeLog (" \n", &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64"); collector_interface->writeLog (" \n", &pp->requested, sizeof (pp->requested) == 4 ? "INT32" : "INT64"); collector_interface->writeLog (" \n", &pp->objp, sizeof (pp->objp) == 4 ? "INT32" : "INT64"); collector_interface->writeLog (" \n"); collector_interface->writeLog ("\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 = (intptr_t) 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 = (intptr_t) 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 = (intptr_t) 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 = (intptr_t) 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 = (intptr_t) 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; }