Skip to content

Commit 29c42ee

Browse files
committed
Replace single condition variable with event flags - one dedicated flag per thread.
1 parent 46d08b2 commit 29c42ee

File tree

2 files changed

+44
-33
lines changed

2 files changed

+44
-33
lines changed

Diff for: src/io/serial/SerialDispatcher.cpp

+29-30
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
SerialDispatcher::SerialDispatcher(arduino::HardwareSerial & serial)
3030
: _is_initialized{false}
3131
, _mutex{}
32-
, _cond{_mutex}
3332
, _serial{serial}
3433
, _thread(osPriorityRealtime, 4096, nullptr, "SerialDispatcher")
3534
, _has_tread_started{false}
@@ -68,11 +67,8 @@ void SerialDispatcher::begin(unsigned long baudrate, uint16_t config)
6867
/* Since the thread is not in the list yet we are
6968
* going to create a new entry to the list.
7069
*/
71-
ThreadCustomerData data;
72-
data.thread_id = current_thread_id;
73-
data.block_tx_buffer = false;
74-
data.prefix_func = nullptr;
75-
data.suffix_func = nullptr;
70+
uint32_t const thread_event_flag = (1<<(_thread_customer_list.size()));
71+
ThreadCustomerData data{current_thread_id, thread_event_flag};
7672
_thread_customer_list.push_back(data);
7773
}
7874
}
@@ -87,7 +83,10 @@ void SerialDispatcher::end()
8783
osThreadId_t const current_thread_id = rtos::ThisThread::get_id();
8884
std::remove_if(std::begin(_thread_customer_list),
8985
std::end (_thread_customer_list),
90-
[current_thread_id](ThreadCustomerData const d) -> bool { return (d.thread_id == current_thread_id); });
86+
[current_thread_id](ThreadCustomerData const d) -> bool
87+
{
88+
return (d.thread_id == current_thread_id);
89+
});
9190

9291
/* If no thread consumers are left also end
9392
* the serial device altogether.
@@ -104,7 +103,7 @@ int SerialDispatcher::available()
104103
{
105104
mbed::ScopedLock<rtos::Mutex> lock(_mutex);
106105
auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id());
107-
if (iter == std::end(_thread_customer_list)) return 0;
106+
assert(iter != std::end(_thread_customer_list));
108107

109108
prepareSerialReader(iter);
110109
handleSerialReader();
@@ -116,7 +115,7 @@ int SerialDispatcher::peek()
116115
{
117116
mbed::ScopedLock<rtos::Mutex> lock(_mutex);
118117
auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id());
119-
if (iter == std::end(_thread_customer_list)) return 0;
118+
assert(iter != std::end(_thread_customer_list));
120119

121120
prepareSerialReader(iter);
122121
handleSerialReader();
@@ -128,7 +127,7 @@ int SerialDispatcher::read()
128127
{
129128
mbed::ScopedLock<rtos::Mutex> lock(_mutex);
130129
auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id());
131-
if (iter == std::end(_thread_customer_list)) return 0;
130+
assert(iter != std::end(_thread_customer_list));
132131

133132
prepareSerialReader(iter);
134133
handleSerialReader();
@@ -150,14 +149,8 @@ size_t SerialDispatcher::write(uint8_t const b)
150149
size_t SerialDispatcher::write(const uint8_t * data, size_t len)
151150
{
152151
mbed::ScopedLock<rtos::Mutex> lock(_mutex);
153-
154152
auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id());
155-
156-
/* If this thread hasn't registered yet
157-
* with the SerialDispatcher via 'begin'.
158-
*/
159-
if (iter == std::end(_thread_customer_list))
160-
return 0;
153+
assert(iter != std::end(_thread_customer_list));
161154

162155
size_t bytes_written = 0;
163156
for (; (bytes_written < len) && iter->tx_buffer.availableForStore(); bytes_written++)
@@ -166,7 +159,7 @@ size_t SerialDispatcher::write(const uint8_t * data, size_t len)
166159
/* Inform the worker thread that new data has
167160
* been written to a Serial transmit buffer.
168161
*/
169-
_cond.notify_one();
162+
_data_available_for_transmit.set(iter->thread_event_flag);
170163

171164
return bytes_written;
172165
}
@@ -175,32 +168,37 @@ void SerialDispatcher::block()
175168
{
176169
mbed::ScopedLock<rtos::Mutex> lock(_mutex);
177170
auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id());
178-
if (iter == std::end(_thread_customer_list)) return;
171+
assert(iter != std::end(_thread_customer_list));
172+
179173
iter->block_tx_buffer = true;
180174
}
181175

182176
void SerialDispatcher::unblock()
183177
{
184178
mbed::ScopedLock<rtos::Mutex> lock(_mutex);
185179
auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id());
186-
if (iter == std::end(_thread_customer_list)) return;
180+
assert(iter != std::end(_thread_customer_list));
181+
187182
iter->block_tx_buffer = false;
188-
_cond.notify_one();
183+
184+
_data_available_for_transmit.set(iter->thread_event_flag);
189185
}
190186

191187
void SerialDispatcher::prefix(PrefixInjectorCallbackFunc func)
192188
{
193189
mbed::ScopedLock<rtos::Mutex> lock(_mutex);
194190
auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id());
195-
if (iter == std::end(_thread_customer_list)) return;
191+
assert(iter != std::end(_thread_customer_list));
192+
196193
iter->prefix_func = func;
197194
}
198195

199196
void SerialDispatcher::suffix(SuffixInjectorCallbackFunc func)
200197
{
201198
mbed::ScopedLock<rtos::Mutex> lock(_mutex);
202199
auto iter = findThreadCustomerDataById(rtos::ThisThread::get_id());
203-
if (iter == std::end(_thread_customer_list)) return;
200+
assert(iter != std::end(_thread_customer_list));
201+
204202
iter->suffix_func = func;
205203
}
206204

@@ -226,12 +224,10 @@ void SerialDispatcher::threadFunc()
226224

227225
while(!_terminate_thread)
228226
{
229-
/* Prevent race conditions by multi-threaded
230-
* access to shared data.
231-
*/
232-
mbed::ScopedLock<rtos::Mutex> lock(_mutex);
233-
/* Wait for new data to be available */
234-
_cond.wait();
227+
/* Wait for data to be available in a transmit buffer. */
228+
static uint32_t constexpr ALL_EVENT_FLAGS = 0x7fffffff;
229+
_data_available_for_transmit.wait_any(ALL_EVENT_FLAGS, osWaitForever, /* clear */ true);
230+
235231
/* Iterate over all list entries. */
236232
std::for_each(std::begin(_thread_customer_list),
237233
std::end (_thread_customer_list),
@@ -303,7 +299,10 @@ std::list<SerialDispatcher::ThreadCustomerData>::iterator SerialDispatcher::find
303299
{
304300
return std::find_if(std::begin(_thread_customer_list),
305301
std::end (_thread_customer_list),
306-
[thread_id](ThreadCustomerData const d) -> bool { return (d.thread_id == thread_id); });
302+
[thread_id](ThreadCustomerData const d) -> bool
303+
{
304+
return (d.thread_id == thread_id);
305+
});
307306
}
308307

309308
void SerialDispatcher::prepareSerialReader(std::list<ThreadCustomerData>::iterator & iter)

Diff for: src/io/serial/SerialDispatcher.h

+15-3
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class SerialDispatcher : public arduino::HardwareSerial
7171

7272
bool _is_initialized;
7373
rtos::Mutex _mutex;
74-
rtos::ConditionVariable _cond;
74+
rtos::EventFlags _data_available_for_transmit;
7575
arduino::HardwareSerial & _serial;
7676

7777
rtos::Thread _thread;
@@ -84,15 +84,27 @@ class SerialDispatcher : public arduino::HardwareSerial
8484
static int constexpr THREADSAFE_SERIAL_TRANSMIT_RINGBUFFER_SIZE = 128;
8585
typedef arduino::RingBufferN<THREADSAFE_SERIAL_TRANSMIT_RINGBUFFER_SIZE> SerialTransmitRingbuffer;
8686

87-
typedef struct
87+
class ThreadCustomerData
8888
{
89+
public:
90+
ThreadCustomerData(osThreadId_t const t, uint32_t const t_event_flag)
91+
: thread_id{t}
92+
, thread_event_flag{t_event_flag}
93+
, tx_buffer{}
94+
, block_tx_buffer{false}
95+
, rx_buffer{}
96+
, prefix_func{nullptr}
97+
, suffix_func{nullptr}
98+
{ }
99+
89100
osThreadId_t thread_id;
101+
uint32_t thread_event_flag;
90102
SerialTransmitRingbuffer tx_buffer;
91103
bool block_tx_buffer;
92104
mbed::SharedPtr<arduino::RingBuffer> rx_buffer; /* Only when a thread has expressed interested to read from serial a receive ringbuffer is allocated. */
93105
PrefixInjectorCallbackFunc prefix_func;
94106
SuffixInjectorCallbackFunc suffix_func;
95-
} ThreadCustomerData;
107+
};
96108

97109
std::list<ThreadCustomerData> _thread_customer_list;
98110

0 commit comments

Comments
 (0)