@@ -31,10 +31,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
31
* @author{Abhi Gundrala <[email protected] >}
32
32
*/
33
33
34
- #if !defined(LF_SINGLE_THREADED )
35
- #error "Only the single-threaded runtime has support for RP2040"
36
- #endif
37
-
38
34
#include "lf_rp2040_support.h"
39
35
#include "platform.h"
40
36
#include "utils/util.h"
@@ -51,6 +47,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51
47
*/
52
48
static critical_section_t _lf_crit_sec ;
53
49
50
+ /**
51
+ * critical section struct for atomics implementation
52
+ */
53
+ static critical_section_t _lf_atomics_crit_sec ;
54
+
54
55
/**
55
56
* binary semaphore for lf event notification
56
57
* used by external isr or second core thread.
@@ -63,13 +64,14 @@ static uint32_t _lf_num_nested_crit_sec = 0;
63
64
64
65
/**
65
66
* Initialize basic runtime infrastructure and
66
- * synchronization structs for an single-threaded runtime.
67
+ * synchronization structs for a single-threaded runtime.
67
68
*/
68
69
void _lf_initialize_clock (void ) {
69
70
// init stdio lib
70
71
stdio_init_all ();
71
72
// init sync structs
72
73
critical_section_init (& _lf_crit_sec );
74
+ critical_section_init (& _lf_atomics_crit_sec );
73
75
sem_init (& _lf_sem_irq_event , 0 , 1 );
74
76
}
75
77
@@ -214,6 +216,170 @@ int _lf_single_threaded_notify_of_event() {
214
216
sem_release (& _lf_sem_irq_event );
215
217
return 0 ;
216
218
}
219
+
220
+ #else // LF_SINGLE_THREADED
221
+
222
+ #warning "Threaded runtime on RP2040 is still experimental"
223
+
224
+ /**
225
+ * @brief Get the number of cores on the host machine.
226
+ */
227
+ int lf_available_cores () {
228
+ // Right now, runtime creates 1 main thread and 1 worker thread
229
+ // In the future, this may be changed to 2 (if main thread also functions
230
+ // as a worker thread)
231
+ return 1 ;
232
+ }
233
+
234
+ static void * (* thread_1 ) (void * );
235
+ static void * thread_1_args ;
236
+ static int num_create_threads_called = 0 ;
237
+ static semaphore_t thread_1_done ;
238
+ static void * thread_1_return ;
239
+
240
+ #define MAGIC_THREAD1_ID 314159
241
+
242
+ void core1_entry () {
243
+ thread_1_return = thread_1 (thread_1_args );
244
+ sem_release (& thread_1_done );
245
+
246
+ // infinite loop; core1 should never exit
247
+ while (1 ){
248
+ tight_loop_contents ();
249
+ }
250
+ }
251
+
252
+ int lf_thread_create (lf_thread_t * thread , void * (* lf_thread ) (void * ), void * arguments ) {
253
+ // make sure this fn is only called once
254
+ if (num_create_threads_called != 0 ) {
255
+ return 1 ;
256
+ }
257
+ thread_1 = lf_thread ;
258
+ thread_1_args = arguments ;
259
+ num_create_threads_called += 1 ;
260
+ sem_init (& thread_1_done , 0 , 1 );
261
+ multicore_launch_core1 (core1_entry );
262
+ * thread = MAGIC_THREAD1_ID ;
263
+ return 0 ;
264
+ }
265
+
266
+ int lf_thread_join (lf_thread_t thread , void * * thread_return ) {
267
+ if (thread != MAGIC_THREAD1_ID ) {
268
+ return 1 ;
269
+ }
270
+ sem_acquire_blocking (& thread_1_done );
271
+ sem_release (& thread_1_done ); // in case join is called again
272
+ if (thread_return ) {
273
+ * thread_return = thread_1_return ;
274
+ }
275
+ return 0 ;
276
+ }
277
+
278
+ int lf_mutex_init (lf_mutex_t * mutex ) {
279
+ mutex_init (mutex );
280
+ return 0 ;
281
+ }
282
+
283
+ int lf_mutex_lock (lf_mutex_t * mutex ) {
284
+ mutex_enter_blocking (mutex );
285
+ return 0 ;
286
+ }
287
+
288
+ int lf_mutex_unlock (lf_mutex_t * mutex ) {
289
+ mutex_exit (mutex );
290
+ return 0 ;
291
+ }
292
+
293
+ int lf_cond_init (lf_cond_t * cond , lf_mutex_t * mutex ) {
294
+ sem_init (& (cond -> sema ), 0 , 1 );
295
+ cond -> mutex = mutex ;
296
+ return 0 ;
297
+ }
298
+
299
+ int lf_cond_broadcast (lf_cond_t * cond ) {
300
+ sem_reset (& (cond -> sema ), 1 );
301
+ return 0 ;
302
+ }
303
+
304
+ int lf_cond_signal (lf_cond_t * cond ) {
305
+ sem_reset (& (cond -> sema ), 1 );
306
+ return 0 ;
307
+ }
308
+
309
+ int lf_cond_wait (lf_cond_t * cond ) {
310
+ mutex_exit (cond -> mutex );
311
+ sem_acquire_blocking (& (cond -> sema ));
312
+ mutex_enter_blocking (cond -> mutex );
313
+ return 0 ;
314
+ }
315
+
316
+ int lf_cond_timedwait (lf_cond_t * cond , instant_t absolute_time_ns ) {
317
+ absolute_time_t a = from_us_since_boot (absolute_time_ns / 1000 );
318
+ bool acquired_permit = sem_acquire_block_until (& (cond -> sema ), a );
319
+ return acquired_permit ? 0 : LF_TIMEOUT ;
320
+ }
321
+
322
+
323
+ // Atomics
324
+ // Implemented by just entering a critical section and doing the arithmetic.
325
+ // This is somewhat inefficient considering enclaves. Since we get a critical
326
+ // section in between different enclaves
327
+
328
+
329
+ /**
330
+ * @brief Add `value` to `*ptr` and return original value of `*ptr`
331
+ */
332
+ int _rp2040_atomic_fetch_add (int * ptr , int value ) {
333
+ critical_section_enter_blocking (& _lf_atomics_crit_sec );
334
+ int res = * ptr ;
335
+ * ptr += value ;
336
+ critical_section_exit (& _lf_atomics_crit_sec );
337
+ return res ;
338
+ }
339
+ /**
340
+ * @brief Add `value` to `*ptr` and return new updated value of `*ptr`
341
+ */
342
+ int _rp2040_atomic_add_fetch (int * ptr , int value ) {
343
+ critical_section_enter_blocking (& _lf_atomics_crit_sec );
344
+ int res = * ptr + value ;
345
+ * ptr = res ;
346
+ critical_section_exit (& _lf_atomics_crit_sec );
347
+ return res ;
348
+ }
349
+
350
+ /**
351
+ * @brief Compare and swap for boolaen value.
352
+ * If `*ptr` is equal to `value` then overwrite it
353
+ * with `newval`. If not do nothing. Retruns true on overwrite.
354
+ */
355
+ bool _rp2040_bool_compare_and_swap (bool * ptr , bool value , bool newval ) {
356
+ critical_section_enter_blocking (& _lf_atomics_crit_sec );
357
+ bool res = false;
358
+ if (* ptr == value ) {
359
+ * ptr = newval ;
360
+ res = true;
361
+ }
362
+ critical_section_exit (& _lf_atomics_crit_sec );
363
+ return res ;
364
+ }
365
+
366
+ /**
367
+ * @brief Compare and swap for integers. If `*ptr` is equal
368
+ * to `value`, it is updated to `newval`. The function returns
369
+ * the original value of `*ptr`.
370
+ */
371
+ int _rp2040_val_compare_and_swap (int * ptr , int value , int newval ) {
372
+ critical_section_enter_blocking (& _lf_atomics_crit_sec );
373
+ int res = * ptr ;
374
+ if (* ptr == value ) {
375
+ * ptr = newval ;
376
+ }
377
+ critical_section_exit (& _lf_atomics_crit_sec );
378
+ return res ;
379
+ }
380
+
381
+
382
+
217
383
#endif // LF_SINGLE_THREADED
218
384
219
385
0 commit comments