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
21namespace asio {
22namespace 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.
26template <typename Key, typename Value = unsigned char>
27class call_stack
28{
29public:
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
108private:
109  // The top of the stack of calls for the current thread.
110  static tss_ptr<context> top_;
111};
112
113template <typename Key, typename Value>
114tss_ptr<typename call_stack<Key, Value>::context>
115call_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