MEL
Microthread & Execution library
Event_mthread.h
1 #pragma once
2 /*
3  * SPDX-FileCopyrightText: 2005,2022 Daniel Barrientos <danivillamanin@gmail.com>
4  *
5  * SPDX-License-Identifier: MIT
6  */
7 #include <MelLibType.h>
8 #include <list>
9 #include <tasking/Process.h>
10 #include <core/Callback.h>
11 #include <tasking/ProcessScheduler.h>
12 #include <mutex>
13 namespace mel
14 {
15  namespace tasking
16  {
17  using ::mel::tasking::Process;
18  using std::list;
19  using mel::core::Callback;
20  enum class EEventMTWaitCode {
21  EVENTMT_WAIT_OK,
22  EVENTMT_WAIT_TIMEOUT,
23  EVENTMT_WAIT_KILL};
24  static const int EVENTMT_WAIT_INFINITE = -1;
25  class MEL_API EventBase
26  {
27  public:
28  EventBase(bool autoRelease=true, bool signaled=false);
29 
30  void reset();
31  private:
32 
33  typedef list< std::shared_ptr<Process> > TProcessList;
34  void _triggerActivation( bool sendToAll );
35  protected:
36  bool mSignaled;
37  bool mAutoRelease;
38  TProcessList mWaitingProcesses;
39  void _set( bool sendToAll );
40 
41  };
42 
46  class MEL_API EventMTThreadSafePolicy : public EventBase
47  {
48  public:
49  EventMTThreadSafePolicy(bool autoRelease, bool signaled);
50  void set(bool sendToAll)
51  {
52  std::scoped_lock<std::mutex> lck(mCS);
53  EventBase::_set(sendToAll);
54  }
55  protected:
56  EEventMTWaitCode _wait( unsigned int msecs );
57  template <class F>
58  EEventMTWaitCode _waitAndDo( F postSleep,unsigned int msecs )
59  {
60  EEventMTWaitCode result = EEventMTWaitCode::EVENTMT_WAIT_OK;
61  mCS.lock();
62  if ( !mSignaled )
63  {
65  mWaitingProcesses.push_back( p );
66 
67  Process::ESwitchResult switchResult;
68  if ( msecs == EVENTMT_WAIT_INFINITE )
69  switchResult = ::mel::tasking::Process::sleepAndDo([this,postSleep]()
70  {
71  mCS.unlock();
72  postSleep();
73  } );
74  else
75  switchResult = ::mel::tasking::Process::waitAndDo(msecs, [this,postSleep]()
76  {
77  mCS.unlock();
78  postSleep();
79  });
80  switch ( switchResult )
81  {
83  result = EEventMTWaitCode::EVENTMT_WAIT_KILL;
84  break;
86  result = EEventMTWaitCode::EVENTMT_WAIT_OK;
87  break;
88  default:
89  result = EEventMTWaitCode::EVENTMT_WAIT_TIMEOUT;
90  break;
91  }
92  //remove process form list. It's safe to do it here because current process is already waiting (now is returning)
93  //maybe other process do wait on this events
94  mCS.lock();
95  mWaitingProcesses.remove( p );
96  mCS.unlock();
97  }else
98  {
99  mCS.unlock();
100  postSleep();
101  }
102  return result;
103  }
104  private:
105  std::mutex mCS;
106  };
110  class MEL_API EventNoMTThreadSafePolicy : public EventBase
111  {
112  public:
113  EventNoMTThreadSafePolicy(bool autoRelease, bool signaled);
114  inline void set(bool sendToAll)
115  {
116  EventBase::_set(sendToAll);
117  }
118  protected:
119  EEventMTWaitCode _wait( unsigned int msecs );
120  template <class F>
121  EEventMTWaitCode _waitAndDo( F postSleep,unsigned int msecs )
122  {
123  EEventMTWaitCode result = EEventMTWaitCode::EVENTMT_WAIT_OK;
124  if ( !mSignaled )
125  {
127  mWaitingProcesses.push_back( p );
128 
129  Process::ESwitchResult switchResult;
130  if ( msecs == EVENTMT_WAIT_INFINITE )
131  switchResult = ::mel::tasking::Process::sleepAndDo([postSleep]()
132  {
133  postSleep();
134  } );
135  else
136  switchResult = ::mel::tasking::Process::waitAndDo(msecs, [this,postSleep]()
137  {
138  postSleep();
139  });
140  switch ( switchResult )
141  {
143  result = EEventMTWaitCode::EVENTMT_WAIT_KILL;
144  break;
146  result = EEventMTWaitCode::EVENTMT_WAIT_OK;
147  break;
148  default:
149  result = EEventMTWaitCode::EVENTMT_WAIT_TIMEOUT;
150  break;
151  }
152  //remove process form list. It's safe to do it here because current process is already waiting (now is returning)
153  //maybe other process do wait on this events
154  mWaitingProcesses.remove( p );
155  }else
156  {
157  postSleep();
158  }
159  return result;
160  }
161 
162  };
166  template <class MultithreadPolicy = EventMTThreadSafePolicy> class Event_mthread : public MultithreadPolicy
167  {
168  public:
169 
177  Event_mthread(bool autoRelease=true, bool signaled=false):MultithreadPolicy(autoRelease,signaled){}
178  //~Event_mthread();
179 
184  void set( bool sendToAll = true ){MultithreadPolicy::set(sendToAll);}
185 
191  inline EEventMTWaitCode wait( unsigned int msecs = EVENTMT_WAIT_INFINITE)
192  {
193  return MultithreadPolicy::_wait( msecs );
194  }
195 
200  template <class F>
201  EEventMTWaitCode waitAndDo( F postSleep,unsigned int msecs = EVENTMT_WAIT_INFINITE )
202  {
203  return MultithreadPolicy::_waitAndDo( postSleep,msecs );
204  }
205 
206  private:
207 
208 
209  };
210  }
211 }
create Callback from callable
Definition: Callback_Impl.h:142
class similar to Event Class (which is for thread synchronization) but for Process (with Microthread ...
Definition: Event_mthread.h:167
EEventMTWaitCode wait(unsigned int msecs=EVENTMT_WAIT_INFINITE)
Definition: Event_mthread.h:191
void set(bool sendToAll=true)
Definition: Event_mthread.h:184
Event_mthread(bool autoRelease=true, bool signaled=false)
Definition: Event_mthread.h:177
EEventMTWaitCode waitAndDo(F postSleep, unsigned int msecs=EVENTMT_WAIT_INFINITE)
Definition: Event_mthread.h:201
Definition: Event_mthread.h:26
Policy for multithread safe event.
Definition: Event_mthread.h:47
Policy for non-multithread safe event.
Definition: Event_mthread.h:111
static ESwitchResult sleepAndDo(F postSleep)
Sleep current process and execute given callable. To reactivate to you must use wakeUp.
Definition: Process.h:391
static ESwitchResult waitAndDo(unsigned int msegs, F postWait) OPTIMIZE_FLAGS
Wait for a given time and execute given callable.
Definition: Process.h:380
ESwitchResult
Reason why the process returns from context switch.
Definition: Process.h:127
@ ESWITCH_KILL
return from context switch because a kill
static std::shared_ptr< Process > getCurrentProcess()
Definition: Callback_Impl.h:11