Fix: syscall event rule: emission sites not compared in is_equal
[lttng-tools.git] / src / bin / lttng-relayd / sessiond-trace-chunks.cpp
index 18ef586d00c85d62e5b92bfbc083979dc32e5bf6..9d793c9bcf79315e722447fcb3c205f785a60c54 100644 (file)
@@ -5,19 +5,22 @@
  *
  */
 
-#include "sessiond-trace-chunks.h"
+#include "sessiond-trace-chunks.hpp"
+
+#include <common/defaults.hpp>
+#include <common/error.hpp>
+#include <common/hashtable/hashtable.hpp>
+#include <common/hashtable/utils.hpp>
+#include <common/macros.hpp>
+#include <common/string-utils/format.hpp>
+#include <common/trace-chunk-registry.hpp>
+#include <common/urcu.hpp>
+
+#include <inttypes.h>
+#include <stdio.h>
 #include <urcu.h>
 #include <urcu/rculfhash.h>
 #include <urcu/ref.h>
-#include <common/macros.h>
-#include <common/hashtable/hashtable.h>
-#include <common/hashtable/utils.h>
-#include <common/trace-chunk-registry.h>
-#include <common/defaults.h>
-#include <common/error.h>
-#include <common/string-utils/format.h>
-#include <stdio.h>
-#include <inttypes.h>
 
 /*
  * Lifetime of trace chunks within the relay daemon.
@@ -56,6 +59,7 @@ struct sessiond_trace_chunk_registry {
        struct cds_lfht *ht;
 };
 
+namespace {
 struct trace_chunk_registry_ht_key {
        lttng_uuid sessiond_uuid;
 };
@@ -70,59 +74,48 @@ struct trace_chunk_registry_ht_element {
        struct lttng_trace_chunk_registry *trace_chunk_registry;
        struct sessiond_trace_chunk_registry *sessiond_trace_chunk_registry;
 };
+} /* namespace */
 
-static
-unsigned long trace_chunk_registry_ht_key_hash(
-               const struct trace_chunk_registry_ht_key *key)
+static unsigned long trace_chunk_registry_ht_key_hash(const struct trace_chunk_registry_ht_key *key)
 {
-       uint64_t uuid_h1 = ((uint64_t *) key->sessiond_uuid)[0];
-       uint64_t uuid_h2 = ((uint64_t *) key->sessiond_uuid)[1];
+       const uint64_t uuid_h1 = *reinterpret_cast<const uint64_t *>(&key->sessiond_uuid[0]);
+       const uint64_t uuid_h2 = *reinterpret_cast<const uint64_t *>(&key->sessiond_uuid[1]);
 
-       return hash_key_u64(&uuid_h1, lttng_ht_seed) ^
-                       hash_key_u64(&uuid_h2, lttng_ht_seed);
+       return hash_key_u64(&uuid_h1, lttng_ht_seed) ^ hash_key_u64(&uuid_h2, lttng_ht_seed);
 }
 
 /* cds_lfht match function */
-static
-int trace_chunk_registry_ht_key_match(struct cds_lfht_node *node,
-               const void *_key)
+static int trace_chunk_registry_ht_key_match(struct cds_lfht_node *node, const void *_key)
 {
-       const struct trace_chunk_registry_ht_key *key =
-                       (struct trace_chunk_registry_ht_key *) _key;
+       const struct trace_chunk_registry_ht_key *key = (struct trace_chunk_registry_ht_key *) _key;
        struct trace_chunk_registry_ht_element *registry;
 
-       registry = container_of(node, typeof(*registry), ht_node);
-       return lttng_uuid_is_equal(key->sessiond_uuid,
-                       registry->key.sessiond_uuid);
+       registry = lttng::utils::container_of(node, &trace_chunk_registry_ht_element::ht_node);
+       return key->sessiond_uuid == registry->key.sessiond_uuid;
 }
 
-static
-void trace_chunk_registry_ht_element_free(struct rcu_head *node)
+static void trace_chunk_registry_ht_element_free(struct rcu_head *node)
 {
        struct trace_chunk_registry_ht_element *element =
-                       container_of(node, typeof(*element), rcu_node);
+               lttng::utils::container_of(node, &trace_chunk_registry_ht_element::rcu_node);
 
        free(element);
 }
 
-static
-void trace_chunk_registry_ht_element_release(struct urcu_ref *ref)
+static void trace_chunk_registry_ht_element_release(struct urcu_ref *ref)
 {
        struct trace_chunk_registry_ht_element *element =
-                       container_of(ref, typeof(*element), ref);
+               lttng::utils::container_of(ref, &trace_chunk_registry_ht_element::ref);
        char uuid_str[LTTNG_UUID_STR_LEN];
 
        lttng_uuid_to_str(element->key.sessiond_uuid, uuid_str);
 
-       DBG("Destroying trace chunk registry associated to sessiond {%s}",
-                       uuid_str);
+       DBG("Destroying trace chunk registry associated to sessiond {%s}", uuid_str);
        if (element->sessiond_trace_chunk_registry) {
                /* Unpublish. */
-               rcu_read_lock();
-               cds_lfht_del(element->sessiond_trace_chunk_registry->ht,
-                               &element->ht_node);
-               rcu_read_unlock();
-               element->sessiond_trace_chunk_registry = NULL;
+               lttng::urcu::read_lock_guard read_lock;
+               cds_lfht_del(element->sessiond_trace_chunk_registry->ht, &element->ht_node);
+               element->sessiond_trace_chunk_registry = nullptr;
        }
 
        lttng_trace_chunk_registry_destroy(element->trace_chunk_registry);
@@ -130,16 +123,12 @@ void trace_chunk_registry_ht_element_release(struct urcu_ref *ref)
        call_rcu(&element->rcu_node, trace_chunk_registry_ht_element_free);
 }
 
-static
-bool trace_chunk_registry_ht_element_get(
-               struct trace_chunk_registry_ht_element *element)
+static bool trace_chunk_registry_ht_element_get(struct trace_chunk_registry_ht_element *element)
 {
        return urcu_ref_get_unless_zero(&element->ref);
 }
 
-static
-void trace_chunk_registry_ht_element_put(
-               struct trace_chunk_registry_ht_element *element)
+static void trace_chunk_registry_ht_element_put(struct trace_chunk_registry_ht_element *element)
 {
        if (!element) {
                return;
@@ -149,16 +138,15 @@ void trace_chunk_registry_ht_element_put(
 }
 
 /* Acquires a reference to the returned element on behalf of the caller. */
-static
-struct trace_chunk_registry_ht_element *trace_chunk_registry_ht_element_find(
-               struct sessiond_trace_chunk_registry *sessiond_registry,
-               const struct trace_chunk_registry_ht_key *key)
+static struct trace_chunk_registry_ht_element *
+trace_chunk_registry_ht_element_find(struct sessiond_trace_chunk_registry *sessiond_registry,
+                                    const struct trace_chunk_registry_ht_key *key)
 {
-       struct trace_chunk_registry_ht_element *element = NULL;
+       struct trace_chunk_registry_ht_element *element = nullptr;
        struct cds_lfht_node *node;
        struct cds_lfht_iter iter;
 
-       rcu_read_lock();
+       lttng::urcu::read_lock_guard read_lock;
        cds_lfht_lookup(sessiond_registry->ht,
                        trace_chunk_registry_ht_key_hash(key),
                        trace_chunk_registry_ht_key_match,
@@ -166,23 +154,22 @@ struct trace_chunk_registry_ht_element *trace_chunk_registry_ht_element_find(
                        &iter);
        node = cds_lfht_iter_get_node(&iter);
        if (node) {
-               element = container_of(node, typeof(*element), ht_node);
+               element =
+                       lttng::utils::container_of(node, &trace_chunk_registry_ht_element::ht_node);
                /*
                 * Only consider the look-up as successful if a reference
                 * could be acquired.
                 */
                if (!trace_chunk_registry_ht_element_get(element)) {
-                       element = NULL;
+                       element = nullptr;
                }
        }
-       rcu_read_unlock();
        return element;
 }
 
-static
-int trace_chunk_registry_ht_element_create(
-               struct sessiond_trace_chunk_registry *sessiond_registry,
-               const struct trace_chunk_registry_ht_key *key)
+static int
+trace_chunk_registry_ht_element_create(struct sessiond_trace_chunk_registry *sessiond_registry,
+                                      const struct trace_chunk_registry_ht_key *key)
 {
        int ret = 0;
        struct trace_chunk_registry_ht_element *new_element;
@@ -197,7 +184,7 @@ int trace_chunk_registry_ht_element_create(
                goto end;
        }
 
-       new_element = (trace_chunk_registry_ht_element *) zmalloc(sizeof(*new_element));
+       new_element = zmalloc<trace_chunk_registry_ht_element>();
        if (!new_element) {
                ret = -1;
                goto end;
@@ -207,70 +194,73 @@ int trace_chunk_registry_ht_element_create(
        urcu_ref_init(&new_element->ref);
        cds_lfht_node_init(&new_element->ht_node);
        new_element->trace_chunk_registry = trace_chunk_registry;
-       trace_chunk_registry = NULL;
+       trace_chunk_registry = nullptr;
 
        /* Attempt to publish the new element. */
-       rcu_read_lock();
-       while (1) {
-               struct cds_lfht_node *published_node;
-               struct trace_chunk_registry_ht_element *published_element;
+       {
+               /*
+                * Keep the rcu read lock is held accross all attempts
+                * purely for efficiency reasons.
+                */
+               lttng::urcu::read_lock_guard read_lock;
+               while (true) {
+                       struct cds_lfht_node *published_node;
+                       struct trace_chunk_registry_ht_element *published_element;
 
-               published_node = cds_lfht_add_unique(sessiond_registry->ht,
+                       published_node = cds_lfht_add_unique(
+                               sessiond_registry->ht,
                                trace_chunk_registry_ht_key_hash(&new_element->key),
                                trace_chunk_registry_ht_key_match,
                                &new_element->key,
                                &new_element->ht_node);
-               if (published_node == &new_element->ht_node) {
-                       /* New element published successfully. */
-                       DBG("Created trace chunk registry for sessiond {%s}",
-                                       uuid_str);
-                       new_element->sessiond_trace_chunk_registry =
-                                       sessiond_registry;
-                       break;
+                       if (published_node == &new_element->ht_node) {
+                               /* New element published successfully. */
+                               DBG("Created trace chunk registry for sessiond {%s}", uuid_str);
+                               new_element->sessiond_trace_chunk_registry = sessiond_registry;
+                               break;
+                       }
+
+                       /*
+                        * An equivalent element was published during the creation of
+                        * this element. Attempt to acquire a reference to the one that
+                        * was already published and release the reference to the copy
+                        * we created if successful.
+                        */
+                       published_element = lttng::utils::container_of(
+                               published_node, &trace_chunk_registry_ht_element::ht_node);
+                       if (trace_chunk_registry_ht_element_get(published_element)) {
+                               DBG("Acquired reference to trace chunk registry of sessiond {%s}",
+                                   uuid_str);
+                               trace_chunk_registry_ht_element_put(new_element);
+                               new_element = nullptr;
+                               break;
+                       }
+                       /*
+                        * A reference to the previously published element could not
+                        * be acquired. Hence, retry to publish our copy of the
+                        * element.
+                        */
                }
-
-               /*
-                * An equivalent element was published during the creation of
-                * this element. Attempt to acquire a reference to the one that
-                * was already published and release the reference to the copy
-                * we created if successful.
-                */
-               published_element = container_of(published_node,
-                               typeof(*published_element), ht_node);
-               if (trace_chunk_registry_ht_element_get(published_element)) {
-                       DBG("Acquired reference to trace chunk registry of sessiond {%s}",
-                                       uuid_str);
-                       trace_chunk_registry_ht_element_put(new_element);
-                       new_element = NULL;
-                       break;
-               }
-               /*
-                * A reference to the previously published element could not
-                * be acquired. Hence, retry to publish our copy of the
-                * element.
-                */
        }
-       rcu_read_unlock();
 end:
        if (ret < 0) {
-               ERR("Failed to create trace chunk registry for session daemon {%s}",
-                               uuid_str);
+               ERR("Failed to create trace chunk registry for session daemon {%s}", uuid_str);
        }
        lttng_trace_chunk_registry_destroy(trace_chunk_registry);
        return ret;
 }
 
-struct sessiond_trace_chunk_registry *sessiond_trace_chunk_registry_create(void)
+struct sessiond_trace_chunk_registry *sessiond_trace_chunk_registry_create()
 {
        struct sessiond_trace_chunk_registry *sessiond_registry =
-                       (sessiond_trace_chunk_registry *) zmalloc(sizeof(*sessiond_registry));
+               zmalloc<sessiond_trace_chunk_registry>();
 
        if (!sessiond_registry) {
                goto end;
        }
 
-       sessiond_registry->ht = cds_lfht_new(DEFAULT_HT_SIZE,
-                       1, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
+       sessiond_registry->ht = cds_lfht_new(
+               DEFAULT_HT_SIZE, 1, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, nullptr);
        if (!sessiond_registry->ht) {
                goto error;
        }
@@ -279,47 +269,42 @@ end:
        return sessiond_registry;
 error:
        sessiond_trace_chunk_registry_destroy(sessiond_registry);
-       return NULL;
+       return nullptr;
 }
 
-void sessiond_trace_chunk_registry_destroy(
-               struct sessiond_trace_chunk_registry *sessiond_registry)
+void sessiond_trace_chunk_registry_destroy(struct sessiond_trace_chunk_registry *sessiond_registry)
 {
-       int ret = cds_lfht_destroy(sessiond_registry->ht, NULL);
+       int ret = cds_lfht_destroy(sessiond_registry->ht, nullptr);
 
        LTTNG_ASSERT(!ret);
        free(sessiond_registry);
 }
 
 int sessiond_trace_chunk_registry_session_created(
-               struct sessiond_trace_chunk_registry *sessiond_registry,
-               const lttng_uuid sessiond_uuid)
+       struct sessiond_trace_chunk_registry *sessiond_registry, const lttng_uuid& sessiond_uuid)
 {
        int ret = 0;
        struct trace_chunk_registry_ht_key key;
        struct trace_chunk_registry_ht_element *element;
 
-       lttng_uuid_copy(key.sessiond_uuid, sessiond_uuid);
+       key.sessiond_uuid = sessiond_uuid;
 
        element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
        if (element) {
                char uuid_str[LTTNG_UUID_STR_LEN];
 
                lttng_uuid_to_str(sessiond_uuid, uuid_str);
-               DBG("Acquired reference to trace chunk registry of sessiond {%s}",
-                               uuid_str);
+               DBG("Acquired reference to trace chunk registry of sessiond {%s}", uuid_str);
                goto end;
        } else {
-               ret = trace_chunk_registry_ht_element_create(
-                               sessiond_registry, &key);
+               ret = trace_chunk_registry_ht_element_create(sessiond_registry, &key);
        }
 end:
        return ret;
 }
 
 int sessiond_trace_chunk_registry_session_destroyed(
-               struct sessiond_trace_chunk_registry *sessiond_registry,
-               const lttng_uuid sessiond_uuid)
+       struct sessiond_trace_chunk_registry *sessiond_registry, const lttng_uuid& sessiond_uuid)
 {
        int ret = 0;
        struct trace_chunk_registry_ht_key key;
@@ -327,12 +312,11 @@ int sessiond_trace_chunk_registry_session_destroyed(
        char uuid_str[LTTNG_UUID_STR_LEN];
 
        lttng_uuid_to_str(sessiond_uuid, uuid_str);
-       lttng_uuid_copy(key.sessiond_uuid, sessiond_uuid);
+       key.sessiond_uuid = sessiond_uuid;
 
        element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
        if (element) {
-               DBG("Releasing reference to trace chunk registry of sessiond {%s}",
-                               uuid_str);
+               DBG("Releasing reference to trace chunk registry of sessiond {%s}", uuid_str);
                /*
                 * Release the reference held by the session and the reference
                 * acquired through the "find" operation.
@@ -340,37 +324,36 @@ int sessiond_trace_chunk_registry_session_destroyed(
                trace_chunk_registry_ht_element_put(element);
                trace_chunk_registry_ht_element_put(element);
        } else {
-               ERR("Failed to find trace chunk registry of sessiond {%s}",
-                               uuid_str);
+               ERR("Failed to find trace chunk registry of sessiond {%s}", uuid_str);
                ret = -1;
        }
        return ret;
 }
 
-struct lttng_trace_chunk *sessiond_trace_chunk_registry_publish_chunk(
-               struct sessiond_trace_chunk_registry *sessiond_registry,
-               const lttng_uuid sessiond_uuid, uint64_t session_id,
-               struct lttng_trace_chunk *new_chunk)
+struct lttng_trace_chunk *
+sessiond_trace_chunk_registry_publish_chunk(struct sessiond_trace_chunk_registry *sessiond_registry,
+                                           const lttng_uuid& sessiond_uuid,
+                                           uint64_t session_id,
+                                           struct lttng_trace_chunk *new_chunk)
 {
        enum lttng_trace_chunk_status status;
        uint64_t chunk_id;
        bool is_anonymous_chunk;
        struct trace_chunk_registry_ht_key key;
-       struct trace_chunk_registry_ht_element *element = NULL;
+       struct trace_chunk_registry_ht_element *element = nullptr;
        char uuid_str[LTTNG_UUID_STR_LEN];
        char chunk_id_str[MAX_INT_DEC_LEN(typeof(chunk_id))] = "-1";
-       struct lttng_trace_chunk *published_chunk = NULL;
+       struct lttng_trace_chunk *published_chunk = nullptr;
        bool trace_chunk_already_published;
 
        lttng_uuid_to_str(sessiond_uuid, uuid_str);
-       lttng_uuid_copy(key.sessiond_uuid, sessiond_uuid);
+       key.sessiond_uuid = sessiond_uuid;
 
        status = lttng_trace_chunk_get_id(new_chunk, &chunk_id);
        if (status == LTTNG_TRACE_CHUNK_STATUS_OK) {
                int ret;
 
-               ret = snprintf(chunk_id_str, sizeof(chunk_id_str), "%" PRIu64,
-                               chunk_id);
+               ret = snprintf(chunk_id_str, sizeof(chunk_id_str), "%" PRIu64, chunk_id);
                if (ret < 0) {
                        lttng_strncpy(chunk_id_str, "-1", sizeof(chunk_id_str));
                        WARN("Failed to format trace chunk id");
@@ -384,9 +367,10 @@ struct lttng_trace_chunk *sessiond_trace_chunk_registry_publish_chunk(
        }
 
        DBG("Attempting to publish trace chunk: sessiond {%s}, session_id = "
-                       "%" PRIu64 ", chunk_id = %s",
-                       uuid_str, session_id,
-                       is_anonymous_chunk ? "anonymous" : chunk_id_str);
+           "%" PRIu64 ", chunk_id = %s",
+           uuid_str,
+           session_id,
+           is_anonymous_chunk ? "anonymous" : chunk_id_str);
 
        element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
        if (!element) {
@@ -394,9 +378,10 @@ struct lttng_trace_chunk *sessiond_trace_chunk_registry_publish_chunk(
                goto end;
        }
 
-       published_chunk = lttng_trace_chunk_registry_publish_chunk(
-                       element->trace_chunk_registry, session_id, new_chunk,
-                       &trace_chunk_already_published);
+       published_chunk = lttng_trace_chunk_registry_publish_chunk(element->trace_chunk_registry,
+                                                                  session_id,
+                                                                  new_chunk,
+                                                                  &trace_chunk_already_published);
        /*
         * When the trace chunk is first published, two references to the
         * published chunks exist. One is taken by the registry while the other
@@ -423,74 +408,71 @@ end:
        return published_chunk;
 }
 
-struct lttng_trace_chunk *
-sessiond_trace_chunk_registry_get_anonymous_chunk(
-               struct sessiond_trace_chunk_registry *sessiond_registry,
-               const lttng_uuid sessiond_uuid,
-               uint64_t session_id)
+struct lttng_trace_chunk *sessiond_trace_chunk_registry_get_anonymous_chunk(
+       struct sessiond_trace_chunk_registry *sessiond_registry,
+       const lttng_uuid& sessiond_uuid,
+       uint64_t session_id)
 {
-       struct lttng_trace_chunk *chunk = NULL;
+       struct lttng_trace_chunk *chunk = nullptr;
        struct trace_chunk_registry_ht_element *element;
        struct trace_chunk_registry_ht_key key;
        char uuid_str[LTTNG_UUID_STR_LEN];
 
        lttng_uuid_to_str(sessiond_uuid, uuid_str);
 
-       lttng_uuid_copy(key.sessiond_uuid, sessiond_uuid);
+       key.sessiond_uuid = sessiond_uuid;
        element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
        if (!element) {
-               ERR("Failed to find trace chunk registry of sessiond {%s}",
-                               uuid_str);
+               ERR("Failed to find trace chunk registry of sessiond {%s}", uuid_str);
                goto end;
        }
 
-       chunk = lttng_trace_chunk_registry_find_anonymous_chunk(
-                       element->trace_chunk_registry,
-                       session_id);
+       chunk = lttng_trace_chunk_registry_find_anonymous_chunk(element->trace_chunk_registry,
+                                                               session_id);
        trace_chunk_registry_ht_element_put(element);
 end:
        return chunk;
 }
 
 struct lttng_trace_chunk *
-sessiond_trace_chunk_registry_get_chunk(
-               struct sessiond_trace_chunk_registry *sessiond_registry,
-               const lttng_uuid sessiond_uuid,
-               uint64_t session_id, uint64_t chunk_id)
+sessiond_trace_chunk_registry_get_chunk(struct sessiond_trace_chunk_registry *sessiond_registry,
+                                       const lttng_uuid& sessiond_uuid,
+                                       uint64_t session_id,
+                                       uint64_t chunk_id)
 {
-       struct lttng_trace_chunk *chunk = NULL;
+       struct lttng_trace_chunk *chunk = nullptr;
        struct trace_chunk_registry_ht_element *element;
        struct trace_chunk_registry_ht_key key;
        char uuid_str[LTTNG_UUID_STR_LEN];
 
        lttng_uuid_to_str(sessiond_uuid, uuid_str);
 
-       lttng_uuid_copy(key.sessiond_uuid, sessiond_uuid);
+       key.sessiond_uuid = sessiond_uuid;
        element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
        if (!element) {
-               ERR("Failed to find trace chunk registry of sessiond {%s}",
-                               uuid_str);
+               ERR("Failed to find trace chunk registry of sessiond {%s}", uuid_str);
                goto end;
        }
 
        chunk = lttng_trace_chunk_registry_find_chunk(
-                       element->trace_chunk_registry,
-                       session_id, chunk_id);
+               element->trace_chunk_registry, session_id, chunk_id);
        trace_chunk_registry_ht_element_put(element);
 end:
        return chunk;
 }
 
 int sessiond_trace_chunk_registry_chunk_exists(
-               struct sessiond_trace_chunk_registry *sessiond_registry,
-               const lttng_uuid sessiond_uuid,
-               uint64_t session_id, uint64_t chunk_id, bool *chunk_exists)
+       struct sessiond_trace_chunk_registry *sessiond_registry,
+       const lttng_uuid& sessiond_uuid,
+       uint64_t session_id,
+       uint64_t chunk_id,
+       bool *chunk_exists)
 {
        int ret;
        struct trace_chunk_registry_ht_element *element;
        struct trace_chunk_registry_ht_key key;
 
-       lttng_uuid_copy(key.sessiond_uuid, sessiond_uuid);
+       key.sessiond_uuid = sessiond_uuid;
        element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
        if (!element) {
                char uuid_str[LTTNG_UUID_STR_LEN];
@@ -503,15 +485,13 @@ int sessiond_trace_chunk_registry_chunk_exists(
                 * connection/registry. This would indicate a protocol
                 * (or internal) error.
                 */
-               ERR("Failed to find trace chunk registry of sessiond {%s}",
-                               uuid_str);
+               ERR("Failed to find trace chunk registry of sessiond {%s}", uuid_str);
                ret = -1;
                goto end;
        }
 
        ret = lttng_trace_chunk_registry_chunk_exists(
-                       element->trace_chunk_registry,
-                       session_id, chunk_id, chunk_exists);
+               element->trace_chunk_registry, session_id, chunk_id, chunk_exists);
        trace_chunk_registry_ht_element_put(element);
 end:
        return ret;
This page took 0.032011 seconds and 4 git commands to generate.