예제 #1
0
 continue_writing_result continue_writing() override {
     CPPA_LOG_TRACE("");
     CPPA_LOG_DEBUG_IF(!m_has_unwritten_data, "nothing to write (done)");
     while (m_has_unwritten_data) {
         size_t written;
         try { written = m_out->write_some(m_buf.data(), m_buf.size()); }
         catch (std::exception& e) {
             CPPA_LOG_ERROR(to_verbose_string(e));
             static_cast<void>(e); // keep compiler happy
             return write_failure;
         }
         if (written != m_buf.size()) {
             CPPA_LOG_DEBUG("tried to write " << m_buf.size() << "bytes, "
                            << "only " << written << " bytes written");
             m_buf.erase_leading(written);
             return write_continue_later;
         }
         else {
             m_buf.clear();
             m_has_unwritten_data = false;
             CPPA_LOG_DEBUG("write done, " << written << " bytes written");
         }
     }
     return write_done;
 }
void middleman_event_handler::alteration(continuable* ptr,
                                         event_bitmask e,
                                         fd_meta_event etype) {
    native_socket_type fd;
    switch (e) {
        case event::read:
            fd = ptr->read_handle();
            break;
        case event::write: {
            fd = ptr->write_handle();
            break;
        }
        case event::both: {
            fd = ptr->read_handle();
            auto wrfd = ptr->write_handle();
            if (fd != wrfd) {
                CPPA_LOG_DEBUG("read_handle != write_handle, split "
                               "into two function calls");
                // split into two function calls
                e = event::read;
                alteration(ptr, event::write, etype);
            }
            break;
        }
        default:
            CPPA_CRITICAL("invalid bitmask");
            return;
    }
    m_alterations.emplace_back(fd_meta_info(fd, ptr, e), etype);
}
예제 #3
0
void local_actor::join(const group& what) {
    CPPA_LOG_TRACE(CPPA_TSARG(what));
    if (what && m_subscriptions.count(what) == 0) {
        CPPA_LOG_DEBUG("join group: " << to_string(what));
        m_subscriptions.insert(std::make_pair(what, what->subscribe(this)));
    }
}
예제 #4
0
 void register_for_writing() {
     if (!m_has_unwritten_data) {
         CPPA_LOG_DEBUG("register for writing");
         m_has_unwritten_data = true;
         m_middleman->continue_writer(this);
     }
 }
void middleman_event_handler::update() {
    CPPA_LOG_TRACE("");
    auto mless = [](const fd_meta_info& lhs, native_socket_type rhs) {
        return lhs.fd < rhs;
    };
    for (auto& elem_pair : m_alterations) {
        auto& elem = elem_pair.first;
        auto old = event::none;
        auto last = m_meta.end();
        auto iter = std::lower_bound(m_meta.begin(), last, elem.fd, mless);
        if (iter != last) old = iter->mask;
        auto mask = next_bitmask(old, elem.mask, elem_pair.second);
        auto ptr = elem.ptr;
        CPPA_LOG_DEBUG("new bitmask for "
                       << elem.ptr << ": " << eb2str(mask));
        if (iter == last || iter->fd != elem.fd) {
            CPPA_LOG_ERROR_IF(mask == event::none,
                              "cannot erase " << ptr << " (no such element)");
            if (mask != event::none) {
                m_meta.insert(iter, elem);
                handle_event(fd_meta_event::add, elem.fd,
                             event::none, mask, ptr);
            }
        }
        else if (iter->fd == elem.fd) {
            CPPA_REQUIRE(iter->ptr == elem.ptr);
            if (mask == event::none) {
                // note: we cannot decide whether it's safe to dispose `ptr`,
                // because we didn't parse all alterations yet
                m_dispose_list.emplace_back(ptr);
                m_meta.erase(iter);
                handle_event(fd_meta_event::erase, elem.fd, old, mask, ptr);
            }
            else {
                iter->mask = mask;
                handle_event(fd_meta_event::mod, elem.fd, old, mask, ptr);
            }
        }
    }
    m_alterations.clear();
    // m_meta won't be touched inside loop
    auto first = m_meta.begin();
    auto last = m_meta.end();
    auto is_alive = [&](native_socket_type fd) -> bool {
        auto iter = std::lower_bound(first, last, fd, mless);
        return iter != last && iter->fd == fd;
    };
    // check whether elements in dispose list can be safely deleted
    for (auto elem : m_dispose_list) {
        auto rd = elem->read_handle();
        auto wr = elem->write_handle();
        if  ( (rd == wr && !is_alive(rd))
           || (rd != wr && !is_alive(rd) && !is_alive(wr))) {
           elem->dispose();
        }
    }
    m_dispose_list.clear();
}
예제 #6
0
actor_registry::value_type actor_registry::get_entry(actor_id key) const {
    shared_guard guard(m_instances_mtx);
    auto i = m_entries.find(key);
    if (i != m_entries.end()) {
        return i->second;
    }
    CPPA_LOG_DEBUG("no cache entry found for " << CPPA_ARG(key));
    return {nullptr, exit_reason::not_exited};
}
예제 #7
0
 void send_to_acquaintances(const any_tuple& what) {
     // send to all remote subscribers
     auto sender = last_sender();
     CPPA_LOG_DEBUG("forward message to " << m_acquaintances.size()
                    << " acquaintances; " << CPPA_TSARG(sender)
                    << ", " << CPPA_TSARG(what));
     for (auto& acquaintance : m_acquaintances) {
         acquaintance->enqueue({sender, acquaintance}, what);
     }
 }
예제 #8
0
void thread_pool_scheduler::destroy() {
    CPPA_LOG_TRACE("");
    m_queue.push_back(&m_dummy);
    CPPA_LOG_DEBUG("join supervisor");
    m_supervisor.join();
    // make sure job queue is empty, because destructor of m_queue would
    // otherwise delete elements it shouldn't
    CPPA_LOG_DEBUG("flush queue");
    auto ptr = m_queue.try_pop();
    while (ptr != nullptr) {
        if (ptr != &m_dummy) {
            /*FIXME bool hidden = ptr->is_hidden();
            ptr->deref();
            std::atomic_thread_fence(std::memory_order_seq_cst);
            if (!hidden)*/ get_actor_registry()->dec_running();
        }
        ptr = m_queue.try_pop();
    }
    super::destroy();
}
예제 #9
0
 void operator()() {
     CPPA_LOG_TRACE("");
     detail::cs_thread fself;
     job_ptr job = nullptr;
     for (;;) {
         aggressive(job) || moderate(job) || relaxed(job);
         CPPA_LOG_DEBUG("dequeued new job");
         if (job == m_dummy) {
             CPPA_LOG_DEBUG("received dummy (quit)");
             // dummy of doom received ...
             m_job_queue->push_back(job); // kill the next guy
             return;                      // and say goodbye
         }
         if (job->resume(&fself) == resumable::done) {
             CPPA_LOG_DEBUG("actor is done");
             /*FIXME bool hidden = job->is_hidden();
             job->deref();
             if (!hidden)*/ get_actor_registry()->dec_running();
         }
         job = nullptr;
     }
 }
예제 #10
0
 void alteration(const continuable_reader_ptr& ptr,
                 event_bitmask e,
                 fd_meta_event etype) {
     native_socket_type fd;
     switch (e) {
         case event::read:
             fd = ptr->read_handle();
             break;
         case event::write: {
             auto wptr = ptr->as_io();
             if (wptr) fd = wptr->write_handle();
             else {
                 CPPA_LOG_ERROR("ptr->downcast() returned nullptr");
                 return;
             }
             break;
         }
         case event::both: {
             fd = ptr->read_handle();
             auto wptr = ptr->as_io();
             if (wptr) {
                 auto wrfd = wptr->write_handle();
                 if (fd != wrfd) {
                     CPPA_LOG_DEBUG("read_handle != write_handle, split "
                                    "into two function calls");
                     // split into two function calls
                     e = event::read;
                     alteration(ptr, event::write, etype);
                 }
             }
             else {
                 CPPA_LOG_ERROR("ptr->downcast() returned nullptr");
                 return;
             }
             break;
         }
         default:
             CPPA_LOG_ERROR("invalid bitmask");
             return;
     }
     m_alterations.emplace_back(fd_meta_info(fd, ptr, e), etype);
 }
예제 #11
0
 void update() {
     CPPA_LOG_TRACE("");
     for (auto& elem_pair : m_alterations) {
         auto& elem = elem_pair.first;
         auto old = event::none;
         auto last = end(m_meta);
         auto iter = lower_bound(begin(m_meta), last, elem.fd, m_less);
         if (iter != last) old = iter->mask;
         auto mask = next_bitmask(old, elem.mask, elem_pair.second);
         auto ptr = elem.ptr.get();
         CPPA_LOG_DEBUG("new bitmask for "
                        << elem.ptr.get() << ": " << eb2str(mask));
         if (iter == last || iter->fd != elem.fd) {
             CPPA_LOG_INFO_IF(mask == event::none,
                              "cannot erase " << ptr
                              << " (not found in m_meta)");
             if (mask != event::none) {
                 m_meta.insert(iter, elem);
                 d()->handle_event(fd_meta_event::add, elem.fd,
                              event::none, mask, ptr);
             }
         }
         else if (iter->fd == elem.fd) {
             CPPA_REQUIRE(iter->ptr == elem.ptr);
             if (mask == event::none) {
                 m_meta.erase(iter);
                 d()->handle_event(fd_meta_event::erase, elem.fd, old, mask, ptr);
             }
             else {
                 iter->mask = mask;
                 d()->handle_event(fd_meta_event::mod, elem.fd, old, mask, ptr);
             }
         }
     }
     m_alterations.clear();
 }
void default_actor_addressing::write(serializer* sink, const actor_ptr& ptr) {
    CPPA_REQUIRE(sink != nullptr);
    if (ptr == nullptr) {
        CPPA_LOG_DEBUG("serialize nullptr");
        sink->write_value(static_cast<actor_id>(0));
        process_information::serialize_invalid(sink);
    }
    else {
        // local actor?
        if (!ptr->is_proxy()) {
            get_actor_registry()->put(ptr->id(), ptr);
        }
        auto pinf = m_pinf;
        if (ptr->is_proxy()) {
            auto dptr = ptr.downcast<default_actor_proxy>();
            if (dptr) pinf = dptr->process_info();
            else CPPA_LOG_ERROR("downcast failed");
        }
        sink->write_value(ptr->id());
        sink->write_value(pinf->process_id());
        sink->write_raw(process_information::node_id_size,
                        pinf->node_id().data());
    }
}
예제 #13
0
 resumable::resume_result resume(detail::cs_thread*,
                                 execution_unit* host) override {
     auto d = static_cast<Derived*>(this);
     d->m_host = host;
     CPPA_LOG_TRACE("id = " << d->id());
     auto done_cb = [&]() -> bool {
         CPPA_LOG_TRACE("");
         d->bhvr_stack().clear();
         d->bhvr_stack().cleanup();
         d->on_exit();
         if (!d->bhvr_stack().empty()) {
             CPPA_LOG_DEBUG("on_exit did set a new behavior in on_exit");
             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 = [&] {
         return    d->bhvr_stack().empty()
                || d->planned_exit_reason() != exit_reason::not_exited;
     };
     // actors without behavior or that have already defined
     // an exit reason must not be resumed
     CPPA_REQUIRE(!d->m_initialized || !actor_done());
     if (!d->m_initialized) {
         d->m_initialized = true;
         auto bhvr = d->make_behavior();
         if (bhvr) d->become(std::move(bhvr));
         // else: make_behavior() might have just called become()
         if (actor_done() && done_cb()) return resume_result::done;
         // else: enter resume loop
     }
     try {
         for (;;) {
             auto ptr = d->next_message();
             if (ptr) {
                 if (d->invoke_message(ptr)) {
                     if (actor_done() && done_cb()) {
                         CPPA_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() && done_cb()) {
                             CPPA_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) {
                     CPPA_LOG_DEBUG("add message to cache");
                     d->push_to_cache(std::move(ptr));
                 }
             }
             else {
                 CPPA_LOG_DEBUG("no more element in mailbox; "
                                "going to block");
                 if (d->mailbox().try_block()) {
                     return resumable::resume_later;
                 }
                 // else: try again
             }
         }
     }
     catch (actor_exited& what) {
         CPPA_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) {
         CPPA_LOG_WARNING("actor died because of exception: "
                          << detail::demangle(typeid(e))
                          << ", what() = " << e.what());
         if (d->exit_reason() == exit_reason::not_exited) {
             d->quit(exit_reason::unhandled_exception);
         }
     }
     catch (...) {
         CPPA_LOG_WARNING("actor died because of an unknown exception");
         if (d->exit_reason() == exit_reason::not_exited) {
             d->quit(exit_reason::unhandled_exception);
         }
     }
     done_cb();
     return resumable::done;
 }