carb/detail/TSan.h
File members: carb/detail/TSan.h
// Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once
#include "../Defines.h"
#if defined DOXYGEN_BUILD || CARB_TSAN_ENABLED
# define CARB_IF_TSAN(...) __VA_ARGS__
# define CARB_IF_NOT_TSAN(...)
#else
# define CARB_IF_TSAN(...)
# define CARB_IF_NOT_TSAN(...) __VA_ARGS__
#endif
#if CARB_TSAN_ENABLED && defined __has_include && __has_include(<sanitizer/tsan_interface.h>)
// Include the official header
# include <sanitizer/tsan_interface.h>
#elif !defined SANITIZER_TSAN_INTERFACE_H // from sanitizer/tsan_interface.h (already included)
// Definitions must match sanitizer/tsan_interface.h
// Mutex has static storage duration and no-op constructor and destructor.
// This effectively makes tsan ignore destroy annotation.
constexpr unsigned __tsan_mutex_linker_init = 1 << 0;
// Mutex is write reentrant.
constexpr unsigned __tsan_mutex_write_reentrant = 1 << 1;
// Mutex is read reentrant.
constexpr unsigned __tsan_mutex_read_reentrant = 1 << 2;
// Mutex does not have static storage duration, and must not be used after
// its destructor runs. The opposite of __tsan_mutex_linker_init.
// If this flag is passed to __tsan_mutex_destroy, then the destruction
// is ignored unless this flag was previously set on the mutex.
constexpr unsigned __tsan_mutex_not_static = 1 << 8;
// Mutex operation flags:
// Denotes read lock operation.
constexpr unsigned __tsan_mutex_read_lock = 1 << 3;
// Denotes try lock operation.
constexpr unsigned __tsan_mutex_try_lock = 1 << 4;
// Denotes that a try lock operation has failed to acquire the mutex.
constexpr unsigned __tsan_mutex_try_lock_failed = 1 << 5;
// Denotes that the lock operation acquires multiple recursion levels.
// Number of levels is passed in recursion parameter.
// This is useful for annotation of e.g. Java builtin monitors,
// for which wait operation releases all recursive acquisitions of the mutex.
constexpr unsigned __tsan_mutex_recursive_lock = 1 << 6;
// Denotes that the unlock operation releases all recursion levels.
// Number of released levels is returned and later must be passed to
// the corresponding __tsan_mutex_post_lock annotation.
constexpr unsigned __tsan_mutex_recursive_unlock = 1 << 7;
// Flags for __tsan_switch_to_fiber:
// Do not establish a happens-before relation between fibers
constexpr unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
extern "C"
{
# if CARB_TSAN_ENABLED
// __tsan_release establishes a happens-before relation with a preceding
// __tsan_acquire on the same address.
void __tsan_acquire(void* addr);
void __tsan_release(void* addr);
// Annotate creation of a mutex.
// Supported flags: mutex creation flags.
void __tsan_mutex_create(void* addr, unsigned flags);
// Annotate destruction of a mutex.
// Supported flags:
// - __tsan_mutex_linker_init
// - __tsan_mutex_not_static
void __tsan_mutex_destroy(void* addr, unsigned flags);
// Annotate start of lock operation.
// Supported flags:
// - __tsan_mutex_read_lock
// - __tsan_mutex_try_lock
// - all mutex creation flags
void __tsan_mutex_pre_lock(void* addr, unsigned flags);
// Annotate end of lock operation.
// Supported flags:
// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_lock)
// - __tsan_mutex_try_lock (must match __tsan_mutex_pre_lock)
// - __tsan_mutex_try_lock_failed
// - __tsan_mutex_recursive_lock
// - all mutex creation flags
void __tsan_mutex_post_lock(void* addr, unsigned flags, int recursion);
// Annotate start of unlock operation.
// Supported flags:
// - __tsan_mutex_read_lock
// - __tsan_mutex_recursive_unlock
int __tsan_mutex_pre_unlock(void* addr, unsigned flags);
// Annotate end of unlock operation.
// Supported flags:
// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_unlock)
void __tsan_mutex_post_unlock(void* addr, unsigned flags);
// Annotate start/end of notify/signal/broadcast operation.
// Supported flags: none.
void __tsan_mutex_pre_signal(void* addr, unsigned flags);
void __tsan_mutex_post_signal(void* addr, unsigned flags);
// Annotate start/end of a region of code where lock/unlock/signal operation
// diverts to do something else unrelated to the mutex. This can be used to
// annotate, for example, calls into cooperative scheduler or contention
// profiling code.
// These annotations must be called only from within
// __tsan_mutex_pre/post_lock, __tsan_mutex_pre/post_unlock,
// __tsan_mutex_pre/post_signal regions.
// Supported flags: none.
void __tsan_mutex_pre_divert(void* addr, unsigned flags);
void __tsan_mutex_post_divert(void* addr, unsigned flags);
// Fiber switching API.
// - TSAN context for fiber can be created by __tsan_create_fiber
// and freed by __tsan_destroy_fiber.
// - TSAN context of current fiber or thread can be obtained
// by calling __tsan_get_current_fiber.
// - __tsan_switch_to_fiber should be called immediatly before switch
// to fiber, such as call of swapcontext.
// - Fiber name can be set by __tsan_set_fiber_name.
void* __tsan_get_current_fiber(void);
void* __tsan_create_fiber(unsigned flags);
void __tsan_destroy_fiber(void* fiber);
void __tsan_switch_to_fiber(void* fiber, unsigned flags);
void __tsan_set_fiber_name(void* fiber, const char* name);
# else
// clang-format off
inline constexpr void __tsan_acquire(void *) {}
inline constexpr void __tsan_release(void *) {}
inline constexpr void __tsan_mutex_create(void *, unsigned) noexcept {}
inline constexpr void __tsan_mutex_destroy(void *, unsigned) noexcept {}
inline constexpr void __tsan_mutex_pre_lock(void *, unsigned) noexcept {}
inline constexpr void __tsan_mutex_post_lock(void *, unsigned, int) noexcept {}
inline constexpr int __tsan_mutex_pre_unlock(void *, unsigned) noexcept { return 0; }
inline constexpr void __tsan_mutex_post_unlock(void *, unsigned) noexcept {}
inline constexpr void __tsan_mutex_pre_signal(void *, unsigned) noexcept {}
inline constexpr void __tsan_mutex_post_signal(void *, unsigned) noexcept {}
inline constexpr void __tsan_mutex_pre_divert(void *, unsigned) noexcept {}
inline constexpr void __tsan_mutex_post_divert(void *, unsigned) noexcept {}
inline void *__tsan_get_current_fiber(void) noexcept { return nullptr; }
inline void *__tsan_create_fiber(unsigned) noexcept { return nullptr; }
inline constexpr void __tsan_destroy_fiber(void *) noexcept {}
inline constexpr void __tsan_switch_to_fiber(void *, unsigned) noexcept {}
inline constexpr void __tsan_set_fiber_name(void *, const char *) noexcept {}
// clang-format on
# endif
}
#endif