runtime/dyninst/common_session_state.h - systemtap
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
// Will be included once by runtime/common_session_state.h, which is included
// once by translate.cxx c_unparser::emit_common_header ().
// Forward declarations for things in runtime/dyninst/shm.c
static void *_stp_shm_base;
static void *_stp_shm_alloc(size_t size);
#include "session_attributes.h"
#include "transport.h"
// Global state shared throughout the module
struct stp_runtime_session {
atomic_t _session_state;
atomic_t _error_count;
atomic_t _skipped_count;
atomic_t _skipped_count_lowstack;
atomic_t _skipped_count_reentrant;
atomic_t _skipped_count_uprobe_reg;
atomic_t _skipped_count_uprobe_unreg;
unsigned long _hash_seed;
struct _stp_session_attributes _session_attributes;
#ifdef STP_ALIBI
atomic_t _probe_alibi[STP_PROBE_COUNT];
#endif
#ifdef STP_TIMING
offptr_t _probe_timing[STP_PROBE_COUNT]; // offptr<Stat>
#endif
struct stp_globals _global;
struct _stp_transport_session_data _transport_data;
// NB: the context includes a number of pointers, which wouldn't be
// kosher for shared memory, but it's ok as long as they're only set
// and dereferenced within each separate handler invocation.
struct context _context[]; // variably-sized to cpu count
};
static inline struct stp_runtime_session* _stp_session(void)
{
// Since the session is always the first thing allocated, it lives
// directly at the start of shared memory.
// NB: We always reference the main shm pointer, rather than our own
// local copy, because reallocations may cause it to move dynamically.
return _stp_shm_base;
}
#define GET_SESSION_ATOMIC(name) \
static inline atomic_t *name(void) { \
if (unlikely(_stp_session() == NULL)) \
return NULL; \
return &_stp_session()->_##name; \
}
GET_SESSION_ATOMIC(session_state);
GET_SESSION_ATOMIC(error_count);
GET_SESSION_ATOMIC(skipped_count);
GET_SESSION_ATOMIC(skipped_count_lowstack);
GET_SESSION_ATOMIC(skipped_count_reentrant);
GET_SESSION_ATOMIC(skipped_count_uprobe_reg);
GET_SESSION_ATOMIC(skipped_count_uprobe_unreg);
#undef GET_SESSION_ATOMIC
static inline unsigned long _stap_hash_seed()
{
if (likely(_stp_session()))
return _stp_session()->_hash_seed;
return 0;
}
static inline struct _stp_session_attributes *stp_session_attributes(void)
{
if (likely(_stp_session()))
return &_stp_session()->_session_attributes;
return NULL;
}
#ifdef STP_ALIBI
static inline atomic_t *probe_alibi(size_t index)
{
// Do some simple bounds-checking. Translator-generated code
// should never get this wrong, but better to be safe.
index = clamp_t(size_t, index, 0, STP_PROBE_COUNT - 1);
if (likely(_stp_session()))
return &_stp_session()->_probe_alibi[index];
return NULL;
}
#endif
#ifdef STP_TIMING
static inline Stat probe_timing(size_t index)
{
// Do some simple bounds-checking. Translator-generated code
// should never get this wrong, but better to be safe.
index = clamp_t(size_t, index, 0, STP_PROBE_COUNT - 1);
if (likely(_stp_session()))
return offptr_get(&_stp_session()->_probe_timing[index]);
return NULL;
}
#endif
static inline struct context* stp_session_context(size_t index)
{
// Do some simple bounds-checking. Translator-generated code
// should never get this wrong, but better to be safe.
index = clamp_t(size_t, index, 0, _stp_runtime_num_contexts - 1);
if (likely(_stp_session()))
return &_stp_session()->_context[index];
return NULL;
}
static inline struct _stp_transport_session_data *stp_transport_data(void)
{
if (_stp_session())
return &_stp_session()->_transport_data;
return NULL;
}
#define _global_raw(name) (_stp_session()->_global.name)
#define _global_type(name) typeof(_global_raw(name))
#define _global_cast_type(name) _global_type(name ## _typed)
#define _global_offptr_p(name) \
__builtin_types_compatible_p(_global_type(name), offptr_t)
#define _global_compat_p(name, value) \
__builtin_types_compatible_p(_global_cast_type(name), typeof(value))
// NB: The (offptr_t*) cast is unfortunately necessary for the first expression
// to pass syntax on long/string types, but __builtin_choose_expr will still
// direct them to the second expression due to the _global_offptr_p check.
#define global(name) \
__builtin_choose_expr(_global_offptr_p(name), \
((_global_cast_type(name)) \
offptr_get((offptr_t*)&_global_raw(name))), \
_global_raw(name))
// NB: This is only used for pointer->offptr assignments, for stats and maps.
// Unlike global() which just returns string/long types by value, here we'd
// have to encode their separate assignment schemes, in a way that stays
// syntax-compatible with all others. The translator can do that simpler.
// NB: Evaluate the value *before* the offptr destination is computed, in
// case the value's allocation causes shm to move.
#define global_set(name, value) ({ \
typeof(value) __value = (value); \
offptr_set(&_global_raw(name), \
__builtin_choose_expr(_global_compat_p(name, __value), \
__value, (void)0)); \
__value; })
#define global_lock(name) (&_global_raw(name ## _lock))
#define global_lock_init(name) \
stp_pthread_rwlock_init_shared(global_lock(name))
#ifdef STP_TIMING
#define global_skipped(name) (&_global_raw(name ## _lock_skip_count))
#endif
static int stp_session_init(void)
{
size_t i;
// Reserve space for the session at the beginning of shared memory.
size_t session_size = sizeof(struct stp_runtime_session)
+ sizeof(struct context) * _stp_runtime_num_contexts;
void *session = _stp_shm_zalloc(session_size);
if (!session)
return -ENOMEM;
// If we weren't the very first thing allocated, then something is wrong!
if (session != _stp_shm_base)
return -EINVAL;
atomic_set(session_state(), STAP_SESSION_STARTING);
atomic_set(error_count(), 0);
atomic_set(skipped_count(), 0);
atomic_set(skipped_count_lowstack(), 0);
atomic_set(skipped_count_reentrant(), 0);
atomic_set(skipped_count_uprobe_reg(), 0);
atomic_set(skipped_count_uprobe_unreg(), 0);
_stp_session()->_hash_seed = _stp_random_u ((unsigned long)-1);
stp_session_attributes_init();
#ifdef STP_ALIBI
// Initialize all the alibi counters
for (i = 0; i < STP_PROBE_COUNT; ++i)
atomic_set(probe_alibi(i), 0);
#endif
#ifdef STP_TIMING
// Initialize each Stat used for timing information
for (i = 0; i < STP_PROBE_COUNT; ++i) {
// NB: we don't check for null return here, but instead at
// passage to probe handlers and at final printing.
Stat st = _stp_stat_init(HIST_NONE);
// NB: allocate first, then dereference the session after, in case
// allocation-resizing causes the whole thing to move around.
offptr_set(&_stp_session()->_probe_timing[i], st);
}
#endif
return _stp_dyninst_transport_session_init();
}
static int stp_session_init_finished(void)
{
return stp_dyninst_session_init_finished();
}