]> sourceware.org Git - systemtap.git/commitdiff
stapdyn: Move contexts into shm
authorJosh Stone <jistone@redhat.com>
Wed, 12 Dec 2012 23:34:39 +0000 (15:34 -0800)
committerJosh Stone <jistone@redhat.com>
Wed, 12 Dec 2012 23:34:39 +0000 (15:34 -0800)
David already abstracted different allocation schemes for runtime
contexts, so this time the kernel runtime needs no change.  The dyninst
runtime now has the per-cpu contexts included in shared memory.

* translate.cxx (c_unparser::emit_common_header): Move runtime_context.h
  and common_session_state.h right after the struct context definition.
* runtime/dyninst/common_session_state.h: Add struct context[] to shm.
  (stp_session_context): New function to access a specific context.
* runtime/dyninst/runtime_context.h (_stp_runtime_contexts_alloc/free):
  Don't manage memory anymore, just initialize the locks and be done.
  Use stp_session_context throughout to retrieve contexts.
* runtime/dyninst/runtime.h (stp_pthread_mutex_init_shared): New, set
  the PTHREAD_PROCESS_SHARED attribute while initializing a mutex.
* runtime/dyninst/shm.c (_stp_shm_finalize): dbug the final mmap addr.

runtime/dyninst/common_session_state.h
runtime/dyninst/runtime.h
runtime/dyninst/runtime_context.h
runtime/dyninst/shm.c
translate.cxx

index 9e7928998fd6e3662517b2555c36c584386b7e8d..c1d46571eb1d72ce8a3cb64b49efc05b875b5f51 100644 (file)
@@ -27,6 +27,11 @@ struct stp_runtime_session {
        // 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)
@@ -77,12 +82,23 @@ static inline Stat probe_timing(size_t index)
 #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;
 
index c5c89f130bfc66a02c8f4c4619323e1d74814d5b..e5b1a38cb3991db6813888a9b403f707478b6f1a 100644 (file)
@@ -136,6 +136,35 @@ static void systemtap_module_exit(void);
 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
index beda374a410a7d52bdde658d26961b4e871e0f27..8290517422fd5f8b15aa5ebe58c4c19a4e0ed1e9 100644 (file)
 #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)
@@ -30,28 +35,16 @@ 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;
        }
     }
@@ -62,15 +55,11 @@ static void _stp_runtime_contexts_free(void)
 {
     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);
     }
 }
 
@@ -90,6 +79,7 @@ static int _stp_runtime_get_data_index(void)
 
 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
@@ -110,19 +100,21 @@ static struct context * _stp_runtime_entryfn_get_context(void)
     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;
@@ -161,7 +153,8 @@ static void _stp_runtime_context_wait(void)
        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
@@ -174,8 +167,7 @@ static void _stp_runtime_context_wait(void)
                 * 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);
                }
            }
        }
index 041f11f8d1971aa790d8b46b36826e02d7b528dd..639282f1467f809807c0aafa369e9c15e620f6ba 100644 (file)
@@ -214,7 +214,8 @@ static void _stp_shm_finalize(void)
                close(_stp_shm_fd);
                _stp_shm_fd = -1;
        }
-       shm_dbug("mapped %zi bytes, used %zi", _stp_shm_size, _stp_shm_allocated);
+       shm_dbug("mapped %zi bytes @ %p, used %zi", _stp_shm_size,
+                _stp_shm_base, _stp_shm_allocated);
 }
 
 
index 0f7e910aed315ad7250fcef18dae988ff941d384..6ff6695a90bfa47b95d9e1d5f09552878c28ac9a 100644 (file)
@@ -957,9 +957,7 @@ translator_output::line ()
 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)
@@ -1113,7 +1111,12 @@ c_unparser::emit_common_header ()
   // 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 ();
 
@@ -6653,7 +6656,6 @@ translate_pass (systemtap_session& s)
 
       s.up->emit_common_header (); // context etc.
 
-      s.op->newline() << "#include \"runtime_context.h\"";
       if (s.need_unwind)
        s.op->newline() << "#include \"stack.c\"";
 
This page took 0.036245 seconds and 5 git commands to generate.