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