diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-08-08 15:28:38 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-08-09 17:56:07 +0200 |
commit | 6e24f98c582f0032acfa9accba3bd44834f35a0b (patch) | |
tree | 265d932d83bf280f1f3caf57598715bbc0fe6ed1 | |
parent | modules: Update rtems (diff) | |
download | rtems-central-6e24f98c582f0032acfa9accba3bd44834f35a0b.tar.bz2 |
spec: Specify user extensions
22 files changed, 1120 insertions, 29 deletions
@@ -36,7 +36,7 @@ build: - gccdeps.py - long_gcc.py - testsuites/validation/tc-basedefs-pendant.h - - testsuites/validation/tc-terminate.h + - testsuites/validation/tc-userext.h - testsuites/validation/tr-model-chains-api.h - testsuites/validation/tr-model-events-mgr.h - testsuites/validation/ts-config.h diff --git a/spec/rtems/userext/req/thread-begin-iterate-remove.yml b/spec/rtems/userext/req/thread-begin-iterate-remove.yml new file mode 100644 index 00000000..bd96175f --- /dev/null +++ b/spec/rtems/userext/req/thread-begin-iterate-remove.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + While the ${/glossary/userextensions:/term} are iterated to invoke the thread + begin extensions, when an extension set is removed, the removed extension set + shall not be a next extension set for any iteration in progress after the + removal. +type: requirement diff --git a/spec/rtems/userext/req/thread-begin-order.yml b/spec/rtems/userext/req/thread-begin-order.yml new file mode 100644 index 00000000..5314defb --- /dev/null +++ b/spec/rtems/userext/req/thread-begin-order.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + The thread begin ${/glossary/userextensions:/term} shall be invoked in + ${/glossary/extension-forward-order:/term}. +type: requirement diff --git a/spec/rtems/userext/req/thread-create-allocator-owner.yml b/spec/rtems/userext/req/thread-create-allocator-owner.yml new file mode 100644 index 00000000..a8525006 --- /dev/null +++ b/spec/rtems/userext/req/thread-create-allocator-owner.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +- role: requirement-refinement + uid: /score/object/req/allocator-mutex +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + The thread invoking the thread create ${/glossary/userextensions:/term} shall + be the owner of the allocator mutex. +type: requirement diff --git a/spec/rtems/userext/req/thread-create-iterate-remove.yml b/spec/rtems/userext/req/thread-create-iterate-remove.yml new file mode 100644 index 00000000..4fa9e331 --- /dev/null +++ b/spec/rtems/userext/req/thread-create-iterate-remove.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + While the ${/glossary/userextensions:/term} are iterated to invoke the thread + create extensions, when an extension set is removed, the removed extension + set shall not be a next extension set for any iteration in progress after the + removal. +type: requirement diff --git a/spec/rtems/userext/req/thread-create-order.yml b/spec/rtems/userext/req/thread-create-order.yml new file mode 100644 index 00000000..418d3c11 --- /dev/null +++ b/spec/rtems/userext/req/thread-create-order.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + The thread create ${/glossary/userextensions:/term} shall be invoked in + ${/glossary/extension-forward-order:/term}. +type: requirement diff --git a/spec/rtems/userext/req/thread-delete-allocator-owner.yml b/spec/rtems/userext/req/thread-delete-allocator-owner.yml new file mode 100644 index 00000000..13216996 --- /dev/null +++ b/spec/rtems/userext/req/thread-delete-allocator-owner.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +- role: requirement-refinement + uid: /score/object/req/allocator-mutex +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + The thread invoking the thread delete ${/glossary/userextensions:/term} shall + be the owner of the allocator mutex. +type: requirement diff --git a/spec/rtems/userext/req/thread-delete-iterate-remove.yml b/spec/rtems/userext/req/thread-delete-iterate-remove.yml new file mode 100644 index 00000000..59a17bd3 --- /dev/null +++ b/spec/rtems/userext/req/thread-delete-iterate-remove.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + While the ${/glossary/userextensions:/term} are iterated to invoke the thread + delete extensions, when an extension set is removed, the removed extension + set shall not be a next extension set for any iteration in progress after the + removal. +type: requirement diff --git a/spec/rtems/userext/req/thread-delete-order.yml b/spec/rtems/userext/req/thread-delete-order.yml new file mode 100644 index 00000000..d3fc1710 --- /dev/null +++ b/spec/rtems/userext/req/thread-delete-order.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + The thread delete ${/glossary/userextensions:/term} shall be invoked in + ${/glossary/extension-reverse-order:/term}. +type: requirement diff --git a/spec/rtems/userext/req/thread-exitted-iterate-remove.yml b/spec/rtems/userext/req/thread-exitted-iterate-remove.yml new file mode 100644 index 00000000..aa53e3b2 --- /dev/null +++ b/spec/rtems/userext/req/thread-exitted-iterate-remove.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + While the ${/glossary/userextensions:/term} are iterated to invoke the thread + exitted extensions, when an extension set is removed, the removed extension + set shall not be a next extension set for any iteration in progress after the + removal. +type: requirement diff --git a/spec/rtems/userext/req/thread-exitted-order.yml b/spec/rtems/userext/req/thread-exitted-order.yml new file mode 100644 index 00000000..64c3f3ff --- /dev/null +++ b/spec/rtems/userext/req/thread-exitted-order.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + The thread exitted ${/glossary/userextensions:/term} shall be invoked in + ${/glossary/extension-forward-order:/term}. +type: requirement diff --git a/spec/rtems/userext/req/thread-restart-iterate-remove.yml b/spec/rtems/userext/req/thread-restart-iterate-remove.yml new file mode 100644 index 00000000..7b75e5d5 --- /dev/null +++ b/spec/rtems/userext/req/thread-restart-iterate-remove.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + While the ${/glossary/userextensions:/term} are iterated to invoke the thread + restart extensions, when an extension set is removed, the removed extension + set shall not be a next extension set for any iteration in progress after the + removal. +type: requirement diff --git a/spec/rtems/userext/req/thread-restart-order.yml b/spec/rtems/userext/req/thread-restart-order.yml new file mode 100644 index 00000000..6d1546a5 --- /dev/null +++ b/spec/rtems/userext/req/thread-restart-order.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + The thread restart ${/glossary/userextensions:/term} shall be invoked in + ${/glossary/extension-forward-order:/term}. +type: requirement diff --git a/spec/rtems/userext/req/thread-start-iterate-remove.yml b/spec/rtems/userext/req/thread-start-iterate-remove.yml new file mode 100644 index 00000000..6059efea --- /dev/null +++ b/spec/rtems/userext/req/thread-start-iterate-remove.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + While the ${/glossary/userextensions:/term} are iterated to invoke the thread + start extensions, when an extension set is removed, the removed extension set + shall not be a next extension set for any iteration in progress after the + removal. +type: requirement diff --git a/spec/rtems/userext/req/thread-start-order.yml b/spec/rtems/userext/req/thread-start-order.yml new file mode 100644 index 00000000..98ff2bd4 --- /dev/null +++ b/spec/rtems/userext/req/thread-start-order.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + The thread start ${/glossary/userextensions:/term} shall be invoked in + ${/glossary/extension-forward-order:/term}. +type: requirement diff --git a/spec/rtems/userext/req/thread-switch-order.yml b/spec/rtems/userext/req/thread-switch-order.yml new file mode 100644 index 00000000..754633f9 --- /dev/null +++ b/spec/rtems/userext/req/thread-switch-order.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + The thread switch ${/glossary/userextensions:/term} shall be invoked in + ${/glossary/extension-forward-order:/term}. +type: requirement diff --git a/spec/rtems/userext/req/thread-terminate-iterate-remove.yml b/spec/rtems/userext/req/thread-terminate-iterate-remove.yml new file mode 100644 index 00000000..f5522854 --- /dev/null +++ b/spec/rtems/userext/req/thread-terminate-iterate-remove.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + While the ${/glossary/userextensions:/term} are iterated to invoke the thread + terminate extensions, when an extension set is removed, the removed extension + set shall not be a next extension set for any iteration in progress after the + removal. +type: requirement diff --git a/spec/rtems/userext/req/thread-terminate-order.yml b/spec/rtems/userext/req/thread-terminate-order.yml new file mode 100644 index 00000000..6ceb4ad7 --- /dev/null +++ b/spec/rtems/userext/req/thread-terminate-order.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: null +references: [] +requirement-type: functional +text: | + The thread terminate ${/glossary/userextensions:/term} shall be invoked in + ${/glossary/extension-reverse-order:/term}. +type: requirement diff --git a/spec/rtems/userext/val/userext.yml b/spec/rtems/userext/val/userext.yml new file mode 100644 index 00000000..e85f6197 --- /dev/null +++ b/spec/rtems/userext/val/userext.yml @@ -0,0 +1,716 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: [] +test-actions: +- action-brief: | + Create five dynamic extensions. Switch to a started thread. Delete three + dynamic extension during the thread begin invocation. Clean up the used + resources. + action-code: | + rtems_tcb *executing; + rtems_tcb *thread; + rtems_id id; + + id = CreateTask( "WORK", PRIO_LOW ); + thread = GetThread( id ); + StartTask( id, BeginWorker, NULL ); + executing = StartTestCase( THREAD_BEGIN ); + SetPriority( id, PRIO_HIGH ); + KillZombies(); + checks: + - brief: | + Check that the thread switch extensions were invoked in the right order + before the thread begin extensions. + code: | + CheckForward( THREAD_SWITCH, 1, 1, executing, thread ); + links: + - role: validation + uid: ../req/thread-switch-order + - brief: | + Check that the thread begin extensions were invoked in the right order. + code: | + CheckForward( THREAD_BEGIN, 8, 1, thread, NULL ); + links: + - role: validation + uid: ../req/thread-begin-iterate-remove + - role: validation + uid: ../req/thread-begin-order + - brief: | + Check that the other extensions were not invoked. + code: | + CheckForward( THREAD_CREATE, 0, 0, NULL, NULL ); + CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL ); + CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL ); + CheckForward( THREAD_RESTART, 0, 0, NULL, NULL ); + CheckForward( THREAD_START, 0, 0, NULL, NULL ); + CheckReverse( THREAD_TERMINATE, 0, 0, NULL, NULL ); + links: [] + - brief: | + Check that the thread begin extension of the extension set deleted + before its turn in the invocation was not invoked. + code: | + CheckDeletedNotInvoked( THREAD_BEGIN ); + links: + - role: validation + uid: ../req/thread-begin-iterate-remove + links: [] +- action-brief: | + Create five dynamic extensions. Create a thread. Delete three dynamic + extension during the thread create invocation. Clean up the used + resources. + action-code: | + rtems_tcb *executing; + rtems_tcb *thread; + rtems_id id; + + executing = StartTestCase( THREAD_CREATE ); + id = CreateTask( "WORK", PRIO_NORMAL ); + thread = GetThread( id ); + StopTestCase(); + DeleteTask( id ); + KillZombies(); + checks: + - brief: | + Check that the thread create extensions were invoked in the right order. + code: | + CheckForward( THREAD_CREATE, 1, 1, executing, thread ); + links: + - role: validation + uid: ../req/thread-create-iterate-remove + - role: validation + uid: ../req/thread-create-order + - brief: | + Check that the thread create extensions were invoked under protection of + the allocator mutex. + code: | + T_eq_u32( thread_create_allocator_owner_count, 6 ); + links: + - role: validation + uid: ../req/thread-create-allocator-owner + - brief: | + Check that the other extensions were not invoked. + code: | + CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL ); + CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL ); + CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL ); + CheckForward( THREAD_RESTART, 0, 0, NULL, NULL ); + CheckForward( THREAD_START, 0, 0, NULL, NULL ); + CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL ); + CheckReverse( THREAD_TERMINATE, 0, 0, NULL, NULL ); + links: [] + - brief: | + Check that the thread create extension of the extension set deleted + before its turn in the invocation was not invoked. + code: | + CheckDeletedNotInvoked( THREAD_CREATE ); + links: + - role: validation + uid: ../req/thread-create-iterate-remove + links: [] +- action-brief: | + Create five dynamic extensions. Delete a thread. Delete three dynamic + extension during the thread delete invocation. Clean up the used + resources. + action-code: | + rtems_tcb *executing; + rtems_tcb *thread; + rtems_id id; + + id = CreateTask( "WORK", PRIO_NORMAL ); + thread = GetThread( id ); + DeleteTask( id ); + executing = StartTestCase( THREAD_DELETE ); + KillZombies(); + StopTestCase(); + checks: + - brief: | + Check that the thread delete extensions were invoked in the right order. + code: | + CheckReverse( THREAD_DELETE, 1, 1, executing, thread ); + links: + - role: validation + uid: ../req/thread-delete-iterate-remove + - role: validation + uid: ../req/thread-delete-order + - brief: | + Check that the thread delete extensions were invoked under protection of + the allocator mutex. + code: | + T_eq_u32( thread_delete_allocator_owner_count, 6 ); + links: + - role: validation + uid: ../req/thread-delete-allocator-owner + - brief: | + Check that the other extensions were not invoked. + code: | + CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL ); + CheckForward( THREAD_CREATE, 0, 0, NULL, NULL ); + CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL ); + CheckForward( THREAD_RESTART, 0, 0, NULL, NULL ); + CheckForward( THREAD_START, 0, 0, NULL, NULL ); + CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL ); + CheckReverse( THREAD_TERMINATE, 0, 0, NULL, NULL ); + links: [] + - brief: | + Check that the thread delete extension of the extension set deleted + before its turn in the invocation was not invoked. + code: | + CheckDeletedNotInvoked( THREAD_DELETE ); + links: + - role: validation + uid: ../req/thread-delete-iterate-remove + links: [] +- action-brief: | + Create five dynamic extensions. Return from a thread entry. Delete three + dynamic extension during the thread exitted invocation. Clean up the used + resources. + action-code: | + rtems_tcb *thread; + rtems_id id; + + id = CreateTask( "WORK", PRIO_HIGH ); + thread = GetThread( id ); + StartTask( id, ExittedWorker, NULL ); + KillZombies(); + checks: + - brief: | + Check that the thread exitted extensions were invoked in the right order. + code: | + CheckForward( THREAD_EXITTED, 1, 1, thread, NULL ); + links: + - role: validation + uid: ../req/thread-exitted-iterate-remove + - role: validation + uid: ../req/thread-exitted-order + - brief: | + Check that the other extensions were not invoked. + code: | + CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL ); + CheckForward( THREAD_CREATE, 0, 0, NULL, NULL ); + CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL ); + CheckForward( THREAD_RESTART, 0, 0, NULL, NULL ); + CheckForward( THREAD_START, 0, 0, NULL, NULL ); + CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL ); + CheckReverse( THREAD_TERMINATE, 0, 0, NULL, NULL ); + links: [] + - brief: | + Check that the thread exitted extension of the extension set deleted + before its turn in the invocation was not invoked. + code: | + CheckDeletedNotInvoked( THREAD_EXITTED ); + links: + - role: validation + uid: ../req/thread-exitted-iterate-remove + links: [] +- action-brief: | + Create five dynamic extensions. Restart a thread. Delete three + dynamic extension during the thread restart invocation. Clean up the used + resources. + action-code: | + rtems_tcb *thread; + rtems_id id; + + id = CreateTask( "WORK", PRIO_HIGH ); + thread = GetThread( id ); + StartTask( id, RestartWorker, NULL ); + KillZombies(); + checks: + - brief: | + Check that the thread restart extensions were invoked in the right order. + code: | + CheckForward( THREAD_RESTART, 1, 1, thread, thread ); + links: + - role: validation + uid: ../req/thread-restart-iterate-remove + - role: validation + uid: ../req/thread-restart-order + - brief: | + Check that the other extensions were not invoked. + code: | + CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL ); + CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL ); + CheckForward( THREAD_CREATE, 0, 0, NULL, NULL ); + CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL ); + CheckForward( THREAD_START, 0, 0, NULL, NULL ); + CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL ); + CheckForward( THREAD_TERMINATE, 0, 0, NULL, NULL ); + links: [] + - brief: | + Check that the thread restart extension of the extension set deleted + before its turn in the invocation was not invoked. + code: | + CheckDeletedNotInvoked( THREAD_RESTART ); + links: + - role: validation + uid: ../req/thread-restart-iterate-remove + links: [] +- action-brief: | + Create five dynamic extensions. Start a thread. Delete three dynamic + extension during the thread start invocation. Clean up the used resources. + action-code: | + rtems_tcb *executing; + rtems_tcb *thread; + rtems_id id; + + id = CreateTask( "WORK", PRIO_LOW ); + thread = GetThread( id ); + executing = StartTestCase( THREAD_START ); + StartTask( id, StartWorker, NULL ); + StopTestCase(); + DeleteTask( id ); + KillZombies(); + checks: + - brief: | + Check that the thread start extensions were invoked in the right order. + code: | + CheckForward( THREAD_START, 1, 1, executing, thread ); + links: + - role: validation + uid: ../req/thread-start-iterate-remove + - role: validation + uid: ../req/thread-start-order + - brief: | + Check that the other extensions were not invoked. + code: | + CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL ); + CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL ); + CheckForward( THREAD_CREATE, 0, 0, NULL, NULL ); + CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL ); + CheckForward( THREAD_RESTART, 0, 0, NULL, NULL ); + CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL ); + CheckForward( THREAD_TERMINATE, 0, 0, NULL, NULL ); + links: [] + - brief: | + Check that the thread start extension of the extension set deleted + before its turn in the invocation was not invoked. + code: | + CheckDeletedNotInvoked( THREAD_START ); + links: + - role: validation + uid: ../req/thread-start-iterate-remove + links: [] +- action-brief: | + Create five dynamic extensions. Terminate a thread. Delete three dynamic + extension during the thread terminate invocation. Clean up the used + resources. + action-code: | + rtems_tcb *thread; + rtems_id id; + + id = CreateTask( "WORK", PRIO_HIGH ); + thread = GetThread( id ); + StartTask( id, TerminateWorker, NULL ); + KillZombies(); + checks: + - brief: | + Check that the thread terminate extensions were invoked in the right + order. + code: | + CheckReverse( THREAD_TERMINATE, 1, 1, thread, NULL ); + links: + - role: validation + uid: ../req/thread-terminate-iterate-remove + - role: validation + uid: ../req/thread-terminate-order + - brief: | + Check that the other extensions were not invoked. + code: | + CheckForward( THREAD_BEGIN, 0, 0, NULL, NULL ); + CheckForward( THREAD_EXITTED, 0, 0, NULL, NULL ); + CheckForward( THREAD_CREATE, 0, 0, NULL, NULL ); + CheckReverse( THREAD_DELETE, 0, 0, NULL, NULL ); + CheckForward( THREAD_RESTART, 0, 0, NULL, NULL ); + CheckForward( THREAD_START, 0, 0, NULL, NULL ); + CheckForward( THREAD_SWITCH, 0, 0, NULL, NULL ); + links: [] + - brief: | + Check that the thread terminate extension of the extension set deleted + before its turn in the invocation was not invoked. + code: | + CheckDeletedNotInvoked( THREAD_TERMINATE ); + links: + - role: validation + uid: ../req/thread-terminate-iterate-remove + links: [] +test-brief: | + Tests the thread user extensions. +test-context: [] +test-context-support: null +test-description: null +test-header: null +test-includes: +- rtems/score/atomic.h +- rtems/score/apimutex.h +- string.h +test-local-includes: +- tc-userext.h +- tx-support.h +test-setup: + brief: null + code: | + SetSelfPriority( PRIO_NORMAL ); + description: null +test-stop: null +test-support: | + typedef struct { + unsigned int counter; + rtems_tcb *executing; + rtems_tcb *thread; + } ExtensionEvent; + + typedef enum { + THREAD_BEGIN, + THREAD_CREATE, + THREAD_DELETE, + THREAD_EXITTED, + THREAD_RESTART, + THREAD_START, + THREAD_SWITCH, + THREAD_TERMINATE, + EXTENSION_KIND_COUNT + } ExtensionKind; + + static rtems_id extension_ids[ 7 ]; + + static Atomic_Uint extension_counter[ RTEMS_ARRAY_SIZE( extension_ids ) ] + [ EXTENSION_KIND_COUNT ]; + + static ExtensionEvent extension_events[ RTEMS_ARRAY_SIZE( extension_ids ) ] + [ EXTENSION_KIND_COUNT ][ 3 ]; + + static Atomic_Uint global_counter; + + static ExtensionKind extension_under_test = EXTENSION_KIND_COUNT; + + static uint32_t thread_create_allocator_owner_count; + + static uint32_t thread_delete_allocator_owner_count; + + static void StopTestCase( void ) + { + ExtensionKind kind; + rtems_status_code sc; + + kind = extension_under_test; + extension_under_test = EXTENSION_KIND_COUNT; + + sc = rtems_extension_delete( extension_ids[ 2 ] ); + T_rsc_success( sc ); + + if ( kind == THREAD_SWITCH ) { + sc = rtems_extension_delete( extension_ids[ 3 ] ); + T_rsc_success( sc ); + + sc = rtems_extension_delete( extension_ids[ 4 ] ); + T_rsc_success( sc ); + + sc = rtems_extension_delete( extension_ids[ 5 ] ); + T_rsc_success( sc ); + } + + sc = rtems_extension_delete( extension_ids[ 6 ] ); + T_rsc_success( sc ); + } + + static void Extension( + size_t index, + ExtensionKind kind, + rtems_tcb *executing, + rtems_tcb *thread + ) + { + unsigned int gc; + unsigned int c; + rtems_status_code sc; + + if ( extension_under_test == EXTENSION_KIND_COUNT ) { + return; + } + + if ( kind == THREAD_CREATE && _RTEMS_Allocator_is_owner() ) { + ++thread_create_allocator_owner_count; + } + + if ( kind == THREAD_DELETE && _RTEMS_Allocator_is_owner() ) { + ++thread_delete_allocator_owner_count; + } + + gc = _Atomic_Fetch_add_uint( &global_counter, 1, ATOMIC_ORDER_RELAXED ) + 1; + c = _Atomic_Fetch_add_uint( + &extension_counter[ index ][ kind ], + 1, + ATOMIC_ORDER_RELAXED + ); + + if ( c < RTEMS_ARRAY_SIZE( extension_events[ index ][ kind ] ) ) { + extension_events[ index ][ kind ][ c ].counter = gc; + extension_events[ index ][ kind ][ c ].executing = executing; + extension_events[ index ][ kind ][ c ].thread = thread; + } + + if ( kind == THREAD_SWITCH ) { + /* Extension set deletion is not allowed in thread switch extensions */ + return; + } + + if ( kind != extension_under_test ) { + return; + } + + if ( kind == THREAD_DELETE || kind == THREAD_TERMINATE ) { + if ( index == 6 ) { + sc = rtems_extension_delete( extension_ids[ 5 ] ); + T_rsc_success( sc ); + } else if ( index == 3 ) { + sc = rtems_extension_delete( extension_ids[ 3 ] ); + T_rsc_success( sc ); + } else if ( index == 2 ) { + sc = rtems_extension_delete( extension_ids[ 4 ] ); + T_rsc_success( sc ); + } + } else { + if ( index == 2 ) { + sc = rtems_extension_delete( extension_ids[ 3 ] ); + T_rsc_success( sc ); + } else if ( index == 5 ) { + sc = rtems_extension_delete( extension_ids[ 5 ] ); + T_rsc_success( sc ); + } else if ( index == 6 ) { + sc = rtems_extension_delete( extension_ids[ 4 ] ); + T_rsc_success( sc ); + } + } + + if ( index == 6 && ( kind == THREAD_EXITTED || kind == THREAD_RESTART ) ) { + StopTestCase(); + rtems_task_exit(); + } + + if ( index == 0 && kind == THREAD_TERMINATE ) { + StopTestCase(); + } + } + + #define DEFINE_EXTENSIONS( index, linkage ) \ + linkage void ThreadBeginExtension##index( rtems_tcb *executing ) \ + { \ + Extension( index, THREAD_BEGIN, executing, NULL ); \ + } \ + linkage bool ThreadCreateExtension##index( \ + rtems_tcb *executing, \ + rtems_tcb *created \ + ) \ + { \ + Extension( index, THREAD_CREATE, executing, created ); \ + return true; \ + } \ + linkage void ThreadDeleteExtension##index( \ + rtems_tcb *executing, \ + rtems_tcb *deleted \ + ) \ + { \ + Extension( index, THREAD_DELETE, executing, deleted ); \ + } \ + linkage void ThreadExittedExtension##index( rtems_tcb *executing ) \ + { \ + Extension( index, THREAD_EXITTED, executing, NULL ); \ + } \ + linkage void ThreadRestartExtension##index( \ + rtems_tcb *executing, \ + rtems_tcb *restarted \ + ) \ + { \ + Extension( index, THREAD_RESTART, executing, restarted ); \ + } \ + linkage void ThreadStartExtension##index( \ + rtems_tcb *executing, \ + rtems_tcb *started \ + ) \ + { \ + Extension( index, THREAD_START, executing, started ); \ + } \ + linkage void ThreadSwitchExtension##index( \ + rtems_tcb *executing, \ + rtems_tcb *heir \ + ) \ + { \ + Extension( index, THREAD_SWITCH, executing, heir ); \ + } \ + linkage void ThreadTerminateExtension##index( rtems_tcb *executing ) \ + { \ + Extension( index, THREAD_TERMINATE, executing, NULL ); \ + } + + DEFINE_EXTENSIONS( 0, ) + DEFINE_EXTENSIONS( 1, ) + + #define DEFINE_EXTENSIONS_AND_TABLE( index ) \ + DEFINE_EXTENSIONS( index, static ) \ + static const rtems_extensions_table table_##index = { \ + .thread_begin = ThreadBeginExtension##index, \ + .thread_create = ThreadCreateExtension##index, \ + .thread_delete = ThreadDeleteExtension##index, \ + .thread_exitted = ThreadExittedExtension##index, \ + .thread_restart = ThreadRestartExtension##index, \ + .thread_start = ThreadStartExtension##index, \ + .thread_switch = ThreadSwitchExtension##index, \ + .thread_terminate = ThreadTerminateExtension##index \ + } + + DEFINE_EXTENSIONS_AND_TABLE( 2 ); + DEFINE_EXTENSIONS_AND_TABLE( 3 ); + DEFINE_EXTENSIONS_AND_TABLE( 4 ); + DEFINE_EXTENSIONS_AND_TABLE( 5 ); + DEFINE_EXTENSIONS_AND_TABLE( 6 ); + + static const rtems_extensions_table * const tables[] = { + NULL, + NULL, + &table_2, + &table_3, + &table_4, + &table_5, + &table_6 + }; + + static rtems_tcb *StartTestCase( ExtensionKind kind ) + { + size_t i; + + thread_create_allocator_owner_count = 0; + thread_delete_allocator_owner_count = 0; + _Atomic_Store_uint( &global_counter, 0, ATOMIC_ORDER_RELAXED ); + memset( extension_counter, 0, sizeof( extension_counter ) ); + memset( extension_events, 0, sizeof( extension_events ) ); + + extension_under_test = kind; + + for ( i = 2; i < RTEMS_ARRAY_SIZE( extension_ids ); ++i ) { + rtems_status_code sc; + + sc = rtems_extension_create( + rtems_build_name( ' ', ' ', ' ', '2' + i ), + tables[ i ], + &extension_ids[ i ] + ); + T_rsc_success( sc ); + } + + return GetExecuting(); + } + + static void CheckForward( + ExtensionKind kind, + unsigned int counter, + unsigned int increment, + rtems_tcb *executing, + rtems_tcb *thread + ) + { + size_t i; + + for ( i = 0; i < RTEMS_ARRAY_SIZE( extension_ids ); ++i ) { + if ( i == 3 && kind != THREAD_SWITCH ) { + continue; + } + + if ( counter == 0 ) { + T_eq_uint( extension_counter[ i ][ kind ], 0 ); + } else { + T_eq_uint( extension_counter[ i ][ kind ], 1 ); + T_eq_uint( extension_events[ i ][ kind ][ 0 ].counter, counter ); + T_eq_ptr( extension_events[ i ][ kind ][ 0 ].executing, executing ); + T_eq_ptr( extension_events[ i ][ kind ][ 0 ].thread, thread ); + + counter += increment; + } + } + } + + static void CheckReverse( + ExtensionKind kind, + unsigned int counter, + unsigned int increment, + rtems_tcb *executing, + rtems_tcb *thread + ) + { + size_t i; + + for ( i = 0; i < RTEMS_ARRAY_SIZE( extension_ids ); ++i ) { + if ( i == 5 && kind != THREAD_SWITCH ) { + continue; + } + + if ( counter == 0 ) { + T_eq_uint( extension_counter[ i ][ kind ], 0 ); + } else { + T_eq_uint( extension_counter[ i ][ kind ], 1 ); + T_eq_uint( + extension_events[ i ][ kind ][ 0 ].counter, + 7 - counter + ); + T_eq_ptr( extension_events[ i ][ kind ][ 0 ].executing, executing ); + T_eq_ptr( extension_events[ i ][ kind ][ 0 ].thread, thread ); + + counter += increment; + } + } + } + + static void CheckDeletedNotInvoked( ExtensionKind kind ) + { + size_t index; + + if ( kind == THREAD_DELETE || kind == THREAD_TERMINATE ) { + index = 5; + } else { + index = 3; + } + + T_eq_uint( extension_events[ index ][ kind ][ 0 ].counter, 0 ); + T_null( extension_events[ index ][ kind ][ 0 ].executing ); + T_null( extension_events[ index ][ kind ][ 0 ].thread ); + } + + static void BeginWorker( rtems_task_argument arg ) + { + T_eq_u32( arg, 0 ); + StopTestCase(); + rtems_task_exit(); + } + + static void ExittedWorker( rtems_task_argument arg ) + { + T_eq_u32( arg, 0 ); + (void) StartTestCase( THREAD_EXITTED ); + } + + static void RestartWorker( rtems_task_argument arg ) + { + T_eq_u32( arg, 0 ); + (void) StartTestCase( THREAD_RESTART ); + (void) rtems_task_restart( RTEMS_SELF, 1 ); + } + + static void StartWorker( rtems_task_argument arg ) + { + (void) arg; + T_unreachable(); + } + + static void TerminateWorker( rtems_task_argument arg ) + { + T_eq_u32( arg, 0 ); + (void) StartTestCase( THREAD_TERMINATE ); + rtems_task_exit(); + } +test-target: testsuites/validation/tc-userext.c +test-teardown: + brief: null + code: | + RestoreRunnerPriority(); + description: null +type: test-case diff --git a/spec/score/interr/val/terminate.yml b/spec/score/interr/val/terminate.yml index 4cb94657..2021fb1b 100644 --- a/spec/score/interr/val/terminate.yml +++ b/spec/score/interr/val/terminate.yml @@ -5,14 +5,12 @@ enabled-by: true links: [] test-actions: - action-brief: | - Create three dynamic extensions. Call the system termination procedure. - Delete one dynamic extension during the fatal extension invocation. Delete - the two remaining dynamic extensions. + Create five dynamic extensions. Call the system termination procedure. + Delete three dynamic extension during the fatal extension invocation. + Delete the two remaining dynamic extensions. action-code: | rtems_status_code sc; rtems_extensions_table table; - rtems_id id_2; - rtems_id id_3; bool shutdown_ok; #if defined(RTEMS_SMP) @@ -27,7 +25,7 @@ test-actions: sc = rtems_extension_create( rtems_build_name( ' ', ' ', ' ', '2' ), &table, - &id_2 + &extension_ids[ 2 ] ); T_step_rsc_success( ${step}, sc ); @@ -35,7 +33,7 @@ test-actions: sc = rtems_extension_create( rtems_build_name( ' ', ' ', ' ', '3' ), &table, - &id_3 + &extension_ids[ 3 ] ); T_step_rsc_success( ${step}, sc ); @@ -43,7 +41,23 @@ test-actions: sc = rtems_extension_create( rtems_build_name( ' ', ' ', ' ', '4' ), &table, - &extension_id_4 + &extension_ids[ 4 ] + ); + T_step_rsc_success( ${step}, sc ); + + table.fatal = FatalExtension5; + sc = rtems_extension_create( + rtems_build_name( ' ', ' ', ' ', '5' ), + &table, + &extension_ids[ 5 ] + ); + T_step_rsc_success( ${step}, sc ); + + table.fatal = FatalExtension6; + sc = rtems_extension_create( + rtems_build_name( ' ', ' ', ' ', '6' ), + &table, + &extension_ids[ 6 ] ); T_step_rsc_success( ${step}, sc ); @@ -55,10 +69,10 @@ test-actions: test_case_active = false; - sc = rtems_extension_delete( id_2 ); + sc = rtems_extension_delete( extension_ids[ 2 ] ); T_step_rsc_success( ${step}, sc ); - sc = rtems_extension_delete( id_3 ); + sc = rtems_extension_delete( extension_ids[ 6 ] ); T_step_rsc_success( ${step}, sc ); checks: - brief: | @@ -81,7 +95,17 @@ test-actions: ); T_step_eq_int( ${step}, - info[ 3 ].source, + info[ 4 ].source, + RTEMS_FATAL_SOURCE_APPLICATION + ); + T_step_eq_int( + ${step}, + info[ 5 ].source, + RTEMS_FATAL_SOURCE_APPLICATION + ); + T_step_eq_int( + ${step}, + info[ 6 ].source, RTEMS_FATAL_SOURCE_APPLICATION ); links: @@ -94,7 +118,9 @@ test-actions: T_step_false( ${step}, info[ 0 ].always_set_to_false ); T_step_false( ${step}, info[ 1 ].always_set_to_false ); T_step_false( ${step}, info[ 2 ].always_set_to_false ); - T_step_false( ${step}, info[ 3 ].always_set_to_false ); + T_step_false( ${step}, info[ 4 ].always_set_to_false ); + T_step_false( ${step}, info[ 5 ].always_set_to_false ); + T_step_false( ${step}, info[ 6 ].always_set_to_false ); links: - role: validation uid: ../req/terminate-userext @@ -104,7 +130,9 @@ test-actions: T_step_eq_ulong( ${step}, info[ 0 ].code, 123456 ); T_step_eq_ulong( ${step}, info[ 1 ].code, 123456 ); T_step_eq_ulong( ${step}, info[ 2 ].code, 123456 ); - T_step_eq_ulong( ${step}, info[ 3 ].code, 123456 ); + T_step_eq_ulong( ${step}, info[ 4 ].code, 123456 ); + T_step_eq_ulong( ${step}, info[ 5 ].code, 123456 ); + T_step_eq_ulong( ${step}, info[ 6 ].code, 123456 ); links: - role: validation uid: ../req/terminate-userext @@ -114,7 +142,9 @@ test-actions: T_step_eq_uint( ${step}, info[ 0 ].counter, 1 ); T_step_eq_uint( ${step}, info[ 1 ].counter, 2 ); T_step_eq_uint( ${step}, info[ 2 ].counter, 3 ); - T_step_eq_uint( ${step}, info[ 3 ].counter, 4 ); + T_step_eq_uint( ${step}, info[ 4 ].counter, 4 ); + T_step_eq_uint( ${step}, info[ 5 ].counter, 5 ); + T_step_eq_uint( ${step}, info[ 6 ].counter, 6 ); links: - role: validation uid: /rtems/userext/req/fatal-order @@ -122,10 +152,10 @@ test-actions: Check that the fatal extension in the deleted extension set was not invoked. code: | - T_step_eq_int( ${step}, info[ 4 ].source, 0 ); - T_step_false( ${step}, info[ 4 ].always_set_to_false ); - T_step_eq_ulong( ${step}, info[ 4 ].code, 0 ); - T_step_eq_uint( ${step}, info[ 4 ].counter, 0 ); + T_step_eq_int( ${step}, info[ 3 ].source, 0 ); + T_step_false( ${step}, info[ 3 ].always_set_to_false ); + T_step_eq_ulong( ${step}, info[ 3 ].code, 0 ); + T_step_eq_uint( ${step}, info[ 3 ].counter, 0 ); links: - role: validation uid: /rtems/userext/req/fatal-iterate-remove @@ -170,7 +200,7 @@ test-actions: - brief: | Check that the system was finally halted. code: | - T_step_eq_uint( ${step}, counter, 5 ); + T_step_eq_uint( ${step}, counter, 7 ); links: - role: validation uid: ../req/terminate-halt @@ -193,7 +223,7 @@ test-includes: - setjmp.h - string.h test-local-includes: -- tc-terminate.h +- tc-userext.h test-setup: null test-stop: null test-support: | @@ -206,7 +236,7 @@ test-support: | static Atomic_Uint counter; - static FatalInfo info[ 5 ]; + static FatalInfo info[ 7 ]; static bool test_case_active; @@ -220,7 +250,7 @@ test-support: | static rtems_fatal_code halt_code; - static rtems_id extension_id_4; + static rtems_id extension_ids[ 7 ]; static unsigned int GetCounter( void ) { @@ -284,7 +314,12 @@ test-support: | rtems_fatal_code code ) { + rtems_status_code sc; + FatalExtension( source, always_set_to_false, code, 2 ); + + sc = rtems_extension_delete( extension_ids[ 3 ] ); + T_quiet_rsc_success( sc ); } static void FatalExtension3( @@ -293,21 +328,44 @@ test-support: | rtems_fatal_code code ) { + FatalExtension( source, always_set_to_false, code, 3 ); + } + + static void FatalExtension4( + rtems_fatal_source source, + bool always_set_to_false, + rtems_fatal_code code + ) + { + FatalExtension( source, always_set_to_false, code, 4 ); + } + + static void FatalExtension5( + rtems_fatal_source source, + bool always_set_to_false, + rtems_fatal_code code + ) + { rtems_status_code sc; - FatalExtension( source, always_set_to_false, code, 3 ); + FatalExtension( source, always_set_to_false, code, 5 ); - sc = rtems_extension_delete( extension_id_4 ); + sc = rtems_extension_delete( extension_ids[ 5 ] ); T_quiet_rsc_success( sc ); } - static void FatalExtension4( + static void FatalExtension6( rtems_fatal_source source, bool always_set_to_false, rtems_fatal_code code ) { - FatalExtension( source, always_set_to_false, code, 3 ); + rtems_status_code sc; + + FatalExtension( source, always_set_to_false, code, 6 ); + + sc = rtems_extension_delete( extension_ids[ 4 ] ); + T_quiet_rsc_success( sc ); } test-target: testsuites/validation/tc-terminate.c test-teardown: null diff --git a/spec/testsuites/terminate.yml b/spec/testsuites/terminate.yml index 555947c4..8ac5466d 100644 --- a/spec/testsuites/terminate.yml +++ b/spec/testsuites/terminate.yml @@ -25,7 +25,7 @@ test-code: | test-description: null test-includes: [] test-local-includes: -- tc-terminate.h -test-suite-name: Fatal +- tc-userext.h +test-suite-name: Terminate test-target: testsuites/validation/ts-terminate.c type: test-suite diff --git a/spec/testsuites/userext.yml b/spec/testsuites/userext.yml new file mode 100644 index 00000000..4e1aa505 --- /dev/null +++ b/spec/testsuites/userext.yml @@ -0,0 +1,44 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: /req/test-suites +test-brief: | + This validation test suite contains a test cases related to the invocation of + user extensions. +test-code: | + const char rtems_test_name[] = "${.:/test-suite-name}"; + + #define CONFIGURE_MAXIMUM_PROCESSORS 2 + + #define CONFIGURE_INITIAL_EXTENSIONS \ + { \ + .thread_begin = ThreadBeginExtension0, \ + .thread_create = ThreadCreateExtension0, \ + .thread_delete = ThreadDeleteExtension0, \ + .thread_exitted = ThreadExittedExtension0, \ + .thread_restart = ThreadRestartExtension0, \ + .thread_start = ThreadStartExtension0, \ + .thread_switch = ThreadSwitchExtension0, \ + .thread_terminate = ThreadTerminateExtension0 \ + }, { \ + .thread_begin = ThreadBeginExtension1, \ + .thread_create = ThreadCreateExtension1, \ + .thread_delete = ThreadDeleteExtension1, \ + .thread_exitted = ThreadExittedExtension1, \ + .thread_restart = ThreadRestartExtension1, \ + .thread_start = ThreadStartExtension1, \ + .thread_switch = ThreadSwitchExtension1, \ + .thread_terminate = ThreadTerminateExtension1 \ + } + + #include "ts-default.h" +test-description: null +test-includes: [] +test-local-includes: +- tc-userext.h +test-suite-name: Userext +test-target: testsuites/validation/ts-userext.c +type: test-suite |