4343#include <stdint.h>
4444#include <cmocka.h>
4545#include <time.h>
46+ #include <pthread.h>
4647
4748#include <nuttx/arch.h>
4849#include <nuttx/notifier.h>
5859#define WDG_DEFAULT_TIMEOUT 2000
5960#define WDG_DEFAULT_TESTCASE 0
6061#define WDG_DEFAULT_DEVIATION 20
62+ #ifndef BOARDIOC_RESETCAUSE_SYS_CHIPPOR
63+ # define BOARDIOC_RESETCAUSE_SYS_CHIPPOR 0
64+ #endif
65+ #ifndef BOARDIOC_RESETCAUSE_SYS_RWDT
66+ # define BOARDIOC_RESETCAUSE_SYS_RWDT 0
67+ #endif
6168#if defined(CONFIG_ARCH_ARMV7A ) && defined(CONFIG_ARCH_HAVE_TRUSTZONE )
6269#define WDG_COUNT_TESTCASE 3
6370#else
@@ -89,6 +96,12 @@ struct wdg_state_s
8996 uint32_t deviation ;
9097 int test_case ;
9198 bool test_getstatus ;
99+ #ifdef CONFIG_WATCHDOG_TIMEOUT_NOTIFIER
100+ unsigned int notifier_calls ;
101+ unsigned long notifier_action [8 ];
102+ FAR void * notifier_data [8 ];
103+ int notifier_id [8 ];
104+ #endif
92105};
93106
94107static sem_t g_semaphore ;
@@ -297,18 +310,10 @@ static int capture_callback(int irq, FAR void *context, FAR void *arg)
297310struct watchdog_notifier_test_nb_s
298311{
299312 struct notifier_block nb ;
300- int id ;
301- };
302-
303- struct watchdog_notifier_test_ctx_s
304- {
305- unsigned int calls ;
306- unsigned long action [8 ];
307- FAR void * data [8 ];
308- int id [8 ];
313+ int id ;
309314};
310315
311- static FAR struct watchdog_notifier_test_ctx_s * g_notifier_test_ctx ;
316+ static FAR struct wdg_state_s * g_notifier_test_state ;
312317
313318static int watchdog_notifier_test_callback (FAR struct notifier_block * nb ,
314319 unsigned long action ,
@@ -317,18 +322,16 @@ static int watchdog_notifier_test_callback(FAR struct notifier_block *nb,
317322 FAR struct watchdog_notifier_test_nb_s * test_nb ;
318323 unsigned int index ;
319324
320- test_nb = (FAR struct watchdog_notifier_test_nb_s * )
321- ((FAR char * )nb - offsetof(struct watchdog_notifier_test_nb_s ,
322- nb ));
323- index = g_notifier_test_ctx -> calls ;
325+ test_nb = container_of (nb , struct watchdog_notifier_test_nb_s , nb );
326+ index = g_notifier_test_state -> notifier_calls ;
324327 if (index < 8 )
325328 {
326- g_notifier_test_ctx -> action [index ] = action ;
327- g_notifier_test_ctx -> data [index ] = data ;
328- g_notifier_test_ctx -> id [index ] = test_nb -> id ;
329+ g_notifier_test_state -> notifier_action [index ] = action ;
330+ g_notifier_test_state -> notifier_data [index ] = data ;
331+ g_notifier_test_state -> notifier_id [index ] = test_nb -> id ;
329332 }
330333
331- g_notifier_test_ctx -> calls ++ ;
334+ g_notifier_test_state -> notifier_calls ++ ;
332335 return OK ;
333336}
334337
@@ -353,10 +356,7 @@ static unsigned long watchdog_notifier_test_expected_action(void)
353356
354357static void drivertest_watchdog_notifier (FAR void * * state )
355358{
356- struct watchdog_notifier_test_ctx_s context =
357- {
358- 0
359- };
359+ FAR struct wdg_state_s * wdg_state = * state ;
360360
361361 struct watchdog_notifier_test_nb_s low =
362362 {
@@ -382,7 +382,8 @@ static void drivertest_watchdog_notifier(FAR void **state)
382382
383383 UNUSED (state );
384384 expected_action = watchdog_notifier_test_expected_action ();
385- g_notifier_test_ctx = & context ;
385+ wdg_state -> notifier_calls = 0 ;
386+ g_notifier_test_state = wdg_state ;
386387
387388 /* Registration is priority ordered, and duplicate registration of the
388389 * same notifier must not result in a duplicate callback.
@@ -394,35 +395,116 @@ static void drivertest_watchdog_notifier(FAR void **state)
394395
395396 watchdog_automonitor_timeout ();
396397
397- assert_int_equal (context . calls , 2 );
398- assert_int_equal (context . id [0 ], high .id );
399- assert_int_equal (context . id [1 ], low .id );
400- assert_int_equal (context . action [0 ], expected_action );
401- assert_int_equal (context . action [1 ], expected_action );
402- assert_null (context . data [0 ]);
403- assert_null (context . data [1 ]);
398+ assert_int_equal (wdg_state -> notifier_calls , 2 );
399+ assert_int_equal (wdg_state -> notifier_id [0 ], high .id );
400+ assert_int_equal (wdg_state -> notifier_id [1 ], low .id );
401+ assert_int_equal (wdg_state -> notifier_action [0 ], expected_action );
402+ assert_int_equal (wdg_state -> notifier_action [1 ], expected_action );
403+ assert_null (wdg_state -> notifier_data [0 ]);
404+ assert_null (wdg_state -> notifier_data [1 ]);
404405
405406 /* Every timeout notification is delivered to all currently registered
406407 * callbacks.
407408 */
408409
409410 watchdog_automonitor_timeout ();
410- assert_int_equal (context . calls , 4 );
411- assert_int_equal (context . id [2 ], high .id );
412- assert_int_equal (context . id [3 ], low .id );
411+ assert_int_equal (wdg_state -> notifier_calls , 4 );
412+ assert_int_equal (wdg_state -> notifier_id [2 ], high .id );
413+ assert_int_equal (wdg_state -> notifier_id [3 ], low .id );
413414
414415 /* Unregistering one callback removes only that callback. */
415416
416417 watchdog_notifier_chain_unregister (& high .nb );
417418 watchdog_automonitor_timeout ();
418- assert_int_equal (context . calls , 5 );
419- assert_int_equal (context . id [4 ], low .id );
419+ assert_int_equal (wdg_state -> notifier_calls , 5 );
420+ assert_int_equal (wdg_state -> notifier_id [4 ], low .id );
420421
421422 watchdog_notifier_chain_unregister (& low .nb );
422423 watchdog_automonitor_timeout ();
423- assert_int_equal (context .calls , 5 );
424+ assert_int_equal (wdg_state -> notifier_calls , 5 );
425+
426+ g_notifier_test_state = NULL ;
427+ }
428+
429+ struct watchdog_notifier_race_s
430+ {
431+ struct watchdog_notifier_test_nb_s nb ;
432+ volatile bool stop ;
433+ };
434+
435+ static volatile unsigned int g_notifier_race_callbacks ;
436+
437+ static int watchdog_notifier_race_callback (FAR struct notifier_block * nb ,
438+ unsigned long action ,
439+ FAR void * data )
440+ {
441+ UNUSED (nb );
442+ UNUSED (action );
443+ UNUSED (data );
444+ g_notifier_race_callbacks ++ ;
445+ return OK ;
446+ }
447+
448+ static FAR void * watchdog_notifier_race_worker (FAR void * arg )
449+ {
450+ FAR struct watchdog_notifier_race_s * race = arg ;
451+ unsigned int count ;
452+
453+ for (count = 0 ; count < 2000 && !race -> stop ; count ++ )
454+ {
455+ watchdog_notifier_chain_register (& race -> nb .nb );
456+ watchdog_automonitor_timeout ();
457+ watchdog_notifier_chain_unregister (& race -> nb .nb );
458+ }
424459
425- g_notifier_test_ctx = NULL ;
460+ return NULL ;
461+ }
462+
463+ static void drivertest_watchdog_notifier_race (FAR void * * state )
464+ {
465+ struct watchdog_notifier_race_s race =
466+ {
467+ .nb =
468+ {
469+ .nb =
470+ {
471+ .notifier_call = watchdog_notifier_race_callback ,
472+ .priority = 10
473+ },
474+ .id = 3
475+ }
476+ };
477+
478+ pthread_t thread ;
479+ unsigned int count ;
480+ int ret ;
481+
482+ UNUSED (state );
483+ g_notifier_race_callbacks = 0 ;
484+ watchdog_notifier_chain_register (& race .nb .nb );
485+ ret = pthread_create (& thread , NULL , watchdog_notifier_race_worker , & race );
486+ assert_int_equal (ret , 0 );
487+ usleep (1000 );
488+
489+ /* Interleave timeout delivery with registration and unregistration from
490+ * another task. The test is successful if the notifier chain remains
491+ * usable and no callback observes a non-NULL payload.
492+ */
493+
494+ for (count = 0 ; count < 2000 ; count ++ )
495+ {
496+ watchdog_automonitor_timeout ();
497+ if ((count & 0x3f ) == 0 )
498+ {
499+ usleep (1000 );
500+ }
501+ }
502+
503+ race .stop = true;
504+ ret = pthread_join (thread , NULL );
505+ assert_int_equal (ret , 0 );
506+ watchdog_notifier_chain_unregister (& race .nb .nb );
507+ assert_true (g_notifier_race_callbacks > 0 );
426508}
427509
428510#endif /* CONFIG_WATCHDOG_TIMEOUT_NOTIFIER */
@@ -441,7 +523,9 @@ static void drivertest_watchdog_feeding(FAR void **state)
441523 int ret ;
442524 uint32_t start_ms ;
443525 FAR struct wdg_state_s * wdg_state ;
526+ #ifdef CONFIG_BOARDCTL_RESET_CAUSE
444527 struct boardioc_reset_cause_s reset_cause ;
528+ #endif
445529
446530 wdg_state = (FAR struct wdg_state_s * )* state ;
447531
@@ -452,8 +536,10 @@ static void drivertest_watchdog_feeding(FAR void **state)
452536 return ;
453537 }
454538
539+ #ifdef CONFIG_BOARDCTL_RESET_CAUSE
455540 boardctl (BOARDIOC_RESET_CAUSE , (uintptr_t )& reset_cause );
456541 assert_int_equal (reset_cause .cause , BOARDIOC_RESETCAUSE_SYS_CHIPPOR );
542+ #endif
457543
458544 dev_fd = wdg_init (wdg_state );
459545
@@ -497,7 +583,9 @@ static void drivertest_watchdog_feeding(FAR void **state)
497583static void drivertest_watchdog_interrupts (FAR void * * state )
498584{
499585 FAR struct wdg_state_s * wdg_state ;
586+ #ifdef CONFIG_BOARDCTL_RESET_CAUSE
500587 struct boardioc_reset_cause_s reset_cause ;
588+ #endif
501589
502590 wdg_state = (FAR struct wdg_state_s * )* state ;
503591
@@ -506,8 +594,10 @@ static void drivertest_watchdog_interrupts(FAR void **state)
506594 return ;
507595 }
508596
597+ #ifdef CONFIG_BOARDCTL_RESET_CAUSE
509598 boardctl (BOARDIOC_RESET_CAUSE , (uintptr_t )& reset_cause );
510599 assert_int_equal (reset_cause .cause , BOARDIOC_RESETCAUSE_SYS_RWDT );
600+ #endif
511601
512602 wdg_init (wdg_state );
513603
@@ -542,7 +632,9 @@ static void drivertest_watchdog_loop(FAR void **state)
542632 int ret ;
543633 static struct wdog_s wdog ;
544634 FAR struct wdg_state_s * wdg_state ;
635+ #ifdef CONFIG_BOARDCTL_RESET_CAUSE
545636 struct boardioc_reset_cause_s reset_cause ;
637+ #endif
546638
547639 wdg_state = (FAR struct wdg_state_s * )* state ;
548640
@@ -551,8 +643,10 @@ static void drivertest_watchdog_loop(FAR void **state)
551643 return ;
552644 }
553645
646+ #ifdef CONFIG_BOARDCTL_RESET_CAUSE
554647 boardctl (BOARDIOC_RESET_CAUSE , (uintptr_t )& reset_cause );
555648 assert_int_equal (reset_cause .cause , BOARDIOC_RESETCAUSE_SYS_RWDT );
649+ #endif
556650
557651 wdg_init (wdg_state );
558652
@@ -581,15 +675,19 @@ static void drivertest_watchdog_api(FAR void **state)
581675 uint32_t start_ms ;
582676 FAR struct wdg_state_s * wdg_state ;
583677 struct watchdog_status_s status ;
678+ #ifdef CONFIG_BOARDCTL_RESET_CAUSE
584679 struct boardioc_reset_cause_s reset_cause ;
680+ #endif
585681 struct watchdog_capture_s watchdog_capture ;
586682
587683 wdg_state = (FAR struct wdg_state_s * )* state ;
588684
589685 assert_int_equal (wdg_state -> test_case , 3 );
590686
687+ #ifdef CONFIG_BOARDCTL_RESET_CAUSE
591688 boardctl (BOARDIOC_RESET_CAUSE , (uintptr_t )& reset_cause );
592689 assert_int_equal (reset_cause .cause , BOARDIOC_RESETCAUSE_SYS_RWDT );
690+ #endif
593691
594692 dev_fd = wdg_init (wdg_state );
595693
@@ -681,14 +779,17 @@ int main(int argc, FAR char *argv[])
681779
682780 const struct CMUnitTest tests [] =
683781 {
782+ #ifndef CONFIG_TESTING_DRIVER_TEST_WATCHDOG_ONLY
684783 cmocka_unit_test_prestate (drivertest_watchdog_feeding , & wdg_state ),
685784 cmocka_unit_test_prestate (drivertest_watchdog_interrupts , & wdg_state ),
686785 cmocka_unit_test_prestate (drivertest_watchdog_loop , & wdg_state ),
687786#if !defined (CONFIG_ARCH_ARMV7A ) || !defined (CONFIG_ARCH_HAVE_TRUSTZONE )
688787 cmocka_unit_test_prestate (drivertest_watchdog_api , & wdg_state ),
689788#endif
789+ #endif
690790#ifdef CONFIG_WATCHDOG_TIMEOUT_NOTIFIER
691- cmocka_unit_test_prestate (drivertest_watchdog_notifier , & wdg_state )
791+ cmocka_unit_test_prestate (drivertest_watchdog_notifier , & wdg_state ),
792+ cmocka_unit_test_prestate (drivertest_watchdog_notifier_race , & wdg_state )
692793#endif
693794 };
694795
0 commit comments