Mark3 Realtime Kernel
eventflag.cpp
Go to the documentation of this file.
1 /*===========================================================================
2  _____ _____ _____ _____
3  ___| _|__ __|_ |__ __|__ |__ __| __ |__ ______
4 | \ / | || \ || | || |/ / ||___ |
5 | \/ | || \ || \ || \ ||___ |
6 |__/\__/|__|_||__|\__\ __||__|\__\ __||__|\__\ __||______|
7  |_____| |_____| |_____| |_____|
8 
9 --[Mark3 Realtime Platform]--------------------------------------------------
10 
11 Copyright (c) 2012 - 2019 m0slevin, all rights reserved.
12 See license.txt for more information
13 ===========================================================================*/
19 #include "mark3.h"
20 
21 #if KERNEL_EVENT_FLAGS
22 
23 namespace Mark3
24 {
25 namespace
26 {
27  //---------------------------------------------------------------------------
38  void TimedEventFlag_Callback(Thread* pclOwner_, void* pvData_)
39  {
40  KERNEL_ASSERT(nullptr != pclOwner_);
41  KERNEL_ASSERT(nullptr != pvData_);
42 
43  auto* pclEventFlag = static_cast<EventFlag*>(pvData_);
44 
45  pclOwner_->SetExpired(true);
46  pclOwner_->SetEventFlagMask(0);
47 
48  pclEventFlag->WakeMe(pclOwner_);
49  if (pclOwner_->GetCurPriority() >= Scheduler::GetCurrentThread()->GetCurPriority()) {
50  Thread::Yield();
51  }
52  }
53 } // anonymous namespace
54 //---------------------------------------------------------------------------
56 {
57  // If there are any threads waiting on this object when it goes out
58  // of scope, set a kernel panic.
59  if (nullptr != m_clBlockList.HighestWaiter()) {
61  }
62 }
63 
64 //---------------------------------------------------------------------------
65 void EventFlag::Init()
66 {
68  m_u16SetMask = 0;
70 }
71 
72 //---------------------------------------------------------------------------
73 void EventFlag::WakeMe(Thread* pclChosenOne_)
74 {
76  KERNEL_ASSERT(nullptr != pclChosenOne_);
77 
78  UnBlock(pclChosenOne_);
79 }
80 
81 //---------------------------------------------------------------------------
82 uint16_t EventFlag::Wait_i(uint16_t u16Mask_, EventFlagOperation eMode_, uint32_t u32TimeMS_)
83 {
86 
87  auto bThreadYield = false;
88  auto bMatch = false;
89 
90  auto clEventTimer = Timer {};
91  auto bUseTimer = false;
92 
93  // Ensure we're operating in a critical section while we determine
94  // whether or not we need to block the current thread on this object.
95 
96  { // Begin critical section
97  const auto cs = CriticalGuard{};
98 
99  // Check to see whether or not the current mask matches any of the
100  // desired bits.
101  g_pclCurrent->SetEventFlagMask(u16Mask_);
102 
103  if ((EventFlagOperation::All_Set == eMode_) || (EventFlagOperation::All_Clear == eMode_)) {
104  // Check to see if the flags in their current state match all of
105  // the set flags in the event flag group, with this mask.
106  if ((m_u16SetMask & u16Mask_) == u16Mask_) {
107  bMatch = true;
108  g_pclCurrent->SetEventFlagMask(u16Mask_);
109 
110  if (EventFlagOperation::All_Clear == eMode_) {
111  m_u16SetMask &= ~u16Mask_;
112  g_pclCurrent->SetExpired(false);
113  }
114  }
115  } else if ((EventFlagOperation::Any_Set == eMode_) || (EventFlagOperation::Any_Clear == eMode_)) {
116  // Check to see if the existing flags match any of the set flags in
117  // the event flag group with this mask
118  if ((m_u16SetMask & u16Mask_) != 0) {
119  bMatch = true;
121 
122  if (EventFlagOperation::Any_Clear == eMode_) {
123  m_u16SetMask &= ~u16Mask_;
124  g_pclCurrent->SetExpired(false);
125  }
126  }
127  }
128 
129  // We're unable to match this pattern as-is, so we must block.
130  if (!bMatch) {
131  // Reset the current thread's event flag mask & mode
132  g_pclCurrent->SetEventFlagMask(u16Mask_);
134 
135  if (0u != u32TimeMS_) {
136  g_pclCurrent->SetExpired(false);
137  clEventTimer.Init();
138  clEventTimer.Start(false, u32TimeMS_, TimedEventFlag_Callback, this);
139  bUseTimer = true;
140  }
141 
142  // Add the thread to the object's block-list.
144 
145  // Trigger that
146  bThreadYield = true;
147  }
148 
149  // If bThreadYield is set, it means that we've blocked the current thread,
150  // and must therefore rerun the scheduler to determine what thread to
151  // switch to.
152  if (bThreadYield) {
153  // Switch threads immediately
154  Thread::Yield();
155  }
156  } // end critical section
157 
162  if (bUseTimer && bThreadYield) {
163  clEventTimer.Stop();
164  }
165 
166  return g_pclCurrent->GetEventFlagMask();
167 }
168 
169 //---------------------------------------------------------------------------
170 uint16_t EventFlag::Wait(uint16_t u16Mask_, EventFlagOperation eMode_)
171 {
173  return Wait_i(u16Mask_, eMode_, 0);
174 }
175 
176 //---------------------------------------------------------------------------
177 uint16_t EventFlag::Wait(uint16_t u16Mask_, EventFlagOperation eMode_, uint32_t u32TimeMS_)
178 {
180  return Wait_i(u16Mask_, eMode_, u32TimeMS_);
181 }
182 
183 //---------------------------------------------------------------------------
184 void EventFlag::Set(uint16_t u16Mask_)
185 {
187 
188  auto bReschedule = false;
189 
190  const auto cs = CriticalGuard{};
191  // Walk through the whole block list, checking to see whether or not
192  // the current flag set now matches any/all of the masks and modes of
193  // the threads involved.
194 
195  m_u16SetMask |= u16Mask_;
196  auto u16NewMask = m_u16SetMask;
197 
198  // Start at the head of the list, and iterate through until we hit the
199  // "head" element in the list again. Ensure that we handle the case where
200  // we remove the first or last elements in the list, or if there's only
201  // one element in the list.
202 
203  auto* pclCurrent = m_clBlockList.GetHead();
204  // Do nothing when there are no objects blocking.
205  if (nullptr != pclCurrent) {
206  // First loop - process every thread in the block-list and check to
207  // see whether or not the current flags match the event-flag conditions
208  // on the thread.
209  auto* pclPrev = (Thread*){};
210  do {
211  pclPrev = pclCurrent;
212  pclCurrent = pclCurrent->GetNext();
213 
214  // Read the thread's event mask/mode
215  auto u16ThreadMask = pclPrev->GetEventFlagMask();
216  auto eThreadMode = pclPrev->GetEventFlagMode();
217 
218  // For the "any" mode - unblock the blocked threads if one or more bits
219  // in the thread's bitmask match the object's bitmask
220  if ((EventFlagOperation::Any_Set == eThreadMode) || (EventFlagOperation::Any_Clear == eThreadMode)) {
221  if ((u16ThreadMask & m_u16SetMask) != 0) {
222  pclPrev->SetEventFlagMode(EventFlagOperation::Pending_Unblock);
223  pclPrev->SetEventFlagMask(m_u16SetMask & u16ThreadMask);
224  bReschedule = true;
225 
226  // If the "clear" variant is set, then clear the bits in the mask
227  // that caused the thread to unblock.
228  if (EventFlagOperation::Any_Clear == eThreadMode) {
229  u16NewMask &= ~(u16ThreadMask & u16Mask_);
230  }
231  }
232  }
233  // For the "all" mode, every set bit in the thread's requested bitmask must
234  // match the object's flag mask.
235  else if ((EventFlagOperation::All_Set == eThreadMode) || (EventFlagOperation::All_Clear == eThreadMode)) {
236  if ((u16ThreadMask & m_u16SetMask) == u16ThreadMask) {
237  pclPrev->SetEventFlagMode(EventFlagOperation::Pending_Unblock);
238  pclPrev->SetEventFlagMask(u16ThreadMask);
239  bReschedule = true;
240 
241  // If the "clear" variant is set, then clear the bits in the mask
242  // that caused the thread to unblock.
243  if (EventFlagOperation::All_Clear == eThreadMode) {
244  u16NewMask &= ~(u16ThreadMask & u16Mask_);
245  }
246  }
247  }
248  }
249  // To keep looping, ensure that there's something in the list, and
250  // that the next item isn't the head of the list.
251  while (pclPrev != m_clBlockList.GetTail());
252 
253  // Second loop - go through and unblock all of the threads that
254  // were tagged for unblocking.
255  pclCurrent = m_clBlockList.GetHead();
256  auto bIsTail = false;
257  do {
258  pclPrev = pclCurrent;
259  pclCurrent = pclCurrent->GetNext();
260 
261  // Check to see if this is the condition to terminate the loop
262  if (pclPrev == m_clBlockList.GetTail()) {
263  bIsTail = true;
264  }
265 
266  // If the first pass indicated that this thread should be
267  // unblocked, then unblock the thread
268  if (pclPrev->GetEventFlagMode() == EventFlagOperation::Pending_Unblock) {
269  UnBlock(pclPrev);
270  }
271  } while (!bIsTail);
272  }
273 
274  // If we awoke any threads, re-run the scheduler
275  if (bReschedule) {
276  Thread::Yield();
277  }
278 
279  // Update the bitmask based on any "clear" operations performed along
280  // the way
281  m_u16SetMask = u16NewMask;
282 }
283 
284 //---------------------------------------------------------------------------
285 void EventFlag::Clear(uint16_t u16Mask_)
286 {
288 
289  // Just clear the bitfields in the local object.
290  const auto cs = CriticalGuard{};
291  m_u16SetMask &= ~u16Mask_;
292 }
293 
294 //---------------------------------------------------------------------------
295 uint16_t EventFlag::GetMask()
296 {
298 
299  // Return the presently held event flag values in this object. Ensure
300  // we get this within a critical section to guarantee atomicity.
301  const auto cs = CriticalGuard{};
302  auto u16Return = m_u16SetMask;
303  return u16Return;
304 }
305 } // namespace Mark3
306 #endif // #if KERNEL_EVENT_FLAGS
uint16_t m_u16SetMask
Event flags currently set in this object.
Definition: eventflag.h:119
EventFlagOperation
Definition: kerneltypes.h:50
Block until all bits in the specified bitmask are set.
void UnBlock(Thread *pclThread_)
UnBlock Unblock a thread that is already blocked on this object, returning it to the "ready" state by...
Definition: blocking.cpp:56
uint16_t GetMask()
GetMask Returns the state of the 16-bit bitmask within this object.
#define KERNEL_ASSERT(x)
Definition: kerneldebug.h:36
void BlockPriority(Thread *pclThread_)
BlockPriority Same as Block(), but ensures that threads are added to the block-list in priority-order...
Definition: blocking.cpp:41
void Set(uint16_t u16Mask_)
Set Set additional flags in this object (logical OR). This API can potentially result in threads bloc...
Block until any bits in the specified bitmask are cleared.
void Clear(uint16_t u16Mask_)
ClearFlags - Clear a specific set of flags within this object, specific by bitmask.
Definition: atomic.cpp:23
uint16_t GetEventFlagMask()
GetEventFlagMask returns the thread&#39;s current event-flag mask, which is used in conjunction with the ...
Definition: thread.h:317
Mark3::Thread * g_pclCurrent
Definition: scheduler.cpp:25
PORT_PRIO_TYPE GetCurPriority(void)
GetCurPriority Return the priority of the current thread.
Definition: thread.h:181
uint16_t Wait_i(uint16_t u16Mask_, EventFlagOperation eMode_, uint32_t u32TimeMS_)
Wait_i Interal abstraction used to manage both timed and untimed wait operations. ...
Single include file given to users of the Mark3 Kernel API.
void SetExpired(bool bExpired_)
SetExpired Set the status of the current blocking call on the thread.
Definition: thread.cpp:417
void SetEventFlagMask(uint16_t u16Mask_)
SetEventFlagMask Sets the active event flag bitfield mask.
Definition: thread.h:323
Block until all bits in the specified bitmask are cleared.
uint16_t Wait(uint16_t u16Mask_, EventFlagOperation eMode_)
Wait Block a thread on the specific flags in this event flag group.
bool IsInitialized(void)
IsInitialized.
Definition: blocking.h:123
static void Yield(void)
Yield Yield the thread - this forces the system to call the scheduler and determine what thread shoul...
Definition: thread.cpp:304
void SetEventFlagMode(EventFlagOperation eMode_)
SetEventFlagMode Sets the active event flag operation mode.
Definition: thread.h:330
void Init()
Init Initializes the EventFlag object prior to use.
Thread * HighestWaiter()
HighestWaiter Return a pointer to the highest-priority thread in the thread-list. ...
Definition: threadlist.cpp:128
ThreadList m_clBlockList
Definition: blocking.h:133
void WakeMe(Thread *pclChosenOne_)
WakeMe Wake the given thread, currently blocking on this object.
void SetInitialized(void)
SetInitialized.
Definition: blocking.h:117
static Thread * GetCurrentThread()
GetCurrentThread Return the pointer to the currently-running thread.
Definition: scheduler.h:116
#define PANIC_ACTIVE_EVENTFLAG_DESCOPED
Definition: paniccodes.h:31
Block until any bits in the specified bitmask are set.
static void Panic(uint16_t u16Cause_)
Panic Cause the kernel to enter its panic state.
Definition: kernel.cpp:70