Mark3 Realtime Kernel
notify.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 ===========================================================================*/
21 #include "mark3.h"
22 namespace Mark3
23 {
24 namespace
25 {
26  //---------------------------------------------------------------------------
27  void TimedNotify_Callback(Thread* pclOwner_, void* pvData_)
28  {
29  KERNEL_ASSERT(nullptr != pclOwner_);
30  KERNEL_ASSERT(nullptr != pvData_);
31 
32  auto* pclNotify = static_cast<Notify*>(pvData_);
33 
34  // Indicate that the semaphore has expired on the thread
35  pclOwner_->SetExpired(true);
36 
37  // Wake up the thread that was blocked on this semaphore.
38  pclNotify->WakeMe(pclOwner_);
39 
40  if (pclOwner_->GetCurPriority() >= Scheduler::GetCurrentThread()->GetCurPriority()) {
41  Thread::Yield();
42  }
43  }
44 } // anonymous namespace
45 
46 //---------------------------------------------------------------------------
48 {
49  // If there are any threads waiting on this object when it goes out
50  // of scope, set a kernel panic.
51  if (nullptr != m_clBlockList.GetHead()) {
53  }
54 }
55 
56 //---------------------------------------------------------------------------
57 void Notify::Init(void)
58 {
61 
62  m_bPending = false;
63 }
64 
65 //---------------------------------------------------------------------------
66 void Notify::Signal(void)
67 {
69 
70  auto bReschedule = false;
71 
72  { // Begin critical section
73  const auto cs = CriticalGuard{};
74  auto* pclCurrent = m_clBlockList.GetHead();
75  if (nullptr == pclCurrent) {
76  m_bPending = true;
77  } else {
78  while (nullptr != pclCurrent) {
79  UnBlock(pclCurrent);
80  if (!bReschedule && (pclCurrent->GetCurPriority() >= Scheduler::GetCurrentThread()->GetCurPriority())) {
81  bReschedule = true;
82  }
83  pclCurrent = m_clBlockList.GetHead();
84  }
85  m_bPending = false;
86  }
87  } // end critical section
88 
89  if (bReschedule) {
90  Thread::Yield();
91  }
92 }
93 
94 //---------------------------------------------------------------------------
95 void Notify::Wait(bool* pbFlag_)
96 {
97  KERNEL_ASSERT(nullptr != pbFlag_);
99 
100  auto bEarlyExit = false;
101  { // Begin critical section
102  const auto cs = CriticalGuard{};
103  if (!m_bPending) {
105  if (nullptr != pbFlag_) {
106  *pbFlag_ = false;
107  }
108  } else {
109  m_bPending = false;
110  bEarlyExit = true;
111  }
112  } // End critical section
113 
114  if (bEarlyExit) {
115  return;
116  }
117 
118  Thread::Yield();
119  if (nullptr != pbFlag_) {
120  *pbFlag_ = true;
121  }
122 }
123 
124 //---------------------------------------------------------------------------
125 bool Notify::Wait(uint32_t u32WaitTimeMS_, bool* pbFlag_)
126 {
127  KERNEL_ASSERT(nullptr != pbFlag_);
129 
130  auto bUseTimer = false;
131  auto bEarlyExit = false;
132  auto clNotifyTimer = Timer {};
133 
134  { // Begin critical section
135  const auto cs = CriticalGuard{};
136  if (!m_bPending) {
137  if (0u != u32WaitTimeMS_) {
138  bUseTimer = true;
139  g_pclCurrent->SetExpired(false);
140 
141  clNotifyTimer.Init();
142  clNotifyTimer.Start(false, u32WaitTimeMS_, TimedNotify_Callback, this);
143  }
144 
146 
147  if (nullptr != pbFlag_) {
148  *pbFlag_ = false;
149  }
150  } else {
151  m_bPending = false;
152  bEarlyExit = true;
153  }
154  } // end critical section
155 
156  if (bEarlyExit) {
157  return true;
158  }
159 
160  Thread::Yield();
161 
162  if (bUseTimer) {
163  clNotifyTimer.Stop();
164  return (g_pclCurrent->GetExpired() == false);
165  }
166 
167  if (nullptr != pbFlag_) {
168  *pbFlag_ = true;
169  }
170 
171  return true;
172 }
173 
174 //---------------------------------------------------------------------------
175 void Notify::WakeMe(Thread* pclChosenOne_)
176 {
177  KERNEL_ASSERT(nullptr != pclChosenOne_);
179 
180  UnBlock(pclChosenOne_);
181 }
182 } // namespace Mark3
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
#define KERNEL_ASSERT(x)
Definition: kerneldebug.h:36
void Block(Thread *pclThread_)
Block Blocks a thread on this object. This is the fundamental operation performed by any sort of bloc...
Definition: blocking.cpp:26
Definition: atomic.cpp:23
Mark3::Thread * g_pclCurrent
Definition: scheduler.cpp:25
bool m_bPending
Definition: notify.h:89
PORT_PRIO_TYPE GetCurPriority(void)
GetCurPriority Return the priority of the current thread.
Definition: thread.h:181
void WakeMe(Thread *pclChosenOne_)
WakeMe Wake the specified thread from its current blocking queue. Note that this is only public in or...
Definition: notify.cpp:175
Single include file given to users of the Mark3 Kernel API.
The Thread Class. This object providing the fundamental thread control data structures and functions ...
Definition: thread.h:64
void SetExpired(bool bExpired_)
SetExpired Set the status of the current blocking call on the thread.
Definition: thread.cpp:417
#define PANIC_ACTIVE_NOTIFY_DESCOPED
Definition: paniccodes.h:32
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 Signal(void)
Signal Signal the notification object. This will cause the highest priority thread currently blocking...
Definition: notify.cpp:66
void Init(void)
Init Initialze the Notification object prior to use.
Definition: notify.cpp:57
void Wait(bool *pbFlag_)
Wait Block the current thread, waiting for a signal on the object.
Definition: notify.cpp:95
The CriticalGuard class. This class provides an implemention of RAII for critical sections...
Definition: criticalguard.h:38
bool GetExpired()
GetExpired Return the status of the most-recent blocking call on the thread.
Definition: thread.cpp:424
The Timer Class. This class provides kernel-managed timers, used to provide high-precision delays...
Definition: timer.h:68
ThreadList m_clBlockList
Definition: blocking.h:133
void SetInitialized(void)
SetInitialized.
Definition: blocking.h:117
static Thread * GetCurrentThread()
GetCurrentThread Return the pointer to the currently-running thread.
Definition: scheduler.h:116
static void Panic(uint16_t u16Cause_)
Panic Cause the kernel to enter its panic state.
Definition: kernel.cpp:70