+namespace simgrid {
+namespace msg {
+
+Task::Task(const std::string& name, double flops_amount, double bytes_amount, void* data)
+ : name_(name), flops_amount(flops_amount), bytes_amount(bytes_amount)
+{
+ static std::atomic_ullong counter{0};
+ id_ = counter++;
+ set_data(data);
+ if (MC_is_active())
+ MC_ignore_heap(&(id_), sizeof(id_));
+}
+
+Task::Task(const std::string& name, std::vector<s4u::Host*>&& hosts, std::vector<double>&& flops_amount,
+ std::vector<double>&& bytes_amount, void* data)
+ : Task(name, 1.0, 0, data)
+{
+ parallel_ = true;
+ hosts_ = std::move(hosts);
+ flops_parallel_amount = std::move(flops_amount);
+ bytes_parallel_amount = std::move(bytes_amount);
+}
+
+Task* Task::create(const std::string& name, double flops_amount, double bytes_amount, void* data)
+{
+ return new Task(name, flops_amount, bytes_amount, data);
+}
+
+Task* Task::create_parallel(const std::string& name, int host_nb, const msg_host_t* host_list, double* flops_amount,
+ double* bytes_amount, void* data)
+{
+ std::vector<s4u::Host*> hosts(host_list, host_list + host_nb);
+ std::vector<double> flops;
+ std::vector<double> bytes;
+ if (flops_amount != nullptr)
+ flops = std::vector<double>(flops_amount, flops_amount + host_nb);
+ if (bytes_amount != nullptr)
+ bytes = std::vector<double>(bytes_amount, bytes_amount + host_nb * host_nb);
+
+ return new Task(name, std::move(hosts), std::move(flops), std::move(bytes), data);
+}
+
+msg_error_t Task::execute()
+{
+ /* checking for infinite values */
+ xbt_assert(std::isfinite(flops_amount), "flops_amount is not finite!");
+
+ msg_error_t status = MSG_OK;
+ if (flops_amount <= 0.0)
+ return MSG_OK;
+
+ try {
+ set_used();
+ if (parallel_)
+ compute = s4u::this_actor::exec_init(hosts_, flops_parallel_amount, bytes_parallel_amount);
+ else
+ compute = s4u::this_actor::exec_init(flops_amount);
+
+ compute->set_name(name_)
+ ->set_tracing_category(tracing_category_)
+ ->set_timeout(timeout_)
+ ->set_priority(1 / priority_)
+ ->set_bound(bound_)
+ ->wait();
+
+ set_not_used();
+ XBT_DEBUG("Execution task '%s' finished", get_cname());
+ } catch (const HostFailureException&) {
+ status = MSG_HOST_FAILURE;
+ } catch (const TimeoutException&) {
+ status = MSG_TIMEOUT;
+ } catch (const CancelException&) {
+ status = MSG_TASK_CANCELED;
+ }
+
+ /* action ended, set comm and compute = nullptr, the actions is already destroyed in the main function */
+ flops_amount = 0.0;
+ comm = nullptr;
+ compute = nullptr;
+
+ return status;
+}
+
+s4u::CommPtr Task::send_async(const std::string& alias, void_f_pvoid_t cleanup, bool detached)
+{
+ if (TRACE_actor_is_enabled()) {
+ container_t process_container = instr::Container::by_name(instr_pid(*MSG_process_self()));
+ std::string key = std::string("p") + std::to_string(get_id());
+ instr::Container::get_root()->get_link("ACTOR_TASK_LINK")->start_event(process_container, "SR", key);
+ }
+
+ /* Prepare the task to send */
+ set_used();
+ this->comm = nullptr;
+ msg_global->sent_msg++;
+
+ s4u::CommPtr s4u_comm = s4u::Mailbox::by_name(alias)->put_init(this, bytes_amount)->set_rate(get_rate());
+ if (TRACE_is_enabled() && has_tracing_category())
+ s4u_comm->set_tracing_category(tracing_category_);
+
+ comm = s4u_comm;
+
+ if (detached)
+ comm->detach(cleanup);
+ else
+ comm->start();
+
+ return comm;
+}
+
+msg_error_t Task::send(const std::string& alias, double timeout)
+{
+ msg_error_t ret = MSG_OK;
+ /* Try to send it */
+ try {
+ comm = nullptr; // needed, otherwise MC gets confused.
+ s4u::CommPtr s4u_comm = send_async(alias, nullptr, false);
+ comm = s4u_comm;
+ comm->wait_for(timeout);
+ } catch (const TimeoutException&) {
+ ret = MSG_TIMEOUT;
+ } catch (const CancelException&) {
+ ret = MSG_HOST_FAILURE;
+ } catch (const NetworkFailureException&) {
+ ret = MSG_TRANSFER_FAILURE;
+ /* If the send failed, it is not used anymore */
+ set_not_used();
+ }
+
+ return ret;
+}
+void Task::cancel()
+{
+ if (compute) {
+ compute->cancel();
+ } else if (comm) {
+ comm->cancel();
+ }
+ set_not_used();
+}
+
+void Task::set_priority(double priority)
+{
+ xbt_assert(std::isfinite(1.0 / priority), "priority is not finite!");
+ priority_ = 1.0 / priority;
+}
+
+s4u::Actor* Task::get_sender()
+{
+ return comm ? comm->get_sender() : nullptr;
+}
+
+s4u::Host* Task::get_source()
+{
+ return comm ? comm->get_sender()->get_host() : nullptr;
+}
+
+void Task::set_used()
+{
+ if (is_used_)
+ report_multiple_use();
+ is_used_ = true;
+}
+
+void Task::report_multiple_use() const