Skip to content

Commit 986411c

Browse files
author
deepikabhavnani
committed
Add thread safety to CRC class
Thread safety is added to serialize the hardware CRC and will not impact the software CRC.
1 parent ec4c33c commit 986411c

File tree

3 files changed

+107
-24
lines changed

3 files changed

+107
-24
lines changed

TESTS/mbed_drivers/crc/main.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,41 @@ void test_any_polynomial()
125125
}
126126
}
127127

128+
void test_thread(void)
129+
{
130+
char test[] = "123456789";
131+
uint32_t crc;
132+
MbedCRC<POLY_32BIT_ANSI, 32> ct;
133+
TEST_ASSERT_EQUAL(0, ct.compute((void *)test, strlen((const char*)test), &crc));
134+
TEST_ASSERT_EQUAL(0xCBF43926, crc);
135+
}
136+
137+
void test_thread_safety()
138+
{
139+
char test[] = "123456789";
140+
uint32_t crc;
141+
142+
MbedCRC<POLY_16BIT_IBM, 16> ct;
143+
144+
TEST_ASSERT_EQUAL(0, ct.compute_partial_start(&crc));
145+
TEST_ASSERT_EQUAL(0, ct.compute_partial((void *)&test, 4, &crc));
146+
147+
Thread t1(osPriorityNormal1, 320);
148+
t1.start(callback(test_thread));
149+
TEST_ASSERT_EQUAL(0, ct.compute_partial((void *)&test[4], 5, &crc));
150+
TEST_ASSERT_EQUAL(0, ct.compute_partial_stop(&crc));
151+
TEST_ASSERT_EQUAL(0xBB3D, crc);
152+
153+
// Wait for the thread to finish
154+
t1.join();
155+
}
156+
128157
Case cases[] = {
129158
Case("Test supported polynomials", test_supported_polynomials),
130159
Case("Test partial CRC", test_partial_crc),
131160
Case("Test SD CRC polynomials", test_sd_crc),
132-
Case("Test not supported polynomials", test_any_polynomial)
161+
Case("Test not supported polynomials", test_any_polynomial),
162+
Case("Test thread safety", test_thread_safety)
133163
};
134164

135165
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)

drivers/MbedCRC.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ namespace mbed {
2222
/** \addtogroup drivers */
2323
/** @{*/
2424

25+
SingletonPtr<PlatformMutex> mbed_crc_mutex;
26+
2527
/* Default values for different types of polynomials
2628
*/
2729
template<>

drivers/MbedCRC.h

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "drivers/TableCRC.h"
2020
#include "hal/crc_api.h"
2121
#include "platform/mbed_assert.h"
22+
#include "platform/SingletonPtr.h"
23+
#include "platform/PlatformMutex.h"
2224

2325
/* This is invalid warning from the compiler for below section of code
2426
if ((width < 8) && (NULL == _crc_table)) {
@@ -45,6 +47,7 @@ namespace mbed {
4547
* ROM polynomial tables for supported polynomials (:: crc_polynomial_t) will be used for
4648
* software CRC computation, if ROM tables are not available then CRC is computed runtime
4749
* bit by bit for all data input.
50+
* @note Synchronization level: Thread safe
4851
*
4952
* @tparam polynomial CRC polynomial value in hex
5053
* @tparam width CRC polynomial width
@@ -79,21 +82,22 @@ namespace mbed {
7982
* uint32_t crc = 0;
8083
*
8184
* printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width());
82-
*
8385
* ct.compute_partial_start(&crc);
8486
* ct.compute_partial((void *)&test, 4, &crc);
8587
* ct.compute_partial((void *)&test[4], 5, &crc);
8688
* ct.compute_partial_stop(&crc);
87-
*
8889
* printf("The CRC of data \"123456789\" is : 0x%lx\n", crc);
8990
* return 0;
9091
* }
9192
* @endcode
9293
* @ingroup drivers
9394
*/
9495

96+
extern SingletonPtr<PlatformMutex> mbed_crc_mutex;
97+
9598
template <uint32_t polynomial = POLY_32BIT_ANSI, uint8_t width = 32>
9699
class MbedCRC {
100+
97101
public:
98102
enum CrcMode
99103
{
@@ -104,7 +108,6 @@ class MbedCRC {
104108
BITWISE
105109
};
106110

107-
public:
108111
typedef uint64_t crc_data_size_t;
109112

110113
/** Lifetime of CRC object
@@ -113,7 +116,7 @@ class MbedCRC {
113116
* @param final_xor Final Xor value
114117
* @param reflect_data
115118
* @param reflect_remainder
116-
* @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t
119+
* @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t
117120
* MbedCRC <POLY_7BIT_SD, 7> ct; --- Valid POLY_7BIT_SD
118121
* MbedCRC <0x1021, 16> ct; --- Valid POLY_16BIT_CCITT
119122
* MbedCRC <POLY_16BIT_CCITT, 32> ct; --- Invalid, compilation error
@@ -135,6 +138,8 @@ class MbedCRC {
135138
}
136139

137140
/** Compute CRC for the data input
141+
* Compute CRC performs the initialization, computation and collection of
142+
* final CRC.
138143
*
139144
* @param buffer Data bytes
140145
* @param size Size of data
@@ -144,52 +149,73 @@ class MbedCRC {
144149
int32_t compute(void *buffer, crc_data_size_t size, uint32_t *crc)
145150
{
146151
MBED_ASSERT(crc != NULL);
147-
int32_t status;
148-
if (0 != (status = compute_partial_start(crc))) {
149-
*crc = 0;
152+
int32_t status = 0;
153+
154+
status = compute_partial_start(crc);
155+
if (0 != status) {
156+
unlock();
150157
return status;
151158
}
152-
if (0 != (status = compute_partial(buffer, size, crc))) {
153-
*crc = 0;
159+
160+
status = compute_partial(buffer, size, crc);
161+
if (0 != status) {
162+
unlock();
154163
return status;
155164
}
156-
if (0 != (status = compute_partial_stop(crc))) {
157-
*crc = 0;
158-
return status;
165+
166+
status = compute_partial_stop(crc);
167+
if (0 != status) {
168+
*crc = 0;
159169
}
160-
return 0;
170+
171+
return status;
172+
161173
}
162174

163175
/** Compute partial CRC for the data input.
164176
*
165177
* CRC data if not available fully, CRC can be computed in parts with available data.
166-
* Previous CRC output should be passed as argument to the current compute_partial call.
167-
* @pre: Call \ref compute_partial_start to start the partial CRC calculation.
168-
* @post: Call \ref compute_partial_stop to get the final CRC value.
178+
*
179+
* In case of hardware, intermediate values and states are saved by hardware and mutex
180+
* locking is used to serialize access to hardware CRC.
181+
*
182+
* In case of software CRC, previous CRC output should be passed as argument to the
183+
* current compute_partial call. Please note the intermediate CRC value is maintained by
184+
* application and not the driver.
185+
*
186+
* @pre: Call `compute_partial_start` to start the partial CRC calculation.
187+
* @post: Call `compute_partial_stop` to get the final CRC value.
169188
*
170189
* @param buffer Data bytes
171190
* @param size Size of data
172191
* @param crc CRC value is intermediate CRC value filled by API.
173192
* @return 0 on success or a negative error code on failure
174-
* @note: CRC as output in compute_partial is not final CRC value, call @ref compute_partial_stop
193+
* @note: CRC as output in compute_partial is not final CRC value, call `compute_partial_stop`
175194
* to get final correct CRC value.
176195
*/
177196
int32_t compute_partial(void *buffer, crc_data_size_t size, uint32_t *crc)
178197
{
198+
int32_t status = 0;
199+
179200
switch (_mode) {
180201
#ifdef DEVICE_CRC
181202
case HARDWARE:
182203
hal_crc_compute_partial((uint8_t *)buffer, size);
183204
*crc = 0;
184-
return 0;
205+
break;
185206
#endif
186207
case TABLE:
187-
return table_compute_partial(buffer, size, crc);
208+
status = table_compute_partial(buffer, size, crc);
209+
break;
188210
case BITWISE:
189-
return bitwise_compute_partial(buffer, size, crc);
211+
status = bitwise_compute_partial(buffer, size, crc);
212+
break;
213+
default:
214+
status = -1;
215+
break;
190216
}
191217

192-
return -1;
218+
return status;
193219
}
194220

195221
/** Compute partial start, indicate start of partial computation
@@ -200,14 +226,15 @@ class MbedCRC {
200226
* @param crc Initial CRC value set by the API
201227
* @return 0 on success or a negative in case of failure
202228
* @note: CRC is an out parameter and must be reused with compute_partial
203-
* and compute_partial_stop without any modifications in application.
229+
* and `compute_partial_stop` without any modifications in application.
204230
*/
205231
int32_t compute_partial_start(uint32_t *crc)
206232
{
207233
MBED_ASSERT(crc != NULL);
208234

209235
#ifdef DEVICE_CRC
210236
if (_mode == HARDWARE) {
237+
lock();
211238
crc_mbed_config_t config;
212239
config.polynomial = polynomial;
213240
config.width = width;
@@ -218,7 +245,7 @@ class MbedCRC {
218245

219246
hal_crc_compute_partial_start(&config);
220247
}
221-
#endif // DEVICE_CRC
248+
#endif
222249

223250
*crc = _initial_value;
224251
return 0;
@@ -239,6 +266,7 @@ class MbedCRC {
239266
#ifdef DEVICE_CRC
240267
if (_mode == HARDWARE) {
241268
*crc = hal_crc_get_result();
269+
unlock();
242270
return 0;
243271
}
244272
#endif
@@ -252,6 +280,7 @@ class MbedCRC {
252280
} else {
253281
*crc = (reflect_remainder(p_crc) ^ _final_xor) & get_crc_mask();
254282
}
283+
unlock();
255284
return 0;
256285
}
257286

@@ -281,6 +310,28 @@ class MbedCRC {
281310
uint32_t *_crc_table;
282311
CrcMode _mode;
283312

313+
/** Acquire exclusive access to CRC hardware/software
314+
*/
315+
void lock()
316+
{
317+
#ifdef DEVICE_CRC
318+
if (_mode == HARDWARE) {
319+
mbed_crc_mutex->lock();
320+
}
321+
#endif
322+
}
323+
324+
/** Release exclusive access to CRC hardware/software
325+
*/
326+
virtual void unlock()
327+
{
328+
#ifdef DEVICE_CRC
329+
if (_mode == HARDWARE) {
330+
mbed_crc_mutex->unlock();
331+
}
332+
#endif
333+
}
334+
284335
/** Get the current CRC data size
285336
*
286337
* @return CRC data size in bytes

0 commit comments

Comments
 (0)