| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 | // Copyright The OpenTelemetry Authors// SPDX-License-Identifier: Apache-2.0#pragma once#include <stddef.h>#include <algorithm>#include "opentelemetry/common/macros.h"#include "opentelemetry/context/context.h"#include "opentelemetry/context/context_value.h"#include "opentelemetry/nostd/shared_ptr.h"#include "opentelemetry/nostd/string_view.h"#include "opentelemetry/nostd/unique_ptr.h"#include "opentelemetry/version.h"OPENTELEMETRY_BEGIN_NAMESPACEnamespace context{// The Token object provides is returned when attaching objects to the// RuntimeContext object and is associated with a context object, and// can be provided to the RuntimeContext Detach method to remove the// associated context from the RuntimeContext.class Token{public:  bool operator==(const Context &other) const noexcept { return context_ == other; }  ~Token() noexcept;private:  friend class RuntimeContextStorage;  // A constructor that sets the token's Context object to the  // one that was passed in.  Token(const Context &context) : context_(context) {}  const Context context_;};/** * RuntimeContextStorage is used by RuntimeContext to store Context frames. * * Custom context management strategies can be implemented by deriving from * this class and passing an initialized RuntimeContextStorage object to * RuntimeContext::SetRuntimeContextStorage. */class OPENTELEMETRY_EXPORT RuntimeContextStorage{public:  /**   * Return the current context.   * @return the current context   */  virtual Context GetCurrent() noexcept = 0;  /**   * Set the current context.   * @param the new current context   * @return a token for the new current context. This never returns a nullptr.   */  virtual nostd::unique_ptr<Token> Attach(const Context &context) noexcept = 0;  /**   * Detach the context related to the given token.   * @param token a token related to a context   * @return true if the context could be detached   */  virtual bool Detach(Token &token) noexcept = 0;  virtual ~RuntimeContextStorage() {}protected:  nostd::unique_ptr<Token> CreateToken(const Context &context) noexcept  {    return nostd::unique_ptr<Token>(new Token(context));  }};/** * Construct and return the default RuntimeContextStorage * @return a ThreadLocalContextStorage */static RuntimeContextStorage *GetDefaultStorage() noexcept;// Provides a wrapper for propagating the context object globally.//// By default, a thread-local runtime context storage is used.class OPENTELEMETRY_EXPORT RuntimeContext{public:  // Return the current context.  static Context GetCurrent() noexcept { return GetRuntimeContextStorage()->GetCurrent(); }  // Sets the current 'Context' object. Returns a token  // that can be used to reset to the previous Context.  static nostd::unique_ptr<Token> Attach(const Context &context) noexcept  {    return GetRuntimeContextStorage()->Attach(context);  }  // Resets the context to a previous value stored in the  // passed in token. Returns true if successful, false otherwise  static bool Detach(Token &token) noexcept { return GetRuntimeContextStorage()->Detach(token); }  // Sets the Key and Value into the passed in context or if a context is not  // passed in, the RuntimeContext.  // Should be used to SetValues to the current RuntimeContext, is essentially  // equivalent to RuntimeContext::GetCurrent().SetValue(key,value). Keep in  // mind that the current RuntimeContext will not be changed, and the new  // context will be returned.  static Context SetValue(nostd::string_view key,                          const ContextValue &value,                          Context *context = nullptr) noexcept  {    Context temp_context;    if (context == nullptr)    {      temp_context = GetCurrent();    }    else    {      temp_context = *context;    }    return temp_context.SetValue(key, value);  }  // Returns the value associated with the passed in key and either the  // passed in context* or the runtime context if a context is not passed in.  // Should be used to get values from the current RuntimeContext, is  // essentially equivalent to RuntimeContext::GetCurrent().GetValue(key).  static ContextValue GetValue(nostd::string_view key, Context *context = nullptr) noexcept  {    Context temp_context;    if (context == nullptr)    {      temp_context = GetCurrent();    }    else    {      temp_context = *context;    }    return temp_context.GetValue(key);  }  /**   * Provide a custom runtime context storage.   *   * This provides a possibility to override the default thread-local runtime   * context storage. This has to be set before any spans are created by the   * application, otherwise the behavior is undefined.   *   * @param storage a custom runtime context storage   */  static void SetRuntimeContextStorage(      const nostd::shared_ptr<RuntimeContextStorage> &storage) noexcept  {    GetStorage() = storage;  }  /**   * Provide a pointer to const runtime context storage.   *   * The returned pointer can only be used for extending the lifetime of the runtime context   * storage.   *   */  static nostd::shared_ptr<const RuntimeContextStorage> GetConstRuntimeContextStorage() noexcept  {    return GetRuntimeContextStorage();  }private:  static nostd::shared_ptr<RuntimeContextStorage> GetRuntimeContextStorage() noexcept  {    return GetStorage();  }  OPENTELEMETRY_API_SINGLETON static nostd::shared_ptr<RuntimeContextStorage> &GetStorage() noexcept  {    static nostd::shared_ptr<RuntimeContextStorage> context(GetDefaultStorage());    return context;  }};inline Token::~Token() noexcept{  context::RuntimeContext::Detach(*this);}// The ThreadLocalContextStorage class is a derived class from// RuntimeContextStorage and provides a wrapper for propagating context through// cpp thread locally. This file must be included to use the RuntimeContext// class if another implementation has not been registered.class ThreadLocalContextStorage : public RuntimeContextStorage{public:  ThreadLocalContextStorage() noexcept = default;  // Return the current context.  Context GetCurrent() noexcept override { return GetStack().Top(); }  // Resets the context to the value previous to the passed in token. This will  // also detach all child contexts of the passed in token.  // Returns true if successful, false otherwise.  bool Detach(Token &token) noexcept override  {    // In most cases, the context to be detached is on the top of the stack.    if (token == GetStack().Top())    {      GetStack().Pop();      return true;    }    if (!GetStack().Contains(token))    {      return false;    }    while (!(token == GetStack().Top()))    {      GetStack().Pop();    }    GetStack().Pop();    return true;  }  // Sets the current 'Context' object. Returns a token  // that can be used to reset to the previous Context.  nostd::unique_ptr<Token> Attach(const Context &context) noexcept override  {    GetStack().Push(context);    return CreateToken(context);  }private:  // A nested class to store the attached contexts in a stack.  class Stack  {    friend class ThreadLocalContextStorage;    Stack() noexcept : size_(0), capacity_(0), base_(nullptr) {}    // Pops the top Context off the stack.    void Pop() noexcept    {      if (size_ == 0)      {        return;      }      // Store empty Context before decrementing `size`, to ensure      // the shared_ptr object (if stored in prev context object ) are released.      // The stack is not resized, and the unused memory would be reutilised      // for subsequent context storage.      base_[size_ - 1] = Context();      size_ -= 1;    }    bool Contains(const Token &token) const noexcept    {      for (size_t pos = size_; pos > 0; --pos)      {        if (token == base_[pos - 1])        {          return true;        }      }      return false;    }    // Returns the Context at the top of the stack.    Context Top() const noexcept    {      if (size_ == 0)      {        return Context();      }      return base_[size_ - 1];    }    // Pushes the passed in context pointer to the top of the stack    // and resizes if necessary.    void Push(const Context &context) noexcept    {      size_++;      if (size_ > capacity_)      {        Resize(size_ * 2);      }      base_[size_ - 1] = context;    }    // Reallocates the storage array to the pass in new capacity size.    void Resize(size_t new_capacity) noexcept    {      size_t old_size = size_ - 1;      if (new_capacity == 0)      {        new_capacity = 2;      }      Context *temp = new Context[new_capacity];      if (base_ != nullptr)      {        // vs2015 does not like this construct considering it unsafe:        // - std::copy(base_, base_ + old_size, temp);        // Ref.        // https://stackoverflow.com/questions/12270224/xutility2227-warning-c4996-std-copy-impl        for (size_t i = 0; i < (std::min)(old_size, new_capacity); i++)        {          temp[i] = base_[i];        }        delete[] base_;      }      base_     = temp;      capacity_ = new_capacity;    }    ~Stack() noexcept { delete[] base_; }    size_t size_;    size_t capacity_;    Context *base_;  };  OPENTELEMETRY_API_SINGLETON Stack &GetStack()  {    static thread_local Stack stack_ = Stack();    return stack_;  }};static RuntimeContextStorage *GetDefaultStorage() noexcept{  return new ThreadLocalContextStorage();}}  // namespace contextOPENTELEMETRY_END_NAMESPACE
 |