blob: 85a0a6eb6af5691dba838650c9caa0371be5c2f4 [file] [log] [blame]
/*
Copyright 2005-2010 Intel Corporation. All Rights Reserved.
This file is part of Threading Building Blocks.
Threading Building Blocks is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
Threading Building Blocks 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 Threading Building Blocks; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
As a special exception, you may use this file as part of a free software
library without restriction. Specifically, if other files instantiate
templates or use macros or inline functions from this file, or you compile
this file and link it with other files to produce an executable, this
file does not by itself cause the resulting executable to be covered by
the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
#include "ittnotify_config.h"
#if ITT_PLATFORM==ITT_PLATFORM_WIN
#include <windows.h>
#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */
#include <pthread.h>
#include <dlfcn.h>
#include <errno.h>
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "disable_warnings.h"
#define INTEL_NO_MACRO_BODY
#include "ittnotify.h"
#include "legacy/ittnotify.h"
#include "internal/ittnotify.h"
#include "prototype/ittnotify.h"
#include "ittnotify_types.h"
#ifndef INTEL_ITTNOTIFY_PREFIX
#define INTEL_ITTNOTIFY_PREFIX __itt_
#endif /* INTEL_ITTNOTIFY_PREFIX */
#ifndef INTEL_ITTNOTIFY_POSTFIX
#define INTEL_ITTNOTIFY_POSTFIX _ptr_
#endif /* INTEL_ITTNOTIFY_POSTFIX */
#define _N_(n) ITT_JOIN(INTEL_ITTNOTIFY_PREFIX,n)
#ifndef CDECL
#if ITT_PLATFORM==ITT_PLATFORM_WIN
#define CDECL __cdecl
#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
#define CDECL
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
#endif /* CDECL */
#ifndef STDCALL
#if ITT_PLATFORM==ITT_PLATFORM_WIN
#define STDCALL __stdcall
#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */
#define STDCALL
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
#endif /* STDCALL */
#if ITT_PLATFORM==ITT_PLATFORM_WIN
typedef FARPROC FPTR;
typedef DWORD TIDT;
#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */
typedef void* FPTR;
typedef pthread_t TIDT;
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
/* OS communication functions */
#if ITT_PLATFORM==ITT_PLATFORM_WIN
typedef HMODULE lib_t;
typedef CRITICAL_SECTION mutex_t;
#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */
typedef void* lib_t;
typedef pthread_mutex_t mutex_t;
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
static volatile long ittnotify_init = 0;
static lib_t ittnotify_lib = NULL;
static __itt_error_notification_t* error_handler = NULL;
#if ITT_OS==ITT_OS_WIN
static const char* ittnotify_lib_name = "libittnotify.dll";
#elif ITT_OS==ITT_OS_LINUX
static const char* ittnotify_lib_name = "libittnotify.so";
#elif ITT_OS==ITT_OS_MAC
static const char* ittnotify_lib_name = "libittnotify.dylib";
#else
#error Unsupported or unknown OS.
#endif
#ifndef LIB_VAR_NAME
#if ITT_ARCH==ITT_ARCH_IA32
#define LIB_VAR_NAME INTEL_LIBITTNOTIFY32
#else
#define LIB_VAR_NAME INTEL_LIBITTNOTIFY64
#endif
#endif /* LIB_VAR_NAME */
#if ITT_PLATFORM==ITT_PLATFORM_WIN
#define __itt_get_proc(lib, name) GetProcAddress(lib, name)
#define __itt_mutex_init(mutex) InitializeCriticalSection(mutex)
#define __itt_mutex_lock(mutex) EnterCriticalSection(mutex)
#define __itt_mutex_unlock(mutex) LeaveCriticalSection(mutex)
#define __itt_load_lib(name) LoadLibraryA(name)
#define __itt_unload_lib(handle) FreeLibrary(handle)
#define __itt_system_error() (int)GetLastError()
#define __itt_fstrcmp(s1, s2) lstrcmpA(s1, s2)
#define __itt_fstrlen(s) lstrlenA(s)
#define __itt_fstrcpyn(s1, s2, l) lstrcpynA(s1, s2, l)
#define __itt_thread_id() GetCurrentThreadId()
#define __itt_thread_yield() SwitchToThread()
#ifndef ITT_SIMPLE_INIT
static int __itt_interlocked_increment(volatile int* ptr)
{
ITT_BUILD_ASSERT(sizeof(int) == sizeof(long));
return InterlockedIncrement((volatile long *)ptr);
}
#endif /* ITT_SIMPLE_INIT */
#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */
#define __itt_get_proc(lib, name) dlsym(lib, name)
#define __itt_mutex_init(mutex) \
{ \
pthread_mutexattr_t mutex_attr; \
int error_code = pthread_mutexattr_init(&mutex_attr); \
if (error_code) \
__itt_report_error(__itt_error_system, "pthread_mutexattr_init", error_code); \
error_code = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE); \
if (error_code) \
__itt_report_error(__itt_error_system, "pthread_mutexattr_settype", error_code); \
error_code = pthread_mutex_init(mutex, &mutex_attr); \
if (error_code) \
__itt_report_error(__itt_error_system, "pthread_mutex_init", error_code); \
error_code = pthread_mutexattr_destroy(&mutex_attr); \
if (error_code) \
__itt_report_error(__itt_error_system, "pthread_mutexattr_destroy", error_code); \
}
#define __itt_mutex_lock(mutex) pthread_mutex_lock(mutex)
#define __itt_mutex_unlock(mutex) pthread_mutex_unlock(mutex)
#define __itt_load_lib(name) dlopen(name, RTLD_LAZY)
#define __itt_unload_lib(handle) dlclose(handle)
#define __itt_system_error() errno
#define __itt_fstrcmp(s1, s2) strcmp(s1, s2)
#define __itt_fstrlen(s) strlen(s)
#define __itt_fstrcpyn(s1, s2, l) strncpy(s1, s2, l)
#define __itt_thread_id() pthread_self()
#define __itt_thread_yield() sched_yield()
#if ITT_ARCH==ITT_ARCH_IA64
#ifdef __INTEL_COMPILER
#define __TBB_machine_fetchadd4(addr, val) __fetchadd4_acq((void *)addr, val)
#else /* __INTEL_COMPILER */
// TODO: Add Support for not Intel compilers for IA64
#endif /* __INTEL_COMPILER */
#else /* ITT_ARCH!=ITT_ARCH_IA64 */
#ifndef ITT_SIMPLE_INIT
static int __TBB_machine_fetchadd4(volatile void* ptr, int addend)
{
int result;
__asm__ __volatile__("lock\nxaddl %0,%1"
: "=r"(result),"=m"(*(int *)ptr)
: "0"(addend), "m"(*(int *)ptr)
: "memory");
return result;
}
#endif // ITT_SIMPLE_INIT
#endif /* ITT_ARCH==ITT_ARCH_IA64 */
#ifndef ITT_SIMPLE_INIT
static int __itt_interlocked_increment(volatile int* ptr)
{
return __TBB_machine_fetchadd4(ptr, 1) + 1;
}
#endif /* ITT_SIMPLE_INIT */
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
const int _N_(err) = 0;
typedef int (__itt_init_ittlib_t)(const char*, __itt_group_id);
/* this define used to control initialization function name. */
#ifndef __itt_init_ittlib_name
static int _N_(init_ittlib)(const char*, __itt_group_id);
static __itt_init_ittlib_t* __itt_init_ittlib_ptr = _N_(init_ittlib);
#define __itt_init_ittlib_name __itt_init_ittlib_ptr
#endif /* __itt_init_ittlib_name */
/* building pointers to imported funcs */
#undef ITT_STUBV
#undef ITT_STUB
#define ITT_STUB(api,type,name,args,params,ptr,group,format) \
static type api ITT_JOIN(_N_(name),_init) args; \
typedef type api name##_t args; \
extern "C" name##_t* ITTNOTIFY_NAME(name); \
name##_t* ITTNOTIFY_NAME(name) = ITT_JOIN(_N_(name),_init); \
static type api ITT_JOIN(_N_(name),_init) args \
{ \
if (__itt_init_ittlib_name(NULL, __itt_group_none) \
&& ITTNOTIFY_NAME(name) \
&& ITTNOTIFY_NAME(name) != ITT_JOIN(_N_(name),_init)) \
return ITTNOTIFY_NAME(name) params; \
else \
return (type)0; \
}
#define ITT_STUBV(api,type,name,args,params,ptr,group,format) \
static type api ITT_JOIN(_N_(name),_init) args; \
typedef type api name##_t args; \
extern "C" name##_t* ITTNOTIFY_NAME(name); \
name##_t* ITTNOTIFY_NAME(name) = ITT_JOIN(_N_(name),_init); \
static type api ITT_JOIN(_N_(name),_init) args \
{ \
if (__itt_init_ittlib_name(NULL, __itt_group_none) \
&& ITTNOTIFY_NAME(name) \
&& ITTNOTIFY_NAME(name) != ITT_JOIN(_N_(name),_init)) \
ITTNOTIFY_NAME(name) params; \
else \
return; \
}
/* Define types and *_init functions. */
#include "ittnotify_static.h"
ITT_GROUP_LIST(group_list);
typedef struct __itt_group_alias_
{
const char* env_var;
__itt_group_id groups;
} __itt_group_alias;
static __itt_group_alias group_alias[] = {
{ "KMP_FOR_TPROFILE", (__itt_group_id)(__itt_group_control | __itt_group_thread | __itt_group_sync | __itt_group_mark) },
{ "KMP_FOR_TCHECK", (__itt_group_id)(__itt_group_control | __itt_group_thread | __itt_group_fsync | __itt_group_mark) },
{ NULL, (__itt_group_none) }
};
typedef struct __itt_func_map_
{
const char* name;
void** func_ptr;
__itt_group_id group;
} __itt_func_map;
#define __ptr_(pname,name,group) {ITT_TO_STR(ITT_JOIN(__itt_,pname)), (void**)(void*)&ITTNOTIFY_NAME(name), (__itt_group_id)(group)},
#undef ITT_STUB
#undef ITT_STUBV
#define ITT_STUB(api,type,name,args,params,nameindll,group,format) __ptr_(nameindll,name,group)
#define ITT_STUBV ITT_STUB
static __itt_func_map func_map[] = {
#include "ittnotify_static.h"
{NULL, NULL, __itt_group_none}
};
#ifndef ITT_SIMPLE_INIT
#undef ITT_STUBV
#undef ITT_STUB
#define ITT_STUBV(api,type,name,args,params,ptr,group,format) \
ITT_EXTERN_C type api _N_(name) args \
{ \
if (ITTNOTIFY_NAME(name)) \
ITTNOTIFY_NAME(name) params; \
else \
return; \
}
#define ITT_STUB(api,type,name,args,params,ptr,group,format) \
ITT_EXTERN_C type api _N_(name) args \
{ \
if (ITTNOTIFY_NAME(name)) \
return ITTNOTIFY_NAME(name) params; \
else \
return (type)0; \
}
/* Define ITT functions. */
#include "ittnotify_static.h"
#endif /* ITT_SIMPLE_INIT */
static const char* __itt_fsplit(const char* s, const char* sep, const char** out, int* len)
{
int i;
int j;
if (!s || !sep || !out || !len)
return 0;
for (i = 0; s[i]; i++)
{
int b = 0;
for (j = 0; sep[j]; j++)
if (s[i] == sep[j])
{
b = 1;
break;
}
if (!b)
break;
}
if (!s[i])
return 0;
*len = 0;
*out = s + i;
for (; s[i]; i++, (*len)++)
{
int b = 0;
for (j = 0; sep[j]; j++)
if (s[i] == sep[j])
{
b = 1;
break;
}
if (b)
break;
}
for (; s[i]; i++)
{
int b = 0;
for (j = 0; sep[j]; j++)
if (s[i] == sep[j])
{
b = 1;
break;
}
if (!b)
break;
}
return s + i;
}
#ifdef ITT_NOTIFY_EXT_REPORT
ITT_EXTERN_C void _N_(error_handler)(__itt_error_code, va_list args);
#endif /* ITT_NOTIFY_EXT_REPORT */
static void __itt_report_error(__itt_error_code code, ...)
{
va_list args;
va_start( args, code );
if (error_handler != NULL)
error_handler(code, args);
#ifdef ITT_NOTIFY_EXT_REPORT
_N_(error_handler)(code, args);
#endif /* ITT_NOTIFY_EXT_REPORT */
va_end(args);
}
static const char* __itt_get_env_var(const char* name)
{
#define MAX_ENV_VALUE_SIZE 4086
static char env_buff[MAX_ENV_VALUE_SIZE];
static char* env_value = (char*)&env_buff;
if (name != NULL)
{
#if ITT_PLATFORM==ITT_PLATFORM_WIN
size_t max_len = MAX_ENV_VALUE_SIZE - ((size_t)env_value - (size_t)&env_buff);
DWORD rc = GetEnvironmentVariableA(name, env_value, (DWORD)max_len);
if (rc >= max_len)
{
__itt_report_error(__itt_error_env_too_long, name, (size_t)rc - 1, (size_t)(max_len - 1));
}
else if (rc > 0)
{
char* ret = env_value;
env_value += rc + 1;
return ret;
}
else
{
/* If environment variable is empty, GetEnvirornmentVariables() returns zero (number of */
/* characters (not including terminating null), and GetLastError() returns ERROR_SUCCESS. */
DWORD err = GetLastError();
if (err == ERROR_SUCCESS)
return env_value;
if (err != ERROR_ENVVAR_NOT_FOUND)
__itt_report_error(__itt_error_cant_read_env, name, (int)err);
}
#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */
char* env = getenv(name);
if (env != NULL)
{
size_t len = strlen(env);
size_t max_len = MAX_ENV_VALUE_SIZE - ((size_t)env_value - (size_t)&env_buff);
if (len < max_len)
{
char* ret = env_value;
strncpy(env_value, env, len + 1);
env_value += len + 1;
return ret;
} else
__itt_report_error(__itt_error_env_too_long, name, (size_t)len, (size_t)(max_len - 1));
}
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
}
return NULL;
}
static const char* __itt_get_lib_name()
{
const char* lib_name = __itt_get_env_var(ITT_TO_STR(LIB_VAR_NAME));
return (lib_name == NULL) ? ittnotify_lib_name : lib_name;
}
#ifndef min
#define min(a,b) (a) < (b) ? (a) : (b)
#endif /* min */
static __itt_group_id __itt_get_groups()
{
int i;
__itt_group_id res = __itt_group_none;
const char* var_name = "INTEL_ITTNOTIFY_GROUPS";
const char* group_str = __itt_get_env_var(var_name);
if (group_str != NULL)
{
int len;
char gr[255];
const char* chunk;
while ((group_str = __itt_fsplit(group_str, ",; ", &chunk, &len)) != NULL)
{
__itt_fstrcpyn(gr, chunk, sizeof(gr));
gr[min((size_t)len, sizeof(gr) - 1)] = 0;
for (i = 0; group_list[i].name != NULL; i++)
{
if (!__itt_fstrcmp(gr, group_list[i].name))
{
res = (__itt_group_id)(res | group_list[i].id);
break;
}
}
}
/* TODO: !!! Workaround for bug with warning for unknown group !!!
* Should be fixed in new initialization scheme.
* Now the following groups should be set always.
*/
for (i = 0; group_list[i].id != __itt_group_none; i++)
if (group_list[i].id != __itt_group_all && group_list[i].id > __itt_group_splitter)
res = (__itt_group_id)(res | group_list[i].id);
return res;
}
else
{
for (i = 0; group_alias[i].env_var != NULL; i++)
if (__itt_get_env_var(group_alias[i].env_var) != NULL)
return group_alias[i].groups;
}
return res;
}
static int __itt_is_legacy_lib(lib_t lib)
{
if (lib == NULL)
return 0; // if unknown assume NO
if (__itt_get_proc(lib, "__itt_api_version"))
return 0; // New interface - NO
return 1; // It's legacy otherwise
}
#if ITT_PLATFORM==ITT_PLATFORM_WIN
#pragma warning(push)
#pragma warning(disable: 4054)
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
/* ITT_EXTERN_C - should be exported after agreament
static void _N_(fini_ittlib)(void)
{
int i;
if (ittnotify_init)
{
// Clear all pointers
for (i = 0; func_map[i].name != NULL; i++)
*func_map[i].func_ptr = NULL;
if (ittnotify_lib != NULL)
__itt_unload_lib(ittnotify_lib);
ittnotify_lib = NULL;
ittnotify_init = 0;
}
}
*/
static int _N_(init_ittlib)(const char* lib_name, __itt_group_id groups)
{
int i, ret = 0;
static volatile TIDT current_thread = 0;
if (!ittnotify_init)
{
#ifndef ITT_SIMPLE_INIT
static mutex_t mutex;
static volatile int inter_counter = 0;
static volatile int mutex_initialized = 0;
if (!mutex_initialized)
{
if (__itt_interlocked_increment(&inter_counter) == 1)
{
__itt_mutex_init(&mutex);
mutex_initialized = 1;
}
else
while (!mutex_initialized)
__itt_thread_yield();
}
__itt_mutex_lock(&mutex);
#endif /* ITT_SIMPLE_INIT */
if (!ittnotify_init)
{
if (current_thread == 0)
{
current_thread = __itt_thread_id();
if (groups == __itt_group_none)
groups = __itt_get_groups();
if (groups == __itt_group_none)
{
// Clear all pointers
for (i = 0; func_map[i].name != NULL; i++ )
*func_map[i].func_ptr = NULL;
}
else
{
__itt_group_id zero_group = __itt_group_none;
if (lib_name == NULL)
lib_name = __itt_get_lib_name();
ittnotify_lib = __itt_load_lib(lib_name);
if (ittnotify_lib != NULL)
{
if (__itt_is_legacy_lib(ittnotify_lib))
groups = __itt_group_legacy;
for (i = 0; func_map[i].name != NULL; i++)
{
if (func_map[i].group & groups)
{
*func_map[i].func_ptr = (void*)__itt_get_proc(ittnotify_lib, func_map[i].name);
if (*func_map[i].func_ptr == NULL)
{
__itt_report_error(__itt_error_no_symbol, lib_name, func_map[i].name );
zero_group = (__itt_group_id)(zero_group | func_map[i].group);
}
}
else
*func_map[i].func_ptr = NULL;
}
if (groups == __itt_group_legacy)
{
// Compatibility with legacy tools
ITTNOTIFY_NAME(sync_prepare) = ITTNOTIFY_NAME(notify_sync_prepare);
ITTNOTIFY_NAME(sync_cancel) = ITTNOTIFY_NAME(notify_sync_cancel);
ITTNOTIFY_NAME(sync_acquired) = ITTNOTIFY_NAME(notify_sync_acquired);
ITTNOTIFY_NAME(sync_releasing) = ITTNOTIFY_NAME(notify_sync_releasing);
}
}
else
{
// Clear all pointers
for (i = 0; func_map[i].name != NULL; i++)
*func_map[i].func_ptr = NULL;
__itt_report_error(__itt_error_no_module, lib_name,
#if ITT_PLATFORM==ITT_PLATFORM_WIN
__itt_system_error()
#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
dlerror()
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
);
}
#ifdef ITT_COMPLETE_GROUP
for (i = 0; func_map[i].name != NULL; i++)
if (func_map[i].group & zero_group)
*func_map[i].func_ptr = NULL;
#endif /* ITT_COMPLETE_GROUP */
/* evaluating if any function ptr is non empty */
for (i = 0; func_map[i].name != NULL; i++)
{
if (*func_map[i].func_ptr != NULL)
{
ret = 1;
break;
}
}
}
ittnotify_init = 1;
current_thread = 0;
}
}
#ifndef ITT_SIMPLE_INIT
__itt_mutex_unlock(&mutex);
#endif /* ITT_SIMPLE_INIT */
}
return ret;
}
ITT_EXTERN_C __itt_error_notification_t* _N_(set_error_handler)(__itt_error_notification_t* handler)
{
__itt_error_notification_t* prev = error_handler;
error_handler = handler;
return prev;
}
#if ITT_PLATFORM==ITT_PLATFORM_WIN
#pragma warning(pop)
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */