// use offptr_t instead of regular pointers.
Stat _probe_timing[STP_PROBE_COUNT];
#endif
+
+ // 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)
#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);
+ return &_stp_session()->_context[index];
+}
+
+
static int stp_session_init(void)
{
size_t i;
// Reserve space for the session at the beginning of shared memory.
- void *session = _stp_shm_zalloc(sizeof(struct stp_runtime_session));
+ 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;
static unsigned long stap_hash_seed; /* Init during module startup */
+static int stp_pthread_mutex_init_shared(pthread_mutex_t *mutex)
+{
+ int rc;
+ pthread_mutexattr_t attr;
+
+ rc = pthread_mutexattr_init(&attr);
+ if (rc != 0) {
+ _stp_error("pthread_mutexattr_init failed");
+ return rc;
+ }
+
+ rc = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+ if (rc != 0) {
+ _stp_error("pthread_mutexattr_setpshared failed");
+ goto err_attr;
+ }
+
+ rc = pthread_mutex_init(mutex, &attr);
+ if (rc != 0) {
+ _stp_error("pthread_mutex_init failed");
+ goto err_attr;
+ }
+
+err_attr:
+ (void)pthread_mutexattr_destroy(&attr);
+ return rc;
+}
+
+
/*
* For stapdyn to work in a multiprocess environment, the module must be
* prepared to be loaded multiple times in different processes. Thus, we have
#include <sched.h>
#include <pthread.h>
+/* Defined later in common_session_state.h */
+static inline struct context* stp_session_context(size_t index);
+
static int _stp_runtime_num_contexts;
-static struct context *_stp_runtime_contexts = NULL;
+
+/* Locally-cached context pointer -- see _stp_runtime_entryfn_get_context()
+ * and _stp_runtime_entryfn_put_context(). */
static __thread struct context *contexts;
static int _stp_runtime_contexts_init(void)
static int _stp_runtime_contexts_alloc(void)
{
- size_t size;
int i;
- /* Allocate context data. */
- size = sizeof(struct context) * _stp_runtime_num_contexts;
- _stp_runtime_contexts = _stp_kzalloc_gfp(size, STP_ALLOC_SLEEP_FLAGS);
- if (_stp_runtime_contexts == NULL) {
- _stp_error("context (size %lu) allocation failed",
- (unsigned long)size);
- return -ENOMEM;
- }
-
- /* Initialize context data. */
+ /* The allocation was already done in stp_session_init;
+ * we just need to initialize the context data. */
for (i = 0; i < _stp_runtime_num_contexts; i++) {
int rc;
-
- _stp_runtime_contexts[i].data_index = i;
- rc = pthread_mutex_init(&_stp_runtime_contexts[i].lock, NULL);
+ struct context *c = stp_session_context(i);
+ rc = stp_pthread_mutex_init_shared(&c->lock);
if (rc != 0) {
- _stp_error("pthread mutex initialization failed");
- _stp_kfree(_stp_runtime_contexts);
- _stp_runtime_contexts = NULL;
+ _stp_error("context mutex initialization failed");
return rc;
}
}
{
int i;
- if (_stp_runtime_contexts != NULL) {
- /* Teardown context locks. */
- for (i = 0; i < _stp_runtime_num_contexts; i++) {
- (void)pthread_mutex_destroy(&_stp_runtime_contexts[i].lock);
- }
-
- /* Free context data. */
- _stp_kfree(_stp_runtime_contexts);
- _stp_runtime_contexts = NULL;
+ /* The context memory is managed elsewhere;
+ * we just need to teardown the context locks. */
+ for (i = 0; i < _stp_runtime_num_contexts; i++) {
+ struct context *c = stp_session_context(i);
+ (void)pthread_mutex_destroy(&c->lock);
}
}
static struct context * _stp_runtime_entryfn_get_context(void)
{
+ struct context *c;
int i, index, rc, data_index;
/* If 'contexts' (which is thread-local storage) is already set
for (i = 0; i < _stp_runtime_num_contexts; i++, index++) {
if (index >= _stp_runtime_num_contexts)
index = 0;
- if (pthread_mutex_trylock(&_stp_runtime_contexts[index].lock) == 0) {
+ c = stp_session_context(index);
+ if (pthread_mutex_trylock(&c->lock) == 0) {
/* We found a free context structure. Now that it is
* locked, set the TLS pointer and return the context. */
- contexts = &_stp_runtime_contexts[index];
+ contexts = c;
return contexts;
}
}
/* If we're here, we couldn't find a free context structure. Wait
* on one. */
- rc = pthread_mutex_lock(&_stp_runtime_contexts[data_index].lock);
+ c = stp_session_context(data_index);
+ rc = pthread_mutex_lock(&c->lock);
if (rc == 0) {
- contexts = &_stp_runtime_contexts[data_index];
+ contexts = c;
return contexts;
}
return NULL;
struct timespec now, elapsed;
for (i = 0; i < _stp_runtime_num_contexts; i++) {
- if (atomic_read (&_stp_runtime_contexts[i].busy)) {
+ struct context *c = stp_session_context(i);
+ if (atomic_read (&c->busy)) {
holdon = 1;
/* Just In case things are really stuck, let's print
* context, print one. */
if (elapsed.tv_sec > 0 && (i > hold_index)) {
hold_index = i;
- _stp_error("context[%d] stuck: %s", i,
- &_stp_runtime_contexts[i].probe_point);
+ _stp_error("context[%d] stuck: %s", i, c->probe_point);
}
}
}
void
c_unparser::emit_common_header ()
{
- // Common (static atomic) state of the stap session.
o->newline();
- o->newline() << "#include \"common_session_state.h\"";
// Per CPU context for probes. Includes common shared state held for
// all probes (defined in common_probe_context), the probe locals (union)
// Use a separate union for compiled-printf locals, no nesting required.
emit_compiled_printf_locals ();
- o->newline(-1) << "};\n";
+ o->newline(-1) << "};\n"; // end of struct context
+
+ o->newline() << "#include \"runtime_context.h\"";
+
+ // Common (static atomic) state of the stap session.
+ o->newline() << "#include \"common_session_state.h\"";
emit_map_type_instantiations ();
s.up->emit_common_header (); // context etc.
- s.op->newline() << "#include \"runtime_context.h\"";
if (s.need_unwind)
s.op->newline() << "#include \"stack.c\"";