@@ -31,10 +31,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3131 * @author{Abhi Gundrala <[email protected] >} 3232 */
3333
34- #if !defined(LF_SINGLE_THREADED )
35- #error "Only the single-threaded runtime has support for RP2040"
36- #endif
37-
3834#include "lf_rp2040_support.h"
3935#include "platform.h"
4036#include "utils/util.h"
@@ -51,6 +47,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5147 */
5248static critical_section_t _lf_crit_sec ;
5349
50+ /**
51+ * critical section struct for atomics implementation
52+ */
53+ static critical_section_t _lf_atomics_crit_sec ;
54+
5455/**
5556 * binary semaphore for lf event notification
5657 * used by external isr or second core thread.
@@ -63,13 +64,14 @@ static uint32_t _lf_num_nested_crit_sec = 0;
6364
6465/**
6566 * Initialize basic runtime infrastructure and
66- * synchronization structs for an single-threaded runtime.
67+ * synchronization structs for a single-threaded runtime.
6768 */
6869void _lf_initialize_clock (void ) {
6970 // init stdio lib
7071 stdio_init_all ();
7172 // init sync structs
7273 critical_section_init (& _lf_crit_sec );
74+ critical_section_init (& _lf_atomics_crit_sec );
7375 sem_init (& _lf_sem_irq_event , 0 , 1 );
7476}
7577
@@ -214,6 +216,170 @@ int _lf_single_threaded_notify_of_event() {
214216 sem_release (& _lf_sem_irq_event );
215217 return 0 ;
216218}
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+
217383#endif // LF_SINGLE_THREADED
218384
219385
0 commit comments