Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Improve handling of dependencies, debug and example
[simgrid.git] / include / simgrid / s4u / Activity.hpp
1 /* Copyright (c) 2006-2020. 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 #ifndef SIMGRID_S4U_ACTIVITY_HPP
7 #define SIMGRID_S4U_ACTIVITY_HPP
8
9 #include "xbt/asserts.h"
10 #include <atomic>
11 #include <set>
12 #include <simgrid/forward.h>
13 #include <string>
14 #include <vector>
15 #include <xbt/log.hpp>
16 #include <xbt/signal.hpp>
17
18 XBT_LOG_EXTERNAL_CATEGORY(s4u_activity);
19
20 namespace simgrid {
21 namespace s4u {
22
23 /** @brief Activities
24  *
25  * This class is the ancestor of every activities that an actor can undertake.
26  * That is, activities are all the things that do take time to the actor in the simulated world.
27  */
28 class XBT_PUBLIC Activity {
29   friend Comm;
30   friend XBT_PUBLIC void intrusive_ptr_release(Comm * c);
31   friend XBT_PUBLIC void intrusive_ptr_add_ref(Comm * c);
32
33   friend Exec;
34   friend ExecSeq;
35   friend ExecPar;
36   friend XBT_PUBLIC void intrusive_ptr_release(Exec * e);
37   friend XBT_PUBLIC void intrusive_ptr_add_ref(Exec * e);
38
39   friend Io;
40   friend XBT_PUBLIC void intrusive_ptr_release(Io* i);
41   friend XBT_PUBLIC void intrusive_ptr_add_ref(Io* i);
42
43 protected:
44   Activity()  = default;
45   virtual ~Activity() = default;
46 public:
47 #ifndef DOXYGEN
48   Activity(Activity const&) = delete;
49   Activity& operator=(Activity const&) = delete;
50 #endif
51
52   enum class State { INITED = 0, STARTING, STARTED, CANCELED, ERRORED, FINISHED };
53
54   /** Starts a previously created activity.
55    *
56    * This function is optional: you can call wait() even if you didn't call start()
57    */
58   virtual Activity* start() = 0;
59   /** Blocks until the activity is terminated */
60   virtual Activity* wait() = 0;
61   /** Blocks until the activity is terminated, or until the timeout is elapsed
62    *  Raises: timeout exception.*/
63   virtual Activity* wait_for(double timeout) = 0;
64   /** Blocks until the activity is terminated, or until the time limit is reached
65    * Raises: timeout exception. */
66   void wait_until(double time_limit);
67
68   /** Cancel that activity */
69   virtual Activity* cancel() = 0;
70   /** Retrieve the current state of the activity */
71   Activity::State get_state() { return state_; }
72   void set_state(Activity::State state) { state_ = state; }
73   /** Tests whether the given activity is terminated yet. This is a pure function. */
74   virtual bool test() = 0;
75
76   /** Get the remaining amount of work that this Activity entails. When it's 0, it's done. */
77   virtual double get_remaining();
78
79   /** Set the [remaining] amount of work that this Activity will entail
80    *
81    * It is forbidden to change the amount of work once the Activity is started */
82   Activity* set_remaining(double remains);
83
84   /** Returns the internal implementation of this Activity */
85   kernel::activity::ActivityImpl* get_impl() const { return pimpl_.get(); }
86
87 private:
88   kernel::activity::ActivityImplPtr pimpl_ = nullptr;
89   Activity::State state_                   = Activity::State::INITED;
90   double remains_                          = 0;
91 };
92
93 template <class AnyActivity> class Activity_T : public Activity {
94 private:
95   std::string name_             = "unnamed";
96   std::string tracing_category_ = "";
97   void* user_data_              = nullptr;
98   std::atomic_int_fast32_t refcount_{0};
99   std::vector<AnyActivity*> successors_;
100   std::set<AnyActivity*> dependencies_;
101
102 public:
103 #ifndef DOXYGEN
104   friend void intrusive_ptr_release(AnyActivity* a)
105   {
106     if (a->refcount_.fetch_sub(1, std::memory_order_release) == 1) {
107       std::atomic_thread_fence(std::memory_order_acquire);
108       delete a;
109     }
110   }
111   friend void intrusive_ptr_add_ref(AnyActivity* a) { a->refcount_.fetch_add(1, std::memory_order_relaxed); }
112 #endif
113
114   void add_successor(AnyActivity* a)
115   {
116     successors_.push_back(a);
117     a->add_dependency_on(static_cast<AnyActivity*>(this));
118   }
119   void remove_successor() { successors_.pop_back(); }
120   AnyActivity* get_successor() { return successors_.back(); }
121   bool has_successors() { return not successors_.empty(); }
122
123   void add_dependency_on(AnyActivity* a) { dependencies_.insert({a}); }
124   void remove_dependency_on(AnyActivity* a) { dependencies_.erase(a); }
125   bool has_dependencies() { return not dependencies_.empty(); }
126   void release_dependencies()
127   {
128     while (has_successors()) {
129       AnyActivity* b = get_successor();
130       XBT_CDEBUG(s4u_activity, "Remove a dependency from '%s' on '%s'", get_cname(), b->get_cname());
131       b->remove_dependency_on(static_cast<AnyActivity*>(this));
132       if (not b->has_dependencies()) {
133         b->vetoable_start();
134       }
135       remove_successor();
136     }
137   }
138
139   AnyActivity* vetoable_start()
140   {
141     set_state(State::STARTING);
142     if (has_dependencies())
143       return static_cast<AnyActivity*>(this);
144     set_state(State::STARTED);
145     XBT_CDEBUG(s4u_activity, "All dependencies are solved, let's start '%s'", get_cname());
146     static_cast<AnyActivity*>(this)->start();
147     return static_cast<AnyActivity*>(this);
148   }
149
150   AnyActivity* set_name(const std::string& name)
151   {
152     xbt_assert(get_state() == State::INITED, "Cannot change the name of an activity after its start");
153     name_ = name;
154     return static_cast<AnyActivity*>(this);
155   }
156   const std::string& get_name() { return name_; }
157   const char* get_cname() { return name_.c_str(); }
158
159   AnyActivity* set_tracing_category(const std::string& category)
160   {
161     xbt_assert(get_state() == State::INITED, "Cannot change the tracing category of an activity after its start");
162     tracing_category_ = category;
163     return static_cast<AnyActivity*>(this);
164   }
165   const std::string& get_tracing_category() { return tracing_category_; }
166
167   AnyActivity* set_user_data(void* data)
168   {
169     user_data_ = data;
170     return static_cast<AnyActivity*>(this);
171   }
172
173   void* get_user_data() { return user_data_; }
174 };
175
176 } // namespace s4u
177 } // namespace simgrid
178
179 #endif /* SIMGRID_S4U_ACTIVITY_HPP */