Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
use CRTP to factor refcounting across activity types
[simgrid.git] / src / s4u / s4u_Actor.cpp
1 /* Copyright (c) 2006-2019. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "simgrid/Exception.hpp"
7 #include "simgrid/actor.h"
8 #include "simgrid/modelchecker.h"
9 #include "simgrid/s4u/Actor.hpp"
10 #include "simgrid/s4u/Exec.hpp"
11 #include "simgrid/s4u/Host.hpp"
12 #include "simgrid/s4u/VirtualMachine.hpp"
13 #include "src/include/mc/mc.h"
14 #include "src/kernel/activity/ExecImpl.hpp"
15 #include "src/mc/mc_replay.hpp"
16 #include "src/simix/smx_private.hpp"
17 #include "src/surf/HostImpl.hpp"
18
19 #include <algorithm>
20 #include <sstream>
21
22 XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_actor, "S4U actors");
23
24 namespace simgrid {
25 namespace s4u {
26
27 xbt::signal<void(Actor&)> s4u::Actor::on_creation;
28 xbt::signal<void(Actor const&)> s4u::Actor::on_suspend;
29 xbt::signal<void(Actor const&)> s4u::Actor::on_resume;
30 xbt::signal<void(Actor const&)> s4u::Actor::on_sleep;
31 xbt::signal<void(Actor const&)> s4u::Actor::on_wake_up;
32 xbt::signal<void(Actor const&)> s4u::Actor::on_migration_start;
33 xbt::signal<void(Actor const&)> s4u::Actor::on_migration_end;
34 xbt::signal<void(Actor const&)> s4u::Actor::on_termination;
35 xbt::signal<void(Actor const&)> s4u::Actor::on_destruction;
36
37 // ***** Actor creation *****
38 Actor* Actor::self()
39 {
40   kernel::context::Context* self_context = kernel::context::Context::self();
41   if (self_context == nullptr)
42     return nullptr;
43
44   return self_context->get_actor()->ciface();
45 }
46 ActorPtr Actor::init(const std::string& name, s4u::Host* host)
47 {
48   smx_actor_t self = SIMIX_process_self();
49   kernel::actor::ActorImpl* actor =
50       kernel::actor::simcall([self, &name, host] { return self->init(name, host).get(); });
51   return actor->iface();
52 }
53
54 ActorPtr Actor::start(const std::function<void()>& code)
55 {
56   simgrid::kernel::actor::simcall([this, &code] { pimpl_->start(code); });
57   return this;
58 }
59
60 ActorPtr Actor::create(const std::string& name, s4u::Host* host, const std::function<void()>& code)
61 {
62   smx_actor_t self = SIMIX_process_self();
63   kernel::actor::ActorImpl* actor =
64       kernel::actor::simcall([self, &name, host, &code] { return self->init(name, host)->start(code); });
65
66   return actor->iface();
67 }
68
69 ActorPtr Actor::create(const std::string& name, s4u::Host* host, const std::string& function,
70                        std::vector<std::string> args)
71 {
72   simix::ActorCodeFactory& factory = SIMIX_get_actor_code_factory(function);
73   return create(name, host, factory(std::move(args)));
74 }
75
76 void intrusive_ptr_add_ref(Actor* actor)
77 {
78   intrusive_ptr_add_ref(actor->pimpl_);
79 }
80 void intrusive_ptr_release(Actor* actor)
81 {
82   intrusive_ptr_release(actor->pimpl_);
83 }
84 int Actor::get_refcount()
85 {
86   return pimpl_->get_refcount();
87 }
88
89 // ***** Actor methods *****
90
91 void Actor::join()
92 {
93   join(-1);
94 }
95
96 void Actor::join(double timeout)
97 {
98   auto issuer = SIMIX_process_self();
99   auto target = pimpl_;
100   kernel::actor::simcall_blocking<void>([issuer, target, timeout] {
101     if (target->finished_) {
102       // The joined process is already finished, just wake up the issuer right away
103       issuer->simcall_answer();
104     } else {
105       smx_activity_t sync = issuer->join(target, timeout);
106       sync->register_simcall(&issuer->simcall);
107     }
108   });
109 }
110
111 void Actor::set_auto_restart(bool autorestart)
112 {
113   kernel::actor::simcall([this, autorestart]() {
114     xbt_assert(autorestart && not pimpl_->has_to_auto_restart()); // FIXME: handle all cases
115     pimpl_->set_auto_restart(autorestart);
116
117     kernel::actor::ProcessArg* arg = new kernel::actor::ProcessArg(pimpl_->get_host(), pimpl_);
118     XBT_DEBUG("Adding Process %s to the actors_at_boot_ list of Host %s", arg->name.c_str(), arg->host->get_cname());
119     pimpl_->get_host()->pimpl_->actors_at_boot_.emplace_back(arg);
120   });
121 }
122
123 void Actor::on_exit(const std::function<void(int, void*)>& fun, void* data) /* deprecated */
124 {
125   on_exit([fun, data](bool failed) { fun(failed ? SMX_EXIT_FAILURE : SMX_EXIT_SUCCESS, data); });
126 }
127
128 void Actor::on_exit(const std::function<void(bool /*failed*/)>& fun) const
129 {
130   kernel::actor::simcall([this, &fun] { SIMIX_process_on_exit(pimpl_, fun); });
131 }
132
133 void Actor::migrate(Host* new_host)
134 {
135   s4u::Actor::on_migration_start(*this);
136
137   kernel::actor::simcall([this, new_host]() {
138     if (pimpl_->waiting_synchro != nullptr) {
139       // The actor is blocked on an activity. If it's an exec, migrate it too.
140       // FIXME: implement the migration of other kinds of activities
141       kernel::activity::ExecImplPtr exec =
142           boost::dynamic_pointer_cast<kernel::activity::ExecImpl>(pimpl_->waiting_synchro);
143       xbt_assert(exec.get() != nullptr, "We can only migrate blocked actors when they are blocked on executions.");
144       exec->migrate(new_host);
145     }
146     this->pimpl_->set_host(new_host);
147   });
148
149   s4u::Actor::on_migration_end(*this);
150 }
151
152 s4u::Host* Actor::get_host() const
153 {
154   return this->pimpl_->get_host();
155 }
156
157 void Actor::daemonize()
158 {
159   kernel::actor::simcall([this]() { pimpl_->daemonize(); });
160 }
161
162 bool Actor::is_daemon() const
163 {
164   return this->pimpl_->is_daemon();
165 }
166
167 const simgrid::xbt::string& Actor::get_name() const
168 {
169   return this->pimpl_->get_name();
170 }
171
172 const char* Actor::get_cname() const
173 {
174   return this->pimpl_->get_cname();
175 }
176
177 aid_t Actor::get_pid() const
178 {
179   return this->pimpl_->get_pid();
180 }
181
182 aid_t Actor::get_ppid() const
183 {
184   return this->pimpl_->get_ppid();
185 }
186
187 void Actor::suspend()
188 {
189   auto issuer = SIMIX_process_self();
190   auto target = pimpl_;
191   s4u::Actor::on_suspend(*this);
192   kernel::actor::simcall_blocking<void>([issuer, target]() {
193     target->suspend();
194     if (target != issuer) {
195       /* If we are suspending ourselves, then just do not finish the simcall now */
196       issuer->simcall_answer();
197     }
198   });
199 }
200
201 void Actor::resume()
202 {
203   kernel::actor::simcall([this] { pimpl_->resume(); });
204   s4u::Actor::on_resume(*this);
205 }
206
207 bool Actor::is_suspended()
208 {
209   return pimpl_->is_suspended();
210 }
211
212 void Actor::set_kill_time(double kill_time)
213 {
214   kernel::actor::simcall([this, kill_time] { pimpl_->set_kill_time(kill_time); });
215 }
216
217 /** @brief Get the kill time of an actor(or 0 if unset). */
218 double Actor::get_kill_time()
219 {
220   return pimpl_->get_kill_time();
221 }
222
223 void Actor::kill(aid_t pid) // deprecated
224 {
225   kernel::actor::ActorImpl* killer = SIMIX_process_self();
226   kernel::actor::ActorImpl* victim = SIMIX_process_from_PID(pid);
227   if (victim != nullptr) {
228     kernel::actor::simcall([killer, victim] { killer->kill(victim); });
229   } else {
230     std::ostringstream oss;
231     oss << "kill: (" << pid << ") - No such actor" << std::endl;
232     throw std::runtime_error(oss.str());
233   }
234 }
235
236 void Actor::kill()
237 {
238   kernel::actor::ActorImpl* process = SIMIX_process_self();
239   kernel::actor::simcall([this, process] {
240     xbt_assert(pimpl_ != simix_global->maestro_process, "Killing maestro is a rather bad idea");
241     process->kill(pimpl_);
242   });
243 }
244
245 // ***** Static functions *****
246
247 ActorPtr Actor::by_pid(aid_t pid)
248 {
249   kernel::actor::ActorImpl* process = SIMIX_process_from_PID(pid);
250   if (process != nullptr)
251     return process->iface();
252   else
253     return ActorPtr();
254 }
255
256 void Actor::kill_all()
257 {
258   kernel::actor::ActorImpl* self = SIMIX_process_self();
259   kernel::actor::simcall([self] { self->kill_all(); });
260 }
261
262 const std::unordered_map<std::string, std::string>* Actor::get_properties() const
263 {
264   return pimpl_->get_properties();
265 }
266
267 /** Retrieve the property value (or nullptr if not set) */
268 const char* Actor::get_property(const std::string& key) const
269 {
270   return pimpl_->get_property(key);
271 }
272
273 void Actor::set_property(const std::string& key, const std::string& value)
274 {
275   kernel::actor::simcall([this, &key, &value] { pimpl_->set_property(key, value); });
276 }
277
278 Actor* Actor::restart()
279 {
280   return kernel::actor::simcall([this]() { return pimpl_->restart(); });
281 }
282
283 // ***** this_actor *****
284
285 namespace this_actor {
286
287 /** Returns true if run from the kernel mode, and false if run from a real actor
288  *
289  * Everything that is run out of any actor (simulation setup before the engine is run,
290  * computing the model evolutions as a result to the actors' action, etc) is run in
291  * kernel mode, just as in any operating systems.
292  *
293  * In SimGrid, the actor in charge of doing the stuff in kernel mode is called Maestro,
294  * because it is the one scheduling when the others should move or wait.
295  */
296 bool is_maestro()
297 {
298   kernel::actor::ActorImpl* process = SIMIX_process_self();
299   return process == nullptr || process == simix_global->maestro_process;
300 }
301
302 void sleep_for(double duration)
303 {
304   xbt_assert(std::isfinite(duration), "duration is not finite!");
305
306   if (duration > 0) {
307     kernel::actor::ActorImpl* issuer = SIMIX_process_self();
308     Actor::on_sleep(*issuer->ciface());
309
310     kernel::actor::simcall_blocking<void>([issuer, duration]() {
311       if (MC_is_active() || MC_record_replay_is_active()) {
312         MC_process_clock_add(issuer, duration);
313         issuer->simcall_answer();
314         return;
315       }
316       smx_activity_t sync = issuer->sleep(duration);
317       sync->register_simcall(&issuer->simcall);
318     });
319
320     Actor::on_wake_up(*issuer->ciface());
321   }
322 }
323
324 void yield()
325 {
326   kernel::actor::simcall([] { /* do nothing*/ });
327 }
328
329 XBT_PUBLIC void sleep_until(double wakeup_time)
330 {
331   double now = SIMIX_get_clock();
332   if (wakeup_time > now)
333     sleep_for(wakeup_time - now);
334 }
335
336 void execute(double flops)
337 {
338   execute(flops, 1.0 /* priority */);
339 }
340
341 void execute(double flops, double priority)
342 {
343   exec_init(flops)->set_priority(priority)->start()->wait();
344 }
345
346 void parallel_execute(const std::vector<s4u::Host*>& hosts, const std::vector<double>& flops_amounts,
347                       const std::vector<double>& bytes_amounts)
348 {
349   parallel_execute(hosts, flops_amounts, bytes_amounts, -1);
350 }
351
352 void parallel_execute(const std::vector<s4u::Host*>& hosts, const std::vector<double>& flops_amounts,
353                       const std::vector<double>& bytes_amounts, double timeout)
354 {
355   xbt_assert(hosts.size() > 0, "Your parallel executions must span over at least one host.");
356   xbt_assert(hosts.size() == flops_amounts.size() || flops_amounts.empty(),
357              "Host count (%zu) does not match flops_amount count (%zu).", hosts.size(), flops_amounts.size());
358   xbt_assert(hosts.size() * hosts.size() == bytes_amounts.size() || bytes_amounts.empty(),
359              "bytes_amounts must be a matrix of size host_count * host_count (%zu*%zu), but it's of size %zu.",
360              hosts.size(), hosts.size(), flops_amounts.size());
361   /* Check that we are not mixing VMs and PMs in the parallel task */
362   bool is_a_vm = (nullptr != dynamic_cast<VirtualMachine*>(hosts.front()));
363   xbt_assert(std::all_of(hosts.begin(), hosts.end(),
364                          [is_a_vm](s4u::Host* elm) {
365                            bool tmp_is_a_vm = (nullptr != dynamic_cast<VirtualMachine*>(elm));
366                            return is_a_vm == tmp_is_a_vm;
367                          }),
368              "parallel_execute: mixing VMs and PMs is not supported (yet).");
369   /* checking for infinite values */
370   xbt_assert(std::all_of(flops_amounts.begin(), flops_amounts.end(), [](double elm) { return std::isfinite(elm); }),
371              "flops_amounts comprises infinite values!");
372   xbt_assert(std::all_of(bytes_amounts.begin(), bytes_amounts.end(), [](double elm) { return std::isfinite(elm); }),
373              "flops_amounts comprises infinite values!");
374
375   exec_init(hosts, flops_amounts, bytes_amounts)->set_timeout(timeout)->wait();
376 }
377
378 // deprecated
379 void parallel_execute(int host_nb, s4u::Host* const* host_list, const double* flops_amount, const double* bytes_amount,
380                       double timeout)
381 {
382   smx_activity_t s =
383       simcall_execution_parallel_start("", host_nb, host_list, flops_amount, bytes_amount, /* rate */ -1, timeout);
384   simcall_execution_wait(s);
385   delete[] flops_amount;
386   delete[] bytes_amount;
387 }
388
389 // deprecated
390 void parallel_execute(int host_nb, s4u::Host* const* host_list, const double* flops_amount, const double* bytes_amount)
391 {
392   smx_activity_t s = simcall_execution_parallel_start("", host_nb, host_list, flops_amount, bytes_amount,
393                                                       /* rate */ -1, /*timeout*/ -1);
394   simcall_execution_wait(s);
395   delete[] flops_amount;
396   delete[] bytes_amount;
397 }
398
399 ExecPtr exec_init(double flops_amount)
400 {
401   return ExecPtr(new ExecSeq(get_host(), flops_amount));
402 }
403
404 ExecPtr exec_init(const std::vector<s4u::Host*>& hosts, const std::vector<double>& flops_amounts,
405                   const std::vector<double>& bytes_amounts)
406 {
407   return ExecPtr(new ExecPar(hosts, flops_amounts, bytes_amounts));
408 }
409
410 ExecPtr exec_async(double flops)
411 {
412   ExecPtr res = exec_init(flops);
413   res->start();
414   return res;
415 }
416
417 aid_t get_pid()
418 {
419   return SIMIX_process_self()->get_pid();
420 }
421
422 aid_t get_ppid()
423 {
424   return SIMIX_process_self()->get_ppid();
425 }
426
427 std::string get_name()
428 {
429   return SIMIX_process_self()->get_name();
430 }
431
432 const char* get_cname()
433 {
434   return SIMIX_process_self()->get_cname();
435 }
436
437 Host* get_host()
438 {
439   return SIMIX_process_self()->get_host();
440 }
441
442 void suspend()
443 {
444   kernel::actor::ActorImpl* self = SIMIX_process_self();
445   s4u::Actor::on_suspend(*self->ciface());
446   kernel::actor::simcall_blocking<void>([self] { self->suspend(); });
447 }
448
449 void resume()
450 {
451   kernel::actor::ActorImpl* self = SIMIX_process_self();
452   kernel::actor::simcall([self] { self->resume(); });
453   Actor::on_resume(*self->ciface());
454 }
455
456 void exit()
457 {
458   kernel::actor::ActorImpl* self = SIMIX_process_self();
459   simgrid::kernel::actor::simcall([self] { self->exit(); });
460 }
461
462 void on_exit(const std::function<void(bool)>& fun)
463 {
464   SIMIX_process_self()->iface()->on_exit(fun);
465 }
466
467 void on_exit(const std::function<void(int, void*)>& fun, void* data) /* deprecated */
468 {
469   SIMIX_process_self()->iface()->on_exit([fun, data](bool exit) { fun(exit, data); });
470 }
471
472 /** @brief Moves the current actor to another host
473  *
474  * @see simgrid::s4u::Actor::migrate() for more information
475  */
476 void migrate(Host* new_host)
477 {
478   SIMIX_process_self()->iface()->migrate(new_host);
479 }
480
481 } // namespace this_actor
482 } // namespace s4u
483 } // namespace simgrid
484
485 /* **************************** Public C interface *************************** */
486
487 /** @ingroup m_actor_management
488  * @brief Returns the process ID of @a actor.
489  *
490  * This function checks whether @a actor is a valid pointer and return its PID (or 0 in case of problem).
491  */
492 aid_t sg_actor_get_PID(sg_actor_t actor)
493 {
494   /* Do not raise an exception here: this function is called by the logs
495    * and the exceptions, so it would be called back again and again */
496   if (actor == nullptr || actor->get_impl() == nullptr)
497     return 0;
498   return actor->get_pid();
499 }
500
501 /** @ingroup m_actor_management
502  * @brief Returns the process ID of the parent of @a actor.
503  *
504  * This function checks whether @a actor is a valid pointer and return its parent's PID.
505  * Returns -1 if the actor has not been created by any other actor.
506  */
507 aid_t sg_actor_get_PPID(sg_actor_t actor)
508 {
509   return actor->get_ppid();
510 }
511
512 /** @ingroup m_actor_management
513  *
514  * @brief Return a #sg_actor_t given its PID.
515  *
516  * This function search in the list of all the created sg_actor_t for a sg_actor_t  whose PID is equal to @a PID.
517  * If none is found, @c nullptr is returned.
518    Note that the PID are unique in the whole simulation, not only on a given host.
519  */
520 sg_actor_t sg_actor_by_PID(aid_t pid)
521 {
522   return simgrid::s4u::Actor::by_pid(pid).get();
523 }
524
525 /** @ingroup m_actor_management
526  * @brief Return the name of an actor.
527  */
528 const char* sg_actor_get_name(sg_actor_t actor)
529 {
530   return actor->get_cname();
531 }
532
533 sg_host_t sg_actor_get_host(sg_actor_t actor)
534 {
535   return actor->get_host();
536 }
537
538 /** @ingroup m_actor_management
539  * @brief Returns the value of a given actor property
540  *
541  * @param actor an actor
542  * @param name a property name
543  * @return value of a property (or nullptr if the property is not set)
544  */
545 const char* sg_actor_get_property_value(sg_actor_t actor, const char* name)
546 {
547   return actor->get_property(name);
548 }
549
550 /** @ingroup m_actor_management
551  * @brief Return the list of properties
552  *
553  * This function returns all the parameters associated with an actor
554  */
555 xbt_dict_t sg_actor_get_properties(sg_actor_t actor)
556 {
557   xbt_assert(actor != nullptr, "Invalid parameter: First argument must not be nullptr");
558   xbt_dict_t as_dict                        = xbt_dict_new_homogeneous(xbt_free_f);
559   const std::unordered_map<std::string, std::string>* props = actor->get_properties();
560   if (props == nullptr)
561     return nullptr;
562   for (auto const& kv : *props) {
563     xbt_dict_set(as_dict, kv.first.c_str(), xbt_strdup(kv.second.c_str()), nullptr);
564   }
565   return as_dict;
566 }
567
568 /** @ingroup m_actor_management
569  * @brief Suspend the actor.
570  *
571  * This function suspends the actor by suspending the task on which it was waiting for the completion.
572  */
573 void sg_actor_suspend(sg_actor_t actor)
574 {
575   xbt_assert(actor != nullptr, "Invalid parameter: First argument must not be nullptr");
576   actor->suspend();
577 }
578
579 /** @ingroup m_actor_management
580  * @brief Resume a suspended actor.
581  *
582  * This function resumes a suspended actor by resuming the task on which it was waiting for the completion.
583  */
584 void sg_actor_resume(sg_actor_t actor)
585 {
586   xbt_assert(actor != nullptr, "Invalid parameter: First argument must not be nullptr");
587   actor->resume();
588 }
589
590 /** @ingroup m_actor_management
591  * @brief Returns true if the actor is suspended .
592  *
593  * This checks whether an actor is suspended or not by inspecting the task on which it was waiting for the completion.
594  */
595 int sg_actor_is_suspended(sg_actor_t actor)
596 {
597   return actor->is_suspended();
598 }
599
600 /**
601  * @ingroup m_actor_management
602  * @brief Restarts an actor from the beginning.
603  */
604 sg_actor_t sg_actor_restart(sg_actor_t actor)
605 {
606   return actor->restart();
607 }
608
609 /**
610  * @ingroup m_actor_management
611  * @brief Sets the "auto-restart" flag of the actor.
612  * If the flag is set to 1, the actor will be automatically restarted when its host comes back up.
613  */
614 void sg_actor_set_auto_restart(sg_actor_t actor, int auto_restart)
615 {
616   actor->set_auto_restart(auto_restart);
617 }
618
619 /** @ingroup m_actor_management
620  * @brief This actor will be terminated automatically when the last non-daemon actor finishes
621  */
622 void sg_actor_daemonize(sg_actor_t actor)
623 {
624   actor->daemonize();
625 }
626
627 /** @ingroup m_actor_management
628  * @brief Migrates an actor to another location.
629  *
630  * This function changes the value of the #sg_host_t on  which @a actor is running.
631  */
632 void sg_actor_migrate(sg_actor_t process, sg_host_t host)
633 {
634   process->migrate(host);
635 }
636
637 /** @ingroup m_actor_management
638  * @brief Wait for the completion of a #sg_actor_t.
639  *
640  * @param actor the actor to wait for
641  * @param timeout wait until the actor is over, or the timeout expires
642  */
643 void sg_actor_join(sg_actor_t actor, double timeout)
644 {
645   actor->join(timeout);
646 }
647
648 void sg_actor_kill(sg_actor_t actor)
649 {
650   actor->kill();
651 }
652
653 void sg_actor_kill_all()
654 {
655   simgrid::s4u::Actor::kill_all();
656 }
657
658 /** @ingroup m_actor_management
659  * @brief Set the kill time of an actor.
660  *
661  * @param actor an actor
662  * @param kill_time the time when the actor is killed.
663  */
664 void sg_actor_set_kill_time(sg_actor_t actor, double kill_time)
665 {
666   actor->set_kill_time(kill_time);
667 }
668
669 /** Yield the current actor; let the other actors execute first */
670 void sg_actor_yield()
671 {
672   simgrid::s4u::this_actor::yield();
673 }
674
675 void sg_actor_sleep_for(double duration)
676 {
677   simgrid::s4u::this_actor::sleep_for(duration);
678 }
679
680 sg_actor_t sg_actor_attach(const char* name, void* data, sg_host_t host, xbt_dict_t properties)
681 {
682   xbt_assert(host != nullptr, "Invalid parameters: host and code params must not be nullptr");
683   std::unordered_map<std::string, std::string> props;
684   xbt_dict_cursor_t cursor = nullptr;
685   char* key;
686   char* value;
687   xbt_dict_foreach (properties, cursor, key, value)
688     props[key] = value;
689   xbt_dict_free(&properties);
690
691   /* Let's create the process: SIMIX may decide to start it right now, even before returning the flow control to us */
692   smx_actor_t actor = nullptr;
693   try {
694     actor = simgrid::kernel::actor::ActorImpl::attach(name, data, host, &props).get();
695   } catch (simgrid::HostFailureException const&) {
696     xbt_die("Could not attach");
697   }
698
699   simgrid::s4u::this_actor::yield();
700   return actor->ciface();
701 }
702
703 void sg_actor_detach()
704 {
705   simgrid::kernel::actor::ActorImpl::detach();
706 }
707
708 aid_t sg_actor_self_get_pid()
709 {
710   return simgrid::s4u::this_actor::get_pid();
711 }
712
713 aid_t sg_actor_self_get_ppid()
714 {
715   return simgrid::s4u::this_actor::get_ppid();
716 }
717
718 const char* sg_actor_self_get_name()
719 {
720   return simgrid::s4u::this_actor::get_cname();
721 }
722
723 sg_actor_t sg_actor_self()
724 {
725   return simgrid::s4u::Actor::self();
726 }
727
728 void sg_actor_self_execute(double flops)
729 {
730   simgrid::s4u::this_actor::execute(flops);
731 }
732
733 /** @brief Take an extra reference on that actor to prevent it to be garbage-collected */
734 void sg_actor_ref(sg_actor_t actor)
735 {
736   intrusive_ptr_add_ref(actor);
737 }
738 /** @brief Release a reference on that actor so that it can get be garbage-collected */
739 void sg_actor_unref(sg_actor_t actor)
740 {
741   intrusive_ptr_release(actor);
742 }
743
744 /** @brief Return the user data of a #sg_actor_t */
745 void* sg_actor_data(sg_actor_t actor)
746 {
747   return actor->get_data();
748 }
749 /** @brief Set the user data of a #sg_actor_t */
750 void sg_actor_data_set(sg_actor_t actor, void* userdata)
751 {
752   actor->set_data(userdata);
753 }