Beispiel #1
0
bool actor::link_to_impl(const actor_ptr& other) {
    if (other && other != this) {
        guard_type guard{m_mtx};
        // send exit message if already exited
        if (exited()) {
            send_as(this, other, atom("EXIT"), exit_reason());
        }
        // add link if not already linked to other
        // (checked by establish_backlink)
        else if (other->establish_backlink(this)) {
            m_links.push_back(other);
            return true;
        }
    }
    return false;
}
bool abstract_actor::link_to_impl(const actor_addr& other) {
  if (other && other != this) {
    guard_type guard{m_mtx};
    auto ptr = actor_cast<abstract_actor_ptr>(other);
    // send exit message if already exited
    if (exited()) {
      ptr->enqueue(address(), message_id::invalid,
                   make_message(exit_msg{address(), exit_reason()}), m_host);
    }
    // add link if not already linked to other
    // (checked by establish_backlink)
    else if (ptr->establish_backlink(address())) {
      m_links.push_back(ptr);
      return true;
    }
  }
  return false;
}
bool abstract_actor::establish_link_impl(const actor_addr& other) {
  CAF_LOG_TRACE(CAF_TSARG(other));
  if (other && other != this) {
    guard_type guard{mtx_};
    auto ptr = actor_cast<abstract_actor_ptr>(other);
    // send exit message if already exited
    if (exited()) {
      ptr->enqueue(address(), invalid_message_id,
                   make_message(exit_msg{address(), exit_reason()}), host_);
    } else if (ptr->establish_backlink(address())) {
      // add link if not already linked to other
      // (checked by establish_backlink)
      auto tmp = default_attachable::make_link(other);
      attach_impl(tmp);
      return true;
    }
  }
  return false;
}
Beispiel #4
0
bool abstract_actor::link_to_impl(const actor_addr& other) {
    if (other && other != this) {
        guard_type guard{m_mtx};
        auto ptr = detail::raw_access::get(other);
        // send exit message if already exited
        if (exited()) {
            ptr->enqueue({address(), ptr},
                         make_any_tuple(exit_msg{address(), exit_reason()}),
                         m_host);
        }
        // add link if not already linked to other
        // (checked by establish_backlink)
        else if (ptr->establish_backlink(address())) {
            m_links.push_back(ptr);
            return true;
        }
    }
    return false;
}
bool abstract_actor::establish_backlink(const actor_addr& other) {
  uint32_t reason = exit_reason::not_exited;
  if (other && other != this) {
    guard_type guard{m_mtx};
    reason = m_exit_reason;
    if (reason == exit_reason::not_exited) {
      auto i = std::find(m_links.begin(), m_links.end(), other);
      if (i == m_links.end()) {
        m_links.push_back(actor_cast<abstract_actor_ptr>(other));
        return true;
      }
    }
  }
  // send exit message without lock
  if (reason != exit_reason::not_exited) {
    auto ptr = actor_cast<abstract_actor_ptr>(other);
    ptr->enqueue(address(), message_id::invalid,
                 make_message(exit_msg{address(), exit_reason()}), m_host);
  }
  return false;
}
Beispiel #6
0
bool abstract_actor::establish_backlink(const actor_addr& other) {
    std::uint32_t reason = exit_reason::not_exited;
    if (other && other != this) {
        guard_type guard{m_mtx};
        reason = m_exit_reason;
        if (reason == exit_reason::not_exited) {
            auto i = std::find(m_links.begin(), m_links.end(), other);
            if (i == m_links.end()) {
                m_links.push_back(detail::raw_access::get(other));
                return true;
            }
        }
    }
    // send exit message without lock
    if (reason != exit_reason::not_exited) {
        auto ptr = detail::raw_access::unsafe_cast(other);
        ptr->enqueue({address(), ptr},
                     make_any_tuple(exit_msg{address(), exit_reason()}),
                     m_host);
    }
    return false;
}
bool abstract_actor::establish_backlink_impl(const actor_addr& other) {
  CAF_LOG_TRACE(CAF_TSARG(other));
  uint32_t reason = exit_reason::not_exited;
  default_attachable::observe_token tk{other, default_attachable::link};
  if (other && other != this) {
    guard_type guard{mtx_};
    reason = exit_reason_;
    if (reason == exit_reason::not_exited) {
      if (detach_impl(tk, attachables_head_, true, true) == 0) {
        auto tmp = default_attachable::make_link(other);
        attach_impl(tmp);
        return true;
      }
    }
  }
  // send exit message without lock
  if (reason != exit_reason::not_exited) {
    auto ptr = actor_cast<abstract_actor_ptr>(other);
    ptr->enqueue(address(), invalid_message_id,
                 make_message(exit_msg{address(), exit_reason()}), host_);
  }
  return false;
}
Beispiel #8
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;
 }
Beispiel #9
0
/*
 * Called by proc_exit() when a zone's init exits, presumably because
 * it failed.  As long as the given zone is still in the "running"
 * state, we will re-exec() init, but first we need to reset things
 * which are usually inherited across exec() but will break init's
 * assumption that it is being exec()'d from a virgin process.  Most
 * importantly this includes closing all file descriptors (exec only
 * closes those marked close-on-exec) and resetting signals (exec only
 * resets handled signals, and we need to clear any signals which
 * killed init).  Anything else that exec(2) says would be inherited,
 * but would affect the execution of init, needs to be reset.
 */
static int
restart_init(int what, int why)
{
	kthread_t *t = curthread;
	klwp_t *lwp = ttolwp(t);
	proc_t *p = ttoproc(t);
	user_t *up = PTOU(p);

	vnode_t *oldcd, *oldrd;
	int i, err;
	char reason_buf[64];

	/*
	 * Let zone admin (and global zone admin if this is for a non-global
	 * zone) know that init has failed and will be restarted.
	 */
	zcmn_err(p->p_zone->zone_id, CE_WARN,
	    "init(1M) %s: restarting automatically",
	    exit_reason(reason_buf, sizeof (reason_buf), what, why));

	if (!INGLOBALZONE(p)) {
		cmn_err(CE_WARN, "init(1M) for zone %s (pid %d) %s: "
		    "restarting automatically",
		    p->p_zone->zone_name, p->p_pid, reason_buf);
	}

	/*
	 * Remove any fpollinfo_t's for this (last) thread from our file
	 * descriptors so closeall() can ASSERT() that they're all gone.
	 * Then close all open file descriptors in the process.
	 */
	pollcleanup();
	closeall(P_FINFO(p));

	/*
	 * Grab p_lock and begin clearing miscellaneous global process
	 * state that needs to be reset before we exec the new init(1M).
	 */

	mutex_enter(&p->p_lock);
	prbarrier(p);

	p->p_flag &= ~(SKILLED | SEXTKILLED | SEXITING | SDOCORE);
	up->u_cmask = CMASK;

	sigemptyset(&t->t_hold);
	sigemptyset(&t->t_sig);
	sigemptyset(&t->t_extsig);

	sigemptyset(&p->p_sig);
	sigemptyset(&p->p_extsig);

	sigdelq(p, t, 0);
	sigdelq(p, NULL, 0);

	if (p->p_killsqp) {
		siginfofree(p->p_killsqp);
		p->p_killsqp = NULL;
	}

	/*
	 * Reset any signals that are ignored back to the default disposition.
	 * Other u_signal members will be cleared when exec calls sigdefault().
	 */
	for (i = 1; i < NSIG; i++) {
		if (up->u_signal[i - 1] == SIG_IGN) {
			up->u_signal[i - 1] = SIG_DFL;
			sigemptyset(&up->u_sigmask[i - 1]);
		}
	}

	/*
	 * Clear the current signal, any signal info associated with it, and
	 * any signal information from contracts and/or contract templates.
	 */
	lwp->lwp_cursig = 0;
	lwp->lwp_extsig = 0;
	if (lwp->lwp_curinfo != NULL) {
		siginfofree(lwp->lwp_curinfo);
		lwp->lwp_curinfo = NULL;
	}
	lwp_ctmpl_clear(lwp);

	/*
	 * Reset both the process root directory and the current working
	 * directory to the root of the zone just as we do during boot.
	 */
	VN_HOLD(p->p_zone->zone_rootvp);
	oldrd = up->u_rdir;
	up->u_rdir = p->p_zone->zone_rootvp;

	VN_HOLD(p->p_zone->zone_rootvp);
	oldcd = up->u_cdir;
	up->u_cdir = p->p_zone->zone_rootvp;

	if (up->u_cwd != NULL) {
		refstr_rele(up->u_cwd);
		up->u_cwd = NULL;
	}

	mutex_exit(&p->p_lock);

	if (oldrd != NULL)
		VN_RELE(oldrd);
	if (oldcd != NULL)
		VN_RELE(oldcd);

	/* Free the controlling tty.  (freectty() always assumes curproc.) */
	ASSERT(p == curproc);
	(void) freectty(B_TRUE);

	/*
	 * Now exec() the new init(1M) on top of the current process.  If we
	 * succeed, the caller will treat this like a successful system call.
	 * If we fail, we issue messages and the caller will proceed with exit.
	 */
	err = exec_init(p->p_zone->zone_initname, NULL);

	if (err == 0)
		return (0);

	zcmn_err(p->p_zone->zone_id, CE_WARN,
	    "failed to restart init(1M) (err=%d): system reboot required", err);

	if (!INGLOBALZONE(p)) {
		cmn_err(CE_WARN, "failed to restart init(1M) for zone %s "
		    "(pid %d, err=%d): zoneadm(1M) boot required",
		    p->p_zone->zone_name, p->p_pid, err);
	}

	return (-1);
}
 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;
 }
 /**
  * Returns `exit_reason() != exit_reason::not_exited`.
  */
 inline bool exited() const {
   return exit_reason() != exit_reason::not_exited;
 }