uThreads  0.3.0
uThread.h
1 /*******************************************************************************
2  * Copyright © 2015, 2016 Saman Barghi
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  *******************************************************************************/
17 
18 #ifndef UTHREADS_UTHREAD_H_
19 #define UTHREADS_UTHREAD_H_
20 
21 #include <mutex>
22 #include <atomic>
23 #include "../generic/basics.h"
24 #include "../generic/IntrusiveContainers.h"
25 #include "Stack.h"
26 #include "BlockingSync.h"
27 
28 class IOHandler;
29 class Cluster;
30 class uThreadCache;
31 class Scheduler;
32 class kThread;
33 class UTVar;
34 
63 class uThread: public Link<uThread> {
64  friend class uThreadCache;
65  friend class kThread;
66  friend class Cluster;
67  friend class BlockingQueue;
68  friend class IOHandler;
69  friend class Scheduler;
70 
71  // First 64 bytes (CACHELINE_SIZE)
72  //Link* prev (8 bytes)
73  //Link* next (8 bytes)
74 protected:
75  /*
76  * Thread variables
77  */
78 
79  /*
80  * Current Cluster that uThread is executed on.
81  * This variable is used for migrating to another Cluster.
82  */
83  Cluster* currentCluster; //(8 bytes)
84 
85  /*
86  * Current kThread assigned to this uThread
87  */
88  kThread* homekThread; //(8 bytes)
89 
90  /*
91  * Stack Boundary
92  */
93  vaddr stackPointer; // holds stack pointer while thread inactive (8 bytes)
94  vaddr stackBottom; //Bottom of the stack (8 bytes)
95  size_t stackSize; //Size of the stack of the current uThread (8 bytes ?)
96 
97  UTVar* utvar;
98  // First 64 bytes (CACHELINE_SIZE)
99  uint64_t uThreadID; //unique Id for this uThread (8 bytes)
100 private:
101 
102  /*
103  * initUT is the initial uThread that is created when program starts.
104  * initUT holds the context that runs the main thread. It does not have
105  * a separate stack and takes over the underlying kThread(defaultKT)
106  * stack to be able to take control of the main function.
107  */
108  static uThread* initUT;
109 
110 
111  /* This is only used to create mainUT for kThreads */
112  static uThread* createMainUT(Cluster&);
113 
114  /* Variables for Joinable uThread */
115  Mutex joinMtx;
116  ConditionVariable joinWait;
117  Semaphore afterJoin;
118 
119  /*
120  * Wait or Signal the other thread
121  */
122  inline void waitOrSignal(bool caller){
123  joinMtx.acquire();
124  if(joinWait.empty()){
125  joinWait.wait(joinMtx);
126  joinMtx.release();
127  if(caller) afterJoin.V();
128 
129  }else{
130  joinWait.signal(joinMtx);
131  if(!caller) afterJoin.P();
132  }
133  }
134 
135 
136 protected:
137  /* hold various states that uThread can go through */
138  enum class State : std::uint8_t {
139  INITIALIZED, //uThread is initialized
140  READY, //uThread is in a ReadyQueue
141  RUNNING, //<uThread is Running
142  YIELD, //uThread is Yielding
143  MIGRATE, //Migrating to another cluster
144  WAITING, //uThread is Blocked
145  TERMINATED //uThread is done and should be terminated
146  } state;
147 
148  /* hold joinable state of the uThread */
149  enum class JState : std::uint8_t {
150  DETACHED, //Detached
151  JOINABLE, //Joinable
152  JOINING //Joining
153  } jState;
154 
155  //TODO: Add a function to check uThread's stack for overflow ! Prevent overflow or throw an exception or error?
156  //TODO: Add a debug object to project, or a dtrace or lttng functionality
157 
165  uThread(vaddr sb, size_t ss) :
166  stackPointer(vaddr(this)), stackBottom(sb), stackSize(ss), state(
167  State::INITIALIZED), uThreadID(uThreadMasterID++), currentCluster(
168  nullptr), jState(JState::DETACHED), homekThread(nullptr), utvar(nullptr) {
169  totalNumberofUTs++;
170  }
171 
172  /* Create a stack with the given size */
173  static vaddr createStack(size_t);
174 
175  /* in order to avoid allocating memory over and over again, uThreads
176  * are not completely destroyed after termination and are pushed to
177  * a uThreadCache container. When the program asks for a new uThread
178  * this cache is checked, if there is cached uThreads it will be used
179  * instead of allocating new memory.
180  */
181  static uThreadCache utCache; //data structure to cache uThreads
182 
183  /*
184  * Statistics variables
185  */
186  //TODO: Add more variables, number of suspended, number of running ...
187  static std::atomic_ulong totalNumberofUTs; //Total number of existing uThreads
188  static std::atomic_ulong uThreadMasterID; //The main ID counter
189 
190 
191 
192 
193  /*
194  * Destroys the uThread by freeing the memory allocated on the stack.
195  * Since uThread object is saved on its own stack it destroys the uThread
196  * object as well.
197  * If the uThreadCache is not full, this function do not destroy the
198  * object and push it to the uThreadCache.
199  * The object is destroyed either due to the cache being full, or the bool
200  * parameter pass to it, which means force destroying the object, is true.
201  */
202  virtual void destory(bool);
203 
204  /*
205  * This function is used to recycle the uThread as it is pushed in
206  * uThreadCache. It causes the stack pointer points to the beginning of
207  * the stack and change the status of the uThread to INITIALIZED.
208  */
209  void reset();
210 
211  /*
212  * Used to suspend the uThread. Pass a function and an argument
213  * to be called after the context switch.
214  * It is normally the case that the uThread needs to hold on to a lock
215  * or perform some maintenance after the context is switched.
216  */
217  void suspend(funcvoid2_t, void*);
218 
219  //Function to invoke the run function of a uThread
220  static void invoke(funcvoid3_t, ptr_t, ptr_t, ptr_t) __noreturn;
221 
222 public:
224  uThread(const uThread&) = delete;
225 
227  const uThread& operator=(const uThread&) = delete;
228 
238  static uThread* create(size_t ss, bool joinable=false);
239 
245  static uThread* create(bool joinable=false) {
246  return create(defaultStackSize, joinable);
247  }
248 
260  void start(const Cluster& cluster, ptr_t func, ptr_t arg1 = nullptr,
261  ptr_t arg2 = nullptr, ptr_t arg3 = nullptr);
262 
270  static void yield();
271 
278  static void terminate();
279 
287  static void migrate(Cluster*);
288 
293  void resume();
294 
299  bool join();
300 
304  void detach();
305 
306 
312  return *currentCluster;
313  }
314 
321  static uint64_t getTotalNumberofUTs() {
322  return totalNumberofUTs.load();
323  }
324 
329  uint64_t getID() const {
330  return uThreadID;
331  }
332 
337  static uThread* currentUThread();
338 };
339 
340 #endif /* UTHREADS_UTHREAD_H_ */
341 #include "Cluster.h"
static void migrate(Cluster *)
Move the uThread to the provided cluster.
Definition: uThread.cpp:111
void release()
release the Mutex
Definition: BlockingSync.h:191
static void yield()
Causes uThread to yield.
Definition: uThread.cpp:103
static uThread * currentUThread()
Get a pointer to the current running uThread.
Definition: uThread.cpp:170
static void terminate()
Terminates the uThread.
Definition: uThread.cpp:138
uThread(vaddr sb, size_t ss)
Definition: uThread.h:165
A user-level Semaphore.
Definition: BlockingSync.h:294
bool P()
Decrement the value of the Semaphore.
Definition: BlockingSync.h:321
static uThread * create(size_t ss, bool joinable=false)
Create a uThread with a given stack size.
Definition: uThread.cpp:71
A user-level Mutex.
Definition: BlockingSync.h:123
void resume()
Resumes the uThread. If uThread is blocked or is waiting on IO it will be placed back on the ReadyQue...
Definition: uThread.cpp:127
static uThread * create(bool joinable=false)
Create a uThread with default stack size.
Definition: uThread.h:245
static uint64_t getTotalNumberofUTs()
Definition: uThread.h:321
Object to represent kernel threads.
Definition: kThread.h:54
Data structure to cache uThreads.
Definition: uThreadCache.h:33
bool acquire()
acquire the mutex
Definition: BlockingSync.h:182
bool empty()
Whether the waiting list is empty or not.
Definition: BlockingSync.h:284
void V()
increment the value of the Semaphore
Definition: BlockingSync.h:334
Cluster & getCurrentCluster() const
return the current Cluster uThread is executed on
Definition: uThread.h:311
user-level threads (fiber)
Definition: uThread.h:63
Scheduler and Cluster of kThreads.
Definition: Cluster.h:61
void start(const Cluster &cluster, ptr_t func, ptr_t arg1=nullptr, ptr_t arg2=nullptr, ptr_t arg3=nullptr)
start the uThread by calling the function passed to it
Definition: uThread.cpp:94
bool join()
Wait for uThread to finish execution and exit.
Definition: uThread.cpp:150
A queue used to keep track of blocked uThreads.
Definition: BlockingSync.h:36
void detach()
Detach a joinable thread.
Definition: uThread.cpp:161
void wait(Mutex &mutex)
Block uThread on the condition variable using the provided mutex.
Definition: BlockingSync.h:262
const uThread & operator=(const uThread &)=delete
uint64_t getID() const
get the ID of this uThread
Definition: uThread.h:329
A user level condition variable.
Definition: BlockingSync.h:254
void signal(Mutex &mutex)
Unblock one uThread waiting on the condition variable.
Definition: BlockingSync.h:271