Home | History | Annotate | Download | only in detail
      1 //
      2 // detail/call_stack.hpp
      3 // ~~~~~~~~~~~~~~~~~~~~~
      4 //
      5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
      6 //
      7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
      8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      9 //
     10 
     11 #ifndef ASIO_DETAIL_CALL_STACK_HPP
     12 #define ASIO_DETAIL_CALL_STACK_HPP
     13 
     14 
     15 #include "asio/detail/config.hpp"
     16 #include "asio/detail/noncopyable.hpp"
     17 #include "asio/detail/tss_ptr.hpp"
     18 
     19 #include "asio/detail/push_options.hpp"
     20 
     21 namespace asio {
     22 namespace detail {
     23 
     24 // Helper class to determine whether or not the current thread is inside an
     25 // invocation of io_service::run() for a specified io_service object.
     26 template <typename Key, typename Value = unsigned char>
     27 class call_stack
     28 {
     29 public:
     30   // Context class automatically pushes the key/value pair on to the stack.
     31   class context
     32     : private noncopyable
     33   {
     34   public:
     35     // Push the key on to the stack.
     36     explicit context(Key* k)
     37       : key_(k),
     38         next_(call_stack<Key, Value>::top_)
     39     {
     40       value_ = reinterpret_cast<unsigned char*>(this);
     41       call_stack<Key, Value>::top_ = this;
     42     }
     43 
     44     // Push the key/value pair on to the stack.
     45     context(Key* k, Value& v)
     46       : key_(k),
     47         value_(&v),
     48         next_(call_stack<Key, Value>::top_)
     49     {
     50       call_stack<Key, Value>::top_ = this;
     51     }
     52 
     53     // Pop the key/value pair from the stack.
     54     ~context()
     55     {
     56       call_stack<Key, Value>::top_ = next_;
     57     }
     58 
     59     // Find the next context with the same key.
     60     Value* next_by_key() const
     61     {
     62       context* elem = next_;
     63       while (elem)
     64       {
     65         if (elem->key_ == key_)
     66           return elem->value_;
     67         elem = elem->next_;
     68       }
     69       return 0;
     70     }
     71 
     72   private:
     73     friend class call_stack<Key, Value>;
     74 
     75     // The key associated with the context.
     76     Key* key_;
     77 
     78     // The value associated with the context.
     79     Value* value_;
     80 
     81     // The next element in the stack.
     82     context* next_;
     83   };
     84 
     85   friend class context;
     86 
     87   // Determine whether the specified owner is on the stack. Returns address of
     88   // key if present, 0 otherwise.
     89   static Value* contains(Key* k)
     90   {
     91     context* elem = top_;
     92     while (elem)
     93     {
     94       if (elem->key_ == k)
     95         return elem->value_;
     96       elem = elem->next_;
     97     }
     98     return 0;
     99   }
    100 
    101   // Obtain the value at the top of the stack.
    102   static Value* top()
    103   {
    104     context* elem = top_;
    105     return elem ? elem->value_ : 0;
    106   }
    107 
    108 private:
    109   // The top of the stack of calls for the current thread.
    110   static tss_ptr<context> top_;
    111 };
    112 
    113 template <typename Key, typename Value>
    114 tss_ptr<typename call_stack<Key, Value>::context>
    115 call_stack<Key, Value>::top_;
    116 
    117 } // namespace detail
    118 } // namespace asio
    119 
    120 #include "asio/detail/pop_options.hpp"
    121 
    122 #endif // ASIO_DETAIL_CALL_STACK_HPP
    123