// acquires only one lock
 void append(pointer value) {
   CAF_REQUIRE(value != nullptr);
   node* tmp = new node(value);
   lock_guard guard(m_tail_lock);
   // publish & swing last forward
   m_tail.load()->next = tmp;
   m_tail = tmp;
 }
Ejemplo n.º 2
0
 bool match_element(size_t pos, uint16_t typenr,
                    const std::type_info* rtti) const override {
   CAF_REQUIRE(pos < size());
   auto& et = m_types[pos];
   if (et.first != typenr) {
     return false;
   }
   return et.first != 0 || et.second == rtti || *et.second == *rtti;
 }
Ejemplo n.º 3
0
 bool match_element(size_t pos, uint16_t typenr,
                    const std::type_info* rtti) const override {
   CAF_REQUIRE(typenr != 0 || rtti != nullptr);
   auto uti = m_elements[pos]->ti;
   if (uti->type_nr() != typenr) {
     return false;
   }
   return typenr != 0 || uti->equal_to(*rtti);
 }
 // acquires both locks, returns nullptr on failure
 pointer take_tail() {
   pointer result = nullptr;
   unique_node_ptr last;
   { // lifetime scope of guards
     lock_guard guard1(m_head_lock);
     lock_guard guard2(m_tail_lock);
     CAF_REQUIRE(m_head != nullptr);
     last.reset(m_tail.load());
     if (last.get() == m_head.load()) {
       last.release();
       return nullptr;
     }
     result = last->value;
     m_tail = find_predecessor(last.get());
     CAF_REQUIRE(m_tail != nullptr);
     m_tail.load()->next = nullptr;
   }
   return result;
 }
 // acquires both locks
 void prepend(pointer value) {
   CAF_REQUIRE(value != nullptr);
   node* tmp = new node(value);
   node* first = nullptr;
   // acquire both locks since we might touch m_last too
   lock_guard guard1(m_head_lock);
   lock_guard guard2(m_tail_lock);
   first = m_head.load();
   CAF_REQUIRE(first != nullptr);
   auto next = first->next.load();
   // m_first always points to a dummy with no value,
   // hence we put the new element second
   if (next == nullptr) {
     // queue is empty
     CAF_REQUIRE(first == m_tail);
     m_tail = tmp;
   } else {
     CAF_REQUIRE(first != m_tail);
     tmp->next = next;
   }
   first->next = tmp;
 }
Ejemplo n.º 6
0
 msg_type filter_msg(Actor* self, mailbox_element* node) {
   const message& msg = node->msg;
   auto mid = node->mid;
   if (msg.size() == 1) {
     if (msg.type_at(0)->equal_to(typeid(exit_msg))) {
       auto& em = msg.get_as<exit_msg>(0);
       CAF_REQUIRE(!mid.valid());
       // make sure to get rid of attachables if they're no longer needed
       self->unlink_from(em.source);
       if (self->trap_exit() == false) {
         if (em.reason != exit_reason::normal) {
           self->quit(em.reason);
           return msg_type::non_normal_exit;
         }
         return msg_type::normal_exit;
       }
     } else if (msg.type_at(0)->equal_to(typeid(timeout_msg))) {
       auto& tm = msg.get_as<timeout_msg>(0);
       auto tid = tm.timeout_id;
       CAF_REQUIRE(!mid.valid());
       if (self->is_active_timeout(tid)) {
         return msg_type::timeout;
       }
       return self->waits_for_timeout(tid) ? msg_type::inactive_timeout
                                           : msg_type::expired_timeout;
     } else if (msg.type_at(0)->equal_to(typeid(sync_timeout_msg))
                && mid.is_response()) {
       return msg_type::timeout_response;
     }
   }
   if (mid.is_response()) {
     return self->awaits(mid) ? msg_type::sync_response
                              : msg_type::expired_sync_response;
   }
   return msg_type::ordinary;
 }
bool abstract_actor::unlink_from_impl(const actor_addr& other) {
  if (!other) {
    return false;
  }
  guard_type guard{m_mtx};
  // remove_backlink returns true if this actor is linked to other
  auto ptr = actor_cast<abstract_actor_ptr>(other);
  if (!exited() && ptr->remove_backlink(address())) {
    auto i = std::find(m_links.begin(), m_links.end(), ptr);
    CAF_REQUIRE(i != m_links.end());
    m_links.erase(i);
    return true;
  }
  return false;
}
Ejemplo n.º 8
0
void replace_all(std::string& str,
                 const char (&what)[WhatSize],
                 const char (&with)[WithSize]) {
  // end(what) - 1 points to the null-terminator
  auto next = [&](std::string::iterator pos) -> std::string::iterator {
    return std::search(pos, str.end(), std::begin(what), std::end(what) - 1);
  };
  auto i = next(std::begin(str));
  while (i != std::end(str)) {
    auto before = std::distance(std::begin(str), i);
    CAF_REQUIRE(before >= 0);
    str.replace(i, i + WhatSize - 1, with);
    // i became invalidated -> use new iterator pointing
    // to the first character after the replaced text
    i = next(str.begin() + before + (WithSize - 1));
  }
}
Ejemplo n.º 9
0
void actor_namespace::write(serializer* sink, const actor_addr& addr) {
  CAF_REQUIRE(sink != nullptr);
  if (!addr) {
    node_id::host_id_type zero;
    std::fill(zero.begin(), zero.end(), 0);
    sink->write_value(static_cast<actor_id>(0));         // actor id
    sink->write_raw(node_id::host_id_size, zero.data()); // host id
    sink->write_value(static_cast<uint32_t>(0));         // process id
  } else {
    // register locally running actors to be able to deserialize them later
    if (!addr.is_remote()) {
      auto reg = detail::singletons::get_actor_registry();
      reg->put(addr.id(), actor_cast<abstract_actor_ptr>(addr));
    }
    auto pinf = addr.node();
    sink->write_value(addr.id());                                  // actor id
    sink->write_raw(node_id::host_id_size, pinf.host_id().data()); // host id
    sink->write_value(pinf.process_id());                          // process id
  }
}
Ejemplo n.º 10
0
 uint64_t get_cache_entry(const std::type_info* type_token,
                          const Tuple& value) {
   CAF_REQUIRE(type_token != nullptr);
   if (value.dynamically_typed()) {
     return m_dummy.second; // all groups enabled
   }
   size_t i = find_token_pos(type_token);
   // if we didn't found a cache entry ...
   if (i == m_cache_end) {
     // ... 'create' one (override oldest element in cache if full)
     advance_(m_cache_end);
     if (m_cache_end == m_cache_begin) {
       advance_(m_cache_begin);
     }
     m_cache[i].first = type_token;
     idx_token_type idx_token;
     m_cache[i].second = calc_bitmask(m_cases, idx_token, *type_token, value);
   }
   return m_cache[i].second;
 }
Ejemplo n.º 11
0
actor_addr actor_namespace::read(deserializer* source) {
  CAF_REQUIRE(source != nullptr);
  node_id::host_id_type hid;
  auto aid = source->read<uint32_t>();                 // actor id
  source->read_raw(node_id::host_id_size, hid.data()); // host id
  auto pid = source->read<uint32_t>();                 // process id
  node_id this_node = detail::singletons::get_node_id();
  if (aid == 0 && pid == 0) {
    // 0:0 identifies an invalid actor
    return invalid_actor_addr;
  }
  if (pid == this_node.process_id() && hid == this_node.host_id()) {
    // identifies this exact process on this host, ergo: local actor
    auto a = detail::singletons::get_actor_registry()->get(aid);
    // might be invalid
    return a ? a->address() : invalid_actor_addr;
  }
  // identifies a remote actor; create proxy if needed
  return get_or_put({pid, hid}, aid)->address();
}
Ejemplo n.º 12
0
void abstract_actor::cleanup(uint32_t reason) {
  // log as 'actor'
  CAF_LOGM_TRACE("caf::actor", CAF_ARG(m_id) << ", " << CAF_ARG(reason) << ", "
                                             << CAF_ARG(m_is_proxy));
  CAF_REQUIRE(reason != exit_reason::not_exited);
  // move everyhting out of the critical section before processing it
  decltype(m_links) mlinks;
  decltype(m_attachables) mattachables;
  { // lifetime scope of guard
    guard_type guard{m_mtx};
    if (m_exit_reason != exit_reason::not_exited) {
      // already exited
      return;
    }
    m_exit_reason = reason;
    mlinks = std::move(m_links);
    mattachables = std::move(m_attachables);
    // make sure lists are empty
    m_links.clear();
    m_attachables.clear();
  }
  CAF_LOG_INFO_IF(!is_remote(), "actor with ID "
                                << m_id << " had " << mlinks.size()
                                << " links and " << mattachables.size()
                                << " attached functors; exit reason = "
                                << reason << ", class = "
                                << detail::demangle(typeid(*this)));
  // send exit messages
  auto msg = make_message(exit_msg{address(), reason});
  CAF_LOGM_DEBUG("caf::actor", "send EXIT to " << mlinks.size() << " links");
  for (auto& aptr : mlinks) {
    aptr->enqueue(address(), message_id {}.with_high_priority(), msg, m_host);
  }
  CAF_LOGM_DEBUG("caf::actor", "run " << mattachables.size() << " attachables");
  for (attachable_ptr& ptr : mattachables) {
    ptr->actor_exited(reason);
  }
}
Ejemplo n.º 13
0
 void run() {
   CAF_LOG_TRACE("worker with ID " << m_id);
   // scheduling loop
   for (;;) {
     auto job = m_queue_policy.internal_dequeue(this);
     CAF_REQUIRE(job != nullptr);
     CAF_LOG_DEBUG("resume actor " << id_of(job));
     CAF_PUSH_AID_FROM_PTR(dynamic_cast<abstract_actor*>(job));
     switch (job->resume(this)) {
       case resumable::done: {
         job->detach_from_scheduler();
         break;
       }
       case resumable::resume_later: {
         break;
       }
       case resumable::shutdown_execution_unit: {
         m_queue_policy.clear_internal_queue(this);
         return;
       }
     }
     m_queue_policy.assert_stealable(this);
   }
 }
Ejemplo n.º 14
0
remote_actor_proxy::remote_actor_proxy(actor_id aid, node_id nid, actor parent)
    : super(aid, nid), m_parent(parent) {
  CAF_REQUIRE(parent != invalid_actor);
  CAF_LOG_INFO(CAF_ARG(aid) << ", " << CAF_TARG(nid, to_string));
}
Ejemplo n.º 15
0
const uniform_type_info* uniform_typeid_by_nr(uint16_t nr) {
  CAF_REQUIRE(nr > 0 && nr < detail::type_nrs);
  return uti_map().by_type_nr(nr);
}
Ejemplo n.º 16
0
 const uniform_type_info* type_at(size_t pos) const {
   CAF_REQUIRE(pos < size());
   return m_types[pos];
 }
Ejemplo n.º 17
0
 resumable::resume_result resume(execution_unit* new_host,
                                 size_t max_throughput) override {
   CAF_REQUIRE(max_throughput > 0);
   auto d = static_cast<Derived*>(this);
   CAF_LOG_TRACE("id = " << d->id());
   d->host(new_host);
   auto done_cb = [&]() -> bool {
     CAF_LOG_TRACE("");
     d->bhvr_stack().clear();
     d->bhvr_stack().cleanup();
     d->on_exit();
     if (!d->bhvr_stack().empty()) {
       CAF_LOG_DEBUG("on_exit did set a new behavior");
       d->planned_exit_reason(exit_reason::not_exited);
       return false; // on_exit did set a new behavior
     }
     auto rsn = d->planned_exit_reason();
     if (rsn == exit_reason::not_exited) {
       rsn = exit_reason::normal;
       d->planned_exit_reason(rsn);
     }
     d->cleanup(rsn);
     return true;
   };
   auto actor_done = [&]() -> bool {
     if (d->bhvr_stack().empty()
         || d->planned_exit_reason() != exit_reason::not_exited) {
       return done_cb();
     }
     return false;
   };
   // actors without behavior or that have already defined
   // an exit reason must not be resumed
   CAF_REQUIRE(!d->is_initialized()
               || (!d->bhvr_stack().empty()
                   && d->planned_exit_reason() == exit_reason::not_exited));
   std::exception_ptr eptr = nullptr;
   try {
     if (!d->is_initialized()) {
       CAF_LOG_DEBUG("initialize actor");
       d->is_initialized(true);
       auto bhvr = d->make_behavior();
       CAF_LOG_DEBUG_IF(!bhvr, "make_behavior() did not return a behavior, "
                               << "bhvr_stack().empty() = "
                               << std::boolalpha << d->bhvr_stack().empty());
       if (bhvr) {
         // make_behavior() did return a behavior instead of using become()
         CAF_LOG_DEBUG("make_behavior() did return a valid behavior");
         d->become(std::move(bhvr));
       }
       if (actor_done()) {
         CAF_LOG_DEBUG("actor_done() returned true right "
                       << "after make_behavior()");
         return resume_result::done;
       }
     }
     // max_throughput = 0 means infinite
     for (size_t i = 0; i < max_throughput; ++i) {
       auto ptr = d->next_message();
       if (ptr) {
         if (d->invoke_message(ptr)) {
           if (actor_done()) {
             CAF_LOG_DEBUG("actor exited");
             return resume_result::done;
           }
           // continue from cache if current message was
           // handled, because the actor might have changed
           // its behavior to match 'old' messages now
           while (d->invoke_message_from_cache()) {
             if (actor_done()) {
               CAF_LOG_DEBUG("actor exited");
               return resume_result::done;
             }
           }
         }
         // add ptr to cache if invoke_message
         // did not reset it (i.e. skipped, but not dropped)
         if (ptr) {
           CAF_LOG_DEBUG("add message to cache");
           d->push_to_cache(std::move(ptr));
         }
       } else {
         CAF_LOG_DEBUG("no more element in mailbox; going to block");
         if (d->mailbox().try_block()) {
           return resumable::awaiting_message;
         }
         CAF_LOG_DEBUG("try_block() interrupted by new message");
       }
     }
     if (!d->has_next_message() && d->mailbox().try_block()) {
       return resumable::awaiting_message;
     }
     // time's up
     return resumable::resume_later;
   }
   catch (actor_exited& what) {
     CAF_LOG_INFO("actor died because of exception: actor_exited, "
                  "reason = " << what.reason());
     if (d->exit_reason() == exit_reason::not_exited) {
       d->quit(what.reason());
     }
   }
   catch (std::exception& e) {
     CAF_LOG_INFO("actor died because of an exception: "
                  << detail::demangle(typeid(e))
                  << ", what() = " << e.what());
     if (d->exit_reason() == exit_reason::not_exited) {
       d->quit(exit_reason::unhandled_exception);
     }
     eptr = std::current_exception();
   }
   catch (...) {
     CAF_LOG_INFO("actor died because of an unknown exception");
     if (d->exit_reason() == exit_reason::not_exited) {
       d->quit(exit_reason::unhandled_exception);
     }
     eptr = std::current_exception();
   }
   if (eptr) {
     auto opt_reason = d->handle(eptr);
     if (opt_reason) {
       // use exit reason defined by custom handler
       d->planned_exit_reason(*opt_reason);
     }
   }
   if (!actor_done()) {
     // actor has been "revived", try running it again later
     return resumable::resume_later;
   }
   return resumable::done;
 }
Ejemplo n.º 18
0
 T& get() {
   CAF_REQUIRE(valid());
   return *m_value;
 }
Ejemplo n.º 19
0
inline bool local_actor::awaits(message_id response_id) {
  CAF_REQUIRE(response_id.is_response());
  return std::any_of(m_pending_responses.begin(), m_pending_responses.end(),
             [=](message_id other) { return response_id == other; });
}
Ejemplo n.º 20
0
void decorated_tuple::init() {
  CAF_REQUIRE(m_mapping.empty()
              || *(std::max_element(m_mapping.begin(), m_mapping.end()))
                 < static_cast<const pointer&>(m_decorated)->size());
}
Ejemplo n.º 21
0
const uniform_type_info* decorated_tuple::type_at(size_t pos) const {
  CAF_REQUIRE(pos < size());
  return m_decorated->type_at(m_mapping[pos]);
}
Ejemplo n.º 22
0
const void* decorated_tuple::at(size_t pos) const {
  CAF_REQUIRE(pos < size());
  return m_decorated->at(m_mapping[pos]);
}
Ejemplo n.º 23
0
void* decorated_tuple::mutable_at(size_t pos) {
  CAF_REQUIRE(pos < size());
  return m_decorated->mutable_at(m_mapping[pos]);
}
Ejemplo n.º 24
0
 const void* at(size_t pos) const {
   CAF_REQUIRE(pos < size());
   return tup_ptr_access<0, sizeof...(Ts)>::get(pos, m_data);
 }
Ejemplo n.º 25
0
 void* mutable_at(size_t pos) {
   CAF_REQUIRE(pos < size());
   return const_cast<void*>(at(pos));
 }
Ejemplo n.º 26
0
 const T* operator->() const {
   CAF_REQUIRE(valid());
   return m_value;
 }
Ejemplo n.º 27
0
 /**
  * Enqueues a new job to the worker's queue from an internal
  * source, i.e., a job that is currently executed by this worker.
  * @warning Must not be called from other threads.
  */
 void exec_later(job_ptr job) override {
   CAF_REQUIRE(job != nullptr);
   CAF_LOG_TRACE("id = " << id() << " actor id " << id_of(job));
   m_queue_policy.internal_enqueue(this, job);
 }
Ejemplo n.º 28
0
 const T& operator*() const {
   CAF_REQUIRE(valid());
   return *m_value;
 }
Ejemplo n.º 29
0
response_promise::response_promise(const actor_addr& from, const actor_addr& to,
                                   const message_id& id)
    : m_from(from), m_to(to), m_id(id) {
  CAF_REQUIRE(id.is_response() || !id.valid());
}
Ejemplo n.º 30
0
 const T& get() const {
   CAF_REQUIRE(valid());
   return *m_value;
 }