+XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_actor, "S4U actors");
+
+namespace simgrid {
+namespace s4u {
+
+simgrid::xbt::signal<void(simgrid::s4u::ActorPtr)> s4u::Actor::onCreation;
+simgrid::xbt::signal<void(simgrid::s4u::ActorPtr)> s4u::Actor::onDestruction;
+
+// ***** Actor creation *****
+ActorPtr Actor::self()
+{
+ smx_context_t self_context = SIMIX_context_self();
+ if (self_context == nullptr)
+ return simgrid::s4u::ActorPtr();
+
+ return self_context->process()->iface();
+}
+
+ActorPtr Actor::createActor(const char* name, s4u::Host* host, std::function<void()> code)
+{
+ simgrid::kernel::actor::ActorImpl* actor = simcall_process_create(name, std::move(code), nullptr, host, nullptr);
+ return actor->iface();
+}
+
+ActorPtr Actor::createActor(const char* name, s4u::Host* host, const char* function, std::vector<std::string> args)
+{
+ simgrid::simix::ActorCodeFactory& factory = SIMIX_get_actor_code_factory(function);
+ simgrid::simix::ActorCode code = factory(std::move(args));
+ simgrid::kernel::actor::ActorImpl* actor = simcall_process_create(name, std::move(code), nullptr, host, nullptr);
+ return actor->iface();
+}
+
+void intrusive_ptr_add_ref(Actor* actor)
+{
+ intrusive_ptr_add_ref(actor->pimpl_);
+}
+void intrusive_ptr_release(Actor* actor)
+{
+ intrusive_ptr_release(actor->pimpl_);
+}
+
+// ***** Actor methods *****
+
+void Actor::join() {
+ simcall_process_join(this->pimpl_, -1);
+}
+
+void Actor::join(double timeout)
+{
+ simcall_process_join(this->pimpl_, timeout);
+}
+
+void Actor::setAutoRestart(bool autorestart) {
+ simgrid::simix::kernelImmediate([this, autorestart]() { pimpl_->auto_restart = autorestart; });
+}
+
+void Actor::onExit(int_f_pvoid_pvoid_t fun, void* data)
+{
+ simcall_process_on_exit(pimpl_, fun, data);
+}
+
+/** @brief Moves the actor to another host
+ *
+ * If the actor is currently blocked on an execution activity, the activity is also
+ * migrated to the new host. If it's blocked on another kind of activity, an error is
+ * raised as the mandated code is not written yet. Please report that bug if you need it.
+ *
+ * Asynchronous activities started by the actor are not migrated automatically, so you have
+ * to take care of this yourself (only you knows which ones should be migrated).
+ */
+void Actor::migrate(Host* new_host)
+{
+ std::string key;
+ simgrid::instr::LinkType* link = nullptr;
+ if (TRACE_actor_is_enabled()) {
+ static long long int counter = 0;
+
+ key = std::to_string(counter);
+ counter++;
+
+ // start link
+ container_t actor_container = simgrid::instr::Container::byName(instr_pid(this));
+ link = simgrid::instr::Container::getRoot()->getLink("ACTOR_LINK");
+ link->startEvent(actor_container, "M", key);
+
+ // destroy existing container of this process
+ actor_container->removeFromParent();
+ }
+
+ simgrid::simix::kernelImmediate([this, new_host]() {
+ if (pimpl_->waiting_synchro != nullptr) {
+ // The actor is blocked on an activity. If it's an exec, migrate it too.
+ // FIXME: implement the migration of other kind of activities
+ simgrid::kernel::activity::ExecImplPtr exec =
+ boost::dynamic_pointer_cast<simgrid::kernel::activity::ExecImpl>(pimpl_->waiting_synchro);
+ xbt_assert(exec.get() != nullptr, "We can only migrate blocked actors when they are blocked on executions.");
+ exec->migrate(new_host);
+ }
+ SIMIX_process_change_host(this->pimpl_, new_host);
+ });
+
+ if (TRACE_actor_is_enabled()) {
+ // create new container on the new_host location
+ simgrid::instr::Container::byName(new_host->get_name())->createChild(instr_pid(this), "ACTOR");
+ // end link
+ link->endEvent(simgrid::instr::Container::byName(instr_pid(this)), "M", key);
+ }
+}
+
+s4u::Host* Actor::getHost()
+{
+ return this->pimpl_->host;
+}
+
+void Actor::daemonize()
+{
+ simgrid::simix::kernelImmediate([this]() { pimpl_->daemonize(); });
+}
+
+bool Actor::isDaemon()
+{
+ return this->pimpl_->isDaemon();
+}
+
+const simgrid::xbt::string& Actor::get_name() const
+{
+ return this->pimpl_->get_name();
+}
+
+const char* Actor::get_cname() const
+{
+ return this->pimpl_->get_cname();
+}
+
+aid_t Actor::getPid()
+{
+ return this->pimpl_->pid;
+}
+
+aid_t Actor::getPpid()
+{
+ return this->pimpl_->ppid;
+}
+
+void Actor::suspend()
+{
+ if (TRACE_actor_is_enabled())
+ simgrid::instr::Container::byName(instr_pid(this))->getState("ACTOR_STATE")->pushEvent("suspend");
+
+ simcall_process_suspend(pimpl_);
+}
+
+void Actor::resume()
+{
+ simgrid::simix::kernelImmediate([this] { pimpl_->resume(); });
+ if (TRACE_actor_is_enabled())
+ simgrid::instr::Container::byName(instr_pid(this))->getState("ACTOR_STATE")->popEvent();
+}
+
+int Actor::isSuspended()
+{
+ return simgrid::simix::kernelImmediate([this] { return pimpl_->suspended; });
+}
+
+void Actor::setKillTime(double time) {
+ simcall_process_set_kill_time(pimpl_,time);
+}
+
+/** \brief Get the kill time of an actor(or 0 if unset). */
+double Actor::getKillTime()
+{
+ return SIMIX_timer_get_date(pimpl_->kill_timer);
+}
+
+void Actor::kill(aid_t pid)
+{
+ smx_actor_t killer = SIMIX_process_self();
+ smx_actor_t process = SIMIX_process_from_PID(pid);
+ if(process != nullptr) {
+ simgrid::simix::kernelImmediate([killer, process] { SIMIX_process_kill(process, killer); });
+ } else {
+ std::ostringstream oss;
+ oss << "kill: (" << pid << ") - No such actor" << std::endl;
+ throw std::runtime_error(oss.str());
+ }
+}
+
+void Actor::kill() {
+ smx_actor_t process = SIMIX_process_self();
+ simgrid::simix::kernelImmediate(
+ [this, process] { SIMIX_process_kill(pimpl_, (pimpl_ == simix_global->maestro_process) ? pimpl_ : process); });
+}
+
+smx_actor_t Actor::getImpl()
+{
+ return pimpl_;