1 // This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
2 // the main distribution directory for license terms and copyright or visit
3 // https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
4 
5 #pragma once
6 
7 #include <atomic>
8 #include <cstdint>
9 #include <memory>
10 #include <mutex>
11 #include <set>
12 #include <string>
13 #include <type_traits>
14 #include <vector>
15 
16 #include "caf/abstract_channel.hpp"
17 #include "caf/attachable.hpp"
18 #include "caf/detail/core_export.hpp"
19 #include "caf/detail/functor_attachable.hpp"
20 #include "caf/detail/type_traits.hpp"
21 #include "caf/execution_unit.hpp"
22 #include "caf/exit_reason.hpp"
23 #include "caf/fwd.hpp"
24 #include "caf/intrusive_ptr.hpp"
25 #include "caf/mailbox_element.hpp"
26 #include "caf/message_id.hpp"
27 #include "caf/node_id.hpp"
28 
29 namespace caf {
30 
31 /// A unique actor ID.
32 /// @relates abstract_actor
33 using actor_id = uint64_t;
34 
35 /// Denotes an ID that is never used by an actor.
36 constexpr actor_id invalid_actor_id = 0;
37 
38 /// Base class for all actor implementations.
39 class CAF_CORE_EXPORT abstract_actor : public abstract_channel {
40 public:
41   actor_control_block* ctrl() const;
42 
43   ~abstract_actor() override;
44 
45   abstract_actor(const abstract_actor&) = delete;
46   abstract_actor& operator=(const abstract_actor&) = delete;
47 
48   /// Cleans up any remaining state before the destructor is called.
49   /// This function makes sure it is safe to call virtual functions
50   /// in sub classes before destroying the object, because calling
51   /// virtual function in the destructor itself is not safe. Any override
52   /// implementation is required to call `super::destroy()` at the end.
53   virtual void on_destroy();
54 
55   void enqueue(strong_actor_ptr sender, message_id mid, message msg,
56                execution_unit* host) override;
57 
58   /// Enqueues a new message wrapped in a `mailbox_element` to the actor.
59   /// This `enqueue` variant allows to define forwarding chains.
60   virtual void enqueue(mailbox_element_ptr what, execution_unit* host) = 0;
61 
62   /// Attaches `ptr` to this actor. The actor will call `ptr->detach(...)` on
63   /// exit, or immediately if it already finished execution.
64   virtual void attach(attachable_ptr ptr) = 0;
65 
66   /// Convenience function that attaches the functor `f` to this actor. The
67   /// actor executes `f()` on exit or immediately if it is not running.
68   template <class F>
attach_functor(F f)69   void attach_functor(F f) {
70     attach(attachable_ptr{new detail::functor_attachable<F>(std::move(f))});
71   }
72 
73   /// Returns the logical actor address.
74   actor_addr address() const noexcept;
75 
76   /// Detaches the first attached object that matches `what`.
77   virtual size_t detach(const attachable::token& what) = 0;
78 
79   /// Returns the set of accepted messages types as strings or
80   /// an empty set if this actor is untyped.
81   virtual std::set<std::string> message_types() const;
82 
83   /// Returns the ID of this actor.
84   actor_id id() const noexcept;
85 
86   /// Returns the node this actor is living on.
87   node_id node() const noexcept;
88 
89   /// Returns the system that created this actor (or proxy).
90   actor_system& home_system() const noexcept;
91 
92   /****************************************************************************
93    *                 here be dragons: end of public interface                 *
94    ****************************************************************************/
95 
96   /// @cond PRIVATE
97 
98   /// Called by the testing DSL to peek at the next element in the mailbox. Do
99   /// not call this function in production code! The default implementation
100   /// always returns `nullptr`.
101   /// @returns A pointer to the next mailbox element or `nullptr` if the
102   ///          mailbox is empty or the actor does not have a mailbox.
103   virtual mailbox_element* peek_at_next_mailbox_element();
104 
105   template <class... Ts>
eq_impl(message_id mid,strong_actor_ptr sender,execution_unit * ctx,Ts &&...xs)106   void eq_impl(message_id mid, strong_actor_ptr sender, execution_unit* ctx,
107                Ts&&... xs) {
108     enqueue(make_mailbox_element(std::move(sender), mid, {},
109                                  std::forward<Ts>(xs)...),
110             ctx);
111   }
112 
113   // flags storing runtime information                      used by ...
114   static constexpr int has_timeout_flag = 0x0004;      // single_timeout
115   static constexpr int is_registered_flag = 0x0008;    // (several actors)
116   static constexpr int is_initialized_flag = 0x0010;   // event-based actors
117   static constexpr int is_blocking_flag = 0x0020;      // blocking_actor
118   static constexpr int is_detached_flag = 0x0040;      // local_actor
119   static constexpr int collects_metrics_flag = 0x0080; // local_actor
120   static constexpr int is_serializable_flag = 0x0100;  // local_actor
121   static constexpr int is_migrated_from_flag = 0x0200; // local_actor
122   static constexpr int has_used_aout_flag = 0x0400;    // local_actor
123   static constexpr int is_terminated_flag = 0x0800;    // local_actor
124   static constexpr int is_cleaned_up_flag = 0x1000;    // monitorable_actor
125   static constexpr int is_shutting_down_flag = 0x2000; // scheduled_actor
126 
setf(int flag)127   void setf(int flag) {
128     auto x = flags();
129     flags(x | flag);
130   }
131 
unsetf(int flag)132   void unsetf(int flag) {
133     auto x = flags();
134     flags(x & ~flag);
135   }
136 
getf(int flag) const137   bool getf(int flag) const {
138     return (flags() & flag) != 0;
139   }
140 
141   /// Sets `is_registered_flag` and calls `system().registry().inc_running()`.
142   void register_at_system();
143 
144   /// Unsets `is_registered_flag` and calls `system().registry().dec_running()`.
145   void unregister_from_system();
146 
147   /// Causes the actor to establish a link to `other`.
148   virtual void add_link(abstract_actor* other) = 0;
149 
150   /// Causes the actor to remove any established link to `other`.
151   virtual void remove_link(abstract_actor* other) = 0;
152 
153   /// Adds an entry to `other` to the link table of this actor.
154   /// @warning Must be called inside a critical section, i.e.,
155   ///          while holding `mtx_`.
156   virtual bool add_backlink(abstract_actor* other) = 0;
157 
158   /// Removes an entry to `other` from the link table of this actor.
159   /// @warning Must be called inside a critical section, i.e.,
160   ///          while holding `mtx_`.
161   virtual bool remove_backlink(abstract_actor* other) = 0;
162 
163   /// Calls `fun` with exclusive access to an actor's state.
164   template <class F>
exclusive_critical_section(F fun)165   auto exclusive_critical_section(F fun) -> decltype(fun()) {
166     std::unique_lock<std::mutex> guard{mtx_};
167     return fun();
168   }
169 
170   /// Calls `fun` with readonly access to an actor's state.
171   template <class F>
shared_critical_section(F fun)172   auto shared_critical_section(F fun) -> decltype(fun()) {
173     std::unique_lock<std::mutex> guard{mtx_};
174     return fun();
175   }
176 
177   /// Calls `fun` with exclusive access to the state of both `p1` and `p2`. This
178   /// function guarantees that the order of acquiring the locks is always
179   /// identical, independently from the order of `p1` and `p2`.
180   template <class F>
joined_exclusive_critical_section(abstract_actor * p1,abstract_actor * p2,F fun)181   static auto joined_exclusive_critical_section(abstract_actor* p1,
182                                                 abstract_actor* p2, F fun)
183     -> decltype(fun()) {
184     // Make sure to allocate locks always in the same order by starting on the
185     // actor with the lowest address.
186     CAF_ASSERT(p1 != p2 && p1 != nullptr && p2 != nullptr);
187     if (p1 < p2) {
188       std::unique_lock<std::mutex> guard1{p1->mtx_};
189       std::unique_lock<std::mutex> guard2{p2->mtx_};
190       return fun();
191     }
192     std::unique_lock<std::mutex> guard1{p2->mtx_};
193     std::unique_lock<std::mutex> guard2{p1->mtx_};
194     return fun();
195   }
196 
197   /// @endcond
198 
199 protected:
200   explicit abstract_actor(actor_config& cfg);
201 
202   // Guards potentially concurrent access to the state. For example,
203   // `exit_state_`, `attachables_`, and `links_` in a `monitorable_actor`.
204   mutable std::mutex mtx_;
205 };
206 
207 } // namespace caf
208