mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-12-07 13:45:00 -05:00
Merge 2af93b5bd1 into 81c623212a
This commit is contained in:
commit
71c53e6b55
49 changed files with 18747 additions and 30 deletions
8
.github/workflows/verifast-proof-diff.yml
vendored
Normal file
8
.github/workflows/verifast-proof-diff.yml
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
name: verifast-proof-diff
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
proof_diff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: Test/VeriFast/tasks/vTaskSwitchContext/diff.sh `pwd`
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -19,3 +19,7 @@ __pycache__/
|
|||
# Ignore certificate files.
|
||||
*.pem
|
||||
*.crt
|
||||
|
||||
# Ignore OS bookkeeping files
|
||||
.DS_Store
|
||||
.vscode/settings.json
|
||||
|
|
|
|||
8
.gitmodules
vendored
Normal file
8
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[submodule "verification/verifast/demos/FreeRTOS-SMP-Demos"]
|
||||
path = Test/VeriFast/tasks/vTaskSwitchContext/demos/FreeRTOS-SMP-Demos
|
||||
url = https://github.com/Tobias-internship-AWS-2022/FreeRTOS-SMP-Demos.git
|
||||
branch = verifast
|
||||
[submodule "verification/verifast/sdks/pico-sdk"]
|
||||
path = Test/VeriFast/tasks/vTaskSwitchContext/sdks/pico-sdk
|
||||
url = https://github.com/Tobias-internship-AWS-2022/pico-sdk.git
|
||||
branch = verifast
|
||||
8
Test/VeriFast/tasks/vTaskSwitchContext/.gitignore
vendored
Normal file
8
Test/VeriFast/tasks/vTaskSwitchContext/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Ignore log files
|
||||
pp_log
|
||||
|
||||
# Ignore preprocessing output
|
||||
preprocessed_files
|
||||
|
||||
# Ignore generated stats
|
||||
stats
|
||||
601
Test/VeriFast/tasks/vTaskSwitchContext/README.md
Normal file
601
Test/VeriFast/tasks/vTaskSwitchContext/README.md
Normal file
|
|
@ -0,0 +1,601 @@
|
|||
# FreeRTOS VeriFast Proofs
|
||||
This directory contains an unbounded memory safety and thread safety proof
|
||||
for the core of the task scheduler: `vTaskSwitchContext`
|
||||
|
||||
|
||||
|
||||
## VeriFast
|
||||
[VeriFast](https://github.com/verifast/verifast)
|
||||
is a deductive program verifier for C based on separation logic.
|
||||
It supports verifying concurrent code and reasoning about complex data structures.
|
||||
|
||||
VeriFast proofs are *unbounded*.
|
||||
That is, until explicitly specified, it does not assume any bound on the size of the involved data structures.
|
||||
Hence, proofs give us unbounded guarantees.
|
||||
In our case, this means that our proof holds for any number of tasks and any size of the involved data structures.
|
||||
|
||||
Reasoning about concurrent code can be tricky because of all the interleavings that can occur.
|
||||
VeriFast does not assume anything about the occuring interleavings.
|
||||
Therefore, the proven guarantees hold for every possible interleaving that might occur during runtime.
|
||||
|
||||
Being a deductive verifier, VeriFast requires us to manually write a proof.
|
||||
In particular, we have to specify what well-formed data structures look like and to annotate the code with proof steps.
|
||||
It then symbolically executes the annotated code and queries an SMT solver to check the validity of proof steps.
|
||||
|
||||
This directory contains all the specifications and proof steps necessary to check that the scheduler is memory and thread safe.
|
||||
|
||||
|
||||
|
||||
## Key Result
|
||||
Informally, the proof guarantees the following:
|
||||
```
|
||||
Proof Assumptions:
|
||||
- Data structure specification
|
||||
- Locking discipline
|
||||
- Contracts abstracting assembly
|
||||
- FreeRTOS config
|
||||
- Function contract of `vTaskSwitchContext`
|
||||
|
||||
==>
|
||||
|
||||
Unbounded memory & thread safety guarantees for `vTaskSwitchContext`:
|
||||
∀ #tasks. ∀ task interleavings. ∀ interrupt schedules. ∀ data sizes. ∀ cores C1, …, Cn.
|
||||
vTaskSwitchContext(C1) || … || vTaskSwitchContext(Cn)
|
||||
=> (no memory error ∧ no race condition)
|
||||
```
|
||||
|
||||
We have to model certain aspects of the system and our proof assumes that these models are correct (cf. `Proof Assumptions` below for a detailed explanation).
|
||||
In particular, this modeling step includes writing a precondition for `vTaskSwitchContext` that specifies the context in which the function may be called.
|
||||
|
||||
Our proof considers any number of running tasks, any possible task interleavings and any interrupts that might occur during execution.
|
||||
In particular, it considers any possible size for the involved data structures, since it is an unbounded proof.
|
||||
|
||||
The proof ensures that every concurrent execution of `vTaskSwitchContext` on any cores is memory safe and mutually thread safe.
|
||||
That is, when we execute multiple instances of the function on different cores, we won't get any memory errors or data races, no matter how these instances interleave or when interrupts occur.
|
||||
|
||||
|
||||
# Found Buffer Underflow
|
||||
During the verification of `vTaskSwitchContext` we found a buffer underflow, fixed it and verified that our fix works.
|
||||
The guarantees stated in the section above concern the fixed-up code.
|
||||
We submitted the fix as a pull request: [Fixed buffer underflow in prvSelectHighestPriorityTask. #607](https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/607)
|
||||
|
||||
Our verification target `vTaskSwitchContext` calls the auxiliary function `prvSelectHighestPriorityTask` to choose the task that will be scheduled next.
|
||||
This works as long as the idle tasks have already been created.
|
||||
The idle tasks are tasks whose only purpose is to run and do nothing in case there is no other task that can be scheduled.
|
||||
|
||||
However, `prvSelectHighestPriorityTask` can also be called before the idle tasks have been created.
|
||||
When that happens, the function decrements the global variable `uxTopReadyPriority` to -1.
|
||||
This variable is supposed to store the highest priority for which we know that there is a ready task.
|
||||
Priorities start at 0, so -1 is an invalid value.
|
||||
|
||||
During the next regular context switch, `vTaskSwitchContext` calls `prvSelectHighestPriorityTask`.
|
||||
The latter looks at `uxTopReadyPriority` to detect at which priority level it should start its search.
|
||||
Hence, it accesses the global ready list array at index -1, i.e., `pxReadyTasksLists[ uxCurrentPriority ]`.
|
||||
This causes a memory error.
|
||||
|
||||
# Proof Directory Structure
|
||||
```
|
||||
FreeRTOS-Kernel
|
||||
│
|
||||
│
|
||||
│
|
||||
├── *.c files
|
||||
│ The base directory contains the source files. Note that our proof uses
|
||||
│ annotated copies of these files located in the proof directory.
|
||||
│
|
||||
│
|
||||
├── include
|
||||
│ Contains the header files. Note that our proof uses annotated copies of
|
||||
│ these files located in the proof directory.
|
||||
│
|
||||
│
|
||||
├── portable
|
||||
│ └── Thirdparty
|
||||
│ └── GCC
|
||||
│ └── RP2040
|
||||
│ Contains the Raspberry Pi Pico setup.
|
||||
│
|
||||
│
|
||||
├── .github/workflows
|
||||
│ └── verifast-proof-diff.yml
|
||||
│ This workflow is triggered on every pull request and checks for
|
||||
│ potential divergences between the production code and the proof.
|
||||
│
|
||||
│
|
||||
└── Test/VeriFast/tasks/vTaskSwitchContext
|
||||
│
|
||||
├── run-verifast.sh
|
||||
│ Shell script to check the proof with VeriFast.
|
||||
│
|
||||
├── run-vfide.sh
|
||||
│ Shell script to load the proof into the VeriFast IDE.
|
||||
│
|
||||
├── diff.sh
|
||||
│ Shell script to flag changes in the production code that potentially
|
||||
│ break the validity of the VeriFast proof. An empty diff means that the
|
||||
│ proof and the production code remain in sync.
|
||||
│
|
||||
├── preprocessing_scripts
|
||||
│ Contains scripts to preprocess and rewrite the source code.
|
||||
│
|
||||
├── demos
|
||||
│ Contains the FreeRTOS SMP demo. Our proofs use some of its
|
||||
│ configuration files.
|
||||
│
|
||||
├── include
|
||||
│ Contains annotated copies of header files residing in
|
||||
│ 'FreeRTOS-Kernel/include'. These files are annotated with VeriFast
|
||||
| predicates, lemmas and proof steps.
|
||||
│
|
||||
│
|
||||
├── proof
|
||||
│ Contains the VeriFast proof files.
|
||||
│ │
|
||||
│ ├── *.h files
|
||||
│ │ Headers containing VeriFast formalizations and proofs.
|
||||
│ │
|
||||
│ ├── README.md
|
||||
│ │ Contains overview about proof files.
|
||||
│ │
|
||||
│ ├── single_core_proofs
|
||||
│ │ Contains the old list formalization and proofs written by
|
||||
│ │ Aalok Thakkar and Nathan Chong in 2020 for the single-core
|
||||
│ │ setup.
|
||||
│ │
|
||||
│ └── single_core_proofs_extended
|
||||
│ Contains new proofs extending the single-core list
|
||||
│ formalization.
|
||||
│
|
||||
│
|
||||
├── proof_setup
|
||||
│ Contains config files for the proof. The proof assumes a setup for
|
||||
│ RP2040.
|
||||
│
|
||||
├── sdks
|
||||
│ Contains SDKs referenced by the proof setup.
|
||||
│ Some files are annotated with VeriFast contracts.
|
||||
│
|
||||
├── src
|
||||
│ Contains annotated copies of source files residing in the repository's
|
||||
│ base directory 'FreeRTOS-Kernel'. The files are annotated with VeriFast
|
||||
│ predicates, lemmas and proof steps.
|
||||
│
|
||||
└── stats
|
||||
Contains some statistics about the VeriFast proof.
|
||||
```
|
||||
|
||||
|
||||
|
||||
# Checking the Proof
|
||||
The proof can be checked by running one of the scripts `run-verifast.sh` and
|
||||
`run-vfide.sh` residing in this directory (see repo structure above).
|
||||
Both scripts preprocess the annotated code with Clang and rewrite syntax
|
||||
VeriFast does not understand into something equivalent.
|
||||
The result is written to a temporary file (`preprocessed_files/tasks_vf_pp.c`)
|
||||
before it is processed by VeriFast.
|
||||
This file contains a copy of all the code and annotations required to check the
|
||||
proof.
|
||||
Both scripts expect the command line arguments explained below.
|
||||
|
||||
- #### run-verifast.sh:
|
||||
Preprocesses the code and proof files and uses the
|
||||
command-line version of VeriFast to check the resulting proof file.
|
||||
A call must have the form:
|
||||
#### run-verifast.sh \<REPO_BASE_DIR\> \<VERIFAST_DIR\>
|
||||
where
|
||||
- \<REPO_BASE_DIR\> is the absolute path to this repository's base directory,
|
||||
i.e., `FreeRTOS-Kernel` in the repo structure depicted above.
|
||||
- \<VERIFAST_DIR\> is the absolute path to the VeriFast installation
|
||||
directory.
|
||||
|
||||
- #### run-vfide.sh:
|
||||
Preprocesses the code and proof files and loads the resulting proof file into
|
||||
the VeriFast IDE.
|
||||
A call must have the form:
|
||||
#### run-vfide.sh \<REPO_BASE_DIR\> \<VERIFAST_DIR\> \[\<FONT_SIZE\>\]
|
||||
where
|
||||
- \<REPO_BASE_DIR\> \<VERIFAST_DIR\> are as explained above
|
||||
- \<FONT_SIZE\> is an optional argument specifying the IDE's font size.
|
||||
|
||||
|
||||
# Reading the Proof
|
||||
The most important aspects any reader has to know about before they can understand the proof are the locking discipline and the lock invariants.
|
||||
We suggest to read the proof in a top-down approach.
|
||||
That is, the reader should start by reading the documentation and definitions of the most important concepts.
|
||||
Afterwards, we suggest to continue by reading the most important parts of the verified functions:
|
||||
The contracts and the loop invariants.
|
||||
Only once these are understood, we suggest to read the low-level proof annotations in the verified functions (e.g. open/close statements, lemma calls).
|
||||
|
||||
We propose the following order:
|
||||
1. The locking discipline, formalized and documented in `proof/port_locking_contracts.h`.
|
||||
|
||||
FreeRTOS uses macros to invoke synchronization mechanisms (activating/deactivating interrupts and acquiring/releasing locks).
|
||||
The definitions of these macros are port-specific.
|
||||
The file `proof/port_locking_contracts.h` contains contracts abstracting the port-specific definitions and formalizing the synchronization mechanisms and the locking discipline, e.g., the order in which locks have to be acquired.
|
||||
|
||||
2. The lock invariants, formalized and documented in `proof/lock_predicates.h`.
|
||||
|
||||
The invariants express which resources the locks and the masking of interrupts protect.
|
||||
When we acquire a lock or deactivate interrupts, the invariants determine which level of access permissions (i.e. read or write access) we get for the protected resources.
|
||||
Since the locks protect the ready lists and task control blocks, the invariants reference the ready list and task predicates defined in `proof/ready_list_predicates.h` and `task_predicates.h`.
|
||||
|
||||
3. The contracts for the functions we verified, i.e., `vTaskSwitchContext` and `prvSelectHighestPriorityTask`, cf. `src/tasks.c`.
|
||||
|
||||
4. The loop invariants in `prvSelectHighestPriorityTask`.
|
||||
|
||||
5. The low-level proof annotations in `vTaskSwitchContext` and `prvSelectHighestPriorityTask`, e.g., open/close statements and lemma calls.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Maintaining the Proof
|
||||
This directory contains annotated copies of FreeRTOS source and header files.
|
||||
The annotations in these files tell VeriFast which functions it should verify and what the proof looks like.
|
||||
Including these annotations in the production code would lead to a huge visual burden for developers.
|
||||
The downside of including them in a separate copy of the code is that the proof and the production code may get out of sync without anyone noticing.
|
||||
|
||||
Therefore, we provide a GitHub workflow to check for potential divergences, cf.
|
||||
`FreeRTOS-Kernel/.github/workflows/verifast-proof-diff.yml`.
|
||||
The workflow is triggered on every pull request.
|
||||
It aggregates and preprocesses the parts of the production code relevant to our proof as well as the annotated copies in this directory.
|
||||
Afterwards, it computes a diff between both versions and fails if the result is not empty, in which case the diff result will be logged in the GitHub actions log.
|
||||
An empty diff means that the pull request did not change anything that can affect our proof and the proof remains valid.
|
||||
A non-empty diff shows which changes in the pull request potentially impact our proof.
|
||||
In this case, the changes should also be applied to the annotated copies and the proof should be checked again.
|
||||
If the detected divergence was not a false positive and indeed impacted the proof, the proof will likely require manual repair.
|
||||
|
||||
The diff can also be manually checked by running the command
|
||||
`diff.sh <REPO_BASE_DIR>`, where the argument is the absolute path to the repository's base directory.
|
||||
|
||||
|
||||
|
||||
# Disclaimer
|
||||
All scripts and proofs have been tested under OS X 12.6.1 and with the VeriFast nightly build from Dec 31, 2022 (corresponds to commit [9e32b122b54152a2ac75a811aa422d638b56c6ab](https://github.com/verifast/verifast/commit/9e32b122b54152a2ac75a811aa422d638b56c6ab)).
|
||||
|
||||
|
||||
|
||||
# Proof Assumptions
|
||||
We have to model certain aspects of the system in order to reason about the task scheduler.
|
||||
The proof treats these models as assumptions.
|
||||
Therefore, the proof's correctness relies on the correctness of our models.
|
||||
|
||||
|
||||
|
||||
- ### FreeRTOS Configuration
|
||||
The VeriFast proofs assume a setup for the Raspberry Pi Pico, i.e., RP2040, cf. directory `proof_setup`.
|
||||
We use the config files from the official FreeRTOS SMP demo for the RP2040 and from official RP2040 port.
|
||||
The most important properties of this configuration are:
|
||||
- It supports running multiple priorities in parallel on different cores.
|
||||
- Core affinity is deactivated, i.e., all tasks may be scheduled on any core.
|
||||
|
||||
The Raspberry Pi Pico only has two cores and we want to ensure that our proof does not accidentally rely on the properties that come with this binary setup.
|
||||
Hence, we changed the number of cores to an arbitrary large number.
|
||||
|
||||
|
||||
|
||||
- ### Contracts Abstracting Assembly
|
||||
The port layer of FreeRTOS contains assembly code that is essential for our proof.
|
||||
In particular, code to mask interrupts and code to acquire and release locks.
|
||||
VeriFast is a program verifier for C and not designed to handle any kind of assembly.
|
||||
The port-specific assembly is called via macros with a port-specific definition.
|
||||
We redefined these macros to call dummy function prototypes instead.
|
||||
We equipped these prototypes with VeriFast contracts that capture the semantics of the original assembly code, cf. `proof/port_locking_contracts.h`.
|
||||
This way, VeriFast refers to the contracts to reason about the macro calls and does not have to deal with the assembly code.
|
||||
|
||||
|
||||
|
||||
- ### Data structure specification
|
||||
VeriFast expects us to specify the memory layout of the data structures accessed by the task scheduler.
|
||||
In a proof, these specifications tell us what a well-formed instance of a data structure looks like and how me may manipulate it to preserve well-formedness.
|
||||
|
||||
Most notably, the scheduler searches the so called "ready lists", a global array of cyclic doubly linked lists storing tasks of specific priorities that are ready to be scheduled.
|
||||
Reasoning about this data structure is challenging because it requires heavy reasoning about its complex internals.
|
||||
|
||||
Previously, Aalok Thakkar and Nathan Chong used VeriFast to prove functional correctness of the stand-alone list data structure for a single-core setup, c.f. [FreeRTOS Pull Request 836: Update VeriFast proofs](https://github.com/FreeRTOS/FreeRTOS/pull/836).
|
||||
We reused their formalization and proofs as much as possible.
|
||||
However, we had to heavily adapt both to tailor them to the needs of the scheduler proof, cf. `Proof Details` below.
|
||||
|
||||
The reused specification resides in `proofs/single_core_proofs/`.
|
||||
The full ready list array is specified in `proofs/ready_list_predicates.h`.
|
||||
|
||||
|
||||
- ### Function Contract of `vTaskSwitchContext`
|
||||
VeriFast expects every function that it verifies to have a so called "function contract".
|
||||
These contracts consist of a precondition, also called the "requires clause" and a postcondition, also called the "ensures clause".
|
||||
The precondition characterizes the context in which the function may be called.
|
||||
This determines the state in which our proof starts.
|
||||
The postcondition characterizes the state we want to be in when the function terminates.
|
||||
|
||||
Starting from the precondition, VeriFast symbolically executes the function's code and our annotated proof steps.
|
||||
The proof succeeds if every step succeeds and if the proof ends in a state that complies with the specified postcondition.
|
||||
|
||||
Hence, the function contract determines *WHAT* we prove.
|
||||
`vTaskSwitchContext` is called by an interrupt defined in the port layer on some core `C`.
|
||||
This interrupt masks interrupts on this core and acquires the locks protecting the ready lists.
|
||||
Therefore, the precondition of `vTaskSwitchContext` states that:
|
||||
- the function is executed on an arbitrary core `C`
|
||||
- interrupts on core `C` are deactivated
|
||||
- the locks protecting the ready lists have been acquired
|
||||
- that all the relevant global data structures are well-formed
|
||||
|
||||
The postcondition states that all these properties are preserved, which is what the interrupt calling into the scheduler expects.
|
||||
|
||||
|
||||
|
||||
- ### Locking discipline and lock invariants
|
||||
FreeRTOS' SMP implementation uses the following synchronization mechanisms:
|
||||
- Deactivating interrupts:
|
||||
Some data is only meant to be accessed on a specific core C.
|
||||
Such data may only be accessed after interrupts on core C have been deactivated.
|
||||
For instance the global array `pxCurrentTCBs` in `tasks.c` has an entry for
|
||||
every core.
|
||||
`pxCurrentTCBs[C]` stores a pointer to the task control block (TCB) of the task running on core C.
|
||||
Core C is always allowed to read `pxCurrentTCBs[C]`.
|
||||
However, writing requires the interrupts on core C to be deactivated.
|
||||
|
||||
- task lock:
|
||||
The task lock is used to protect ciritical sections and resources from being accessed by multiple tasks simultaneously.
|
||||
|
||||
- ISR lock:
|
||||
The ISR/ interrupt lock is used to protect critical sections and resources from being accessed by multiple interrupts simultaneously.
|
||||
|
||||
- task lock + ISR lock:
|
||||
Access to certain resources and ciritical sections are protected by both the task lock and the ISR lock.
|
||||
For these, it is crucial that we first acquire the task lock and then the ISR lock.
|
||||
Likewise, we must release them in opposite order.
|
||||
Failure to comply with this order may lead to deadlocks.
|
||||
The resources protected by both locks are the main resources this proof deals with.
|
||||
These include the ready lists and the certain access rights to the tasks' run states.
|
||||
|
||||
#### Lock Invariants
|
||||
Every synchronization mechanism protects specific data structures and sections of code.
|
||||
For our proof, we associate every synchronization mechanism `L` with permissions to access the resources it protects.
|
||||
We do this by defining a so called "lock invariant" `I`.
|
||||
Besides pure access permissions the invariant can also specify more specifc properties, such as that a data structure must be well-formed.
|
||||
(We call it "lock invariant" even though we also use the same technique to model the masking of interrupts.)
|
||||
When we acquire lock `L` (or deactivate the interrupts) we produce the lock invariant `I`.
|
||||
That means, we get the access permissions `I` expresses.
|
||||
When we release the lock `L` (or reactivate the interrupts), we consume the invariant `I`.
|
||||
That means that we lose the access permissions granted by `I`.
|
||||
While we hold the lock, we are free to manipulate the resources it protects (according to the permissions granted by `I`).
|
||||
However, we have to prove that whatever we do with these resources preserves any guarantees given by the invariant.
|
||||
For instance, if `I` says a data structure is well-formed then we must prove that our actions preserve well-formedness.
|
||||
Otherwise, consuming `I` during the release step will fail and consequently the entire proof will fail.
|
||||
|
||||
FreeRTOS uses macros with port-specifc definitions to acquire and release locks and to mask and unmask interrupts.
|
||||
We abstracted these with VeriFast contracts defined in `proof/port_locking_contracts.h`.
|
||||
The contracts ensure that invoking any synchronization mechanism produces or consumes the corresponding invariant.
|
||||
The invariants are defined in `proof/lock_predicates.h`
|
||||
|
||||
|
||||
|
||||
|
||||
# Proof Details
|
||||
|
||||
## Context Switches and Ready Lists
|
||||
Our proof ensures that the context switches performed by `vTaskSwitchContext` are memory and thread safe.
|
||||
The most difficult part of a context switch is to find a new task that we can schedule.
|
||||
For that, `vTaskSwitchContext` calls `prvSelectHighestPriorityTask` which searches for the task with the highest priority that can be scheduled.
|
||||
FreeRTOS maintains a global data structure called the "ready lists".
|
||||
It is an array `pxReadyTasksLists` with an entry for every priority level that a task might have.
|
||||
For every such priority level `p`, `pxReadyTasksLists[p]` stores a cyclic doubly linked list containing all tasks of priority level `p` that are ready to be scheduled, including currently running ones.
|
||||
`prvSelectHighestPriorityTask` searches through these lists in descending order.
|
||||
That is, in order to verify `vTaskSwitchContext`, we have to reason about the ready lists.
|
||||
|
||||
|
||||
|
||||
## Reusing the Single-Core List Formalization and Proofs
|
||||
In 2020 Aalok Thakkar and Nathan Chong verified the functional correctness of the FreeRTOS list API for a single-core setup, cf. [FreeRTOS Pull Request 836: Update VeriFast proofs](https://github.com/FreeRTOS/FreeRTOS/pull/836).
|
||||
The list API has not been changed during the port of FreeRTOS to SMP.
|
||||
Ready lists are fully protected by the task and ISR locks, which allows FreeRTOS to continue using the single-core implementation of the list API.
|
||||
|
||||
We reuse the single-core list formalization to model the ready list for each priority level.
|
||||
However, due to challenges that arise in the scheduler, we had to extend and adapt the existing formalization.
|
||||
|
||||
The single-core list formalization and lemmas that we reuse are located in `proofs/single_core_proofs/scp_list_predicates.h`.
|
||||
The list API is defined in `include/list.h` and `src/list.c`.
|
||||
The latter also contains the API proofs.
|
||||
|
||||
|
||||
|
||||
## Comparing the Original List Proofs and Our Adaptation
|
||||
As mentioned, we had to heavily adapt the list formalization and proofs to reuse them for the scheduler verification.
|
||||
Therefore, both `scp_list_predicates.h` and `list.c` contain an updated version of the formalization and proofs used by our context-switch proof and the original version by Aalok Thakkar and Nathan Chong.
|
||||
The latter is guarded by a preprocessor define `VERIFAST_SINGLE_CORE`.
|
||||
We can compare both versions by preprocessing both files twice: Once with the define `VERIFAST_SINGLE_CORE`, which yields the original version, and once without which gives us the version used by our proofs.
|
||||
Afterwards, a diff will show all the adaptations we had to apply.
|
||||
|
||||
|
||||
|
||||
## List Predicates
|
||||
|
||||
The single-core list formalization defines two main predicates:
|
||||
- ```
|
||||
predicate xLIST_ITEM(struct xLIST_ITEM *n,
|
||||
TickType_t xItemValue,
|
||||
struct xLIST_ITEM *pxNext,
|
||||
struct xLIST_ITEM *pxPrevious,
|
||||
struct xLIST *pxContainer;)
|
||||
```
|
||||
Represents a list item of type `xLIST_ITEM`.
|
||||
The arguments have the following semantics:
|
||||
- `n`: A pointer to the node whose memory the predicate represents.
|
||||
- `xItemValue`: The value stored in node `n`.
|
||||
- `pxNext`: The node's "next" pointer, i.e., `n->pxNext`.
|
||||
- `pxPrevious`: The node's "previous" pointer, i.e., `n->pxPrevious`.
|
||||
- `pxContainer`: The doubly linked list containing this node.
|
||||
- ```
|
||||
predicate DLS(struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells,
|
||||
list<TickType_t > vals,
|
||||
struct xLIST *pxContainer)
|
||||
```
|
||||
Represents a non-empty doubly linked list segment.
|
||||
The semantics of the arguments are as follows:
|
||||
- `n`: The left-most node in the segment.
|
||||
- `nPrev`: The left-most node's "previous" pointer, i.e., `n->pxPrevious`.
|
||||
- `mNext`: The right-most node's "next" pointer, i.e., `m->pxNext`.
|
||||
- `m`: The right-most node.
|
||||
- `cells`: A VeriFast list storing pointers to all nodes the list contains.
|
||||
- `vals`: A VeriFast list storing the list nodes' values.
|
||||
- `pxContainer`: A pointer to list struct.
|
||||
|
||||
The single-core formalization also uses `DLS` not just to represent list segments but also to express unsegmented cyclic linked lists.
|
||||
In FreeRTOS lists start with a sentinel, called "end".
|
||||
Using the `DLS` predicate, a cyclic list has the form:
|
||||
`DLS(end, endPrev, end, endPrev, cells, vals, list)`
|
||||
|
||||
|
||||
|
||||
|
||||
## Issue 1: List Predicates Do Not Expose Tasks
|
||||
Each node in a ready list points to task control block (TCB) representing a task that is ready to run.
|
||||
The TCB a node points to is called its "owner".
|
||||
`prvSelectHighestPriorityTask` iterates through the ready lists and looks at each TCB it finds to determine which task to schedule next.
|
||||
Hence, it is crucial that we reason about these TCBs.
|
||||
However, the list predicates depicted above do not expose this information.
|
||||
Hence, we have to extend the predicate signatures to:
|
||||
```
|
||||
predicate xLIST_ITEM(struct xLIST_ITEM *n,
|
||||
TickType_t xItemValue,
|
||||
struct xLIST_ITEM *pxNext,
|
||||
struct xLIST_ITEM *pxPrevious,
|
||||
void* pxOwner,
|
||||
struct xLIST *pxContainer;)
|
||||
```
|
||||
where `pxOwner` is the TCB pointer stored in the represented node
|
||||
and
|
||||
```
|
||||
predicate DLS(struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells,
|
||||
list<TickType_t > vals,
|
||||
list<void*> owners,
|
||||
struct xLIST *pxContainer)
|
||||
```
|
||||
where `owners` is a list of all the TCBs pointed to by the list nodes.
|
||||
|
||||
While this change seems simple on a first glance, it forced us to adapt all the list proofs we reuse.
|
||||
|
||||
|
||||
|
||||
## Issue 2: Model-induced Complexity
|
||||
|
||||
The formalization of doubly-linked list segments induces heavy complexity.
|
||||
The problem lies in the fact that `DLS` cannot express empty list segments.
|
||||
This leads to complex case distinctions whenever we access list nodes.
|
||||
Consequently, our proof becomes very complex and every list access leads to an exponential blow-up of the proof tree.
|
||||
This in turn leads to very bad performance when checking the proof.
|
||||
We solved this problem by introducing a new representation of a cyclic doubly-linked list as a potentially empty prefix, the node we want to access and a potentially empty suffix: `DLS_prefix(....) &*& xLIST_ITEM(node, ...) &*& DLS_suffix(...)`
|
||||
We added lemmas that allow us to freely convert between a `DLS` predicate and our new representation.
|
||||
Thereby, the proof became a lot simpler and it reduced the time needed to check the proof from ~20 minutes to about 12.5 seconds.
|
||||
The following sections explain the details of the problem and our solution.
|
||||
|
||||
### Iterating through a DLS
|
||||
|
||||
The function `prvSelectHighestPriorityTask` iterates through the ready lists.
|
||||
Hence, reasoning about it requires us to reason about iteration through memory described by a `DLS` predicate instance. Consider the following scenario:
|
||||
We have a `DLS` predicate representing our cyclic ready list and a task item pointer `pxTaskItem` which points to an element of this list.
|
||||
|
||||
- `DLS(end, endPrev, end, endPrev, cells, vals, owners, readyList)`
|
||||
- `mem(pxTaskItem, cells) == true`
|
||||
|
||||
Suppose we want to move the task pointer forward
|
||||
|
||||
- `pxTaskItem2 = pxTaskItem->pxNext`
|
||||
|
||||
In order to verify this line we have to do two things:
|
||||
|
||||
1. Justify the heap access to `pxTaskItem->pxNext`
|
||||
2. Prove that `pxTaskItem2` points to an element of the list. This is
|
||||
necessary to reason about any code that uses `pxTaskItem2`.
|
||||
|
||||
We can do this by opening the recursive predicate at the nodes for `pxTaskItem` and `pxTaskItem->next`, for which we can reuse the existing list proof lemmas.
|
||||
When the right parts of the predicate are exposed, we can prove (1) and (2).
|
||||
Afterwards, we have to close the predicate again.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### Proofs Are Hard
|
||||
|
||||
Proving (1) and (2) forces us to consider many different cases, which leads to complicated proofs.
|
||||
The position of `pxTaskItem` in the list determines how we should open the `DLS` (either by using the existing `split` lemma or with VeriFast’s `open` command) and also how we have to close it at the end of the proof.
|
||||
Accessing `pxTaskItem->pxNext` introduces more case splits that complicate the proof.
|
||||
Again, closing the predicate has to account for all the introduced cases.
|
||||
|
||||
Introducing lemmas to open and close the predicate helps us to hide this complexity inside the lemmas.
|
||||
Thereby, the main proof using these lemmas gets shorter.
|
||||
However, the next section explains why this approach does not eliminate the complexity.
|
||||
|
||||
Note that proofs for forward iteration cannot be reused for backwards iteration.
|
||||
Instead the latter requires separate proofs.
|
||||
|
||||
|
||||
|
||||
### Bad Performance
|
||||
|
||||
As explained above, reasoning about a single statement that moves the item pointer forward or backward introduces many case splits. `prvSelectHighestPriorityTask` contains multiple statements that manipulate the item pointer.
|
||||
From VeriFast’s perspective, each consecutive proof of such an iteration statement splits up the proof tree further.
|
||||
In other words: Every iteration statement leads to an exponential blow-up of the sub-proof-tree rooted at this statement.
|
||||
This is the case even though this part of the code we reason about is linear.
|
||||
|
||||
Introducing lemmas for opening and closing shortens the consecutive iteration proofs significantly, but does not eliminate the case splits.
|
||||
The reason for this is that the `DLS` predicate cannot express empty segments and depending on the current proof path, the shape of the heap changes.
|
||||
Our proof has to account for the following possibilities:
|
||||
- non-empty prefix and no suffix:
|
||||
```
|
||||
DLS(...) &*& xLIST_ITEM(node, ...)
|
||||
```
|
||||
- non-empty prefix and non-empty suffix:
|
||||
```
|
||||
DLS(...) &*& xLIST_ITEM(node, ...) &*& DLS(...)
|
||||
```
|
||||
- no prefix and non-empty suffix:
|
||||
```
|
||||
xLIST_ITEM(node, ...) &*& DLS(...)
|
||||
```
|
||||
|
||||
In our proof we know that the ready list we travers always contains the sentinel and an additional node.
|
||||
So, we can eliminate the case where both the prefix and the suffix are empty.
|
||||
|
||||
We cannot unify the representation of the proof state as long as we stick to the `DLS` predicate.
|
||||
Instead the opening lemma’s postcondition and the closing lemma’s precondition must reflect the case split.
|
||||
Consequently, applying the lemmas in a proof introduces the case splits anyway and consecutive iteration statements/ lemma applications increase the number of proof paths exponentially.
|
||||
VeriFast requires ~20 min to reason about 4 iteration statements.
|
||||
|
||||
|
||||
|
||||
### Solution: Introduce new representation for opened DLS
|
||||
|
||||
|
||||
The only way to eliminate the case splits in `prvSelectHighestPriorityTask` is to unify the proof state of an opened `DLS` across all proof paths.
|
||||
We introduce two new predicates that express potentially empty prefixes and suffixes of opened cyclic `DLS`.
|
||||
With that, we can formalize an opened list in a unified way as
|
||||
|
||||
- `DLS_prefix(....) &*& xLIST_ITEM(pxTaskItem, ...) &*& DLS_suffix(...)`
|
||||
|
||||
Additionally, we write opening and closing lemmas that transform the a `DLS` predicate instance into our new representation and back.
|
||||
The proof state we get after opening the list does not force VeriFast to consider any case splits.
|
||||
This finally eliminates the complexity induced by the non-empty list model.
|
||||
|
||||
Eliminating these case splits reduces verification time from ~20min to ~12.5s
|
||||
|
||||
Before we introduced this new list representation, we wrote opening and closing lemmas that used the `DLS` formulation.
|
||||
It turns out that switching to the new representation does not only simplify the proof state we get after opening, but it also simplifies the opening and closing lemmas, though they remain very complicated.
|
||||
|
||||
The old opening and closing lemmas required switching the SMT solver to Z3, which is much slower than VeriFast's standard SMT solver.
|
||||
The lemmas required heavy reasoning about applications of `list<t>` fixpoint functions and the shape of the inductive `list<t>` datatype.
|
||||
VeriFast offers limited capabilities to reason about fixpoint functions (apart from axiomatizing) and the standard SMT solver often has problems reasoning about the shape of results, e.g., assertions of the form `drop(i, vals) == cons(_, _)`.
|
||||
The new lemmas' proofs don’t require Z3.
|
||||
This allowed us to switch back to VeriFast’s standard SMT solver.
|
||||
|
||||
Note that the lemmas still have to consider every possible case internally. That is, the opening and closing lemmas remain complicated.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 345437a815defb4d7ccc549d3f04e7ec0883e8ad
|
||||
80
Test/VeriFast/tasks/vTaskSwitchContext/diff.sh
Executable file
80
Test/VeriFast/tasks/vTaskSwitchContext/diff.sh
Executable file
|
|
@ -0,0 +1,80 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
# This script produces a diff between two versions of 'tasks.c':
|
||||
# (i) The production version of the source file and (ii) the verified version.
|
||||
# The diff is computed from the preprocessed version of both files which include
|
||||
# all code relevant to the proof. That is, that any change in a file required
|
||||
# by the VeriFast proof will shot up in the diff.
|
||||
# The diff report will be written to 'stats/diff_report.txt' directory.
|
||||
#
|
||||
# This script expects the following arguments:
|
||||
# $1 : Absolute path to the base directory of this repository.
|
||||
|
||||
|
||||
# Checking validity of command line arguments.
|
||||
HELP="false"
|
||||
if [ $1 == "-h" ] || [ $1 == "--help" ]; then
|
||||
HELP="true"
|
||||
else
|
||||
if [ $# != 1 ] ; then
|
||||
echo Wrong number of arguments. Found $#, expected 1.
|
||||
HELP="true"
|
||||
fi
|
||||
|
||||
if [ ! -d "$1" ]; then
|
||||
echo Directory "$1" does not exist.
|
||||
HELP="true"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$HELP" != "false" ]; then
|
||||
echo Expected call of the form
|
||||
echo "diff.sh <REPO_BASE_DIR>"
|
||||
echo "where <REPO_BASE_DIR> is the absolute path to the base directory of this repository."
|
||||
exit
|
||||
fi
|
||||
|
||||
|
||||
# Relative or absolute path to the directory this script and `paths.sh` reside in.
|
||||
PREFIX=`dirname $0`
|
||||
# Absolute path to the base of this repository.
|
||||
REPO_BASE_DIR="$1"
|
||||
|
||||
|
||||
# Load functions used to compute paths.
|
||||
. "$PREFIX/paths.sh"
|
||||
|
||||
|
||||
VF_PROOF_BASE_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
PP_SCRIPT_DIR=`pp_script_dir $REPO_BASE_DIR`
|
||||
PP="$PP_SCRIPT_DIR/preprocess_file_for_diff.sh"
|
||||
LOG_DIR=`pp_log_dir $REPO_BASE_DIR`
|
||||
STATS_DIR=`stats_dir $REPO_BASE_DIR`
|
||||
|
||||
# Unpreprocessed verions of tasks.c
|
||||
PROD_TASKS_C=`prod_tasks_c $REPO_BASE_DIR`
|
||||
VF_TASKS_C=`vf_annotated_tasks_c $REPO_BASE_DIR`
|
||||
|
||||
# Preprocessed versions of tasks.c
|
||||
PP_OUT_DIR=`pp_out_dir $REPO_BASE_DIR`
|
||||
PP_PROD_TASKS_C=`pp_prod_tasks_c $REPO_BASE_DIR`
|
||||
PP_VF_TASKS_C=`pp_vf_tasks_c $REPO_BASE_DIR`
|
||||
|
||||
ensure_output_dirs_exist $REPO_BASE_DIR
|
||||
|
||||
echo preprocessing production version of 'tasks.c'
|
||||
$PP $PROD_TASKS_C $PP_PROD_TASKS_C \
|
||||
"$LOG_DIR/pp_prod_tasks_c_error_report.txt" \
|
||||
$REPO_BASE_DIR $VF_PROOF_BASE_DIR
|
||||
|
||||
echo preprocessing verified version of 'tasks.c'
|
||||
$PP $VF_TASKS_C $PP_VF_TASKS_C \
|
||||
"$LOG_DIR/pp_vf_tasks_c_error_report.txt" \
|
||||
$REPO_BASE_DIR $VF_PROOF_BASE_DIR
|
||||
|
||||
|
||||
echo Computing diff:
|
||||
echo
|
||||
|
||||
git diff --no-index --ignore-all-space $PP_PROD_TASKS_C $PP_VF_TASKS_C
|
||||
450
Test/VeriFast/tasks/vTaskSwitchContext/include/list.h
Normal file
450
Test/VeriFast/tasks/vTaskSwitchContext/include/list.h
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
* FreeRTOS SMP Kernel V202110.00
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* https://www.FreeRTOS.org
|
||||
* https://github.com/FreeRTOS
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the list implementation used by the scheduler. While it is tailored
|
||||
* heavily for the schedulers needs, it is also available for use by
|
||||
* application code.
|
||||
*
|
||||
* list_ts can only store pointers to list_item_ts. Each ListItem_t contains a
|
||||
* numeric value (xItemValue). Most of the time the lists are sorted in
|
||||
* descending item value order.
|
||||
*
|
||||
* Lists are created already containing one list item. The value of this
|
||||
* item is the maximum possible that can be stored, it is therefore always at
|
||||
* the end of the list and acts as a marker. The list member pxHead always
|
||||
* points to this marker - even though it is at the tail of the list. This
|
||||
* is because the tail contains a wrap back pointer to the true head of
|
||||
* the list.
|
||||
*
|
||||
* In addition to it's value, each list item contains a pointer to the next
|
||||
* item in the list (pxNext), a pointer to the list it is in (pxContainer)
|
||||
* and a pointer to back to the object that contains it. These later two
|
||||
* pointers are included for efficiency of list manipulation. There is
|
||||
* effectively a two way link between the object containing the list item and
|
||||
* the list item itself.
|
||||
*
|
||||
*
|
||||
* \page ListIntroduction List Implementation
|
||||
* \ingroup FreeRTOSIntro
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
|
||||
#ifdef VERIFAST
|
||||
/* Reason for rewrite:
|
||||
* VeriFast bug:
|
||||
* Both `#ifdef INC_FREERTOS_H` and its negation `#ifdef INC_FREERTOS_H`
|
||||
* evaluate to true. See minimal example `define_name`.
|
||||
*/
|
||||
#define INC_FREERTOS_H
|
||||
/* Remember that this header is included indirectly `tasks.c` after it
|
||||
* includes `FreeRTOS.h`.
|
||||
*/
|
||||
// TODO: Remove this work-around once VF has been fixed.
|
||||
#endif /* VERIFAST */
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
#error "FreeRTOS.h must be included before list.h"
|
||||
#endif
|
||||
|
||||
#ifdef VERIFAST
|
||||
/* Reason for rewrite:
|
||||
* VeriFast's normal and context-free preprocessor consume different
|
||||
* numbers of tokens when expanding `PRIVILEGED_FUNCTION` in this file.
|
||||
*/
|
||||
#define PRIVILEGED_FUNCTION
|
||||
#endif /* VERIFAST */
|
||||
|
||||
/*
|
||||
* The list structure members are modified from within interrupts, and therefore
|
||||
* by rights should be declared volatile. However, they are only modified in a
|
||||
* functionally atomic way (within critical sections of with the scheduler
|
||||
* suspended) and are either passed by reference into a function or indexed via
|
||||
* a volatile variable. Therefore, in all use cases tested so far, the volatile
|
||||
* qualifier can be omitted in order to provide a moderate performance
|
||||
* improvement without adversely affecting functional behaviour. The assembly
|
||||
* instructions generated by the IAR, ARM and GCC compilers when the respective
|
||||
* compiler's options were set for maximum optimisation has been inspected and
|
||||
* deemed to be as intended. That said, as compiler technology advances, and
|
||||
* especially if aggressive cross module optimisation is used (a use case that
|
||||
* has not been exercised to any great extend) then it is feasible that the
|
||||
* volatile qualifier will be needed for correct optimisation. It is expected
|
||||
* that a compiler removing essential code because, without the volatile
|
||||
* qualifier on the list structure members and with aggressive cross module
|
||||
* optimisation, the compiler deemed the code unnecessary will result in
|
||||
* complete and obvious failure of the scheduler. If this is ever experienced
|
||||
* then the volatile qualifier can be inserted in the relevant places within the
|
||||
* list structures by simply defining configLIST_VOLATILE to volatile in
|
||||
* FreeRTOSConfig.h (as per the example at the bottom of this comment block).
|
||||
* If configLIST_VOLATILE is not defined then the preprocessor directives below
|
||||
* will simply #define configLIST_VOLATILE away completely.
|
||||
*
|
||||
* To use volatile list structure members then add the following line to
|
||||
* FreeRTOSConfig.h (without the quotes):
|
||||
* "#define configLIST_VOLATILE volatile"
|
||||
*/
|
||||
#ifndef configLIST_VOLATILE
|
||||
#define configLIST_VOLATILE
|
||||
#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* Macros that can be used to place known values within the list structures,
|
||||
* then check that the known values do not get corrupted during the execution of
|
||||
* the application. These may catch the list data structures being overwritten in
|
||||
* memory. They will not catch data errors caused by incorrect configuration or
|
||||
* use of FreeRTOS.*/
|
||||
#if ( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
|
||||
/* Define the macros to do nothing. */
|
||||
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
|
||||
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
|
||||
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE
|
||||
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE
|
||||
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
|
||||
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
|
||||
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
|
||||
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
|
||||
#define listTEST_LIST_ITEM_INTEGRITY( pxItem )
|
||||
#define listTEST_LIST_INTEGRITY( pxList )
|
||||
#else /* if ( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 ) */
|
||||
/* Define macros that add new members into the list structures. */
|
||||
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1;
|
||||
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2;
|
||||
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1;
|
||||
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2;
|
||||
|
||||
/* Define macros that set the new structure members to known values. */
|
||||
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
|
||||
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
|
||||
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
|
||||
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
|
||||
|
||||
/* Define macros that will assert if one of the structure members does not
|
||||
* contain its expected value. */
|
||||
#define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
|
||||
#define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
|
||||
#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */
|
||||
|
||||
|
||||
/*
|
||||
* Definition of the only type of object that a list can contain.
|
||||
*/
|
||||
struct xLIST;
|
||||
struct xLIST_ITEM
|
||||
{
|
||||
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
|
||||
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */
|
||||
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
|
||||
void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
|
||||
struct xLIST * configLIST_VOLATILE pxContainer; /*< Pointer to the list in which this list item is placed (if any). */
|
||||
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
};
|
||||
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
|
||||
|
||||
struct xMINI_LIST_ITEM
|
||||
{
|
||||
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
configLIST_VOLATILE TickType_t xItemValue;
|
||||
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
|
||||
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
|
||||
};
|
||||
typedef struct xMINI_LIST_ITEM MiniListItem_t;
|
||||
|
||||
/*
|
||||
* Definition of the type of queue used by the scheduler.
|
||||
*/
|
||||
typedef struct xLIST
|
||||
{
|
||||
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
volatile UBaseType_t uxNumberOfItems;
|
||||
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
|
||||
#ifdef VERIFAST
|
||||
/* Reason for rewrite:
|
||||
* This change allows us to reuse the existing single-core list proofs,
|
||||
* for which an identical rewrite for assumed.
|
||||
*/
|
||||
ListItem_t xListEnd;
|
||||
#else
|
||||
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
|
||||
#endif /* VERIFAST */
|
||||
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
} List_t;
|
||||
|
||||
/*
|
||||
* Access macro to set the owner of a list item. The owner of a list item
|
||||
* is the object (usually a TCB) that contains the list item.
|
||||
*
|
||||
* \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
|
||||
|
||||
/*
|
||||
* Access macro to get the owner of a list item. The owner of a list item
|
||||
* is the object (usually a TCB) that contains the list item.
|
||||
*
|
||||
* \page listGET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner )
|
||||
|
||||
/*
|
||||
* Access macro to set the value of the list item. In most cases the value is
|
||||
* used to sort the list in descending order.
|
||||
*
|
||||
* \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )
|
||||
|
||||
/*
|
||||
* Access macro to retrieve the value of the list item. The value can
|
||||
* represent anything - for example the priority of a task, or the time at
|
||||
* which a task should be unblocked.
|
||||
*
|
||||
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
|
||||
|
||||
/*
|
||||
* Access macro to retrieve the value of the list item at the head of a given
|
||||
* list.
|
||||
*
|
||||
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
|
||||
|
||||
/*
|
||||
* Return the list item at the head of the list.
|
||||
*
|
||||
* \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
|
||||
|
||||
/*
|
||||
* Return the next list item.
|
||||
*
|
||||
* \page listGET_NEXT listGET_NEXT
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext )
|
||||
|
||||
/*
|
||||
* Return the list item that marks the end of the list
|
||||
*
|
||||
* \page listGET_END_MARKER listGET_END_MARKER
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
|
||||
|
||||
/*
|
||||
* Access macro to determine if a list contains any items. The macro will
|
||||
* only have the value true if the list is empty.
|
||||
*
|
||||
* \page listLIST_IS_EMPTY listLIST_IS_EMPTY
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
|
||||
|
||||
/*
|
||||
* Access macro to return the number of items in the list.
|
||||
*/
|
||||
#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
|
||||
|
||||
/*
|
||||
* Access function to obtain the owner of the next entry in a list.
|
||||
*
|
||||
* The list member pxIndex is used to walk through a list. Calling
|
||||
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
|
||||
* and returns that entry's pxOwner parameter. Using multiple calls to this
|
||||
* function it is therefore possible to move through every item contained in
|
||||
* a list.
|
||||
*
|
||||
* The pxOwner parameter of a list item is a pointer to the object that owns
|
||||
* the list item. In the scheduler this is normally a task control block.
|
||||
* The pxOwner parameter effectively creates a two way link between the list
|
||||
* item and its owner.
|
||||
*
|
||||
* @param pxTCB pxTCB is set to the address of the owner of the next list item.
|
||||
* @param pxList The list from which the next item owner is to be returned.
|
||||
*
|
||||
* \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
|
||||
{ \
|
||||
List_t * const pxConstList = ( pxList ); \
|
||||
/* Increment the index to the next item and return the item, ensuring */ \
|
||||
/* we don't return the marker used at the end of the list. */ \
|
||||
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
|
||||
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
|
||||
{ \
|
||||
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
|
||||
} \
|
||||
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Access function to obtain the owner of the first entry in a list. Lists
|
||||
* are normally sorted in ascending item value order.
|
||||
*
|
||||
* This function returns the pxOwner member of the first item in the list.
|
||||
* The pxOwner parameter of a list item is a pointer to the object that owns
|
||||
* the list item. In the scheduler this is normally a task control block.
|
||||
* The pxOwner parameter effectively creates a two way link between the list
|
||||
* item and its owner.
|
||||
*
|
||||
* @param pxList The list from which the owner of the head item is to be
|
||||
* returned.
|
||||
*
|
||||
* \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )
|
||||
|
||||
/*
|
||||
* Check to see if a list item is within a list. The list item maintains a
|
||||
* "container" pointer that points to the list it is in. All this macro does
|
||||
* is check to see if the container and the list match.
|
||||
*
|
||||
* @param pxList The list we want to know if the list item is within.
|
||||
* @param pxListItem The list item we want to know if is in the list.
|
||||
* @return pdTRUE if the list item is in the list, otherwise pdFALSE.
|
||||
*/
|
||||
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
|
||||
|
||||
/*
|
||||
* Return the list a list item is contained within (referenced from).
|
||||
*
|
||||
* @param pxListItem The list item being queried.
|
||||
* @return A pointer to the List_t object that references the pxListItem
|
||||
*/
|
||||
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pxContainer )
|
||||
|
||||
/*
|
||||
* This provides a crude means of knowing if a list has been initialised, as
|
||||
* pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise()
|
||||
* function.
|
||||
*/
|
||||
#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )
|
||||
|
||||
/*
|
||||
* Must be called before a list is used! This initialises all the members
|
||||
* of the list structure and inserts the xListEnd item into the list as a
|
||||
* marker to the back of the list.
|
||||
*
|
||||
* @param pxList Pointer to the list being initialised.
|
||||
*
|
||||
* \page vListInitialise vListInitialise
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Must be called before a list item is used. This sets the list container to
|
||||
* null so the item does not think that it is already contained in a list.
|
||||
*
|
||||
* @param pxItem Pointer to the list item being initialised.
|
||||
*
|
||||
* \page vListInitialiseItem vListInitialiseItem
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION;
|
||||
//@ requires pxItem->pxContainer |-> _;
|
||||
//@ ensures pxItem->pxContainer |-> 0;
|
||||
|
||||
/*
|
||||
* Insert a list item into a list. The item will be inserted into the list in
|
||||
* a position determined by its item value (descending item value order).
|
||||
*
|
||||
* @param pxList The list into which the item is to be inserted.
|
||||
*
|
||||
* @param pxNewListItem The item that is to be placed in the list.
|
||||
*
|
||||
* \page vListInsert vListInsert
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
void vListInsert( List_t * const pxList,
|
||||
ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Insert a list item into a list. The item will be inserted in a position
|
||||
* such that it will be the last item within the list returned by multiple
|
||||
* calls to listGET_OWNER_OF_NEXT_ENTRY.
|
||||
*
|
||||
* The list member pxIndex is used to walk through a list. Calling
|
||||
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list.
|
||||
* Placing an item in a list using vListInsertEnd effectively places the item
|
||||
* in the list position pointed to by pxIndex. This means that every other
|
||||
* item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before
|
||||
* the pxIndex parameter again points to the item being inserted.
|
||||
*
|
||||
* @param pxList The list into which the item is to be inserted.
|
||||
*
|
||||
* @param pxNewListItem The list item to be inserted into the list.
|
||||
*
|
||||
* \page vListInsertEnd vListInsertEnd
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
void vListInsertEnd( List_t * const pxList,
|
||||
ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Remove an item from a list. The list item has a pointer to the list that
|
||||
* it is in, so only the list item need be passed into the function.
|
||||
*
|
||||
* @param uxListRemove The item to be removed. The item will remove itself from
|
||||
* the list pointed to by it's pxContainer parameter.
|
||||
*
|
||||
* @return The number of items that remain in the list after the list item has
|
||||
* been removed.
|
||||
*
|
||||
* \page uxListRemove uxListRemove
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* ifndef LIST_H */
|
||||
245
Test/VeriFast/tasks/vTaskSwitchContext/include/portable.h
Normal file
245
Test/VeriFast/tasks/vTaskSwitchContext/include/portable.h
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* FreeRTOS SMP Kernel V202110.00
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* https://www.FreeRTOS.org
|
||||
* https://github.com/FreeRTOS
|
||||
*
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Portable layer API. Each function must be defined for each port.
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
#ifndef PORTABLE_H
|
||||
#define PORTABLE_H
|
||||
|
||||
/* Each FreeRTOS port has a unique portmacro.h header file. Originally a
|
||||
* pre-processor definition was used to ensure the pre-processor found the correct
|
||||
* portmacro.h file for the port being used. That scheme was deprecated in favour
|
||||
* of setting the compiler's include path such that it found the correct
|
||||
* portmacro.h file - removing the need for the constant and allowing the
|
||||
* portmacro.h file to be located anywhere in relation to the port being used.
|
||||
* Purely for reasons of backward compatibility the old method is still valid, but
|
||||
* to make it clear that new projects should not use it, support for the port
|
||||
* specific constants has been moved into the deprecated_definitions.h header
|
||||
* file. */
|
||||
#include "deprecated_definitions.h"
|
||||
|
||||
/* If portENTER_CRITICAL is not defined then including deprecated_definitions.h
|
||||
* did not result in a portmacro.h header file being included - and it should be
|
||||
* included here. In this case the path to the correct portmacro.h header file
|
||||
* must be set in the compiler's include path. */
|
||||
#ifndef portENTER_CRITICAL
|
||||
#include "portmacro.h"
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 32
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x001f )
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 16
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x000f )
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 8
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 4
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x0003 )
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 2
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x0001 )
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 1
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x0000 )
|
||||
#endif
|
||||
|
||||
#ifndef portBYTE_ALIGNMENT_MASK
|
||||
#error "Invalid portBYTE_ALIGNMENT definition"
|
||||
#endif
|
||||
|
||||
#ifndef portNUM_CONFIGURABLE_REGIONS
|
||||
#define portNUM_CONFIGURABLE_REGIONS 1
|
||||
#endif
|
||||
|
||||
#ifndef portHAS_STACK_OVERFLOW_CHECKING
|
||||
#define portHAS_STACK_OVERFLOW_CHECKING 0
|
||||
#endif
|
||||
|
||||
#ifndef portARCH_NAME
|
||||
#define portARCH_NAME NULL
|
||||
#endif
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include "mpu_wrappers.h"
|
||||
|
||||
/*
|
||||
* Setup the stack of a new task so it is ready to be placed under the
|
||||
* scheduler control. The registers have to be placed on the stack in
|
||||
* the order that the port expects to find them.
|
||||
*
|
||||
*/
|
||||
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||
#if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
|
||||
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
|
||||
StackType_t * pxEndOfStack,
|
||||
TaskFunction_t pxCode,
|
||||
void * pvParameters,
|
||||
BaseType_t xRunPrivileged ) PRIVILEGED_FUNCTION;
|
||||
#else
|
||||
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
|
||||
TaskFunction_t pxCode,
|
||||
void * pvParameters,
|
||||
BaseType_t xRunPrivileged ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
#else /* if ( portUSING_MPU_WRAPPERS == 1 ) */
|
||||
#if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
|
||||
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
|
||||
StackType_t * pxEndOfStack,
|
||||
TaskFunction_t pxCode,
|
||||
void * pvParameters ) PRIVILEGED_FUNCTION;
|
||||
#else
|
||||
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
|
||||
TaskFunction_t pxCode,
|
||||
void * pvParameters ) PRIVILEGED_FUNCTION;
|
||||
///@ requires true;
|
||||
///@ ensures true;
|
||||
#endif
|
||||
#endif /* if ( portUSING_MPU_WRAPPERS == 1 ) */
|
||||
|
||||
/* Used by heap_5.c to define the start address and size of each memory region
|
||||
* that together comprise the total FreeRTOS heap space. */
|
||||
typedef struct HeapRegion
|
||||
{
|
||||
uint8_t * pucStartAddress;
|
||||
size_t xSizeInBytes;
|
||||
} HeapRegion_t;
|
||||
|
||||
/* Used to pass information about the heap out of vPortGetHeapStats(). */
|
||||
typedef struct xHeapStats
|
||||
{
|
||||
size_t xAvailableHeapSpaceInBytes; /* The total heap size currently available - this is the sum of all the free blocks, not the largest block that can be allocated. */
|
||||
size_t xSizeOfLargestFreeBlockInBytes; /* The maximum size, in bytes, of all the free blocks within the heap at the time vPortGetHeapStats() is called. */
|
||||
size_t xSizeOfSmallestFreeBlockInBytes; /* The minimum size, in bytes, of all the free blocks within the heap at the time vPortGetHeapStats() is called. */
|
||||
size_t xNumberOfFreeBlocks; /* The number of free memory blocks within the heap at the time vPortGetHeapStats() is called. */
|
||||
size_t xMinimumEverFreeBytesRemaining; /* The minimum amount of total free memory (sum of all free blocks) there has been in the heap since the system booted. */
|
||||
size_t xNumberOfSuccessfulAllocations; /* The number of calls to pvPortMalloc() that have returned a valid memory block. */
|
||||
size_t xNumberOfSuccessfulFrees; /* The number of calls to vPortFree() that has successfully freed a block of memory. */
|
||||
} HeapStats_t;
|
||||
|
||||
/*
|
||||
* Used to define multiple heap regions for use by heap_5.c. This function
|
||||
* must be called before any calls to pvPortMalloc() - not creating a task,
|
||||
* queue, semaphore, mutex, software timer, event group, etc. will result in
|
||||
* pvPortMalloc being called.
|
||||
*
|
||||
* pxHeapRegions passes in an array of HeapRegion_t structures - each of which
|
||||
* defines a region of memory that can be used as the heap. The array is
|
||||
* terminated by a HeapRegions_t structure that has a size of 0. The region
|
||||
* with the lowest start address must appear first in the array.
|
||||
*/
|
||||
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Returns a HeapStats_t structure filled with information about the current
|
||||
* heap state.
|
||||
*/
|
||||
void vPortGetHeapStats( HeapStats_t * pxHeapStats );
|
||||
|
||||
#ifdef VERIFAST
|
||||
/* Reason for rewrite:
|
||||
* VeriFast treats the `malloc` and `free` functions specially,
|
||||
* in a particular built-in way that cannot be axiomatized within
|
||||
* VeriFast's specification language.
|
||||
*
|
||||
* When `malloc( sizeof(struct S) )` is called for a user defined
|
||||
* struct `S`, VeriFast instantiates the corresponding
|
||||
* `malloc_block_S(...)` predicate as well as points-to chunks
|
||||
* for its fields.
|
||||
* Reversely, calling `free` cleans up all the predicates instantiated
|
||||
* by `malloc`.
|
||||
*/
|
||||
#define pvPortMalloc malloc
|
||||
#define vPortFree(ptr) free( (void*) ptr)
|
||||
#else
|
||||
/*
|
||||
* Map to the memory management routines required for the port.
|
||||
*/
|
||||
void * pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION;
|
||||
void vPortFree( void * pv ) PRIVILEGED_FUNCTION;
|
||||
#endif /* VERIFAST */
|
||||
|
||||
|
||||
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
|
||||
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;
|
||||
size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#if( configSTACK_ALLOCATION_FROM_SEPARATE_HEAP == 1 )
|
||||
void *pvPortMallocStack( size_t xSize ) PRIVILEGED_FUNCTION;
|
||||
void vPortFreeStack( void *pv ) PRIVILEGED_FUNCTION;
|
||||
#else
|
||||
#define pvPortMallocStack pvPortMalloc
|
||||
#define vPortFreeStack vPortFree
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Setup the hardware ready for the scheduler to take control. This generally
|
||||
* sets up a tick interrupt and sets timers for the correct tick frequency.
|
||||
*/
|
||||
BaseType_t xPortStartScheduler( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Undo any hardware/ISR setup that was performed by xPortStartScheduler() so
|
||||
* the hardware is left in its original condition after the scheduler stops
|
||||
* executing.
|
||||
*/
|
||||
void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* The structures and methods of manipulating the MPU are contained within the
|
||||
* port layer.
|
||||
*
|
||||
* Fills the xMPUSettings structure with the memory region information
|
||||
* contained in xRegions.
|
||||
*/
|
||||
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||
struct xMEMORY_REGION;
|
||||
void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
|
||||
const struct xMEMORY_REGION * const xRegions,
|
||||
StackType_t * pxBottomOfStack,
|
||||
uint32_t ulStackDepth ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* PORTABLE_H */
|
||||
206
Test/VeriFast/tasks/vTaskSwitchContext/include/stack_macros.h
Normal file
206
Test/VeriFast/tasks/vTaskSwitchContext/include/stack_macros.h
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* FreeRTOS SMP Kernel V202110.00
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* https://www.FreeRTOS.org
|
||||
* https://github.com/FreeRTOS
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STACK_MACROS_H
|
||||
#define STACK_MACROS_H
|
||||
|
||||
/*
|
||||
* Call the stack overflow hook function if the stack of the task being swapped
|
||||
* out is currently overflowed, or looks like it might have overflowed in the
|
||||
* past.
|
||||
*
|
||||
* Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check
|
||||
* the current stack state only - comparing the current top of stack value to
|
||||
* the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1
|
||||
* will also cause the last few stack bytes to be checked to ensure the value
|
||||
* to which the bytes were set when the task was created have not been
|
||||
* overwritten. Note this second test does not guarantee that an overflowed
|
||||
* stack will always be recognised.
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* portSTACK_LIMIT_PADDING is a number of extra words to consider to be in
|
||||
* use on the stack.
|
||||
*/
|
||||
#ifndef portSTACK_LIMIT_PADDING
|
||||
#define portSTACK_LIMIT_PADDING 0
|
||||
#endif
|
||||
|
||||
#if ( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||
|
||||
/* Only the current stack state is to be checked. */
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack + portSTACK_LIMIT_PADDING ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||
|
||||
/* Only the current stack state is to be checked. */
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
\
|
||||
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||
if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack - portSTACK_LIMIT_PADDING ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||
|
||||
#ifdef VERIFAST
|
||||
/* Reason for rewrite:
|
||||
* VeriFast complains about unspecified evaluation order of
|
||||
* - `pxCurrentTCB->pxStack`
|
||||
* - `vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName );`
|
||||
*
|
||||
*/
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() VF__taskCHECK_FOR_STACK_OVERFLOW()
|
||||
|
||||
void VF__taskCHECK_FOR_STACK_OVERFLOW()
|
||||
/*@ requires TCB_stack_p(?gCurrentTCB, ?ulFreeBytesOnStack) &*&
|
||||
TCB_criticalNesting_p(gCurrentTCB, ?uxCriticalNesting) &*&
|
||||
// chunks required by `pxCurrentTCB` aka `xTaskGetCurrentTaskHandle()`
|
||||
interruptState_p(coreID_f(), ?state) &*&
|
||||
interruptsDisabled_f(state) == true &*&
|
||||
pointer(&pxCurrentTCBs[coreID_f], gCurrentTCB);
|
||||
@*/
|
||||
/*@ ensures TCB_stack_p(gCurrentTCB, ulFreeBytesOnStack) &*&
|
||||
TCB_criticalNesting_p(gCurrentTCB, uxCriticalNesting) &*&
|
||||
// chunks required by `pxCurrentTCB` aka `xTaskGetCurrentTaskHandle()`
|
||||
interruptState_p(coreID_f(), state) &*&
|
||||
interruptsDisabled_f(state) == true &*&
|
||||
pointer(&pxCurrentTCBs[coreID_f], gCurrentTCB); \
|
||||
@*/ \
|
||||
{ \
|
||||
/*@ open TCB_stack_p(gCurrentTCB, ulFreeBytesOnStack); @*/ \
|
||||
/*@ assert( stack_p(?pxStack, ?ulStackDepth, ?pxTopOfStack, \
|
||||
?ulFreeBytes, ?ulUsedCells, ?ulUnalignedBytes) ); \
|
||||
@*/ \
|
||||
/*@ open stack_p(_, _, _, _, _, _); @*/ \
|
||||
/* The detour below allows us to skip proving that `ulFreeBytes` \
|
||||
* is a multiple of `sizeof(StackType_t)`. \
|
||||
*/ \
|
||||
/*@ integers__to_chars(pxTopOfStack+1); @*/ \
|
||||
/*@ chars_join((char*) pxStack); @*/ \
|
||||
/*@ chars_to_integers_(pxStack, sizeof(StackType_t), false, 4); @*/ \
|
||||
TCB_t* tcb0 = pxCurrentTCB; \
|
||||
const uint32_t * const pulStack = ( uint32_t * ) tcb0->pxStack; \
|
||||
const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \
|
||||
\
|
||||
/*@ bool gOverflow = false; @*/ \
|
||||
if( ( pulStack[ 0 ] != ulCheckValue ) || \
|
||||
( pulStack[ 1 ] != ulCheckValue ) || \
|
||||
( pulStack[ 2 ] != ulCheckValue ) || \
|
||||
( pulStack[ 3 ] != ulCheckValue ) ) \
|
||||
{ \
|
||||
/*@ gOverflow = true; @*/ \
|
||||
/*@ integers__to_chars(pxStack); @*/ \
|
||||
/*@ chars_join((char*) pxStack); @*/ \
|
||||
/*@ chars_split((char*) pxStack, ulFreeBytesOnStack); @*/ \
|
||||
/*@ close stack_p(pxStack, ulStackDepth, pxTopOfStack, \
|
||||
ulFreeBytes, ulUsedCells, ulUnalignedBytes); \
|
||||
@*/ \
|
||||
/*@ close TCB_stack_p(gCurrentTCB, ulFreeBytesOnStack); @*/ \
|
||||
TCB_t* tcb1 = pxCurrentTCB; \
|
||||
TCB_t* tcb2 = pxCurrentTCB; \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) tcb1, tcb2->pcTaskName ); \
|
||||
} \
|
||||
/*@ \
|
||||
if(!gOverflow) { \
|
||||
integers__to_chars(pxStack); \
|
||||
chars_join((char*) pxStack); \
|
||||
chars_split((char*) pxStack, ulFreeBytesOnStack); \
|
||||
close stack_p(pxStack, ulStackDepth, pxTopOfStack, \
|
||||
ulFreeBytes, ulUsedCells, ulUnalignedBytes); \
|
||||
close TCB_stack_p(gCurrentTCB, ulFreeBytesOnStack); \
|
||||
} \
|
||||
@*/ \
|
||||
}
|
||||
#else
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \
|
||||
const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \
|
||||
\
|
||||
if( ( pulStack[ 0 ] != ulCheckValue ) || \
|
||||
( pulStack[ 1 ] != ulCheckValue ) || \
|
||||
( pulStack[ 2 ] != ulCheckValue ) || \
|
||||
( pulStack[ 3 ] != ulCheckValue ) ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
#endif /* VERIFAST */
|
||||
|
||||
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
int8_t * pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \
|
||||
static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
|
||||
\
|
||||
\
|
||||
pcEndOfStack -= sizeof( ucExpectedStackBytes ); \
|
||||
\
|
||||
/* Has the extremity of the task stack ever been written over? */ \
|
||||
if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Remove stack overflow macro if not being used. */
|
||||
#ifndef taskCHECK_FOR_STACK_OVERFLOW
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW()
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* STACK_MACROS_H */
|
||||
3318
Test/VeriFast/tasks/vTaskSwitchContext/include/task.h
Normal file
3318
Test/VeriFast/tasks/vTaskSwitchContext/include/task.h
Normal file
File diff suppressed because it is too large
Load diff
218
Test/VeriFast/tasks/vTaskSwitchContext/paths.sh
Executable file
218
Test/VeriFast/tasks/vTaskSwitchContext/paths.sh
Executable file
|
|
@ -0,0 +1,218 @@
|
|||
# Returns the absolute path to the directory containing the VeriFast proofs
|
||||
# concerning `vTaskSwitchContext` in `tasks.c`.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base directory.
|
||||
function vf_proof_base_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
echo "$REPO_BASE_DIR/Test/VeriFast/tasks/vTaskSwitchContext"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the directory containing modified versions of
|
||||
# FreeRTOS source files. The VeriFast proofs use these modified verions instead
|
||||
# of the original files.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function vf_proof_mod_src_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_PROOF_DIR/src"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the directory containing modified versions of
|
||||
# FreeRTOS header files. The VeriFast proofs use these modified verions instead
|
||||
# of the original files.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function vf_proof_mod_header_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_PROOF_DIR/include"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the directory containing everything related to
|
||||
# the setup of the VeriFast proofs.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function vf_proof_setup_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_PROOF_DIR/proof_setup"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the directory containing all lemmas and
|
||||
# definitions used written for the VeriFast proofs.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function vf_proof_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_PROOF_DIR/proof"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the version of `tasks.c` containing the VeriFast
|
||||
# proof annotations.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function vf_annotated_tasks_c() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_MOD_SRC_DIR=`vf_proof_mod_src_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_MOD_SRC_DIR/tasks.c"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the directory the unmodified FreeRTOS headers.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function prod_header_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
|
||||
echo "$REPO_BASE_DIR/include"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the directory the unmodified FreeRTOS source
|
||||
# files.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function prod_src_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
|
||||
echo "$REPO_BASE_DIR"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the unmodified version of `tasks.c`.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function prod_tasks_c() {
|
||||
REPO_BASE_DIR="$1"
|
||||
PROD_SRC_DIR=`prod_src_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$PROD_SRC_DIR/tasks.c"
|
||||
}
|
||||
|
||||
|
||||
# Returns the absolute path to the directory containing the preprocessing scripts.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function pp_script_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_PROOF_DIR/preprocessing_scripts"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the preprocesor's output direcotry.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function pp_out_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_PROOF_DIR/preprocessed_files"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the preprocesor's log direcotry.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function pp_log_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_PROOF_DIR/pp_log"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the preprocessed version of `tasks.c` containing
|
||||
# the VeriFast proof annotations. This is the file that is processed by
|
||||
# VeriFast.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function pp_vf_tasks_c() {
|
||||
REPO_BASE_DIR="$1"
|
||||
PP_OUT_DIR=`pp_out_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$PP_OUT_DIR/tasks_vf_pp.c"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the preprocessed unmodified version of `tasks.c`.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function pp_prod_tasks_c() {
|
||||
REPO_BASE_DIR="$1"
|
||||
PP_OUT_DIR=`pp_out_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$PP_OUT_DIR/tasks_prod_pp.c"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the pico sdk.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function pico_sdk_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_PROOF_DIR/sdks/pico-sdk"
|
||||
}
|
||||
|
||||
# Returns the absolute path to the smp_demo_dir.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function smp_demo_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_PROOF_DIR/demos/FreeRTOS-SMP-Demos"
|
||||
}
|
||||
|
||||
|
||||
# Returns the absolute path to directory where the statistic reports are stored.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function stats_dir() {
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
echo "$VF_PROOF_DIR/stats"
|
||||
}
|
||||
|
||||
|
||||
# Ensures that all potentially relevant output direcories exist.
|
||||
#
|
||||
# Expected arguments:
|
||||
# $1 : Absolute path to the repository's base
|
||||
function ensure_output_dirs_exist() {
|
||||
REPO_BASE_DIR="$1"
|
||||
|
||||
PP_OUT_DIR=`pp_out_dir $REPO_BASE_DIR`
|
||||
STATS_DIR=`stats_dir $REPO_BASE_DIR`
|
||||
PP_LOG_DIR=`pp_log_dir $REPO_BASE_DIR`
|
||||
|
||||
if [ ! -d "$PP_OUT_DIR" ]; then
|
||||
mkdir "$PP_OUT_DIR"
|
||||
fi
|
||||
if [ ! -d "$STATS_DIR" ]; then
|
||||
mkdir "$STATS_DIR"
|
||||
fi
|
||||
if [ ! -d "$PP_LOG_DIR" ]; then
|
||||
mkdir "$PP_LOG_DIR"
|
||||
fi
|
||||
}
|
||||
134
Test/VeriFast/tasks/vTaskSwitchContext/preprocessing_scripts/pp_flags.sh
Executable file
134
Test/VeriFast/tasks/vTaskSwitchContext/preprocessing_scripts/pp_flags.sh
Executable file
|
|
@ -0,0 +1,134 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script defines common command line arguments for the preprocessor.
|
||||
|
||||
# This script expects the following arguments:
|
||||
# $1 : Absolute path to the base directory of this repository.
|
||||
# $2 : Absolute path to the VeriFast proof directory.
|
||||
# $3 : Absolute path to the VeriFast installation directory.
|
||||
|
||||
|
||||
REPO_BASE_DIR="$1"
|
||||
VF_PROOF_BASE_DIR="$2"
|
||||
VF_DIR="$3"
|
||||
|
||||
|
||||
# Load functions used to compute paths.
|
||||
. "$VF_PROOF_BASE_DIR/paths.sh"
|
||||
|
||||
PICO_SDK_DIR=`pico_sdk_dir $REPO_BASE_DIR`
|
||||
SMP_DEMO_DIR=`smp_demo_dir $REPO_BASE_DIR`
|
||||
VF_PROOF_MOD_HEADER_DIR=`vf_proof_mod_header_dir $REPO_BASE_DIR`
|
||||
VF_PROOF_MOD_SRC_DIR=`vf_proof_mod_src_dir $REPO_BASE_DIR`
|
||||
PROOF_SETUP_DIR=`vf_proof_setup_dir $REPO_BASE_DIR`
|
||||
PROOF_FILES_DIR=`vf_proof_dir $REPO_BASE_DIR`
|
||||
|
||||
|
||||
|
||||
declare -a BUILD_FLAGS
|
||||
BUILD_FLAGS=(
|
||||
-DFREE_RTOS_KERNEL_SMP=1
|
||||
-DLIB_FREERTOS_KERNEL=1
|
||||
-DLIB_PICO_BIT_OPS=1
|
||||
-DLIB_PICO_BIT_OPS_PICO=1
|
||||
-DLIB_PICO_DIVIDER=1
|
||||
-DLIB_PICO_DIVIDER_HARDWARE=1
|
||||
-DLIB_PICO_DOUBLE=1
|
||||
-DLIB_PICO_DOUBLE_PICO=1
|
||||
-DLIB_PICO_FLOAT=1
|
||||
-DLIB_PICO_FLOAT_PICO=1
|
||||
-DLIB_PICO_INT64_OPS=1
|
||||
-DLIB_PICO_INT64_OPS_PICO=1
|
||||
-DLIB_PICO_MALLOC=1
|
||||
-DLIB_PICO_MEM_OPS=1
|
||||
-DLIB_PICO_MEM_OPS_PICO=1
|
||||
-DLIB_PICO_MULTICORE=1
|
||||
-DLIB_PICO_PLATFORM=1
|
||||
-DLIB_PICO_PRINTF=1
|
||||
-DLIB_PICO_PRINTF_PICO=1
|
||||
-DLIB_PICO_RUNTIME=1
|
||||
-DLIB_PICO_STANDARD_LINK=1
|
||||
-DLIB_PICO_STDIO=1
|
||||
-DLIB_PICO_STDIO_UART=1
|
||||
-DLIB_PICO_STDLIB=1
|
||||
-DLIB_PICO_SYNC=1
|
||||
-DLIB_PICO_SYNC_CORE=1
|
||||
-DLIB_PICO_SYNC_CRITICAL_SECTION=1
|
||||
-DLIB_PICO_SYNC_MUTEX=1
|
||||
-DLIB_PICO_SYNC_SEM=1
|
||||
-DLIB_PICO_TIME=1
|
||||
-DLIB_PICO_UTIL=1
|
||||
-DPICO_BOARD=\"pico\"
|
||||
-DPICO_BUILD=1
|
||||
-DPICO_CMAKE_BUILD_TYPE=\"Release\"
|
||||
-DPICO_COPY_TO_RAM=0
|
||||
-DPICO_CXX_ENABLE_EXCEPTIONS=0
|
||||
-DPICO_NO_FLASH=0
|
||||
-DPICO_NO_HARDWARE=0
|
||||
-DPICO_ON_DEVICE=1
|
||||
-DPICO_STACK_SIZE=0x1000
|
||||
-DPICO_TARGET_NAME=\"on_core_one\"
|
||||
-DPICO_USE_BLOCKED_RAM=0
|
||||
-DmainRUN_FREE_RTOS_ON_CORE=1
|
||||
)
|
||||
|
||||
declare -a PICO_INCLUDE_FLAGS
|
||||
PICO_INCLUDE_FLAGS=(
|
||||
-I"$PICO_SDK_DIR/src/boards/include"
|
||||
-I"$PICO_SDK_DIR/src/common/pico_base/include"
|
||||
-I"$PICO_SDK_DIR/src/common/pico_binary_info/include"
|
||||
-I"$PICO_SDK_DIR/src/common/pico_bit_ops/include"
|
||||
-I"$PICO_SDK_DIR/src/common/pico_divider/include"
|
||||
-I"$PICO_SDK_DIR/src/common/pico_stdlib/include"
|
||||
-I"$PICO_SDK_DIR/src/common/pico_sync/include"
|
||||
-I"$PICO_SDK_DIR/src/common/pico_time/include"
|
||||
-I"$PICO_SDK_DIR/src/common/pico_util/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2040/hardware_regs/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2040/hardware_structs/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/boot_stage2/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_base/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_claim/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_clocks/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_divider/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_exception/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_gpio/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_irq/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_pll/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_resets/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_sync/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_timer/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_uart/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_vreg/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_watchdog/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/hardware_xosc/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_bootrom/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_double/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_float/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_int64_ops/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_malloc/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_multicore/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_platform/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_printf/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_runtime/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_stdio/include"
|
||||
-I"$PICO_SDK_DIR/src/rp2_common/pico_stdio_uart/include"
|
||||
)
|
||||
|
||||
declare -a RP2040_INCLUDE_FLAGS
|
||||
RP2040_INLCUDE_FLAGS=(
|
||||
-I"$SMP_DEMO_DIR/FreeRTOS/Demo/CORTEX_M0+_RP2040/OnEitherCore"
|
||||
-I"$SMP_DEMO_DIR/FreeRTOS/Demo/CORTEX_M0+_RP2040/build/generated/pico_base"
|
||||
-I"$REPO_BASE_DIR/portable/ThirdParty/GCC/RP2040/include"
|
||||
-I"$REPO_BASE_DIR/portable/ThirdParty/GCC/RP2040"
|
||||
)
|
||||
|
||||
declare -a VERIFAST_FLAGS
|
||||
VERIFAST_FLAGS=(
|
||||
-DVERIFAST
|
||||
-DVERIFAST_SKIP_BITVECTOR_PROOF__STACK_ALIGNMENT
|
||||
-I"$VF_DIR/bin"
|
||||
-I"$VF_PROOF_MOD_HEADER_DIR"
|
||||
-I"$VF_PROOF_MOD_SRC_DIR"
|
||||
-I"$PROOF_SETUP_DIR"
|
||||
-I"$PROOF_FILES_DIR"
|
||||
)
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script expects the following command line arguments:
|
||||
# $1 : Absolute path to the source file that should be prepared for VeriFast.
|
||||
# $2 : Absolute path to which the result shall be written.
|
||||
# $3 : Absolute path under which preprocessor error shall be logged.
|
||||
# $4 : Absolute path to the root dir of this repository
|
||||
# $5 : Absolute path to the root of the directory containing the VeriFast proofs
|
||||
# $6 : Absolute path to the VeriFast directory
|
||||
|
||||
SRC_FILE="$1"
|
||||
OUT_FILE="$2"
|
||||
FILE_PP_ERR_LOG="$3"
|
||||
REPO_BASE_DIR="$4"
|
||||
VF_PROOF_BASE_DIR="$5"
|
||||
VF_DIR="$6"
|
||||
|
||||
|
||||
# Load functions used to compute paths.
|
||||
. "$VF_PROOF_BASE_DIR/paths.sh"
|
||||
|
||||
|
||||
PP_SCRIPT_DIR=`pp_script_dir $REPO_BASE_DIR`
|
||||
PP_LOG_DIR=`pp_log_dir $REPO_BASE_DIR`
|
||||
FILE_PP_LOG="$PP_LOG_DIR/pp.c"
|
||||
FILE_RW_LOG="$PP_LOG_DIR/rw.c"
|
||||
|
||||
|
||||
# Ensure that log directory exists
|
||||
if [ ! -d "$PP_LOG_DIR" ]; then
|
||||
mkdir "$PP_LOG_DIR"
|
||||
fi
|
||||
|
||||
|
||||
# Preprocessing the source file
|
||||
# Output is written to '$FILE_PP_LOG' and error report is written to
|
||||
# '$FILE_PP_ERR_LOG'.
|
||||
"$PP_SCRIPT_DIR/preprocess_file_for_verification.sh" $SRC_FILE \
|
||||
$FILE_PP_LOG $FILE_PP_ERR_LOG \
|
||||
$REPO_BASE_DIR $VF_PROOF_BASE_DIR $VF_DIR
|
||||
|
||||
cp "$FILE_PP_LOG" "$FILE_RW_LOG"
|
||||
"$PP_SCRIPT_DIR/vf_rewrite.sh" "$FILE_RW_LOG"
|
||||
cp "$FILE_RW_LOG" "$OUT_FILE"
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
# This script preprocesses a given source file. Include paths are configured to
|
||||
# fit 'tasks.c', but it might also be useful for other source files.
|
||||
# The preprocessor is configured such that `diff`-ing results produced by this
|
||||
# script (from different versions of the same file) yields useful results.
|
||||
#
|
||||
# This script expects the following arguments:
|
||||
# $1 : Absolute path to the source file to be preprocessed.
|
||||
# $2 : Absolute path of the preprocessor's output file.
|
||||
# $3 : Absolute path to which the error report will be written.
|
||||
# $4 : Absolute path to the base directory of this repository.
|
||||
# $5 : Absolute path to the VeriFast proof directory.
|
||||
|
||||
|
||||
SRC_FILE="$1"
|
||||
OUT_FILE="$2"
|
||||
ERR_FILE="$3"
|
||||
REPO_BASE_DIR="$4"
|
||||
VF_PROOF_BASE_DIR="$5"
|
||||
|
||||
|
||||
# Load functions used to compute paths.
|
||||
. "$VF_PROOF_BASE_DIR/paths.sh"
|
||||
|
||||
# Load variables storing preprocessor flags.
|
||||
. "`pp_script_dir $REPO_BASE_DIR`/pp_flags.sh" "$REPO_BASE_DIR" "$VF_PROOF_BASE_DIR"
|
||||
|
||||
PROD_HEADER_DIR=`prod_header_dir $REPO_BASE_DIR`
|
||||
|
||||
|
||||
# Relevant clang flags:
|
||||
# -E : Run preprocessor
|
||||
# -C : Include comments in output
|
||||
# -P : Surpresses line/file pragmas
|
||||
# -D NDEBUG : Deactivate assertions.
|
||||
|
||||
# Note:
|
||||
# The implementation of the `assert` macro is platform dependent and is defined
|
||||
# in the system header `assert.h`. A preprocessed assertion might contain
|
||||
# a reference to the location of the assertion in the source code (e.g. on OS X).
|
||||
# This causes false positives when `diff`-ing preprocessed files. Hence, we
|
||||
# deactivate assertions.
|
||||
|
||||
echo Preprocessing file:
|
||||
echo \"$SRC_FILE\"
|
||||
echo Output will be written to:
|
||||
echo \"$OUT_FILE\"
|
||||
echo Errors will be reported in:
|
||||
echo \"$ERR_FILE\"
|
||||
echo
|
||||
clang -E -P -D NDEBUG \
|
||||
${BUILD_FLAGS[@]} ${RP2040_INLCUDE_FLAGS[@]} ${PICO_INCLUDE_FLAGS[@]} \
|
||||
-I"$PROD_HEADER_DIR" \
|
||||
-c "$SRC_FILE" \
|
||||
1>"$OUT_FILE" 2>"$ERR_FILE"
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
# This script preprocesses a given source file annotated with VeriFast proof
|
||||
# steps. Include paths are configured to fit 'tasks.c', but it might also be
|
||||
# useful for other source files. The preprocessor is configured to include the
|
||||
# proper proof files from VeriFast's standard library and to also include
|
||||
# source code guarded by 'VERIFAST' defines.
|
||||
#
|
||||
# This script expects the following arguments:
|
||||
# $1 : Absolute path to the source file to be preprocessed.
|
||||
# $2 : Absolute path of the preprocessor's output file.
|
||||
# $3 : Absolute path to which the error report will be written.
|
||||
# $4 : Absolute path to the base directory of this repository.
|
||||
# $5 : Absolute path to the VeriFast proof directory.
|
||||
# $6 : Absolute path to the VeriFast installation directory.
|
||||
|
||||
|
||||
SRC_FILE="$1"
|
||||
OUT_FILE="$2"
|
||||
ERR_FILE="$3"
|
||||
REPO_BASE_DIR="$4"
|
||||
VF_PROOF_BASE_DIR="$5"
|
||||
VF_DIR="$6"
|
||||
|
||||
|
||||
|
||||
# Load functions used to compute paths.
|
||||
. "$VF_PROOF_BASE_DIR/paths.sh"
|
||||
|
||||
# Load variables storing preprocessor flags.
|
||||
. "`pp_script_dir $REPO_BASE_DIR`/pp_flags.sh" "$REPO_BASE_DIR" "$VF_PROOF_BASE_DIR" "$VF_DIR"
|
||||
|
||||
|
||||
# Relevant clang flags:
|
||||
# -E : Run preprocessor
|
||||
# -C : Include comments in output
|
||||
# -P : Surpresses line/file pragmas
|
||||
|
||||
echo start preprocessor
|
||||
clang -E -C \
|
||||
\
|
||||
${BUILD_FLAGS[@]} \
|
||||
${VERIFAST_FLAGS[@]} \
|
||||
${RP2040_INLCUDE_FLAGS[@]} \
|
||||
${PICO_INCLUDE_FLAGS[@]} \
|
||||
-I`prod_header_dir $REPO_BASE_DIR` \
|
||||
\
|
||||
-c "$SRC_FILE" \
|
||||
1>"$OUT_FILE" 2>"$ERR_FILE"
|
||||
66
Test/VeriFast/tasks/vTaskSwitchContext/preprocessing_scripts/vf_rewrite.sh
Executable file
66
Test/VeriFast/tasks/vTaskSwitchContext/preprocessing_scripts/vf_rewrite.sh
Executable file
|
|
@ -0,0 +1,66 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script rewrites a given source in-pace such that the result can be
|
||||
# processed by VeriFast. Each rewrite below concerns a specific construct
|
||||
# VeriFast cannot handle. When VeriFast will be extended to handle a
|
||||
# problematic construct we encountered, the corresponding rewirte below can be
|
||||
# deleted.
|
||||
#
|
||||
# This scirpt expects the following arguments:
|
||||
# $1 : The absolute path to the source file to be rewritten in place.
|
||||
#
|
||||
# Note: Callers are responsible to back up the rewritten source file beforehand.
|
||||
|
||||
|
||||
SOURCE_FILE="$1"
|
||||
|
||||
|
||||
# IMPORTANT:
|
||||
# None of the provided regexes must contain the unescaped character '|'
|
||||
#
|
||||
# $1 : sed 'find' regex
|
||||
# $2 : sed 'replace' regex
|
||||
rewrite()
|
||||
{
|
||||
FIND_REGEX=$1
|
||||
REPLACE_REGEX=$2
|
||||
echo "Rewrite pattern: \"$FIND_REGEX\" -> \"$REPLACE_REGEX\""
|
||||
sed -i "" "s|$FIND_REGEX|$REPLACE_REGEX|g" $SOURCE_FILE
|
||||
echo
|
||||
}
|
||||
|
||||
|
||||
echo "Commenting out line/file pragmas"
|
||||
rewrite "^#" "// &"
|
||||
|
||||
echo "Fixing order of 'long', 'unsigned'"
|
||||
echo "Reported issue 338:"
|
||||
echo "https://github.com/verifast/verifast/issues/338"
|
||||
rewrite "long unsigned int" "unsigned long int"
|
||||
|
||||
echo "Delete fixed-sized array typedefs"
|
||||
echo "Reported issue 339:"
|
||||
echo "https://github.com/verifast/verifast/issues/339"
|
||||
rewrite "typedef .*\[[0-9]*\];" ""
|
||||
|
||||
echo "Delete attributes"
|
||||
echo "Reported issue 340:"
|
||||
echo "https://github.com/verifast/verifast/issues/340"
|
||||
rewrite "__attribute__(([_a-z]*))" ""
|
||||
# Note: `\s` or `:space:` not work on MacOs.
|
||||
rewrite "__attribute__( ( [_a-z]* ) )" ""
|
||||
|
||||
echo "Delete void casts (used to suppress compiler warnings)"
|
||||
echo "Reported issue 335"
|
||||
echo "https://github.com/verifast/verifast/issues/335"
|
||||
rewrite "( void ) memset" "memset"
|
||||
|
||||
echo "Removing const qualifiers from pointers"
|
||||
echo "Reported issue 333:"
|
||||
echo "https://github.com/verifast/verifast/issues/333"
|
||||
rewrite "[*] const" "*"
|
||||
rewrite "const [*]" "*"
|
||||
|
||||
echo "Uncomment special includes to allow VeriFast proofs to refer to config macros"
|
||||
rewrite "//VF_include #include" "#include"
|
||||
rewrite "//VF_macro #" "#"
|
||||
55
Test/VeriFast/tasks/vTaskSwitchContext/proof/README.md
Normal file
55
Test/VeriFast/tasks/vTaskSwitchContext/proof/README.md
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
This directory contains the bulk of VeriFast formalizations and proofs.
|
||||
|
||||
|
||||
# Directory Structure
|
||||
```
|
||||
├── lock_predicates.h
|
||||
│ Contains the formalization of the lock invariants, i.e., the invariants
|
||||
│ associated with: Masking interrupts, the task lock and the ISR lock.
|
||||
│ This file also contains the lemmas to prove that the task state updates
|
||||
│ in `prvSelectHighestPriorityTask` preserve the lock invariants.
|
||||
│
|
||||
├── port_locking_contracts.h
|
||||
│ Contains VeriFast function contracts for macros with port-specific
|
||||
│ definitions used to invoke synchronization mechanisms, e.g., masking
|
||||
│ interrupts and acquiring locks. These port-specific definitions often
|
||||
│ contain inline assembly VeriFast cannot reason about. The contracts allow us
|
||||
│ to abstract the semantics of the assembly.
|
||||
│
|
||||
├── ready_list_predicates.h
|
||||
│ Contains the predicates describing the ready lists as well as lemmas to
|
||||
│ reason about ready lists.
|
||||
│
|
||||
├── stack_predicates.h
|
||||
│ Contains the formalization of the stack layout used in the RP2040 port.
|
||||
│
|
||||
├── task_predicates.h
|
||||
│ Contains predicates describing task control blocks.
|
||||
│
|
||||
├── task_running_states.h
|
||||
│ `tasks.c` defines macros that are used to denote task run states.
|
||||
│ The proof headers in this directory cannot refer to these macros.
|
||||
│ This header contains auxiliary definitions used to expose the run state
|
||||
│ macros to the proof headers.
|
||||
│
|
||||
├── verifast_lists_extended.h
|
||||
│ Contains list axioms and lemmas that would naturally fit into VeriFast's
|
||||
│ standard list library `listex.gh`.
|
||||
│
|
||||
├── README.md
|
||||
│
|
||||
├── single_core_proofs
|
||||
│ Contains the old list formalization and proofs written by
|
||||
│ Aalok Thakkar and Nathan Chong in 2020 for the single-core
|
||||
│ setup.
|
||||
│ │
|
||||
│ ├── scp_common.h
|
||||
│ │ Contains auxiliary definitions and lemmas.
|
||||
│ │
|
||||
│ └── scp_list_predicates.h
|
||||
│ Contains the formalizaton of doubly linked lists and list items.
|
||||
│
|
||||
└── single_core_proofs_extended
|
||||
Contains new proofs extending the single-core list
|
||||
formalization.
|
||||
```
|
||||
599
Test/VeriFast/tasks/vTaskSwitchContext/proof/lock_predicates.h
Normal file
599
Test/VeriFast/tasks/vTaskSwitchContext/proof/lock_predicates.h
Normal file
|
|
@ -0,0 +1,599 @@
|
|||
#ifndef LOCK_PREDICATES_H
|
||||
#define LOCK_PREDICATES_H
|
||||
|
||||
#include "task_running_states.h"
|
||||
|
||||
|
||||
#include "verifast_lists_extended.h"
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Locking discipline explained:
|
||||
* FreeRTOS uses the following synchronization mechanisms:
|
||||
* - Deactivating interrupts:
|
||||
* Some data is only meant to be accessed on a specific core C. Such data
|
||||
* may only be accessed after interrupts on core C have been deactivated.
|
||||
* For instance the global array `pxCurrentTCBs` in `tasks.c` has an entry for
|
||||
* every core. `pxCurrentTCBs[C]` stores a pointer to the TCB of the task
|
||||
* running on core C. Core C is always allowed to read `pxCurrentTCBs[C]`.
|
||||
* However, writing requires the interrupts on core C to be deactivated.
|
||||
*
|
||||
* The resources protected by disabling interrupts are represented by the
|
||||
* predicate `coreLocalInterruptInv_p` defined below.
|
||||
*
|
||||
* - task lock:
|
||||
* The task lock is used to protect ciritical sections and resources from
|
||||
* being accessed by multiple tasks simultaneously. The resources protected
|
||||
* by the task lock are represented by the abstract predicate `taskLockInv_p`
|
||||
* defined below. This proof does not deal with resources or code segments
|
||||
* only protected by the task lock. Hence, we leave the predicate abstract.
|
||||
*
|
||||
* - ISR lock:
|
||||
* The ISR/ interrupt lock is used to protect critical sections and resources
|
||||
* from being accessed by multiple interrupts simultaneously. The resources
|
||||
* protected by the ISR lock are represented by the abstract predicate
|
||||
* `isrLockInv_p` defined below. This proof does not deal with resources or
|
||||
* code segments only protected by the ISR lock. Hence, we leave the predicate
|
||||
* abstract.
|
||||
*
|
||||
* - task lock + ISR lock:
|
||||
* Access to certain resources and ciritical sections are protected by both
|
||||
* the task lock and the ISR lock. For these, it is crucial that we first
|
||||
* acquire the task lock and then the ISR lock. Likewise, we must release them
|
||||
* in opposite order. Failure to comply with this order may lead to deadlocks.
|
||||
* The resources protected by both locks are the main resources this proof
|
||||
* deals with. These include the ready lists and the certain access rights
|
||||
* to the tasks' run states. The access rights protected by both locks are
|
||||
* represented by the predicate `taskISRLockInv_p` defined below.
|
||||
* Once both locks have been acquired in the right order, this lock invariant
|
||||
* can be produced by calling the lemma `produce_taskISRLockInv`. Before the
|
||||
* locks can be released, the invariant must be consumed by calling
|
||||
* `consume_taskISRLockInv`. Both lemmas are defined below.
|
||||
*/
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Core local data and access restrictions.
|
||||
* Some data in FreeRTOS such as the pointer to TCB of the task running
|
||||
* on core `C` may only be accessed from core `C`. Such core-local data is
|
||||
* protected by deactivating interrupts.
|
||||
*/
|
||||
|
||||
/*@
|
||||
// Represents the state of interrupts (i.e. activated or deactivated) on a
|
||||
// specific core. The state corresponds to the value of the special register
|
||||
// used for interrupt masking.
|
||||
predicate interruptState_p(uint32_t coreID, uint32_t state);
|
||||
|
||||
// Given an interrupt state (i.e. the value of the special register used to
|
||||
// control interrupt masking), this function returns whether the state expresses
|
||||
// that interrupts are deactivated.
|
||||
fixpoint bool interruptsDisabled_f(uint32_t);
|
||||
|
||||
|
||||
// This predicate expresses that the core we are currently reasoning about
|
||||
// (expressed by constant `coreID_f`) is allowed to access the core-local data
|
||||
// protected by interrupt masking.
|
||||
predicate coreLocalInterruptInv_p() =
|
||||
// Read permission to the entry of `pxCurrentTCBs` that stores a pointer
|
||||
// to the task currenlty running on this core
|
||||
[0.5]pointer(&pxCurrentTCBs[coreID_f], ?currentTCB)
|
||||
&*&
|
||||
// Write permission to the entry of `xYieldPendings` for the current core
|
||||
integer_(&xYieldPendings[coreID_f], sizeof(BaseType_t), true, _)
|
||||
&*&
|
||||
// Write permission to the "critical nesting" field of the task
|
||||
// currently scheduled on this core. The field allows us to check whether
|
||||
// the task is currently in a critical section. Necessary to check whether,
|
||||
// we are allowed to context switch.
|
||||
TCB_criticalNesting_p(currentTCB, ?gCriticalNesting);
|
||||
@*/
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Predicates relevant for all locks
|
||||
*/
|
||||
|
||||
/*@
|
||||
// This predicate is used to remember which locks we're currently holding. Each
|
||||
// Each constists of a pair `(f,id)`. `f` is the fraction of the lock we held
|
||||
// before acquiring. Remembering the fraction is important to ensure that we
|
||||
// reproduce the right fraction of the lock predicate when we release the lock.
|
||||
// Otherwise, we can run into inconsistencies.
|
||||
// `id` is the ID of the acquired lock, i.e., either `taskLockID_f` or
|
||||
// `isrLockID_f`.
|
||||
predicate locked_p(list< pair<real, int> > lockHistory);
|
||||
@*/
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Task lock
|
||||
*/
|
||||
|
||||
/*@
|
||||
fixpoint int taskLockID_f();
|
||||
|
||||
// Represents an unacquired task lock.
|
||||
predicate taskLock_p();
|
||||
|
||||
// Represents the invariant associated with the the task lock, i.e.,
|
||||
// access permissions to the resources and code regions protected by the lock.
|
||||
// These are not relevant to the context-switch proof. Therefore, we leave the
|
||||
// predicate abstract.
|
||||
predicate taskLockInv_p();
|
||||
@*/
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* ISR lock
|
||||
*/
|
||||
|
||||
/*@
|
||||
fixpoint int isrLockID_f();
|
||||
|
||||
// Represents an unacquired ISR lock.
|
||||
predicate isrLock_p();
|
||||
|
||||
// Represents the invariant associated with the the ISR lock, i.e.,
|
||||
// access permissions to the resources and code regions protected by the lock.
|
||||
// These are not relevant to the context-switch proof. Therefore, we leave the
|
||||
// predicate abstract.
|
||||
predicate isrLockInv_p();
|
||||
@*/
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Resources protected by both locks.
|
||||
* Note that the task lock may never be acquired after the ISR lock.
|
||||
*/
|
||||
|
||||
/*@
|
||||
fixpoint int taskISRLockID_f();
|
||||
|
||||
// Represents the access rights protected by both the task and the ISR lock.
|
||||
// Note that FreeRTOS' locking discipline demands the the task lock must be
|
||||
// acquired before the ISR lock. Once, both locks have been acquired in the
|
||||
// right order, ths invariant can be produced by invoking the lemma
|
||||
// `produce_taskISRLockInv` and it can be consumed by invoking
|
||||
// `consume_taskISRLockInv`. The lemmas ensure that we follow the locking
|
||||
// discipline.
|
||||
//
|
||||
// This invariant expresses fine grained access rights to the following:
|
||||
// - some global variables:
|
||||
// + Read permission to the entry of `pxCurrentTCBs` that stores a pointer
|
||||
// to the task currenly running on the core `coreID_f` our proof currently
|
||||
// considers. Together with the read permission from
|
||||
// `coreLocalInterruptInv_p` we get write access to this entry once
|
||||
// interrupts have been deactivated and both locks have been acquired.
|
||||
// + Write permission to `uxSchedulerSuspended`.
|
||||
// + Write permission to `xSchedulerRunning`.
|
||||
// + Write permission to `uxTopReadyPriority`. This variable stores to top
|
||||
// priority for which there is a task that is ready to be scheduled.
|
||||
// - Write access to the ready lists.
|
||||
// - Fine-grained access permissions for task run states:
|
||||
// + (RP-All) Read permission for every task.
|
||||
// + (RP-Current) Read permission for task currently scheduled on this core.
|
||||
// Together, (RP-All) and (RP-Current) give us a write permission for
|
||||
// task scheduled on this core.
|
||||
// + (RP-Unsched) Read permissions for unscheduled tasks.
|
||||
// Together, (RP-All) and (RP-Unsched) give us write permissions for all
|
||||
// unscheduled tasks.
|
||||
// Note that these permissions do not allow us to change the run state of any
|
||||
// task that is currently scheduled on another core.
|
||||
predicate taskISRLockInv_p() =
|
||||
_taskISRLockInv_p(_);
|
||||
|
||||
|
||||
// Auxiliary predicate. Equal to the lock invariant above but exposes
|
||||
// some details.
|
||||
predicate _taskISRLockInv_p(UBaseType_t gTopReadyPriority) =
|
||||
// Access to global variables
|
||||
[0.5]pointer(&pxCurrentTCBs[coreID_f], ?gCurrentTCB) &*&
|
||||
integer_((void*) &uxSchedulerSuspended, sizeof(UBaseType_t), false, _) &*&
|
||||
integer_(&xSchedulerRunning, sizeof(BaseType_t), true, _)
|
||||
&*&
|
||||
// top ready priority must be in range
|
||||
integer_((void*) &uxTopReadyPriority, sizeof(UBaseType_t), false, gTopReadyPriority) &*&
|
||||
0 <= gTopReadyPriority &*& gTopReadyPriority < configMAX_PRIORITIES
|
||||
&*&
|
||||
// tasks / TCBs
|
||||
exists_in_taskISRLockInv_p(?gTasks, ?gStates)
|
||||
&*&
|
||||
// (RP-All) Read permissions for every task
|
||||
// and recording of task states in state list
|
||||
// (∀t ∈ gTasks.
|
||||
// [1/2]TCB_runState_p(t, _))
|
||||
// ∧
|
||||
// ∀i. ∀t. gTasks[i] == t -> gStates[i] == t->xTaskRunState
|
||||
foreach(gTasks, readOnly_TCB_runState_p(gTasks, gStates))
|
||||
&*&
|
||||
// (RP-Current) Read permission for task currently scheduled on this core
|
||||
// (RP-All) + (RP-Current) => Write permission for scheduled task
|
||||
[1/2]TCB_runState_p(gCurrentTCB, ?gCurrentTCB_state) &*&
|
||||
(gCurrentTCB_state == coreID_f() || gCurrentTCB_state == taskTASK_YIELDING) &*&
|
||||
nth(index_of(gCurrentTCB, gTasks), gStates) == gCurrentTCB_state
|
||||
&*&
|
||||
// (RP-Unsched) Read permissions for unscheduled tasks
|
||||
// (RP-All) + (RP-Unsched) => Write permissions for unscheduled tasks
|
||||
// ∀t ∈ tasks. t->xTaskState == taskTASK_NOT_RUNNING
|
||||
// -> [1/2]shared_TCB_p(t, taskTASK_NOT_RUNNING)
|
||||
foreach(gTasks, readOnly_TCB_runState_IF_not_running_p(gTasks, gStates))
|
||||
&*&
|
||||
readyLists_p(?gCellLists, ?gOwnerLists)
|
||||
&*&
|
||||
// gTasks contains all relevant tasks
|
||||
mem(gCurrentTCB, gTasks) == true
|
||||
&*&
|
||||
// ∀l ∈ gOwnerLists. l ⊆ gTasks
|
||||
forall(gOwnerLists, (superset)(gTasks)) == true;
|
||||
|
||||
|
||||
lemma void produce_taskISRLockInv();
|
||||
requires locked_p(?heldLocks) &*&
|
||||
heldLocks == cons(?i, cons(?t, nil)) &*&
|
||||
i == pair(?f_isr, isrLockID_f()) &*&
|
||||
t == pair(?f_task, taskLockID_f());
|
||||
ensures locked_p( cons( pair(_, taskISRLockID_f()), heldLocks) ) &*&
|
||||
taskISRLockInv_p();
|
||||
|
||||
|
||||
lemma void consume_taskISRLockInv();
|
||||
requires locked_p( cons( pair(_, taskISRLockID_f()), ?otherLocks) ) &*&
|
||||
taskISRLockInv_p();
|
||||
ensures locked_p(otherLocks);
|
||||
|
||||
|
||||
|
||||
// Auxiliary predicate to assing names to existentially quantified variables.
|
||||
// Having multiple `exists` chunks on the heap makes matching against their
|
||||
// arguments ambiguous in most cases.
|
||||
predicate exists_in_taskISRLockInv_p(list<void*> gTasks,
|
||||
list<TaskRunning_t> gStates) =
|
||||
exists(gTasks) &*&
|
||||
exists(gStates) &*&
|
||||
length(gTasks) == length(gStates) &*&
|
||||
distinct(gTasks) == true;
|
||||
|
||||
// Auxiliary function that allows us to partially apply the list argument.
|
||||
//
|
||||
// Notes:
|
||||
// - Partial application of fixpoint functions in VeriFast is not documented.
|
||||
// The syntax for partially application is `(<fixpoint_fct>)(<first_arg>)`
|
||||
// - VeriFast only supports partially applying the first argument, e.g.,
|
||||
// `(mem)(0)` is allowed but `(mem)(_)(nil)` is not.
|
||||
fixpoint bool mem_list_elem<t>(list<t> xs, t x) {
|
||||
return mem(x, xs);
|
||||
}
|
||||
|
||||
// Auxiliary predicate to allow foreach-quantification about fraction
|
||||
// and reflection of `t->xTaskRunState` in state list.
|
||||
predicate_ctor readOnly_TCB_runState_p
|
||||
(list<void*> tasks, list<TaskRunning_t> states)
|
||||
(TCB_t* t;) =
|
||||
mem(t, tasks) == true &*&
|
||||
[1/2]TCB_runState_p(t, nth(index_of(t, tasks), states));
|
||||
|
||||
predicate_ctor readOnly_TCB_runState_IF_not_running_p
|
||||
(list<void*> tasks, list<TaskRunning_t> states)
|
||||
(TCB_t* t;) =
|
||||
mem(t, tasks) == true &*&
|
||||
nth(index_of(t, tasks), states) == taskTASK_NOT_RUNNING
|
||||
? [1/2]TCB_runState_p(t, taskTASK_NOT_RUNNING)
|
||||
: true;
|
||||
@*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// The following lemmas are necessary to prove that state updates preserve
|
||||
// the lock invariant.
|
||||
|
||||
/*@
|
||||
lemma void update_readOnly_TCB_runState(TCB_t* t,
|
||||
list<void*> tasks,
|
||||
list<TaskRunning_t> states,
|
||||
int updatedIndex,
|
||||
TaskRunning_t s)
|
||||
requires readOnly_TCB_runState_p(tasks, states)(t) &*&
|
||||
updatedIndex != index_of(t, tasks) &*&
|
||||
mem(t, tasks) == true &*&
|
||||
length(tasks) == length(states);
|
||||
ensures readOnly_TCB_runState_p(tasks, update(updatedIndex, s, states))(t);
|
||||
{
|
||||
list<TaskRunning_t> states2 = update(updatedIndex, s, states);
|
||||
int t_index = index_of(t, tasks);
|
||||
|
||||
if( updatedIndex < 0 || updatedIndex >= length(states) ) {
|
||||
update_out_of_bounds(updatedIndex, s, states);
|
||||
} else {
|
||||
open readOnly_TCB_runState_p(tasks, states)(t);
|
||||
open [1/2]TCB_runState_p(t, nth(t_index, states));
|
||||
|
||||
mem_index_of(t, tasks);
|
||||
nth_update(t_index, updatedIndex, s, states);
|
||||
assert( nth(t_index, states) == nth(t_index, states2) );
|
||||
|
||||
close [1/2]TCB_runState_p(t, nth(t_index, states2));
|
||||
close readOnly_TCB_runState_p(tasks, states2)(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lemma void update_foreach_readOnly_TCB_runState(TCB_t* updatedTask,
|
||||
list<void*> tasks,
|
||||
list<void*> subTasks,
|
||||
list<TaskRunning_t> states,
|
||||
list<TaskRunning_t> states2,
|
||||
TaskRunning_t s)
|
||||
requires
|
||||
mem(updatedTask, tasks) == true &*&
|
||||
length(tasks) == length(states) &*&
|
||||
foreach(subTasks, readOnly_TCB_runState_p(tasks, states)) &*&
|
||||
states2 == update(index_of(updatedTask, tasks), s, states) &*&
|
||||
distinct(tasks) == true &*&
|
||||
mem(updatedTask, subTasks) == false &*&
|
||||
subset(subTasks, tasks) == true;
|
||||
ensures
|
||||
foreach(subTasks, readOnly_TCB_runState_p(tasks, states2));
|
||||
{
|
||||
switch(subTasks) {
|
||||
case nil:
|
||||
open foreach(nil, readOnly_TCB_runState_p(tasks, states));
|
||||
close foreach(nil, readOnly_TCB_runState_p(tasks, states2));
|
||||
case cons(h, rest):
|
||||
int index = index_of(updatedTask, tasks);
|
||||
open foreach(subTasks, readOnly_TCB_runState_p(tasks, states));
|
||||
assert( updatedTask != h );
|
||||
index_of_different(updatedTask, h, tasks);
|
||||
assert( index != index_of(h, tasks) );
|
||||
update_readOnly_TCB_runState(h, tasks, states, index, s);
|
||||
assert( mem(updatedTask, rest) == false );
|
||||
update_foreach_readOnly_TCB_runState(updatedTask, tasks, rest,
|
||||
states, states2, s);
|
||||
close foreach(subTasks, readOnly_TCB_runState_p(tasks, states2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lemma void close_updated_foreach_readOnly_TCB_runState(TCB_t* updatedTask,
|
||||
list<void*> tasks,
|
||||
list<TaskRunning_t> states,
|
||||
list<TaskRunning_t> states2,
|
||||
TaskRunning_t s)
|
||||
requires
|
||||
mem(updatedTask, tasks) == true &*&
|
||||
length(states) == length(tasks) &*&
|
||||
distinct(tasks) == true &*&
|
||||
foreach(remove(updatedTask, tasks), readOnly_TCB_runState_p(tasks, states)) &*&
|
||||
states2 == update(index_of(updatedTask, tasks), s, states) &*&
|
||||
[1/2]TCB_runState_p(updatedTask, s);
|
||||
ensures
|
||||
foreach(tasks, readOnly_TCB_runState_p(tasks, states2));
|
||||
{
|
||||
distinct_mem_remove(updatedTask, tasks);
|
||||
remove_result_subset(updatedTask, tasks);
|
||||
|
||||
close readOnly_TCB_runState_p(tasks, states2)(updatedTask);
|
||||
update_foreach_readOnly_TCB_runState(updatedTask, tasks,
|
||||
remove(updatedTask, tasks),
|
||||
states, states2, s);
|
||||
foreach_unremove(updatedTask, tasks);
|
||||
}
|
||||
|
||||
|
||||
lemma void stopUpdate_foreach_readOnly_TCB_runState_IF_not_running
|
||||
(TCB_t* stoppedTask, list<void*> tasks, list<void*> subTasks,
|
||||
list<TaskRunning_t> states, list<TaskRunning_t> states2)
|
||||
requires
|
||||
distinct(tasks) == true &*&
|
||||
distinct(subTasks) == true &*&
|
||||
length(tasks) == length(states) &*&
|
||||
foreach(subTasks, readOnly_TCB_runState_IF_not_running_p(tasks, states)) &*&
|
||||
states2 == update(index_of(stoppedTask, tasks), taskTASK_NOT_RUNNING, states) &*&
|
||||
nth(index_of(stoppedTask, tasks), states) != taskTASK_NOT_RUNNING &*&
|
||||
subset(subTasks, tasks) == true &*&
|
||||
mem(stoppedTask, tasks) == true &*&
|
||||
mem(stoppedTask, subTasks)
|
||||
? [1/2]TCB_runState_p(stoppedTask, taskTASK_NOT_RUNNING)
|
||||
: true;
|
||||
ensures
|
||||
foreach(subTasks, readOnly_TCB_runState_IF_not_running_p(tasks, states2));
|
||||
{
|
||||
switch(subTasks) {
|
||||
case nil:
|
||||
open foreach(nil, readOnly_TCB_runState_IF_not_running_p(tasks, states));
|
||||
close foreach(nil, readOnly_TCB_runState_IF_not_running_p(tasks, states2));
|
||||
case cons(h, t):
|
||||
if( h == stoppedTask ) {
|
||||
assert( remove(stoppedTask, subTasks) == t );
|
||||
distinct_mem_remove(stoppedTask, subTasks);
|
||||
assert( mem(stoppedTask, t) == false );
|
||||
mem_index_of(stoppedTask, tasks);
|
||||
} else {
|
||||
mem_index_of(stoppedTask, tasks);
|
||||
nth_update(index_of(h, tasks), index_of(stoppedTask, tasks), taskTASK_NOT_RUNNING, states);
|
||||
index_of_different(h, stoppedTask, tasks);
|
||||
assert( index_of(h, tasks) != index_of(stoppedTask, tasks) );
|
||||
assert( nth(index_of(h, tasks), states) == nth(index_of(h, tasks), states2) );
|
||||
}
|
||||
|
||||
nth_update(index_of(stoppedTask, tasks), index_of(stoppedTask, tasks), taskTASK_NOT_RUNNING, states);
|
||||
open foreach(subTasks, readOnly_TCB_runState_IF_not_running_p(tasks, states));
|
||||
open readOnly_TCB_runState_IF_not_running_p(tasks, states)(h);
|
||||
assert( nth(index_of(stoppedTask, tasks), states2) == taskTASK_NOT_RUNNING );
|
||||
close readOnly_TCB_runState_IF_not_running_p(tasks, states2)(h);
|
||||
stopUpdate_foreach_readOnly_TCB_runState_IF_not_running
|
||||
(stoppedTask, tasks, t, states, states2);
|
||||
close foreach(subTasks, readOnly_TCB_runState_IF_not_running_p(tasks, states2));
|
||||
}
|
||||
}
|
||||
|
||||
lemma void updateUnaffectedStates_in_foreach_readOnly_TCB_runState_IF_not_running
|
||||
(TCB_t* updatedTask, list<void*> tasks, list<void*> subTasks,
|
||||
list<TaskRunning_t> states, list<TaskRunning_t> updatedStates,
|
||||
TaskRunning_t s)
|
||||
requires
|
||||
distinct(tasks) == true &*&
|
||||
distinct(subTasks) == true &*&
|
||||
length(tasks) == length(states) &*&
|
||||
mem(updatedTask, tasks) == true &*&
|
||||
mem(updatedTask, subTasks) == false &*&
|
||||
subset(subTasks, tasks) == true &*&
|
||||
foreach(subTasks, readOnly_TCB_runState_IF_not_running_p(tasks, states)) &*&
|
||||
updatedStates == update(index_of(updatedTask, tasks), s, states);
|
||||
ensures
|
||||
foreach(subTasks, readOnly_TCB_runState_IF_not_running_p(tasks, updatedStates));
|
||||
{
|
||||
switch(subTasks) {
|
||||
case nil:
|
||||
open foreach(nil, readOnly_TCB_runState_IF_not_running_p(tasks, states));
|
||||
close foreach(nil, readOnly_TCB_runState_IF_not_running_p(tasks, updatedStates));
|
||||
case cons(h, t):
|
||||
open foreach(subTasks, readOnly_TCB_runState_IF_not_running_p(tasks, states));
|
||||
|
||||
// Prove that update preserves state of `h`.
|
||||
index_of_different(h, updatedTask, tasks);
|
||||
nth_update(index_of(h, tasks), index_of(updatedTask, tasks), s, states);
|
||||
assert( nth(index_of(h, tasks), states) == nth(index_of(h, tasks), updatedStates) );
|
||||
|
||||
open readOnly_TCB_runState_IF_not_running_p(tasks, states)(h);
|
||||
close readOnly_TCB_runState_IF_not_running_p(tasks, updatedStates)(h);
|
||||
updateUnaffectedStates_in_foreach_readOnly_TCB_runState_IF_not_running
|
||||
(updatedTask, tasks, t, states, updatedStates, s);
|
||||
close foreach(subTasks, readOnly_TCB_runState_IF_not_running_p(tasks, updatedStates));
|
||||
}
|
||||
}
|
||||
|
||||
lemma void startUpdate_foreach_readOnly_TCB_runState_IF_not_running
|
||||
(TCB_t* startedTask, list<void*> tasks,
|
||||
list<TaskRunning_t> states, list<TaskRunning_t> updatedStates,
|
||||
int coreID)
|
||||
requires
|
||||
distinct(tasks) == true &*&
|
||||
length(tasks) == length(states) &*&
|
||||
mem(startedTask, tasks) == true &*&
|
||||
foreach(remove(startedTask, tasks), readOnly_TCB_runState_IF_not_running_p(tasks, states)) &*&
|
||||
updatedStates == update(index_of(startedTask, tasks), coreID, states) &*&
|
||||
0 <= coreID &*& coreID < configNUM_CORES;
|
||||
ensures
|
||||
foreach(tasks, readOnly_TCB_runState_IF_not_running_p(tasks, updatedStates));
|
||||
{
|
||||
distinct_remove(startedTask, tasks);
|
||||
distinct_mem_remove(startedTask, tasks);
|
||||
remove_result_subset(startedTask, tasks);
|
||||
updateUnaffectedStates_in_foreach_readOnly_TCB_runState_IF_not_running
|
||||
(startedTask, tasks, remove(startedTask, tasks), states, updatedStates,
|
||||
coreID);
|
||||
|
||||
assert( foreach(remove(startedTask, tasks), readOnly_TCB_runState_IF_not_running_p(tasks, updatedStates)) );
|
||||
close readOnly_TCB_runState_IF_not_running_p(tasks, updatedStates)(startedTask);
|
||||
foreach_unremove(startedTask, tasks);
|
||||
}
|
||||
|
||||
lemma void scheduleRunning_in_foreach_readOnly_TCB_runState_IF_not_running
|
||||
(TCB_t* runningTask, list<void*> tasks,
|
||||
list<TaskRunning_t> states, list<TaskRunning_t> updatedStates,
|
||||
int coreID)
|
||||
requires
|
||||
distinct(tasks) == true &*&
|
||||
length(tasks) == length(states) &*&
|
||||
mem(runningTask, tasks) == true &*&
|
||||
(nth(index_of(runningTask, tasks), states) == coreID
|
||||
|| nth(index_of(runningTask, tasks), states) == taskTASK_YIELDING)
|
||||
&*&
|
||||
foreach(tasks, readOnly_TCB_runState_IF_not_running_p(tasks, states)) &*&
|
||||
updatedStates == update(index_of(runningTask, tasks), coreID, states) &*&
|
||||
0 <= coreID &*& coreID < configNUM_CORES;
|
||||
ensures
|
||||
foreach(tasks, readOnly_TCB_runState_IF_not_running_p(tasks, updatedStates)) &*&
|
||||
nth(index_of(runningTask, tasks), updatedStates) == coreID;
|
||||
{
|
||||
switch(tasks) {
|
||||
case nil:
|
||||
open foreach(nil, readOnly_TCB_runState_IF_not_running_p(tasks, states));
|
||||
close foreach(nil, readOnly_TCB_runState_IF_not_running_p(tasks, updatedStates));
|
||||
case cons(h, t):
|
||||
foreach_remove(runningTask, tasks);
|
||||
|
||||
distinct_remove(runningTask, tasks);
|
||||
distinct_mem_remove(runningTask, tasks);
|
||||
remove_result_subset(runningTask, tasks);
|
||||
updateUnaffectedStates_in_foreach_readOnly_TCB_runState_IF_not_running
|
||||
(runningTask, tasks, remove(runningTask, tasks),
|
||||
states, updatedStates, coreID);
|
||||
|
||||
open readOnly_TCB_runState_IF_not_running_p(tasks, states)(runningTask);
|
||||
close readOnly_TCB_runState_IF_not_running_p(tasks, updatedStates)(runningTask);
|
||||
|
||||
foreach_unremove(runningTask, tasks);
|
||||
}
|
||||
}
|
||||
@*/
|
||||
|
||||
|
||||
/*@
|
||||
lemma list<TaskRunning_t> def_state1(list<void*> tasks,
|
||||
list<TaskRunning_t> states,
|
||||
TCB_t* currentTask,
|
||||
TCB_t* readyTask)
|
||||
requires
|
||||
distinct(tasks) == true &*&
|
||||
length(tasks) == length(states) &*&
|
||||
currentTask != readyTask &*&
|
||||
mem(currentTask, tasks) == true &*&
|
||||
mem(readyTask, tasks) == true &*&
|
||||
nth(index_of(readyTask, tasks), states) == taskTASK_NOT_RUNNING;
|
||||
ensures
|
||||
result == update(index_of(currentTask, tasks), taskTASK_NOT_RUNNING, states) &*&
|
||||
nth(index_of(readyTask, tasks), result) == taskTASK_NOT_RUNNING &*&
|
||||
nth(index_of(currentTask, tasks), result) == taskTASK_NOT_RUNNING;
|
||||
{
|
||||
list<TaskRunning_t> states1 =
|
||||
update(index_of(currentTask, tasks), taskTASK_NOT_RUNNING, states);
|
||||
|
||||
mem_index_of(currentTask, tasks);
|
||||
mem_index_of(readyTask, tasks);
|
||||
nth_update(index_of(readyTask, tasks), index_of(currentTask, tasks), taskTASK_NOT_RUNNING, states);
|
||||
|
||||
return states1;
|
||||
}
|
||||
|
||||
lemma list<TaskRunning_t> def_state2(list<void*> tasks,
|
||||
list<TaskRunning_t> states,
|
||||
TCB_t* currentTask,
|
||||
TCB_t* readyTask,
|
||||
int coreID)
|
||||
requires
|
||||
distinct(tasks) == true &*&
|
||||
length(tasks) == length(states) &*&
|
||||
currentTask != readyTask &*&
|
||||
mem(currentTask, tasks) == true &*&
|
||||
mem(readyTask, tasks) == true &*&
|
||||
nth(index_of(readyTask, tasks), states) == taskTASK_NOT_RUNNING &*&
|
||||
nth(index_of(currentTask, tasks), states) != taskTASK_NOT_RUNNING &*&
|
||||
0 <= coreID &*& coreID < configNUM_CORES;
|
||||
ensures
|
||||
result ==
|
||||
update(index_of(readyTask, tasks), coreID,
|
||||
update(index_of(currentTask, tasks), taskTASK_NOT_RUNNING, states))
|
||||
&*&
|
||||
nth(index_of(readyTask, tasks), result) == coreID &*&
|
||||
nth(index_of(currentTask, tasks), result) == taskTASK_NOT_RUNNING;
|
||||
{
|
||||
list<TaskRunning_t> states1 = def_state1(tasks, states, currentTask, readyTask);
|
||||
|
||||
list<TaskRunning_t> states2 =
|
||||
update(index_of(readyTask, tasks), coreID, states1);
|
||||
|
||||
return states2;
|
||||
}
|
||||
@*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* LOCK_PREDICATES_H */
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
#ifndef PORT_CONTRACTS_H
|
||||
#define PORT_CONTRACTS_H
|
||||
|
||||
/* This file defines function contracts for the macros used to invoke
|
||||
* synchronization mechanisms, e.g., masking interrupts and acquiring locks.
|
||||
* The definitions of these macros are port-specific and involve inline
|
||||
* assembly. VeriFast cannot reason about assembly. Hence, we have to
|
||||
* abstract the assembly's semantics with these contracts.
|
||||
*
|
||||
* Note that we cannot verify that the contracts' correctness. We have to treat
|
||||
* their correctness as a proof assumption.
|
||||
*
|
||||
* Moreover, together with the invariants defined in the proof header
|
||||
* `lock_predicates.h`, the below contracts define the locking discipline that
|
||||
* our proof relies on. The file `lock_predicates.h` contains a more detailed
|
||||
* explanation of the locking discipline.
|
||||
*
|
||||
* In short:
|
||||
* - Data that is only meant to be accessed by the a specific core is protected
|
||||
* by deactivating interrupts on this core. Access permissions are expressed
|
||||
* by `coreLocalInterruptInv_p`.
|
||||
* - The task lock and the ISR lock (i.e. interrupt lock) themselves protect
|
||||
* data and code regions irrelevant to the switch-context proof. Hence,
|
||||
* the respective invariants are left abstract, cf. `taskLockInv_p` and
|
||||
* `isrLockInv_p`.
|
||||
* - FreeRTOS' locking discipline demands that the task lock is acquired before
|
||||
* and released after the ISR lock. The contracts defined below ensure that
|
||||
* we follow this locking discipline.
|
||||
* - The ready lists and the task run states (i.e. the data most important to
|
||||
* the context-switch proof) is protected by a combination of the task lock
|
||||
* and the ISR lock. That is, this data must only be accessed when both
|
||||
* locks have been acquired in the right order. The invariant
|
||||
* `taskISRLockInv_p` expresses these access rights. `lock_predicates.h`
|
||||
* defines lemmas to produce and consume this invariant. The lemmas ensure
|
||||
* that we only produce the invariant when both locks have been acquired in
|
||||
* the right order.
|
||||
*/
|
||||
|
||||
// We want our proofs to hold for an arbitrary number of cores.
|
||||
#undef portGET_CORE_ID
|
||||
#define portGET_CORE_ID() VF__get_core_num()
|
||||
|
||||
/* FreeRTOS core id is always zero based.*/
|
||||
static uint VF__get_core_num(void);
|
||||
//@ requires true;
|
||||
/*@ ensures 0 <= result &*& result < configNUM_CORES &*&
|
||||
result == coreID_f();
|
||||
@*/
|
||||
|
||||
/*@
|
||||
// This contant allows proofs to talk about the ID of the core that the
|
||||
// function we verify is running on. The verified function's contract must
|
||||
// ensure that this constant holds the value of the current core.
|
||||
fixpoint uint coreID_f();
|
||||
|
||||
lemma void coreID_f_range();
|
||||
requires true;
|
||||
ensures 0 <= coreID_f() &*& coreID_f() < configNUM_CORES;
|
||||
@*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* In FreeRTOS interrupts are masked to protect core-local data.
|
||||
* The invariant `coreLocalInterruptInv_p` expresses what data the masking
|
||||
* of interrupts protects on a specific core, cf., `lock_predicates.h`.
|
||||
*
|
||||
* Deactivating the interrupts on the current core produces the invariant
|
||||
* `coreLocalInterruptInv_p()` and thereby gives us the permission to access
|
||||
* the protected data.
|
||||
*/
|
||||
#undef portDISABLE_INTERRUPTS
|
||||
#define portDISABLE_INTERRUPTS VF__portDISABLE_INTERRUPTS
|
||||
uint32_t VF__portDISABLE_INTERRUPTS();
|
||||
//@ requires interruptState_p(?coreID, ?state);
|
||||
/*@ ensures result == state &*&
|
||||
interruptState_p(coreID, ?newState) &*&
|
||||
interruptsDisabled_f(newState) == true &*&
|
||||
interruptsDisabled_f(state) == true
|
||||
? newState == state
|
||||
: coreLocalInterruptInv_p();
|
||||
@*/
|
||||
|
||||
|
||||
/* This macro is used to restore the interrupt state (activated or deactivated)
|
||||
* to a specific value. When an invokation sets the state from deactivated to
|
||||
* activated, the invariant `coreLocalInterruptInv_p()` is consumed.
|
||||
* Thereby, we lose the permission to access the core-local data protected
|
||||
* by the deactivation of interrupts on this core.
|
||||
*/
|
||||
#undef portRESTORE_INTERRUPTS
|
||||
#define portRESTORE_INTERRUPTS(ulState) VF__portRESTORE_INTERRUPTS(ulState)
|
||||
void VF__portRESTORE_INTERRUPTS(uint32_t ulState);
|
||||
/*@ requires interruptState_p(?coreID, ?tmpState) &*&
|
||||
(interruptsDisabled_f(tmpState) == true && interruptsDisabled_f(ulState) == false)
|
||||
? coreLocalInterruptInv_p()
|
||||
: true;
|
||||
@*/
|
||||
/*@ ensures interruptState_p(coreID, ulState);
|
||||
@*/
|
||||
|
||||
|
||||
/* This macro is used to acquire the task lock. The task lock on its own
|
||||
* protects data and core regions that are not relevant to the context-switch
|
||||
* proof. Hence, an invocation produces an abstract invariant `taskLockInv_p()`
|
||||
* and updates the locking history `locked_p(...)` to log that the task log
|
||||
* has been acquired.
|
||||
*
|
||||
* FreeRTOS' locking discipline requires that the task lock must be acquired
|
||||
* before the ISR lock. The precondition `locked_p(nil)` only allows
|
||||
* invocations of this macro when no lock has been acquired, yet.
|
||||
*/
|
||||
#undef portGET_TASK_LOCK
|
||||
#define portGET_TASK_LOCK VF__portGET_TASK_LOCK
|
||||
void VF__portGET_TASK_LOCK();
|
||||
//@ requires [?f]taskLock_p() &*& locked_p(nil);
|
||||
//@ ensures taskLockInv_p() &*& locked_p( cons( pair(f, taskLockID_f()), nil) );
|
||||
|
||||
|
||||
/* This macro is used to release the task lock. An invocation consumes the
|
||||
* task lock invariant `taskLockInv_p` and updates the locking history
|
||||
* `locked_p(...)` to reflect the release.
|
||||
*
|
||||
* FreeRTOS' locking discipline demands that the task lock must be acquired
|
||||
* before and released after the ISR lock. The precondition
|
||||
* `locked_p( cons( pair(?f, taskLockID_f()), nil) )` only allows calls to this
|
||||
* macro when we can prove that we only hold the task lock.
|
||||
* */
|
||||
#undef portRELEASE_TASK_LOCK
|
||||
#define portRELEASE_TASK_LOCK VF__portRELEASE_TASK_LOCK
|
||||
void VF__portRELEASE_TASK_LOCK();
|
||||
//@ requires taskLockInv_p() &*& locked_p( cons( pair(?f, taskLockID_f()), nil) );
|
||||
//@ ensures [f]taskLock_p() &*& locked_p(nil);
|
||||
|
||||
|
||||
/* This macro is used to acquire the ISR lock (i.e. interrupt lock). An
|
||||
* invocation produces the abstract ISR lock invariant `isrLock_p` and
|
||||
* updates the locking history `locked_p(...)` to reflect that the lock has
|
||||
* been acquired.
|
||||
*/
|
||||
#undef portGET_ISR_LOCK
|
||||
#define portGET_ISR_LOCK VF__portGET_ISR_LOCK
|
||||
void VF__portGET_ISR_LOCK();
|
||||
//@ requires [?f]isrLock_p() &*& locked_p(?heldLocks);
|
||||
//@ ensures isrLockInv_p() &*& locked_p( cons( pair(f, isrLockID_f()), heldLocks) );
|
||||
|
||||
|
||||
/* This macro is used to release the ISR lock (i.e. interrupt lock). A call
|
||||
* consumes the ISR lock invariant and updates the locking history
|
||||
* `locked_p(...)` to reflect the release.
|
||||
*/
|
||||
#undef portRELEASE_ISR_LOCK
|
||||
#define portRELEASE_ISR_LOCK VF__portRELEASE_ISR_LOCK
|
||||
void VF__portRELEASE_ISR_LOCK();
|
||||
//@ requires isrLockInv_p() &*& locked_p( cons( pair(?f, isrLockID_f()), ?heldLocks) );
|
||||
//@ ensures [f]isrLock_p() &*& locked_p(heldLocks);
|
||||
|
||||
|
||||
#endif /* PORT_CONTRACTS_H */
|
||||
|
|
@ -0,0 +1,389 @@
|
|||
#ifndef READY_LIST_PREDICATES_H
|
||||
#define READY_LIST_PREDICATES_H
|
||||
|
||||
#include "single_core_proofs/scp_list_predicates.h"
|
||||
|
||||
|
||||
#include "verifast_lists_extended.h"
|
||||
|
||||
|
||||
/*@
|
||||
// This predicate represents the global ready lists, i.e., the global array
|
||||
// `pxReadyTasksLists` in `tasks.c`.
|
||||
// Each index `p` stores a cyclic doubly linked list containing all tasks
|
||||
// of priority `p` that are ready to run.
|
||||
predicate readyLists_p(list<list<struct xLIST_ITEM*> > gCellLists,
|
||||
list<list<void*> > gOwnerLists) =
|
||||
configMAX_PRIORITIES == length(gCellLists) &*&
|
||||
List_array_p(&pxReadyTasksLists, configMAX_PRIORITIES,
|
||||
gCellLists, gOwnerLists) &*&
|
||||
length(gCellLists) == length(gOwnerLists);
|
||||
|
||||
|
||||
predicate List_array_p(List_t* array, int size,
|
||||
list<list<struct xLIST_ITEM*> > cellLists,
|
||||
list<list<void*> > ownerLists) =
|
||||
size >= 0 &*&
|
||||
length(cellLists) == size &*&
|
||||
length(ownerLists) == length(cellLists) &*&
|
||||
size > 0
|
||||
? (
|
||||
cellLists == cons(?gCells, ?gTailCellLists) &*&
|
||||
ownerLists == cons(?gOwners, ?gTailOwnerLists) &*&
|
||||
pointer_within_limits(array) == true &*&
|
||||
xLIST(array, ?gLen, ?gIndex, ?gListEnd, gCells, ?gVals,
|
||||
gOwners)
|
||||
&*&
|
||||
gLen < INT_MAX &*&
|
||||
List_array_p(array + 1, size - 1, gTailCellLists, gTailOwnerLists)
|
||||
)
|
||||
: (
|
||||
cellLists == nil &*&
|
||||
ownerLists == nil
|
||||
);
|
||||
|
||||
lemma void List_array_size_positive(List_t* pxArray)
|
||||
requires List_array_p(pxArray, ?gSize, ?gCellLists, ?gOwnerLists);
|
||||
ensures
|
||||
List_array_p(pxArray, gSize, gCellLists, gOwnerLists) &*&
|
||||
gSize >= 0 &*&
|
||||
gSize == length(gCellLists) &*&
|
||||
length(gCellLists) == length(gOwnerLists);
|
||||
{
|
||||
open List_array_p(pxArray, gSize, gCellLists, gOwnerLists);
|
||||
close List_array_p(pxArray, gSize, gCellLists, gOwnerLists);
|
||||
}
|
||||
|
||||
lemma void List_array_split(List_t* array, int index)
|
||||
requires
|
||||
List_array_p(array, ?gSize, ?gCellLists, ?gOwnerLists) &*&
|
||||
0 <= index &*& index < gSize;
|
||||
ensures
|
||||
List_array_p(array, index, ?gPrefCellLists, ?gPrefOwnerLists) &*&
|
||||
gPrefCellLists == take(index, gCellLists) &*&
|
||||
gPrefOwnerLists == take(index, gOwnerLists) &*&
|
||||
pointer_within_limits(array) == true &*&
|
||||
xLIST(array + index, ?gLen, _, _, ?gCells, ?gVals, ?gOwners) &*&
|
||||
gLen < INT_MAX &*&
|
||||
gCells == nth(index, gCellLists) &*&
|
||||
gOwners == nth(index, gOwnerLists) &*&
|
||||
mem(gOwners, gOwnerLists) == true &*&
|
||||
List_array_p(array + index + 1, gSize-index-1, ?gSufCellLists, ?gSufOwnerLists) &*&
|
||||
gSufCellLists == drop(index+1, gCellLists) &*&
|
||||
gSufOwnerLists == drop(index+1, gOwnerLists);
|
||||
{
|
||||
open List_array_p(array, gSize, gCellLists, gOwnerLists);
|
||||
|
||||
if( index > 0 ) {
|
||||
List_array_split(array + 1, index - 1);
|
||||
}
|
||||
|
||||
close List_array_p(array, index, take(index, gCellLists), take(index, gOwnerLists));
|
||||
}
|
||||
|
||||
lemma void List_array_join(List_t* array)
|
||||
requires
|
||||
List_array_p(array, ?gPrefSize, ?gPrefCellLists, ?gPrefOwnerLists) &*&
|
||||
xLIST(array + gPrefSize, ?gLen, _, _, ?gCells, _, ?gOwners) &*&
|
||||
gLen < INT_MAX &*&
|
||||
pointer_within_limits(array + gPrefSize) == true &*&
|
||||
List_array_p(array + gPrefSize + 1, ?gSufSize, ?gSufCellLists, ?gSufOwnerLists);
|
||||
ensures
|
||||
List_array_p(array, ?gSize, ?gCellLists, ?gOwnerLists) &*&
|
||||
gSize == length(gCellLists) &*&
|
||||
length(gCellLists) == length(gOwnerLists) &*&
|
||||
gSize == gPrefSize + 1 + gSufSize &*&
|
||||
gCellLists == append(gPrefCellLists, cons(gCells, gSufCellLists)) &*&
|
||||
gOwnerLists == append(gPrefOwnerLists, cons(gOwners, gSufOwnerLists));
|
||||
{
|
||||
open List_array_p(array, gPrefSize, gPrefCellLists, gPrefOwnerLists);
|
||||
List_array_size_positive(array + gPrefSize + 1);
|
||||
|
||||
if( gPrefSize > 0 ) {
|
||||
List_array_join(array + 1);
|
||||
}
|
||||
|
||||
close List_array_p(array, gPrefSize + 1 + gSufSize,
|
||||
append(gPrefCellLists, cons(gCells, gSufCellLists)),
|
||||
append(gPrefOwnerLists, cons(gOwners, gSufOwnerLists)));
|
||||
}
|
||||
@*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*@
|
||||
lemma void List_array_p_index_within_limits(List_t* array, int index)
|
||||
requires List_array_p(array, ?gSize, ?gCellLists, ?gOwnerLists) &*&
|
||||
0 <= index &*& index < gSize;
|
||||
ensures List_array_p(array, gSize, gCellLists, gOwnerLists) &*&
|
||||
pointer_within_limits(&array[index]) == true;
|
||||
{
|
||||
open List_array_p(array, gSize, gCellLists, gOwnerLists);
|
||||
if( index > 0) {
|
||||
List_array_p_index_within_limits(&array[1], index-1);
|
||||
}
|
||||
close List_array_p(array, gSize, gCellLists, gOwnerLists);
|
||||
}
|
||||
@*/
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Lemmas to close the ready list predicate in different scenarios.
|
||||
/*@
|
||||
lemma void closeUnchanged_readyLists(list<list<struct xLIST_ITEM*> > cellLists,
|
||||
list<list<void*> > ownerLists)
|
||||
requires
|
||||
configMAX_PRIORITIES == length(cellLists) &*&
|
||||
configMAX_PRIORITIES == length(ownerLists) &*&
|
||||
List_array_p(&pxReadyTasksLists, ?gIndex, ?gPrefCellLists, ?gPrefOwnerLists) &*&
|
||||
gIndex < length(cellLists) &*&
|
||||
xLIST(&pxReadyTasksLists + gIndex, ?gLen, _, _, ?gCells, ?gVals, ?gOwners) &*&
|
||||
gLen < INT_MAX &*&
|
||||
gCells == nth(gIndex, cellLists) &*&
|
||||
gOwners == nth(gIndex, ownerLists) &*&
|
||||
pointer_within_limits(&pxReadyTasksLists + gIndex) == true &*&
|
||||
List_array_p(&pxReadyTasksLists + gIndex + 1, configMAX_PRIORITIES - gIndex - 1,
|
||||
?gSufCellLists, ?gSufOwnerLists) &*&
|
||||
gPrefCellLists == take(gIndex, cellLists) &*&
|
||||
gSufCellLists == drop(gIndex+1, cellLists) &*&
|
||||
gPrefOwnerLists == take(gIndex, ownerLists) &*&
|
||||
gSufOwnerLists == drop(gIndex+1, ownerLists);
|
||||
ensures
|
||||
readyLists_p(cellLists, ownerLists);
|
||||
{
|
||||
// Prove `0 <= gIndex`:
|
||||
open List_array_p(&pxReadyTasksLists, gIndex, gPrefCellLists, gPrefOwnerLists);
|
||||
close List_array_p(&pxReadyTasksLists, gIndex, gPrefCellLists, gPrefOwnerLists);
|
||||
assert( 0 <= gIndex );
|
||||
|
||||
List_array_join(&pxReadyTasksLists);
|
||||
assert( List_array_p(&pxReadyTasksLists, ?gSize, ?gCellLists2, ?gOwnerLists2) );
|
||||
|
||||
append_take_nth_drop(gIndex, cellLists);
|
||||
append_take_nth_drop(gIndex, ownerLists);
|
||||
assert( gSize == configMAX_PRIORITIES );
|
||||
assert( gCellLists2 == cellLists );
|
||||
assert( gOwnerLists2 == ownerLists );
|
||||
|
||||
close readyLists_p(cellLists, ownerLists);
|
||||
}
|
||||
|
||||
lemma void closeReordered_readyLists(list<list<struct xLIST_ITEM*> > cellLists,
|
||||
list<list<void*> > ownerLists,
|
||||
list<struct xLIST_ITEM*> reorderedCells,
|
||||
list<void*> reorderedOwners,
|
||||
list<void*> tasks)
|
||||
requires
|
||||
configMAX_PRIORITIES == length(cellLists) &*&
|
||||
configMAX_PRIORITIES == length(ownerLists) &*&
|
||||
List_array_p(&pxReadyTasksLists, ?gIndex, ?gPrefCellLists, ?gPrefOwnerLists) &*&
|
||||
gIndex < length(cellLists) &*&
|
||||
xLIST(&pxReadyTasksLists + gIndex, ?gLen, _, _, reorderedCells, _, reorderedOwners) &*&
|
||||
gLen < INT_MAX &*&
|
||||
length(reorderedCells) == length(nth(gIndex, cellLists)) &*&
|
||||
length(reorderedOwners) == length(nth(gIndex, ownerLists)) &*&
|
||||
pointer_within_limits(&pxReadyTasksLists + gIndex) == true &*&
|
||||
List_array_p(&pxReadyTasksLists + gIndex + 1, configMAX_PRIORITIES - gIndex - 1,
|
||||
?gSufCellLists, ?gSufOwnerLists) &*&
|
||||
gPrefCellLists == take(gIndex, cellLists) &*&
|
||||
gSufCellLists == drop(gIndex+1, cellLists) &*&
|
||||
gPrefOwnerLists == take(gIndex, ownerLists) &*&
|
||||
gSufOwnerLists == drop(gIndex+1, ownerLists) &*&
|
||||
forall(ownerLists, (superset)(tasks)) == true &*&
|
||||
forall(reorderedOwners, (mem_list_elem)(tasks)) == true;
|
||||
ensures
|
||||
readyLists_p(?gReorderedCellLists, ?gReorderedOwnerLists) &*&
|
||||
forall(gReorderedOwnerLists, (superset)(tasks)) == true;
|
||||
{
|
||||
// Prove that `gIndex != 0 -> gIndex > 0`
|
||||
if(gIndex != 0) {
|
||||
open List_array_p(&pxReadyTasksLists, gIndex, gPrefCellLists, gPrefOwnerLists);
|
||||
close List_array_p(&pxReadyTasksLists, gIndex, gPrefCellLists, gPrefOwnerLists);
|
||||
assert( gIndex > 0 );
|
||||
}
|
||||
|
||||
List_array_join(&pxReadyTasksLists);
|
||||
assert( List_array_p(&pxReadyTasksLists, configMAX_PRIORITIES,
|
||||
?gReorderedCellLists, ?gReorderedOwnerLists) );
|
||||
|
||||
if(gIndex == 0) {
|
||||
assert( nth(0, gReorderedCellLists) == reorderedCells );
|
||||
} else {
|
||||
nth_take(0, gIndex, cellLists);
|
||||
assert( nth(0, gReorderedCellLists) == nth(0, gPrefCellLists) );
|
||||
assert( nth(0, gPrefCellLists) == nth(0, cellLists) );
|
||||
}
|
||||
assert( length(nth(0, gReorderedCellLists)) == length(nth(0, cellLists)) );
|
||||
|
||||
close readyLists_p(gReorderedCellLists, gReorderedOwnerLists);
|
||||
|
||||
|
||||
// Below we prove `forall(gReorderedOwnerLists, (superset)(tasks)) == true`
|
||||
forall_take(ownerLists, (superset)(tasks), gIndex);
|
||||
forall_drop(ownerLists, (superset)(tasks), gIndex+1);
|
||||
assert( forall(gPrefOwnerLists, (superset)(tasks)) == true );
|
||||
assert( forall(gSufOwnerLists, (superset)(tasks)) == true );
|
||||
forall_mem_implies_superset(tasks, reorderedOwners);
|
||||
assert( superset(tasks, reorderedOwners) == true );
|
||||
assert( forall(singleton(reorderedOwners), (superset)(tasks)) == true );
|
||||
assert( forall(cons(reorderedOwners, gSufOwnerLists), (superset)(tasks)) == true );
|
||||
|
||||
forall_append(gPrefOwnerLists, cons(reorderedOwners, gSufOwnerLists),
|
||||
(superset)(tasks));
|
||||
}
|
||||
@*/
|
||||
|
||||
|
||||
/*@
|
||||
predicate VF_reordeReadyList__ghost_args(list<void*> tasks,
|
||||
list<list<struct xLIST_ITEM*> > cellLists,
|
||||
list<list<void*> > ownerLists,
|
||||
int offset)
|
||||
= true;
|
||||
@*/
|
||||
|
||||
void VF_reordeReadyList(List_t* pxReadyList, ListItem_t * pxTaskItem)
|
||||
/*@ requires
|
||||
// ghost arguments
|
||||
VF_reordeReadyList__ghost_args(?gTasks, ?gCellLists, ?gOwnerLists, ?gOffset)
|
||||
&*&
|
||||
length(gCellLists) == configMAX_PRIORITIES &*&
|
||||
length(gOwnerLists) == configMAX_PRIORITIES &*&
|
||||
0 <= gOffset &*& gOffset < length(gCellLists)
|
||||
&*&
|
||||
// current ready list
|
||||
xLIST(pxReadyList, ?gSize, ?gIndex, ?gEnd, ?gCells, ?gVals, ?gOwners) &*&
|
||||
pxReadyList == &pxReadyTasksLists + gOffset &*&
|
||||
pointer_within_limits(pxReadyList) == true &*&
|
||||
gSize < INT_MAX &*&
|
||||
gEnd != pxTaskItem &*&
|
||||
mem(pxTaskItem, gCells) == true &*&
|
||||
gCells == nth(gOffset, gCellLists) &*&
|
||||
gOwners == nth(gOffset, gOwnerLists)
|
||||
&*&
|
||||
// prefix and suffix of ready lists array
|
||||
List_array_p(&pxReadyTasksLists, gOffset, ?gPrefCellLists, ?gPrefOwnerLists) &*&
|
||||
List_array_p(&pxReadyTasksLists + gOffset + 1, configMAX_PRIORITIES - gOffset - 1,
|
||||
?gSufCellLists, ?gSufOwnerLists)
|
||||
&*&
|
||||
gPrefCellLists == take(gOffset, gCellLists) &*&
|
||||
gSufCellLists == drop(gOffset+1, gCellLists) &*&
|
||||
gPrefOwnerLists == take(gOffset, gOwnerLists) &*&
|
||||
gSufOwnerLists == drop(gOffset+1, gOwnerLists) &*&
|
||||
forall(gOwnerLists, (superset)(gTasks)) == true &*&
|
||||
subset(gOwners, gTasks) == true;
|
||||
@*/
|
||||
/*@ ensures
|
||||
readyLists_p(?gReorderedCellLists, ?gReorderedOwnerLists) &*&
|
||||
length(gReorderedCellLists) == length(gCellLists) &*&
|
||||
length(gReorderedOwnerLists) == length(gOwnerLists) &*&
|
||||
length(gReorderedCellLists) == length(gReorderedOwnerLists) &*&
|
||||
forall(gReorderedOwnerLists, (superset)(gTasks)) == true;
|
||||
@*/
|
||||
{
|
||||
//@ open VF_reordeReadyList__ghost_args(_, _, _, _);
|
||||
|
||||
// Proving `∀o ∈ gOwners. o ∈ gTasks`
|
||||
//@ forall_mem(gOwners, gOwnerLists, (superset)(gTasks));
|
||||
//@ assert( superset(gTasks, gOwners) == true );
|
||||
//@ subset_implies_forall_mem(gOwners, gTasks);
|
||||
//@ assert( forall(gOwners, (mem_list_elem)(gTasks)) == true );
|
||||
|
||||
// Proving `length(gCells) == length(gOwners) == gSize + 1`:
|
||||
//@ open xLIST(pxReadyList, gSize, gIndex, gEnd, gCells, gVals, gOwners);
|
||||
//@ close xLIST(pxReadyList, gSize, gIndex, gEnd, gCells, gVals, gOwners);
|
||||
//@ assert( length(gCells) == length(gOwners) );
|
||||
//@ assert( length(gCells) == gSize +1 );
|
||||
|
||||
//@ close exists(pxReadyList);
|
||||
uxListRemove( pxTaskItem );
|
||||
//@ assert( xLIST(pxReadyList, gSize-1, ?gIndex2, gEnd, ?gCells2, ?gVals2, ?gOwners2) );
|
||||
//@ assert( xLIST_ITEM(pxTaskItem, _, _, _, ?gTaskItem_owner, _) );
|
||||
|
||||
// Proving `length(gCell2) == length(gOwners2) == gSize` and `gIndex2 ∈ gCells2`:
|
||||
//@ open xLIST(pxReadyList, gSize-1, gIndex2, gEnd, gCells2, gVals2, gOwners2);
|
||||
//@ close xLIST(pxReadyList, gSize-1, gIndex2, gEnd, gCells2, gVals2, gOwners2);
|
||||
//@ assert( length(gCells2) == gSize );
|
||||
//@ assert( length(gOwners2) == gSize );
|
||||
//@ assert( mem(gIndex2, gCells2) == true );
|
||||
|
||||
// Proving `gTaskItem_owner ∈ gOwners`:
|
||||
//@ assert( gTaskItem_owner == nth(index_of(pxTaskItem, gCells), gOwners) );
|
||||
//@ mem_index_of(pxTaskItem, gCells);
|
||||
//@ nth_implies_mem(index_of(pxTaskItem, gCells), gOwners);
|
||||
//@ assert( mem(gTaskItem_owner, gOwners) == true );
|
||||
|
||||
// Proving `gTaskItem_owner ∈ gTasks`:
|
||||
//@ forall_mem(gTaskItem_owner, gOwners, (mem_list_elem)(gTasks));
|
||||
//@ assert( mem(gTaskItem_owner, gTasks) == true );
|
||||
|
||||
// Proving `gOwners2 ⊆ gTasks`
|
||||
//@ assert( forall(gOwners, (mem_list_elem)(gTasks)) == true );
|
||||
//@ forall_remove_nth(index_of(pxTaskItem, gCells), gOwners, (mem_list_elem)(gTasks));
|
||||
//@ assert( forall(gOwners2, (mem_list_elem)(gTasks)) == true );
|
||||
//@ forall_mem_implies_superset(gTasks, gOwners2);
|
||||
//@ assert( subset(gOwners2, gTasks) == true );
|
||||
|
||||
vListInsertEnd( pxReadyList, pxTaskItem );
|
||||
//@ assert( xLIST(pxReadyList, gSize, ?gIndex3, gEnd, ?gCells3, ?gVals3, ?gOwners3) );
|
||||
|
||||
// Proving `gOwners3 ⊆ gTasks` and `length(gOwners3) == length(gOwners)`:
|
||||
// We must handle the case split introduced by postcondition of `vListInsertEnd`.
|
||||
/*@
|
||||
if( gIndex2 == gEnd ) {
|
||||
assert( gCells3 == append(gCells2, singleton(pxTaskItem)) );
|
||||
assert( gOwners3 == append(gOwners2, singleton(gTaskItem_owner)) );
|
||||
|
||||
assert( subset(singleton(gTaskItem_owner), gTasks) == true );
|
||||
subset_append(gOwners2, singleton(gTaskItem_owner), gTasks);
|
||||
} else {
|
||||
int i = index_of(gIndex2, gCells2);
|
||||
assert( gCells3 == append(take(i, gCells2),
|
||||
append(singleton(pxTaskItem),
|
||||
drop(i, gCells2))) );
|
||||
list<void*> ot = append(singleton(gTaskItem_owner), drop(i, gOwners2));
|
||||
assert( gOwners3 == append(take(i, gOwners2), ot) );
|
||||
|
||||
|
||||
// Proving `take(i, gOwners2) ⊆ gTasks`:
|
||||
subset_take(i, gOwners2);
|
||||
assert( subset(take(i, gOwners2), gOwners2) == true );
|
||||
assert( subset(gOwners2, gTasks) == true );
|
||||
subset_trans(take(i, gOwners2), gOwners2, gTasks);
|
||||
assert( subset(take(i, gOwners2), gTasks) == true );
|
||||
|
||||
// Proving `drop(i, gOwners2) ⊆ gTasks`:
|
||||
subset_drop(i, gOwners2);
|
||||
subset_trans(drop(i, gOwners2), gOwners2, gTasks);
|
||||
assert( subset(drop(i, gOwners2), gTasks) == true );
|
||||
|
||||
// Proving `gOwners3 ⊆ gTasks`:
|
||||
subset_append(singleton(gTaskItem_owner), drop(i, gOwners2), gTasks);
|
||||
subset_append(take(i, gOwners2), ot, gTasks);
|
||||
assert( subset(gOwners3, gTasks) == true );
|
||||
|
||||
// Proving `length(gOwners3) == length(gOwners)`:
|
||||
mem_index_of(gIndex2, gCells2);
|
||||
append_take_nth_drop(i, gOwners2);
|
||||
assert( length(gOwners3) == gSize+1 );
|
||||
}
|
||||
@*/
|
||||
//@ assert( subset(gOwners3, gTasks) == true );
|
||||
//@ assert( length(gOwners3) == length(gOwners) );
|
||||
|
||||
//@ subset_implies_forall_mem(gOwners3, gTasks);
|
||||
//@ assert( forall(gOwners3, (mem_list_elem)(gTasks)) == true );
|
||||
|
||||
//@ closeReordered_readyLists(gCellLists, gOwnerLists, gCells3, gOwners3, gTasks);
|
||||
|
||||
// Proving that reordering preserves the length of cell lists and owner lists:
|
||||
//@ open readyLists_p(?gReorderedCellLists, ?gReorderedOwnerLists);
|
||||
//@ close readyLists_p(gReorderedCellLists, gReorderedOwnerLists);
|
||||
//@ assert( length(gReorderedCellLists) == length(gCellLists) );
|
||||
//@ assert( length(gReorderedOwnerLists) == length(gOwnerLists) );
|
||||
//@ assert( length(gReorderedCellLists) == length(gReorderedOwnerLists) );
|
||||
}
|
||||
#endif /* READY_LIST_PREDICATES_H */
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
This directory contains proof artifacts written by Aalok Thakkar and Nathan Chong.
|
||||
See the following pull request:
|
||||
https://github.com/FreeRTOS/FreeRTOS/pull/836
|
||||
|
|
@ -0,0 +1,630 @@
|
|||
/*
|
||||
* The code below has been taken from:
|
||||
* pull request:
|
||||
* https://github.com/FreeRTOS/FreeRTOS/pull/836
|
||||
* file:
|
||||
* FreeRTOS/Test/VeriFast/include/proof/list.h
|
||||
*
|
||||
* The file has been converted from a ghost header
|
||||
* into a regular header.
|
||||
* It has also been renamed from `common.h` into
|
||||
* `scp_common.h`.
|
||||
* The include guards have been updated accordingly.
|
||||
*
|
||||
* All changes to the proofs, predicates, etc.
|
||||
* are guarded by a check that `VERIFAST_SINGLE_CORE` is
|
||||
* NOT defined.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* FreeRTOS V202112.00
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* https://www.FreeRTOS.org
|
||||
* https://github.com/FreeRTOS
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCP_COMMON_H
|
||||
#define SCP_COMMON_H
|
||||
|
||||
/*@
|
||||
#include <listex.gh>
|
||||
|
||||
fixpoint list<t> rotate_left<t>(int n, list<t> xs) {
|
||||
return append(drop(n, xs), take(n, xs));
|
||||
}
|
||||
|
||||
fixpoint list<t> singleton<t>(t x) {
|
||||
return cons(x, nil);
|
||||
}
|
||||
|
||||
lemma void note(bool b)
|
||||
requires b;
|
||||
ensures b;
|
||||
{}
|
||||
|
||||
lemma_auto void rotate_length<t>(int n, list<t> xs)
|
||||
requires 0 <= n && n <= length(xs);
|
||||
ensures length(rotate_left(n, xs)) == length(xs);
|
||||
{}
|
||||
|
||||
lemma void take_length_eq<t>(int k, list<t> xs, list<t> ys)
|
||||
requires 0 <= k && k <= length(xs) && take(k, xs) == ys;
|
||||
ensures length(ys) == k;
|
||||
{}
|
||||
|
||||
lemma void leq_bound(int x, int b)
|
||||
requires b <= x && x <= b;
|
||||
ensures x == b;
|
||||
{}
|
||||
|
||||
lemma void mul_mono_l_strict(int x, int y, int n)
|
||||
requires 0 < n &*& x < y;
|
||||
ensures x * n < y * n;
|
||||
{
|
||||
for (int i = 1; i < n; i++)
|
||||
invariant i <= n &*& x * i < y * i;
|
||||
decreases n - i;
|
||||
{}
|
||||
}
|
||||
|
||||
lemma void div_leq(int x, int y, int n)
|
||||
requires 0 < n && x * n <= y * n;
|
||||
ensures x <= y;
|
||||
{
|
||||
assert x * n <= y * n;
|
||||
if (x <= y) {
|
||||
mul_mono_l(x,y,n);
|
||||
} else {
|
||||
mul_mono_l_strict(y,x,n); //< contradiction
|
||||
}
|
||||
}
|
||||
|
||||
lemma void div_lt(int x, int y, int n)
|
||||
requires 0 < n && x * n < y * n;
|
||||
ensures x < y;
|
||||
{
|
||||
assert x * n <= y * n;
|
||||
if (x == y) {
|
||||
} else if (x <= y) {
|
||||
mul_mono_l(x,y,n);
|
||||
} else {
|
||||
assert y < x;
|
||||
mul_mono_l(y,x,n); //< contradiction
|
||||
}
|
||||
}
|
||||
|
||||
lemma_auto void mod_same(int n)
|
||||
requires 0 < n;
|
||||
ensures n % n == 0;
|
||||
{
|
||||
div_rem_nonneg(n, n);
|
||||
if (n / n < 1) {} else if (n / n > 1) {
|
||||
mul_mono_l(2, n/n, n);
|
||||
} else {}
|
||||
}
|
||||
|
||||
lemma void mod_lt(int x, int n)
|
||||
requires 0 <= x && x < n;
|
||||
ensures x % n == x;
|
||||
{
|
||||
div_rem_nonneg(x, n);
|
||||
if (x / n > 0) {
|
||||
mul_mono_l(1, x / n, n);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
lemma void mod_plus_one(int x, int y, int n)
|
||||
requires 0 <= y && 0 < n && x == (y % n);
|
||||
ensures ((x+1) % n) == ((y+1) % n);
|
||||
{
|
||||
div_rem_nonneg(y, n);
|
||||
div_rem_nonneg(y+1, n);
|
||||
div_rem_nonneg(y%n+1, n);
|
||||
if (y%n+1 < n) {
|
||||
mod_lt(y%n+1, n);
|
||||
assert y%n == y - y/n*n;
|
||||
assert (y+1)%n == y + 1 - (y + 1)/n*n;
|
||||
if ((y+1)/n > y/n) {
|
||||
mul_mono_l(y/n + 1, (y+1)/n, n);
|
||||
} else if ((y+1)/n < y/n) {
|
||||
mul_mono_l((y+1)/n + 1, y/n, n);
|
||||
}
|
||||
assert y - (y+1)/n*n == y - y/n*n;
|
||||
assert y+1 - (y+1)/n*n == y - y/n*n + 1;
|
||||
assert (y+1)%n == y%n + 1;
|
||||
} else {
|
||||
assert y%n+1 == n;
|
||||
assert (y%n+1)%n == 0;
|
||||
if (y/n + 1 < (y+1)/n) {
|
||||
mul_mono_l(y/n + 2, (y+1)/n, n);
|
||||
} else if (y/n + 1 > (y+1)/n) {
|
||||
mul_mono_l((y+1)/n, y/n, n);
|
||||
}
|
||||
assert (y+1)/n == y/n + 1;
|
||||
note((y+1)/n*n == (y/n + 1)*n);
|
||||
assert (y+1)%n == 0;
|
||||
}
|
||||
assert (y%n+1)%n == (y+1)%n;
|
||||
}
|
||||
|
||||
lemma void mod_mul(int x, int n, int y)
|
||||
requires 0 < n && 0 <= x && 0 <= y;
|
||||
ensures (x*n + y)%n == y%n;
|
||||
{
|
||||
mul_mono_l(0, x, n);
|
||||
div_rem_nonneg(x*n+y, n);
|
||||
div_rem_nonneg(y, n);
|
||||
|
||||
if ((x*n+y)/n > x + y/n) {
|
||||
mul_mono_l(x + y/n + 1, (x*n+y)/n, n);
|
||||
} else if ((x*n+y)/n < x + y/n) {
|
||||
mul_mono_l((x*n+y)/n + 1, x + y/n, n);
|
||||
}
|
||||
note((x*n + y)/n == x + y/n);
|
||||
note((x*n + y)/n*n == (x + y/n)*n);
|
||||
}
|
||||
|
||||
lemma void mod_plus_distr(int x, int y, int n)
|
||||
requires 0 < n && 0 <= x && 0 <= y;
|
||||
ensures ((x % n) + y) % n == (x + y) % n;
|
||||
{
|
||||
div_rem_nonneg(x, n);
|
||||
div_rem_nonneg(x%n+y, n);
|
||||
div_rem_nonneg(x+y, n);
|
||||
|
||||
assert x == x/n*n + x%n;
|
||||
mod_mul(x/n, n, x%n + y);
|
||||
}
|
||||
|
||||
lemma_auto void mod_mod(int x, int n)
|
||||
requires 0 < n && 0 <= x;
|
||||
ensures (x % n) % n == (x % n);
|
||||
{
|
||||
mod_plus_distr(x, 0, n);
|
||||
}
|
||||
|
||||
lemma void mod_plus(int x, int y, int n);
|
||||
requires 0 < n && 0 <= x && 0 <= y;
|
||||
ensures (x + y) % n == ((x % n) + (y % n)) % n;
|
||||
|
||||
lemma_auto void mod_range(int x, int n)
|
||||
requires 0 <= x && 0 < n;
|
||||
ensures 0 <= (x % n) && (x % n) < n;
|
||||
{
|
||||
div_rem_nonneg(x, n);
|
||||
}
|
||||
|
||||
lemma void head_append<t>(list<t> xs, list<t> ys)
|
||||
requires 0 < length(xs);
|
||||
ensures head(append(xs, ys)) == head(xs);
|
||||
{
|
||||
switch(xs)
|
||||
{
|
||||
case cons(c, cs):
|
||||
case nil:
|
||||
}
|
||||
}
|
||||
|
||||
lemma void drop_take_singleton<t>(int i, list<t> xs)
|
||||
requires 0 < i && i < length(xs);
|
||||
ensures drop(i-1, take(i, xs)) == singleton(nth(i-1, xs));
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
if (i == 1) {
|
||||
} else {
|
||||
drop_take_singleton(i-1, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void take_singleton<t>(int i, list<t> xs)
|
||||
requires 0 <= i && i < length(xs);
|
||||
ensures append(take(i, xs), singleton(nth(i, xs))) == take(i+1, xs);
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
if (i == 0) {
|
||||
} else {
|
||||
take_singleton(i-1, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void drop_update_le<t>(int i, int j, t x, list<t> xs)
|
||||
requires 0 <= i && i <= j && j < length(xs);
|
||||
ensures drop(i, update(j, x, xs)) == update(j - i, x, drop(i, xs));
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
if (i == 0) {
|
||||
} else {
|
||||
drop_update_le(i - 1, j - 1, x, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void drop_update_ge<t>(int i, int j, t x, list<t> xs)
|
||||
requires 0 <= j && j < i && i < length(xs);
|
||||
ensures drop(i, update(j, x, xs)) == drop(i, xs);
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
if (j == 0) {
|
||||
} else {
|
||||
drop_update_ge(i - 1, j - 1, x, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void take_update_le<t>(int i, int j, t x, list<t> xs)
|
||||
requires 0 <= i && i <= j;
|
||||
ensures take(i, update(j, x, xs)) == take(i, xs);
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
if (i == 0) {
|
||||
} else {
|
||||
take_update_le(i - 1, j - 1, x, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void take_update_ge<t>(int i, int j, t x, list<t> xs)
|
||||
requires 0 <= j && j < i && i <= length(xs);
|
||||
ensures take(i, update(j, x, xs)) == update(j, x, take(i, xs));
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
if (j == 0) {
|
||||
} else {
|
||||
take_update_ge(i - 1, j - 1, x, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void update_eq_append<t>(int i, t x, list<t> xs)
|
||||
requires 0 <= i && i < length(xs);
|
||||
ensures update(i, x, xs) == append(take(i, xs), cons(x, drop(i + 1, xs)));
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
if (i == 0) {
|
||||
} else {
|
||||
update_eq_append(i - 1, x, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void take_append_ge<t>(int n, list<t> xs, list<t> ys)
|
||||
requires length(xs) <= n;
|
||||
ensures take(n, append(xs, ys)) == append(xs, take(n - length(xs), ys));
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
take_append_ge(n - 1, xs0, ys);
|
||||
}
|
||||
}
|
||||
|
||||
lemma void drop_drop<t>(int m, int n, list<t> xs)
|
||||
requires 0 <= m && 0 <= n;
|
||||
ensures drop(m, drop(n, xs)) == drop(m+n, xs);
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
if (n == 0) {} else {
|
||||
drop_drop(m, n-1, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void take_take<t>(int m, int n, list<t> xs)
|
||||
requires 0 <= m && m <= n && n <= length(xs);
|
||||
ensures take(m, take(n, xs)) == take(m, xs);
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
if (m == 0) {} else {
|
||||
take_take(m - 1, n - 1, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma_auto void take_head<t>(list<t> xs)
|
||||
requires 0 < length(xs);
|
||||
ensures take(1, xs) == singleton(head(xs));
|
||||
{
|
||||
switch(xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
}
|
||||
}
|
||||
|
||||
// Following lemma from `verifast/bin/rt/_list.java`
|
||||
lemma void remove_remove_nth<t>(list<t> xs, t x)
|
||||
requires mem(x, xs) == true;
|
||||
ensures remove(x, xs) == remove_nth(index_of(x, xs), xs);
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(h, tl):
|
||||
if (x == h) {
|
||||
assert index_of(x, xs) == 0;
|
||||
} else {
|
||||
remove_remove_nth(tl, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void mem_take_false<t>(t x, int n, list<t> xs)
|
||||
requires mem(x, xs) == false;
|
||||
ensures mem(x, take(n, xs)) == false;
|
||||
{
|
||||
switch (xs) {
|
||||
case nil:
|
||||
case cons(x0, xs0):
|
||||
if (x0 != x && n != 0)
|
||||
mem_take_false(x, n - 1, xs0);
|
||||
}
|
||||
}
|
||||
|
||||
// Following lemma from `verifast/bin/rt/_list.java`. Renamed to
|
||||
// avoid clash with listex.c's nth_drop lemma.
|
||||
lemma void nth_drop2<t>(list<t> vs, int i)
|
||||
requires 0 <= i && i < length(vs);
|
||||
ensures nth(i, vs) == head(drop(i, vs));
|
||||
{
|
||||
switch (vs) {
|
||||
case nil:
|
||||
case cons(v, vs0):
|
||||
if (i == 0) {
|
||||
} else {
|
||||
nth_drop2(vs0, i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void enq_lemma<t>(int k, int i, list<t> xs, list<t> ys, t z)
|
||||
requires 0 <= k && 0 <= i && 0 < length(xs) && k < length(xs) && i < length(xs) && take(k, rotate_left(i, xs)) == ys;
|
||||
ensures take(k+1, rotate_left(i, update((i+k)%length(xs), z, xs))) == append(ys, cons(z, nil));
|
||||
{
|
||||
int j = (i+k)%length(xs);
|
||||
assert take(k, append(drop(i, xs), take(i, xs))) == ys;
|
||||
if (i + k < length(xs)) {
|
||||
mod_lt(i + k, length(xs));
|
||||
assert j == i + k;
|
||||
drop_update_le(i, i + k, z, xs);
|
||||
assert drop(i, update(i + k, z, xs)) == update(k, z, drop(i, xs));
|
||||
take_update_le(i, i + k, z, xs);
|
||||
assert take(i, update(i + k, z, xs)) == take(i, xs);
|
||||
take_append(k+1, update(k, z, drop(i, xs)), take(i, xs));
|
||||
assert take(k+1, append(update(k, z, drop(i, xs)), take(i, xs))) == take(k+1, update(k, z, drop(i, xs)));
|
||||
update_eq_append(k, z, drop(i, xs));
|
||||
assert update(k, z, drop(i, xs)) == append(take(k, drop(i, xs)), cons(z, drop(k + 1, drop(i, xs))));
|
||||
take_append_ge(k+1, take(k, drop(i, xs)), cons(z, drop(k + 1, drop(i, xs))));
|
||||
assert take(k+1, append(take(k, drop(i, xs)), cons(z, drop(k + 1, drop(i, xs))))) ==
|
||||
append(take(k, drop(i, xs)), {z});
|
||||
take_append(k, drop(i, xs), take(i, xs));
|
||||
assert take(k+1, append(take(k, drop(i, xs)), cons(z, drop(k + 1, drop(i, xs))))) ==
|
||||
append(take(k, append(drop(i, xs), take(i, xs))), {z});
|
||||
assert take(k+1, update(k, z, drop(i, xs))) ==
|
||||
append(take(k, append(drop(i, xs), take(i, xs))), {z});
|
||||
assert take(k+1, append(update(k, z, drop(i, xs)), take(i, xs))) ==
|
||||
append(take(k, append(drop(i, xs), take(i, xs))), {z});
|
||||
assert take(k+1, append(drop(i, update(i + k, z, xs)), take(i, update(i + k, z, xs)))) ==
|
||||
append(take(k, append(drop(i, xs), take(i, xs))), {z});
|
||||
|
||||
} else {
|
||||
assert i + k < 2 * length(xs);
|
||||
div_rem_nonneg(i + k, length(xs));
|
||||
if ((i + k) / length(xs) > 1) {
|
||||
mul_mono_l(2, (i + k) / length(xs), length(xs));
|
||||
} else if ((i + k) / length(xs) < 1) {
|
||||
mul_mono_l((i + k) / length(xs), 0, length(xs));
|
||||
}
|
||||
assert j == i + k - length(xs);
|
||||
assert j < i;
|
||||
drop_update_ge(i, j, z, xs);
|
||||
assert drop(i, update(j, z, xs)) == drop(i, xs);
|
||||
take_update_ge(i, j, z, xs);
|
||||
assert update(j, z, take(i, xs)) == take(i, update(j, z, xs));
|
||||
take_append_ge(k+1, drop(i, xs), take(i, update(j, z, xs)));
|
||||
assert take(k+1, append(drop(i, update(j, z, xs)), take(i, update(j, z, xs)))) ==
|
||||
append(drop(i, xs), take(j+1, update(j, z, take(i, xs))));
|
||||
update_eq_append(j, z, take(i, xs));
|
||||
assert update(j, z, take(i, xs)) == append(take(j, take(i, xs)), cons(z, drop(j + 1, take(i, xs))));
|
||||
take_take(j, i, xs);
|
||||
assert update(j, z, take(i, xs)) == append(take(j, xs), cons(z, drop(j+1, take(i, xs))));
|
||||
take_append_ge(j+1, take(j, xs), cons(z, drop(j+1, take(i, xs))));
|
||||
assert append(drop(i, xs), take(j+1, update(j, z, take(i, xs)))) ==
|
||||
append(drop(i, xs), append(take(j, xs), {z}));
|
||||
take_append_ge(k, drop(i, xs), take(i, xs));
|
||||
append_assoc(drop(i, xs), take(j, xs), {z});
|
||||
assert append(drop(i, xs), append(take(j, xs), {z})) ==
|
||||
append(take(k, append(drop(i, xs), take(i, xs))), {z});
|
||||
assert append(drop(i, xs), take(j+1, update(j, z, take(i, xs)))) ==
|
||||
append(take(k, append(drop(i, xs), take(i, xs))), {z});
|
||||
}
|
||||
assert take(k+1, append(drop(i, update(j, z, xs)), take(i, update(j, z, xs)))) ==
|
||||
append(take(k, append(drop(i, xs), take(i, xs))), {z});
|
||||
assert take(k+1, append(drop(i, update(j, z, xs)), take(i, update(j, z, xs)))) == append(ys, {z});
|
||||
}
|
||||
|
||||
lemma void front_enq_lemma<t>(int k, int i, list<t> xs, list<t> ys, t z)
|
||||
requires 0 < length(xs) && 0 <= k && k < length(xs) && 0 <= i && i < length(xs) && take(k, rotate_left((i+1)%length(xs), xs)) == ys;
|
||||
ensures take(k+1, rotate_left(i, update(i, z, xs))) == cons(z, ys);
|
||||
{
|
||||
int n = length(xs);
|
||||
if (i+1 < n) {
|
||||
mod_lt(i+1, n);
|
||||
assert i < n;
|
||||
assert take(k+1, rotate_left(i, update(i, z, xs))) ==
|
||||
take(k+1, append(drop(i, update(i, z, xs)), take(i, update(i, z, xs))));
|
||||
drop_update_le(i, i, z, xs);
|
||||
take_update_le(i, i, z, xs);
|
||||
assert take(k+1, append(drop(i, update(i, z, xs)), take(i, update(i, z, xs)))) ==
|
||||
take(k+1, append(update(0, z, drop(i, xs)), take(i, xs)));
|
||||
update_eq_append(0, z, drop(i, xs));
|
||||
assert update(0, z, drop(i, xs)) == cons(z, drop(1, drop(i, xs)));
|
||||
drop_drop(1, i, xs);
|
||||
assert take(k+1, append(update(0, z, drop(i, xs)), take(i, xs))) ==
|
||||
take(k+1, append(cons(z, drop(i+1, xs)), take(i, xs)));
|
||||
assert take(k+1, append(cons(z, drop(i+1, xs)), take(i, xs))) ==
|
||||
cons(z, take(k, append(drop(i+1, xs), take(i, xs))));
|
||||
|
||||
assert ys == take(k, rotate_left(i+1, xs));
|
||||
assert ys == take(k, append(drop(i+1, xs), take(i+1, xs)));
|
||||
if (k <= length(drop(i+1, xs))) {
|
||||
take_append(k, drop(i+1, xs), take(i+1, xs));
|
||||
take_append(k, drop(i+1, xs), take(i, xs));
|
||||
} else {
|
||||
take_append_ge(k, drop(i+1, xs), take(i+1, xs));
|
||||
take_append_ge(k, drop(i+1, xs), take(i, xs));
|
||||
|
||||
assert (i+1) + k < 2 * n;
|
||||
div_rem_nonneg((i+1) + k, n);
|
||||
if (((i+1) + k) / n > 1) {
|
||||
mul_mono_l(2, ((i+1) + k) / n, n);
|
||||
} else if (((i+1) + k) / n < 1) {
|
||||
mul_mono_l(((i+1) + k) / n, 0, n);
|
||||
}
|
||||
int j = ((i+1)+k)%n;
|
||||
assert j <= i;
|
||||
int l = length(drop(i+1, xs));
|
||||
assert l == n - i - 1;
|
||||
take_take(k - l, i + 1, xs);
|
||||
take_take(k - l, i, xs);
|
||||
}
|
||||
} else {
|
||||
assert i == (n-1);
|
||||
assert (i + 1) % n == 0;
|
||||
drop_update_le(i, i, z, xs);
|
||||
update_eq_append(0, z, xs);
|
||||
assert take(k+1, rotate_left(i, update(i, z, xs))) ==
|
||||
take(k+1, append(drop(i, update(i, z, xs)), take(i, update(i, z, xs))));
|
||||
drop_update_le(i, i, z, xs);
|
||||
assert take(k+1, rotate_left(i, update(i, z, xs))) ==
|
||||
take(k+1, append(update(0, z, drop(i, xs)), take(i, update(i, z, xs))));
|
||||
update_eq_append(0, z, drop(i, xs));
|
||||
assert take(k+1, rotate_left(i, update(i, z, xs))) ==
|
||||
take(k+1, append(cons(z, drop(1, drop(i, xs))), take(i, update(i, z, xs))));
|
||||
drop_drop(1, i, xs);
|
||||
assert take(k+1, rotate_left(i, update(i, z, xs))) ==
|
||||
take(k+1, append(cons(z, nil), take(i, update(i, z, xs))));
|
||||
take_update_le(i, i, z, xs);
|
||||
assert take(k+1, rotate_left(i, update(i, z, xs))) ==
|
||||
cons(z, take(k, take(i, xs)));
|
||||
take_take(k, i, xs);
|
||||
assert take(k+1, rotate_left(i, update(i, z, xs))) == cons(z, ys);
|
||||
}
|
||||
}
|
||||
|
||||
lemma void deq_lemma<t>(int k, int i, list<t> xs, list<t> ys, t z)
|
||||
requires 0 < k && k <= length(xs) && 0 <= i && i < length(xs) && take(k, rotate_left(i, xs)) == ys && z == head(ys);
|
||||
ensures take(k-1, rotate_left((i+1)%length(xs), xs)) == tail(ys);
|
||||
{
|
||||
int j = (i+1)%length(xs);
|
||||
drop_n_plus_one(i, xs);
|
||||
assert tail(take(k, append(drop(i, xs), take(i, xs)))) == take(k-1, append(drop(i+1, xs), take(i, xs)));
|
||||
if (i+1 < length(xs)) {
|
||||
mod_lt(i+1, length(xs));
|
||||
assert j == i+1;
|
||||
if (k-1 <= length(xs)-j) {
|
||||
take_append(k-1, drop(j, xs), take(j, xs));
|
||||
take_append(k-1, drop(j, xs), take(i, xs));
|
||||
} else {
|
||||
assert k+i > length(xs);
|
||||
take_append_ge(k-1, drop(j, xs), take(j, xs));
|
||||
take_append_ge(k-1, drop(j, xs), take(i, xs));
|
||||
assert k-1-(length(xs)-j) == k+i-length(xs);
|
||||
assert k+i-length(xs) <= i;
|
||||
take_take(k+i-length(xs), j, xs);
|
||||
take_take(k+i-length(xs), i, xs);
|
||||
assert take(k+i-length(xs), take(j, xs)) == take(k+i-length(xs), take(i, xs));
|
||||
}
|
||||
} else {
|
||||
assert i+1 == length(xs);
|
||||
assert (i+1)%length(xs) == 0;
|
||||
assert j == 0;
|
||||
assert append(drop(j, xs), take(j, xs)) == xs;
|
||||
assert append(drop(i+1, xs), take(i, xs)) == take(i, xs);
|
||||
take_append_ge(k-1, drop(i+1, xs), take(i, xs));
|
||||
take_take(k-1, i, xs);
|
||||
}
|
||||
assert take(k-1, append(drop(j, xs), take(j, xs))) == take(k-1, append(drop(i+1, xs), take(i, xs)));
|
||||
assert take(k-1, append(drop(j, xs), take(j, xs))) == tail(take(k, append(drop(i, xs), take(i, xs))));
|
||||
}
|
||||
|
||||
lemma void deq_value_lemma<t>(int k, int i, list<t> xs, list<t> ys)
|
||||
requires 0 < k && k <= length(ys) && 0 <= i && i < length(xs) && take(k, rotate_left(i, xs)) == ys;
|
||||
ensures nth(i, xs) == head(ys);
|
||||
{
|
||||
drop_n_plus_one(i, xs);
|
||||
assert nth(i, xs) == head(take(k, append(drop(i, xs), take(i, xs))));
|
||||
}
|
||||
|
||||
lemma void combine_list_no_change<t>(list<t>prefix, t x, list<t>suffix, int i, list<t> xs)
|
||||
requires 0 <= i && i < length(xs) && prefix == take(i, xs) && x == nth(i, xs) && suffix == drop(i+1, xs);
|
||||
ensures xs == append(prefix, cons(x, suffix));
|
||||
{
|
||||
drop_n_plus_one(i, xs);
|
||||
}
|
||||
|
||||
// Following lemma from `verifast/examples/vstte2010/problem4.java`.
|
||||
lemma void update_rewrite<t>(list<t> vs, t v, int pos)
|
||||
requires 0 <= pos && pos < length(vs);
|
||||
ensures update(pos, v, vs) == append(take(pos, vs), cons(v, (drop(pos+1, vs))));
|
||||
{
|
||||
switch(vs) {
|
||||
case nil:
|
||||
case cons(h, t):
|
||||
if (pos == 0) {
|
||||
} else {
|
||||
update_rewrite(t, v, pos - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void combine_list_update<t>(list<t>prefix, t x, list<t>suffix, int i, list<t> xs)
|
||||
requires 0 <= i && i < length(xs) && prefix == take(i, xs) && suffix == drop(i+1, xs);
|
||||
ensures update(i, x, xs) == append(prefix, cons(x, suffix));
|
||||
{
|
||||
update_rewrite(xs, x, i);
|
||||
}
|
||||
|
||||
@*/
|
||||
|
||||
|
||||
#endif /* SCP_COMMON_H */
|
||||
|
|
@ -0,0 +1,740 @@
|
|||
/*
|
||||
* The code below has been taken from:
|
||||
* pull request:
|
||||
* https://github.com/FreeRTOS/FreeRTOS/pull/836
|
||||
* file:
|
||||
* FreeRTOS/Test/VeriFast/include/proof/list.h
|
||||
*
|
||||
* The file has been renamed from `list.h` into
|
||||
* `scp_list_predicates.h` to avoid naming conflicts.
|
||||
* The include guards have been updated accordingly.
|
||||
*
|
||||
* All changes to the proofs, predicates, etc.
|
||||
* are guarded by a check that `VERIFAST_SINGLE_CORE` is
|
||||
* NOT defined.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* FreeRTOS V202112.00
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* https://www.FreeRTOS.org
|
||||
* https://github.com/FreeRTOS
|
||||
*
|
||||
*/
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
#ifndef SCP_LIST_PREDICATES_H
|
||||
#define SCP_LIST_PREDICATES_H
|
||||
|
||||
#ifndef VERIFAST_SINGLE_CORE
|
||||
/* Reasons for rewrite:
|
||||
* - "common.gh" was converted into regular header "scp_common.h"
|
||||
* - Using existing proof setup instead of definitions below.
|
||||
*/
|
||||
#include "scp_common.h"
|
||||
#else
|
||||
#define VERIFAST
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
//@#include "common.gh"
|
||||
|
||||
typedef size_t TickType_t;
|
||||
typedef size_t UBaseType_t;
|
||||
typedef ssize_t BaseType_t;
|
||||
|
||||
#define pdTRUE 1
|
||||
#define pdFALSE 0
|
||||
|
||||
/* Empty/no-op macros */
|
||||
#define mtCOVERAGE_TEST_MARKER()
|
||||
#define mtCOVERAGE_TEST_DELAY()
|
||||
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
|
||||
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
|
||||
#define listTEST_LIST_INTEGRITY( pxList )
|
||||
#define listTEST_LIST_ITEM_INTEGRITY( pxListItem )
|
||||
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxListItem )
|
||||
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxListItem )
|
||||
#endif /* VERIFAST_SINGLE_CORE */
|
||||
|
||||
/* Max value stored in sentinel xListEnd element */
|
||||
#ifndef VERIFAST_SINGLE_CORE
|
||||
/* Reason for rewrite: Match RP2040 port. */
|
||||
//VF_macro #define portMAX_DELAY 0xffffffffUL
|
||||
|
||||
/* Verify that the preprocessor and our VeriFast proofs evaluate
|
||||
* `portMAX_DELAY` to the same values.
|
||||
*/
|
||||
void validate_portMAX_DELAY_value()
|
||||
//@ requires true;
|
||||
//@ ensures true;
|
||||
{
|
||||
//@ TickType_t gVal = portMAX_DELAY;
|
||||
TickType_t val = portMAX_DELAY;
|
||||
//@ assert(val == gVal);
|
||||
}
|
||||
#else
|
||||
#define portMAX_DELAY UINT_MAX
|
||||
#endif /* VERIFAST_SINGLE_CORE */
|
||||
|
||||
|
||||
#ifdef VERIFAST_SINGLE_CORE
|
||||
/* Reason for deletion:
|
||||
* structs already defined in FreeRTOS header "list.h"
|
||||
*/
|
||||
|
||||
struct xLIST;
|
||||
|
||||
struct xLIST_ITEM {
|
||||
TickType_t xItemValue;
|
||||
struct xLIST_ITEM * pxNext;
|
||||
struct xLIST_ITEM * pxPrevious;
|
||||
void * pvOwner;
|
||||
struct xLIST *pxContainer;
|
||||
};
|
||||
typedef struct xLIST_ITEM ListItem_t;
|
||||
|
||||
typedef struct xLIST {
|
||||
UBaseType_t uxNumberOfItems;
|
||||
struct xLIST_ITEM *pxIndex;
|
||||
#ifdef VERIFAST /*< ***change MiniList_t to ListItem_t*** */
|
||||
struct xLIST_ITEM xListEnd;
|
||||
#else
|
||||
MiniListItem_t xListEnd;
|
||||
#endif
|
||||
} List_t;
|
||||
#endif /* VERIFAST_SINGLE_CORE */
|
||||
|
||||
#ifndef VERIFAST_SINGLE_CORE
|
||||
/* Reasons for rewrite:
|
||||
* - Breaking change in VeriFast. VeriFast now ensures that no uninitialised
|
||||
* values are read. `x |-> _` is interpreted as "uninitialised",
|
||||
* `x |-> ?v` is interpreted as "initialised".
|
||||
* - In order to verify the scheduler, we have to reason about each node's
|
||||
* owner. Hence, the predicate has to expose it.
|
||||
*/
|
||||
/*@
|
||||
predicate xLIST_ITEM(
|
||||
struct xLIST_ITEM *n,
|
||||
TickType_t xItemValue,
|
||||
struct xLIST_ITEM *pxNext,
|
||||
struct xLIST_ITEM *pxPrevious,
|
||||
void* pxOwner,
|
||||
struct xLIST *pxContainer;) =
|
||||
n->xItemValue |-> xItemValue &*&
|
||||
n->pxNext |-> pxNext &*&
|
||||
n->pxPrevious |-> pxPrevious &*&
|
||||
n->pvOwner |-> pxOwner &*&
|
||||
n->pxContainer |-> pxContainer;
|
||||
@*/
|
||||
#else
|
||||
/*@
|
||||
predicate xLIST_ITEM(
|
||||
struct xLIST_ITEM *n,
|
||||
TickType_t xItemValue,
|
||||
struct xLIST_ITEM *pxNext,
|
||||
struct xLIST_ITEM *pxPrevious,
|
||||
struct xLIST *pxContainer;) =
|
||||
n->xItemValue |-> xItemValue &*&
|
||||
n->pxNext |-> pxNext &*&
|
||||
n->pxPrevious |-> pxPrevious &*&
|
||||
n->pvOwner |-> _ &*&
|
||||
n->pxContainer |-> pxContainer;
|
||||
@*/
|
||||
#endif /* VERIFAST_SINGLE_CORE */
|
||||
|
||||
|
||||
|
||||
#ifndef VERIFAST_SINGLE_CORE
|
||||
/* Reason for rewrite:
|
||||
* In order to verify the scheduler, we have to reason about each node's
|
||||
* owner. Hence, the predicate has to expose it.
|
||||
*/
|
||||
|
||||
/* Ferreira et al. (STTT'14) doubly-linked list segment (DLS). */
|
||||
/*@
|
||||
predicate DLS(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells,
|
||||
list<TickType_t > vals,
|
||||
list<void*> owners,
|
||||
struct xLIST *pxContainer) =
|
||||
n == m
|
||||
? cells == cons(n, nil) &*&
|
||||
vals == cons(?v, nil) &*&
|
||||
owners == cons(?ow, nil) &*&
|
||||
xLIST_ITEM(n, v, mnext, nprev, ow, pxContainer)
|
||||
: cells == cons(n, ?cells0) &*&
|
||||
vals == cons(?v, ?vals0) &*&
|
||||
owners == cons(?ow, ?owners0) &*&
|
||||
xLIST_ITEM(n, v, ?o, nprev, ow, pxContainer) &*& DLS(o, n, mnext, m, cells0, vals0, owners0, pxContainer);
|
||||
@*/
|
||||
#else
|
||||
/* Ferreira et al. (STTT'14) doubly-linked list segment (DLS). */
|
||||
/*@
|
||||
predicate DLS(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells,
|
||||
list<TickType_t > vals,
|
||||
struct xLIST *pxContainer) =
|
||||
n == m
|
||||
? cells == cons(n, nil) &*&
|
||||
vals == cons(?v, nil) &*&
|
||||
xLIST_ITEM(n, v, mnext, nprev, pxContainer)
|
||||
: cells == cons(n, ?cells0) &*&
|
||||
vals == cons(?v, ?vals0) &*&
|
||||
xLIST_ITEM(n, v, ?o, nprev, pxContainer) &*& DLS(o, n, mnext, m, cells0, vals0, pxContainer);
|
||||
@*/
|
||||
#endif /* VERIFAST_SINGLE_CORE */
|
||||
|
||||
|
||||
#ifndef VERIFAST_SINGLE_CORE
|
||||
/* Reason for rewrite:
|
||||
* Predicates `xLIST_ITEM` and `DLS` have been extended to expose node
|
||||
* owners. Proofs using these predicates must be adapted as well.
|
||||
*/
|
||||
|
||||
/*@
|
||||
lemma void dls_star_item(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *m,
|
||||
struct xLIST_ITEM *o)
|
||||
requires DLS(n, ?nprev, ?mnext, m, ?cells, ?vals, ?owners, ?l) &*& xLIST_ITEM(o, ?v, ?onext, ?oprev, ?ow, ?l2);
|
||||
ensures DLS(n, nprev, mnext, m, cells, vals, owners, l) &*& xLIST_ITEM(o, v, onext, oprev, ow, l2) &*& mem(o, cells) == false;
|
||||
{
|
||||
open DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
if (n == m) {
|
||||
assert xLIST_ITEM(n, _, _, _, _, _);
|
||||
open xLIST_ITEM(n, _, _, _, _, _);
|
||||
open xLIST_ITEM(o, _, _, _, _, _);
|
||||
assert n != o;
|
||||
close xLIST_ITEM(o, _, _, _, _, _);
|
||||
close xLIST_ITEM(n, _, _, _, _, _);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
}
|
||||
else {
|
||||
assert DLS(?nnext, n, mnext, m, tail(cells), tail(vals), tail(owners), l);
|
||||
dls_star_item(nnext, m, o);
|
||||
open xLIST_ITEM(n, _, _, _, _, _);
|
||||
open xLIST_ITEM(o, _, _, _, _, _);
|
||||
assert n != o;
|
||||
close xLIST_ITEM(o, _, _, _, _, _);
|
||||
close xLIST_ITEM(n, _, _, _, _, _);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lemma void dls_distinct(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells)
|
||||
requires DLS(n, nprev, mnext, m, cells, ?vals, ?owners, ?l);
|
||||
ensures DLS(n, nprev, mnext, m, cells, vals, owners, l) &*& distinct(cells) == true;
|
||||
{
|
||||
if (n == m) {
|
||||
open DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
} else {
|
||||
open DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
assert DLS(?nnext, n, mnext, m, tail(cells), tail(vals), tail(owners), l);
|
||||
dls_distinct(nnext, n, mnext, m, tail(cells));
|
||||
dls_star_item(nnext, m, n);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
}
|
||||
}
|
||||
@*/
|
||||
#else
|
||||
/*@
|
||||
lemma void dls_star_item(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *m,
|
||||
struct xLIST_ITEM *o)
|
||||
requires DLS(n, ?nprev, ?mnext, m, ?cells, ?vals, ?l) &*& xLIST_ITEM(o, ?v, ?onext, ?oprev, ?l2);
|
||||
ensures DLS(n, nprev, mnext, m, cells, vals, l) &*& xLIST_ITEM(o, v, onext, oprev, l2) &*& mem(o, cells) == false;
|
||||
{
|
||||
open DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
if (n == m) {
|
||||
assert xLIST_ITEM(n, _, _, _, _);
|
||||
open xLIST_ITEM(n, _, _, _, _);
|
||||
open xLIST_ITEM(o, _, _, _, _);
|
||||
assert n != o;
|
||||
close xLIST_ITEM(o, _, _, _, _);
|
||||
close xLIST_ITEM(n, _, _, _, _);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
}
|
||||
else {
|
||||
assert DLS(?nnext, n, mnext, m, tail(cells), tail(vals), l);
|
||||
dls_star_item(nnext, m, o);
|
||||
open xLIST_ITEM(n, _, _, _, _);
|
||||
open xLIST_ITEM(o, _, _, _, _);
|
||||
assert n != o;
|
||||
close xLIST_ITEM(o, _, _, _, _);
|
||||
close xLIST_ITEM(n, _, _, _, _);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lemma void dls_distinct(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells)
|
||||
requires DLS(n, nprev, mnext, m, cells, ?vals, ?l);
|
||||
ensures DLS(n, nprev, mnext, m, cells, vals, l) &*& distinct(cells) == true;
|
||||
{
|
||||
if (n == m) {
|
||||
open DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
} else {
|
||||
open DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
assert DLS(?nnext, n, mnext, m, tail(cells), tail(vals), l);
|
||||
dls_distinct(nnext, n, mnext, m, tail(cells));
|
||||
dls_star_item(nnext, m, n);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
}
|
||||
}
|
||||
@*/
|
||||
#endif /* VERIFAST_SINGLE_CORE */
|
||||
|
||||
#ifndef VERIFAST_SINGLE_CORE
|
||||
/* Reason for rewrite:
|
||||
* In order to verify the scheduler, we have to reason about each node's
|
||||
* owner. Hence, the predicate has to expose it.
|
||||
*/
|
||||
|
||||
/*@
|
||||
predicate xLIST(
|
||||
struct xLIST *l,
|
||||
int uxNumberOfItems,
|
||||
struct xLIST_ITEM *pxIndex,
|
||||
struct xLIST_ITEM *xListEnd,
|
||||
list<struct xLIST_ITEM *>cells,
|
||||
list<TickType_t >vals,
|
||||
list<void*> owners) =
|
||||
l->uxNumberOfItems |-> uxNumberOfItems &*&
|
||||
l->pxIndex |-> pxIndex &*&
|
||||
mem(pxIndex, cells) == true &*&
|
||||
xListEnd == &(l->xListEnd) &*&
|
||||
xListEnd == head(cells) &*&
|
||||
portMAX_DELAY == head(vals) &*&
|
||||
struct_xLIST_ITEM_padding(&l->xListEnd) &*&
|
||||
length(cells) == length(vals) &*&
|
||||
length(owners) == length(cells) &*&
|
||||
uxNumberOfItems + 1 == length(cells) &*&
|
||||
DLS(xListEnd, ?endprev, xListEnd, endprev, cells, vals, owners, l);
|
||||
@*/
|
||||
#else
|
||||
/*@
|
||||
predicate xLIST(
|
||||
struct xLIST *l,
|
||||
int uxNumberOfItems,
|
||||
struct xLIST_ITEM *pxIndex,
|
||||
struct xLIST_ITEM *xListEnd,
|
||||
list<struct xLIST_ITEM *>cells,
|
||||
list<TickType_t >vals) =
|
||||
l->uxNumberOfItems |-> uxNumberOfItems &*&
|
||||
l->pxIndex |-> pxIndex &*&
|
||||
mem(pxIndex, cells) == true &*&
|
||||
xListEnd == &(l->xListEnd) &*&
|
||||
xListEnd == head(cells) &*&
|
||||
portMAX_DELAY == head(vals) &*&
|
||||
struct_xLIST_ITEM_padding(&l->xListEnd) &*&
|
||||
length(cells) == length(vals) &*&
|
||||
uxNumberOfItems + 1 == length(cells) &*&
|
||||
DLS(xListEnd, ?endprev, xListEnd, endprev, cells, vals, l);
|
||||
@*/
|
||||
#endif /* VERIFAST_SINGLE_CORE */
|
||||
|
||||
|
||||
|
||||
#ifndef VERIFAST_SINGLE_CORE
|
||||
/* Reason for rewrite:
|
||||
* Predicates `xLIST_ITEM`, `DLS` and `xLIST` have been extended to expose
|
||||
* node owners. Proofs using these predicates must be adapted as well.
|
||||
*/
|
||||
|
||||
|
||||
/*@
|
||||
lemma void xLIST_distinct_cells(struct xLIST *l)
|
||||
requires xLIST(l, ?n, ?idx, ?end, ?cells, ?vals, ?owners);
|
||||
ensures xLIST(l, n, idx, end, cells, vals, owners) &*& distinct(cells) == true;
|
||||
{
|
||||
open xLIST(l, n, idx, end, cells, vals, owners);
|
||||
assert DLS(end, ?endprev, end, _, cells, vals, owners, l);
|
||||
dls_distinct(end, endprev, end, endprev, cells);
|
||||
close xLIST(l, n, idx, end, cells, vals, owners);
|
||||
}
|
||||
|
||||
lemma void xLIST_star_item(struct xLIST *l, struct xLIST_ITEM *x)
|
||||
requires xLIST(l, ?n, ?idx, ?end, ?cells, ?vals, ?owners) &*& xLIST_ITEM(x, ?v, ?xnext, ?xprev, ?ow, ?l2);
|
||||
ensures xLIST(l, n, idx, end, cells, vals, owners) &*& xLIST_ITEM(x, v, xnext, xprev, ow, l2) &*& mem(x, cells) == false;
|
||||
{
|
||||
open xLIST(l, n, idx, end, cells, vals, owners);
|
||||
assert DLS(end, ?endprev, end, _, cells, vals, owners, l);
|
||||
dls_distinct(end, endprev, end, endprev, cells);
|
||||
dls_star_item(end, endprev, x);
|
||||
close xLIST(l, n, idx, end, cells, vals, owners);
|
||||
}
|
||||
|
||||
lemma void dls_first_mem(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells)
|
||||
requires DLS(n, nprev, mnext, m, cells, ?vals, ?owners, ?l);
|
||||
ensures DLS(n, nprev, mnext, m, cells, vals, owners, l) &*& mem(n, cells) == true &*& index_of(n, cells) == 0;
|
||||
{
|
||||
open DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
if (n == m) {
|
||||
assert cells == cons(n, nil);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
} else {
|
||||
assert cells == cons(n, ?tail);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
}
|
||||
}
|
||||
|
||||
lemma void dls_not_empty(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells,
|
||||
struct xLIST_ITEM *x)
|
||||
requires DLS(n, m, n, m, cells, ?vals, ?owners, ?l) &*& mem(x, cells) == true &*& x != n;
|
||||
ensures DLS(n, m, n, m, cells, vals, owners, l) &*& n != m;
|
||||
{
|
||||
open DLS(n, m, n, m, cells, vals, owners, l);
|
||||
close DLS(n, m, n, m, cells, vals, owners, l);
|
||||
}
|
||||
|
||||
lemma void dls_last_mem(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells)
|
||||
requires DLS(n, nprev, mnext, m, cells, ?vals, ?owners, ?l);
|
||||
ensures DLS(n, nprev, mnext, m, cells, vals, owners, l) &*& mem(m, cells) == true &*& index_of(m, cells) == length(cells) - 1;
|
||||
{
|
||||
open DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
if (n == m) {
|
||||
// trivial
|
||||
} else {
|
||||
open xLIST_ITEM(n, _, ?nnext, _, _, l);
|
||||
assert DLS(?o, n, mnext, m, tail(cells), tail(vals), tail(owners), l);
|
||||
dls_last_mem(o, n, mnext, m, tail(cells));
|
||||
close xLIST_ITEM(n, _, nnext, _, _, l);
|
||||
}
|
||||
close DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
}
|
||||
|
||||
|
||||
lemma void split(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells,
|
||||
list<TickType_t > vals,
|
||||
struct xLIST_ITEM *x,
|
||||
int i)
|
||||
requires DLS(n, nprev, mnext, m, cells, vals, ?owners, ?l) &*& x != n &*& mem(x, cells) == true &*& index_of(x,cells) == i;
|
||||
ensures DLS(n, nprev, x, ?xprev, take(i, cells), take(i, vals), take(i, owners), l) &*& DLS(x, xprev, mnext, m, drop(i, cells), drop(i, vals), drop(i, owners), l) &*& xprev == nth(i-1, cells);
|
||||
{
|
||||
open DLS(n, nprev, mnext, m, cells, vals, owners, l);
|
||||
assert n != m;
|
||||
assert xLIST_ITEM(n, ?v, ?nnext, _, ?ow, _);
|
||||
assert DLS(nnext, n, mnext, m, tail(cells), tail(vals), tail(owners), l);
|
||||
if (nnext == x) {
|
||||
close DLS(n, nprev, x, n, singleton(n), singleton(v), singleton(ow), l);
|
||||
open DLS(x, n, mnext, m, tail(cells), tail(vals), tail(owners), l);
|
||||
open xLIST_ITEM(x, _, ?xnext, ?xprev, ?xow, l);
|
||||
close xLIST_ITEM(x, _, xnext, xprev, xow, l);
|
||||
close DLS(x, n, mnext, m, tail(cells), tail(vals), tail(owners), l);
|
||||
} else {
|
||||
assert nnext != x;
|
||||
split(nnext, n, mnext, m, tail(cells), tail(vals), x, i - 1);
|
||||
assert DLS(nnext, n, x, ?xprev, take(i-1, tail(cells)), take(i-1, tail(vals)), take(i-1, tail(owners)), l);
|
||||
dls_distinct(nnext, n, x, xprev, take(i-1, tail(cells)));
|
||||
dls_star_item(nnext, xprev, n);
|
||||
dls_last_mem(nnext, n, x, xprev, take(i-1, tail(cells)));
|
||||
assert n != xprev;
|
||||
close DLS(n, nprev, x, xprev, take(i, cells), take(i, vals), take(i, owners), l);
|
||||
}
|
||||
}
|
||||
|
||||
lemma void join(
|
||||
struct xLIST_ITEM *n1,
|
||||
struct xLIST_ITEM *nprev1,
|
||||
struct xLIST_ITEM *mnext1,
|
||||
struct xLIST_ITEM *m1,
|
||||
list<struct xLIST_ITEM * > cells1,
|
||||
list<TickType_t > vals1,
|
||||
struct xLIST_ITEM *n2,
|
||||
struct xLIST_ITEM *nprev2,
|
||||
struct xLIST_ITEM *mnext2,
|
||||
struct xLIST_ITEM *m2,
|
||||
list<struct xLIST_ITEM * > cells2,
|
||||
list<TickType_t > vals2)
|
||||
requires
|
||||
DLS(n1, nprev1, mnext1, m1, cells1, vals1, ?owners1, ?l) &*&
|
||||
DLS(n2, nprev2, mnext2, m2, cells2, vals2, ?owners2, l) &*&
|
||||
mnext1 == n2 &*& m1 == nprev2;
|
||||
ensures DLS(n1, nprev1, mnext2, m2, append(cells1, cells2), append(vals1, vals2), append(owners1, owners2), l);
|
||||
{
|
||||
if (n1 == m1) {
|
||||
dls_first_mem(n1, nprev1, mnext1, m1, cells1);
|
||||
dls_last_mem(n2, nprev2, mnext2, m2, cells2);
|
||||
open DLS(n1, nprev1, mnext1, m1, cells1, vals1, owners1, l);
|
||||
dls_star_item(n2, m2, n1);
|
||||
close DLS(n1, nprev1, mnext2, m2, append(singleton(n1), cells2), append(vals1, vals2), append(owners1, owners2) ,l);
|
||||
} else {
|
||||
open DLS(n1, nprev1, mnext1, m1, cells1, vals1, owners1, l);
|
||||
assert DLS(?o, n1, mnext1, m1, ?cells1_tail, ?vals1_tail, ?owners1_tail, l);
|
||||
join(o, n1, mnext1, m1, cells1_tail, vals1_tail,
|
||||
n2, nprev2, mnext2, m2, cells2, vals2);
|
||||
assert DLS(o, n1, mnext2, m2, append(cells1_tail, cells2), append(vals1_tail, vals2), append(owners1_tail, owners2), l);
|
||||
dls_last_mem(o, n1, mnext2, m2, append(cells1_tail, cells2));
|
||||
dls_star_item(o, m2, n1);
|
||||
close DLS(n1, nprev1, mnext2, m2, append(cells1, cells2), append(vals1, vals2), append(owners1, owners2), l);
|
||||
}
|
||||
}
|
||||
@*/
|
||||
#else
|
||||
/*@
|
||||
lemma void xLIST_distinct_cells(struct xLIST *l)
|
||||
requires xLIST(l, ?n, ?idx, ?end, ?cells, ?vals);
|
||||
ensures xLIST(l, n, idx, end, cells, vals) &*& distinct(cells) == true;
|
||||
{
|
||||
open xLIST(l, n, idx, end, cells, vals);
|
||||
assert DLS(end, ?endprev, end, _, cells, vals, l);
|
||||
dls_distinct(end, endprev, end, endprev, cells);
|
||||
close xLIST(l, n, idx, end, cells, vals);
|
||||
}
|
||||
|
||||
lemma void xLIST_star_item(struct xLIST *l, struct xLIST_ITEM *x)
|
||||
requires xLIST(l, ?n, ?idx, ?end, ?cells, ?vals) &*& xLIST_ITEM(x, ?v, ?xnext, ?xprev, ?l2);
|
||||
ensures xLIST(l, n, idx, end, cells, vals) &*& xLIST_ITEM(x, v, xnext, xprev, l2) &*& mem(x, cells) == false;
|
||||
{
|
||||
open xLIST(l, n, idx, end, cells, vals);
|
||||
assert DLS(end, ?endprev, end, _, cells, vals, l);
|
||||
dls_distinct(end, endprev, end, endprev, cells);
|
||||
dls_star_item(end, endprev, x);
|
||||
close xLIST(l, n, idx, end, cells, vals);
|
||||
}
|
||||
|
||||
lemma void dls_first_mem(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells)
|
||||
requires DLS(n, nprev, mnext, m, cells, ?vals, ?l);
|
||||
ensures DLS(n, nprev, mnext, m, cells, vals, l) &*& mem(n, cells) == true &*& index_of(n, cells) == 0;
|
||||
{
|
||||
open DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
if (n == m) {
|
||||
assert cells == cons(n, nil);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
} else {
|
||||
assert cells == cons(n, ?tail);
|
||||
close DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
}
|
||||
}
|
||||
|
||||
lemma void dls_not_empty(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells,
|
||||
struct xLIST_ITEM *x)
|
||||
requires DLS(n, m, n, m, cells, ?vals, ?l) &*& mem(x, cells) == true &*& x != n;
|
||||
ensures DLS(n, m, n, m, cells, vals, l) &*& n != m;
|
||||
{
|
||||
open DLS(n, m, n, m, cells, vals, l);
|
||||
close DLS(n, m, n, m, cells, vals, l);
|
||||
}
|
||||
|
||||
lemma void dls_last_mem(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells)
|
||||
requires DLS(n, nprev, mnext, m, cells, ?vals, ?l);
|
||||
ensures DLS(n, nprev, mnext, m, cells, vals, l) &*& mem(m, cells) == true &*& index_of(m, cells) == length(cells) - 1;
|
||||
{
|
||||
open DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
if (n == m) {
|
||||
// trivial
|
||||
} else {
|
||||
open xLIST_ITEM(n, _, ?nnext, _, l);
|
||||
assert DLS(?o, n, mnext, m, tail(cells), tail(vals), l);
|
||||
dls_last_mem(o, n, mnext, m, tail(cells));
|
||||
close xLIST_ITEM(n, _, nnext, _, l);
|
||||
}
|
||||
close DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
}
|
||||
|
||||
|
||||
lemma void split(
|
||||
struct xLIST_ITEM *n,
|
||||
struct xLIST_ITEM *nprev,
|
||||
struct xLIST_ITEM *mnext,
|
||||
struct xLIST_ITEM *m,
|
||||
list<struct xLIST_ITEM * > cells,
|
||||
list<TickType_t > vals,
|
||||
struct xLIST_ITEM *x,
|
||||
int i)
|
||||
requires DLS(n, nprev, mnext, m, cells, vals, ?l) &*& x != n &*& mem(x, cells) == true &*& index_of(x,cells) == i;
|
||||
ensures DLS(n, nprev, x, ?xprev, take(i, cells), take(i, vals), l) &*& DLS(x, xprev, mnext, m, drop(i, cells), drop(i, vals), l) &*& xprev == nth(i-1, cells);
|
||||
{
|
||||
open DLS(n, nprev, mnext, m, cells, vals, l);
|
||||
assert n != m;
|
||||
assert xLIST_ITEM(n, ?v, ?nnext, _, _);
|
||||
assert DLS(nnext, n, mnext, m, tail(cells), tail(vals), l);
|
||||
if (nnext == x) {
|
||||
close DLS(n, nprev, x, n, singleton(n), singleton(v), l);
|
||||
open DLS(x, n, mnext, m, tail(cells), tail(vals), l);
|
||||
open xLIST_ITEM(x, _, ?xnext, ?xprev, l);
|
||||
close xLIST_ITEM(x, _, xnext, xprev, l);
|
||||
close DLS(x, n, mnext, m, tail(cells), tail(vals), l);
|
||||
} else {
|
||||
assert nnext != x;
|
||||
split(nnext, n, mnext, m, tail(cells), tail(vals), x, i - 1);
|
||||
assert DLS(nnext, n, x, ?xprev, take(i-1, tail(cells)), take(i-1, tail(vals)), l);
|
||||
dls_distinct(nnext, n, x, xprev, take(i-1, tail(cells)));
|
||||
dls_star_item(nnext, xprev, n);
|
||||
dls_last_mem(nnext, n, x, xprev, take(i-1, tail(cells)));
|
||||
assert n != xprev;
|
||||
close DLS(n, nprev, x, xprev, take(i, cells), take(i, vals), l);
|
||||
}
|
||||
}
|
||||
|
||||
lemma void join(
|
||||
struct xLIST_ITEM *n1,
|
||||
struct xLIST_ITEM *nprev1,
|
||||
struct xLIST_ITEM *mnext1,
|
||||
struct xLIST_ITEM *m1,
|
||||
list<struct xLIST_ITEM * > cells1,
|
||||
list<TickType_t > vals1,
|
||||
struct xLIST_ITEM *n2,
|
||||
struct xLIST_ITEM *nprev2,
|
||||
struct xLIST_ITEM *mnext2,
|
||||
struct xLIST_ITEM *m2,
|
||||
list<struct xLIST_ITEM * > cells2,
|
||||
list<TickType_t > vals2)
|
||||
requires
|
||||
DLS(n1, nprev1, mnext1, m1, cells1, vals1, ?l) &*&
|
||||
DLS(n2, nprev2, mnext2, m2, cells2, vals2, l) &*&
|
||||
mnext1 == n2 &*& m1 == nprev2;
|
||||
ensures DLS(n1, nprev1, mnext2, m2, append(cells1, cells2), append(vals1, vals2), l);
|
||||
{
|
||||
if (n1 == m1) {
|
||||
dls_first_mem(n1, nprev1, mnext1, m1, cells1);
|
||||
dls_last_mem(n2, nprev2, mnext2, m2, cells2);
|
||||
open DLS(n1, nprev1, mnext1, m1, cells1, vals1, l);
|
||||
dls_star_item(n2, m2, n1);
|
||||
close DLS(n1, nprev1, mnext2, m2, append(singleton(n1), cells2), append(vals1, vals2), l);
|
||||
} else {
|
||||
open DLS(n1, nprev1, mnext1, m1, cells1, vals1, l);
|
||||
assert DLS(?o, n1, mnext1, m1, ?cells1_tail, ?vals1_tail, l);
|
||||
join(o, n1, mnext1, m1, cells1_tail, vals1_tail,
|
||||
n2, nprev2, mnext2, m2, cells2, vals2);
|
||||
assert DLS(o, n1, mnext2, m2, append(cells1_tail, cells2), append(vals1_tail, vals2), l);
|
||||
dls_last_mem(o, n1, mnext2, m2, append(cells1_tail, cells2));
|
||||
dls_star_item(o, m2, n1);
|
||||
close DLS(n1, nprev1, mnext2, m2, append(cells1, cells2), append(vals1, vals2), l);
|
||||
}
|
||||
}
|
||||
@*/
|
||||
#endif /* VERIFAST_SINGLE_CORE */
|
||||
|
||||
/*@
|
||||
lemma void idx_remains_in_list<t>(
|
||||
list<t> cells,
|
||||
t idx,
|
||||
t x,
|
||||
int ix)
|
||||
requires
|
||||
idx != x &*&
|
||||
mem(idx, cells) == true &*&
|
||||
mem(x, cells) == true &*&
|
||||
index_of(x, cells) == ix;
|
||||
ensures mem(idx, remove_nth(ix, cells)) == true;
|
||||
{
|
||||
neq_mem_remove(idx, x, cells);
|
||||
remove_remove_nth(cells, x);
|
||||
}
|
||||
@*/
|
||||
|
||||
// Following lemma from `verifast/examples/shared_boxes/concurrentqueue.c`.
|
||||
// Used in the uxListRemove proof to show that the item to remove `x` must
|
||||
// have value `nth(i, vals)` where `i == index_of(x, cells)`.
|
||||
/*@
|
||||
lemma void drop_nth_index_of<t>(list<t> vs, int i)
|
||||
requires
|
||||
0 <= i && i < length(vs);
|
||||
ensures
|
||||
head(drop(i , vs)) == nth(i, vs);
|
||||
{
|
||||
switch(vs) {
|
||||
case nil:
|
||||
case cons(h, t):
|
||||
if (i == 0) {
|
||||
// trivial
|
||||
} else {
|
||||
drop_nth_index_of(t, i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@*/
|
||||
|
||||
/*@
|
||||
lemma void remove_append<t>(t x, list<t> l1, list<t> l2)
|
||||
requires mem(x, l1) == false;
|
||||
ensures remove(x, append(l1, l2)) == append(l1, remove(x, l2));
|
||||
{
|
||||
switch(l1) {
|
||||
case nil:
|
||||
case cons(h1, t1):
|
||||
remove_append(x, t1, l2);
|
||||
}
|
||||
}
|
||||
@*/
|
||||
|
||||
|
||||
#endif /* SCP_LIST_PREDICATES_H */
|
||||
|
||||
/* *INDENT-ON* */
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
This directory contains proofs that concern the predicates and proofs written
|
||||
by Aalok Thakkar and Nathan Chong, see directory `single_core_proofs`.
|
||||
For now, we want to have a clear separation between the reused proofs in
|
||||
`single_core_proofs` and any new proofs.
|
||||
|
|
@ -0,0 +1,861 @@
|
|||
#ifndef SCP_LIST_PREDICATES_EXTENDED_H
|
||||
#define SCP_LIST_PREDICATES_EXTENDED_H
|
||||
|
||||
#include "single_core_proofs/scp_list_predicates.h"
|
||||
|
||||
/* =============================================================================
|
||||
* The lemmas below assist in opening and closing DLS predicates in a way that
|
||||
* allows accesses to `pxItem->pxNext`.
|
||||
*/
|
||||
|
||||
/* @
|
||||
lemma void DLS_end_next_open(struct xLIST* pxList, struct xLIST_ITEM* pxItem)
|
||||
requires
|
||||
DLS(?gEnd, ?gEndPrev, gEnd, gEndPrev, ?gCells, ?gVals, pxList) &*&
|
||||
mem(pxItem, gCells) == true &*&
|
||||
gEnd == head(gCells) &*&
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gCells) > 1
|
||||
&*&
|
||||
pxItem == gEnd;
|
||||
ensures
|
||||
xLIST_ITEM(gEnd, head(gVals), ?gItem_next, gEndPrev, pxList) &*&
|
||||
DLS(gItem_next, gEnd, gEnd, gEndPrev, drop(1, gCells), drop(1, gVals), pxList ) &*&
|
||||
mem(gItem_next, gCells) == true;
|
||||
{
|
||||
open DLS(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, pxList);
|
||||
// open DLS and xLIST_ITEM predicates to justify
|
||||
// accessing `pxItem->pxNext`
|
||||
assert( xLIST_ITEM(gEnd, ?gItemVal, ?gItem_next, gEndPrev, pxList) );
|
||||
open xLIST_ITEM(gEnd, gItemVal, gItem_next, gEndPrev, pxList);
|
||||
assert( DLS(gItem_next, gEnd, gEnd, gEndPrev,
|
||||
drop(1, gCells), drop(1, gVals), pxList ) );
|
||||
open DLS(gItem_next, gEnd, gEnd, gEndPrev,
|
||||
drop(1, gCells), drop(1, gVals), pxList );
|
||||
|
||||
// open DLS and xLIST_ITEM predicates to prove
|
||||
// `mem( pxItem->pxNext, gCells) == true )`
|
||||
// which requires accessing `pxItem->pxNext`
|
||||
assert( xLIST_ITEM(gItem_next, ?gItem_nextVal, ?gItem_nextNext, gEnd, pxList) );
|
||||
open xLIST_ITEM(gItem_next, gItem_nextVal, gItem_nextNext, gEnd, pxList);
|
||||
assert( mem(pxItem->pxNext, gCells) == true );
|
||||
close xLIST_ITEM(gItem_next, gItem_nextVal, gItem_nextNext, gEnd, pxList);
|
||||
|
||||
// closing what we opened above
|
||||
close DLS(gItem_next, gEnd, gEnd, gEndPrev,
|
||||
drop(1, gCells), drop(1, gVals), pxList );
|
||||
close xLIST_ITEM(gEnd, gItemVal, gItem_next, gEndPrev, pxList);
|
||||
}
|
||||
|
||||
|
||||
lemma void DLS_end_next_close(struct xLIST* pxList, struct xLIST_ITEM* pxItem)
|
||||
requires
|
||||
xLIST_ITEM(?gEnd, ?gItemVal, ?gItem_next, ?gEndPrev, pxList) &*&
|
||||
DLS(gItem_next, gEnd, gEnd, gEndPrev, ?gCells, ?gVals, pxList) &*&
|
||||
// mem(gItem_next, gCells) == true &*&
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gCells) > 0 &*&
|
||||
pxItem == gEnd;
|
||||
ensures
|
||||
DLS(gEnd, gEndPrev, gEnd, gEndPrev,
|
||||
cons(gEnd, gCells), cons(gItemVal, gVals), pxList);
|
||||
{
|
||||
open DLS(gItem_next, gEnd, gEnd, gEndPrev, gCells, gVals, pxList);
|
||||
close DLS(gItem_next, gEnd, gEnd, gEndPrev, gCells, gVals, pxList);
|
||||
dls_star_item(gItem_next, gEndPrev, gEnd);
|
||||
dls_distinct(gItem_next, gEnd, gEnd, gEndPrev, gCells);
|
||||
dls_last_mem(gItem_next, gEnd, gEnd, gEndPrev, gCells);
|
||||
close DLS(gEnd, gEndPrev, gEnd, gEndPrev,
|
||||
cons(gEnd, gCells), cons(gItemVal, gVals), pxList);
|
||||
}
|
||||
|
||||
|
||||
lemma void DLS_nonEndItem_next_open(struct xLIST* pxList, struct xLIST_ITEM* pxItem)
|
||||
requires
|
||||
DLS(?gEnd, ?gEndPrev, gEnd, gEndPrev, ?gCells, ?gVals, pxList) &*&
|
||||
mem(pxItem, gCells) == true &*&
|
||||
gEnd == head(gCells) &*&
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gCells) > 1
|
||||
&*&
|
||||
pxItem != gEnd;
|
||||
ensures
|
||||
// DLS prefix
|
||||
DLS(gEnd, gEndPrev, pxItem, ?pxItem_prev,
|
||||
take(index_of(pxItem, gCells), gCells),
|
||||
take(index_of(pxItem, gCells), gVals),
|
||||
pxList)
|
||||
&*&
|
||||
// item of interest
|
||||
xLIST_ITEM(pxItem, ?gItemVal, ?pxItem_next, pxItem_prev, pxList) &*&
|
||||
gItemVal == nth(index_of(pxItem, gCells), gVals)
|
||||
&*&
|
||||
// DLS suffix
|
||||
(pxItem != gEndPrev
|
||||
? DLS(pxItem_next, pxItem, gEnd, gEndPrev,
|
||||
drop(1, drop(index_of(pxItem, gCells), gCells)),
|
||||
drop(1, drop(index_of(pxItem, gCells), gVals)),
|
||||
pxList)
|
||||
: (pxItem_next == gEnd &*&
|
||||
index_of(pxItem, gCells) == length(gCells) - 1
|
||||
)
|
||||
)
|
||||
&*&
|
||||
mem(pxItem_next, gCells) == true;
|
||||
{
|
||||
int pxItemIndex_0 = index_of(pxItem, gCells);
|
||||
|
||||
|
||||
// open DLS and xLIST_ITEM predicates to justify
|
||||
// accessing `pxItem->pxNext`
|
||||
split(gEnd, gEndPrev, gEnd, gEndPrev,
|
||||
gCells, gVals, pxItem, pxItemIndex_0);
|
||||
// DLS prefix
|
||||
assert( DLS(gEnd, gEndPrev, pxItem, ?pxItem_prev,
|
||||
take(pxItemIndex_0, gCells), take(pxItemIndex_0, gVals),
|
||||
pxList) );
|
||||
// DLS suffix
|
||||
assert( DLS(pxItem, pxItem_prev, gEnd, gEndPrev,
|
||||
drop(pxItemIndex_0, gCells), drop(pxItemIndex_0, gVals),
|
||||
pxList) );
|
||||
open DLS(pxItem, pxItem_prev, gEnd, gEndPrev,
|
||||
drop(pxItemIndex_0, gCells), drop(pxItemIndex_0, gVals),
|
||||
pxList);
|
||||
assert( xLIST_ITEM(pxItem, ?gItemVal, ?pxItem_next, pxItem_prev, pxList) );
|
||||
assert( gItemVal == head(drop(pxItemIndex_0, gVals)) );
|
||||
head_drop_n_equals_nths(gVals, pxItemIndex_0);
|
||||
assert( gItemVal == nth(index_of(pxItem, gCells), gVals) );
|
||||
|
||||
|
||||
// open DLS and xLIST_ITEM predicates to prove
|
||||
// `mem( pxItem->pxNext, gCells) == true )`
|
||||
// which requires accessing `pxItem->pxNext`
|
||||
if(pxItem == gEndPrev) {
|
||||
assert( drop(pxItemIndex_0, gCells) == cons(pxItem, nil) );
|
||||
drop_index_equals_singleton_implies_last_element(gCells, pxItem);
|
||||
assert( pxItemIndex_0 == length(gCells) - 1 );
|
||||
|
||||
// `pxItem` is last element in DLS suffix
|
||||
// -> `pxItem_next` is head fo DLS prefix
|
||||
// open DLS prefix
|
||||
open xLIST_ITEM(pxItem, gItemVal, pxItem_next, pxItem_prev, pxList);
|
||||
assert( gCells == cons(_, _) );
|
||||
assert( mem(pxItem->pxNext, gCells) == true );
|
||||
|
||||
// close item of interest
|
||||
close xLIST_ITEM(pxItem, gItemVal, pxItem_next, pxItem_prev, pxList);
|
||||
} else {
|
||||
// `pxItem` is not end of DLS suffix
|
||||
// -> `pxItem_next` is also in DLS suffix
|
||||
// open DLS suffix one step further
|
||||
|
||||
// rest of DLS suffix
|
||||
assert( DLS(pxItem_next, pxItem, gEnd, gEndPrev,
|
||||
drop(1, drop(pxItemIndex_0, gCells)),
|
||||
drop(1, drop(pxItemIndex_0, gVals)),
|
||||
pxList) );
|
||||
open DLS(pxItem_next, pxItem, gEnd, gEndPrev,
|
||||
drop(1, drop(pxItemIndex_0, gCells)),
|
||||
drop(1, drop(pxItemIndex_0, gVals)),
|
||||
pxList);
|
||||
assert( xLIST_ITEM(pxItem_next, ?gItem_nextVal, ?pxItem_next_next, pxItem, pxList) );
|
||||
open xLIST_ITEM(pxItem, gItemVal, pxItem_next, pxItem_prev, pxList);
|
||||
mem_suffix_implies_mem(pxItem_next, gCells, pxItemIndex_0);
|
||||
assert( mem(pxItem->pxNext, gCells) == true );
|
||||
|
||||
// close rest of DLS suffix
|
||||
close xLIST_ITEM(pxItem_next, gItem_nextVal, pxItem_next_next, pxItem, pxList);
|
||||
close DLS(pxItem_next, pxItem, gEnd, gEndPrev,
|
||||
drop(1, drop(pxItemIndex_0, gCells)),
|
||||
drop(1, drop(pxItemIndex_0, gVals)),
|
||||
pxList);
|
||||
|
||||
// close item of interest
|
||||
close xLIST_ITEM(pxItem, gItemVal, pxItem_next, pxItem_prev, pxList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lemma void DLS_nonEndItem_next_close(struct xLIST* pxList, struct xLIST_ITEM* pxItem,
|
||||
list<struct xLIST_ITEM*> gCells,
|
||||
list<TickType_t> gVals)
|
||||
requires
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gCells) > 1
|
||||
&*&
|
||||
// DLS prefix
|
||||
DLS(?gEnd, ?gEndPrev, pxItem, ?gItem_prev, ?gCellsPrefix, ?gValsPrefix,
|
||||
pxList)
|
||||
&*&
|
||||
mem(pxItem, gCells) == true &*&
|
||||
gCellsPrefix == take(index_of(pxItem, gCells), gCells) &*&
|
||||
gValsPrefix == take(index_of(pxItem, gCells), gVals)
|
||||
&*&
|
||||
// item of interest
|
||||
pxItem != gEnd &*&
|
||||
xLIST_ITEM(pxItem, ?gItemVal, ?gItem_next, gItem_prev, pxList) &*&
|
||||
mem(gItemVal, gVals) == true &*&
|
||||
gItemVal == nth(index_of(pxItem, gCells), gVals)
|
||||
&*&
|
||||
// DLS suffix
|
||||
(pxItem != gEndPrev
|
||||
? DLS(gItem_next, pxItem, gEnd, gEndPrev,
|
||||
drop(1, drop(index_of(pxItem, gCells), gCells)),
|
||||
drop(1, drop(index_of(pxItem, gCells), gVals)),
|
||||
pxList)
|
||||
: (gItem_next == gEnd &*&
|
||||
index_of(pxItem, gCells) == length(gCells) - 1
|
||||
)
|
||||
)
|
||||
&*&
|
||||
mem(gItem_next, gCells) == true;
|
||||
ensures
|
||||
DLS(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, pxList);
|
||||
{
|
||||
int gItemIndex = index_of(pxItem, gCells);
|
||||
head_drop_n_equals_nths(gCells, gItemIndex);
|
||||
head_drop_n_equals_nths(gVals, gItemIndex);
|
||||
|
||||
if( pxItem != gEndPrev ) {
|
||||
assert( drop(gItemIndex, gVals) == cons(_, _) );
|
||||
assert( xLIST_ITEM(pxItem, ?gV, _, gItem_prev, pxList) );
|
||||
nth_index(gCells, pxItem);
|
||||
close DLS(pxItem, gItem_prev, gEnd, gEndPrev,
|
||||
drop(gItemIndex, gCells), drop(gItemIndex, gVals),
|
||||
pxList);
|
||||
join(gEnd, gEndPrev, pxItem, gItem_prev, gCellsPrefix, gValsPrefix,
|
||||
pxItem, gItem_prev, gEnd, gEndPrev, drop(gItemIndex, gCells), drop(gItemIndex, gVals));
|
||||
} else {
|
||||
assert( xLIST_ITEM(pxItem, ?gV, ?gNext, gItem_prev, pxList) );
|
||||
assert( xLIST_ITEM(pxItem, gV, gEnd, gItem_prev, pxList) );
|
||||
close DLS(pxItem, gItem_prev, gEnd, gEndPrev, cons(pxItem, nil), cons(gItemVal, nil), pxList);
|
||||
join(gEnd, gEndPrev, pxItem, gItem_prev, gCellsPrefix, gValsPrefix,
|
||||
pxItem, gItem_prev, gEnd, gEndPrev, cons(pxItem, nil), cons(gItemVal, nil));
|
||||
assert( DLS(gEnd, gEndPrev, gEnd, gEndPrev, ?gCellsRes, ?gValsRes, pxList));
|
||||
|
||||
assert( gCellsPrefix == take(index_of(pxItem, gCells), gCells) );
|
||||
assert( gValsPrefix == take(index_of(pxItem, gCells), gVals) );
|
||||
assert( gCellsRes == append(gCellsPrefix, cons(pxItem, nil)) );
|
||||
assert( gValsRes == append(gValsPrefix, cons(gItemVal, nil)) );
|
||||
|
||||
|
||||
drop_n_plus_one(gCells, index_of(pxItem, gCells));
|
||||
drop_n_plus_one(gVals, index_of(pxItem, gCells));
|
||||
nth_index(gCells, pxItem);
|
||||
|
||||
assert( gCellsRes == gCells );
|
||||
assert( gValsRes == gVals );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lemma void DLS_next_open(struct xLIST* pxList, struct xLIST_ITEM* pxItem)
|
||||
requires
|
||||
DLS(?gEnd, ?gEndPrev, gEnd, gEndPrev, ?gCells, ?gVals, pxList) &*&
|
||||
mem(pxItem, gCells) == true &*&
|
||||
gEnd == head(gCells) &*&
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gCells) > 1;
|
||||
ensures
|
||||
pxItem == gEnd
|
||||
? (
|
||||
xLIST_ITEM(gEnd, head(gVals), ?gItem_next, gEndPrev, pxList) &*&
|
||||
DLS(gItem_next, gEnd, gEnd, gEndPrev, drop(1, gCells), drop(1, gVals), pxList ) &*&
|
||||
mem(gItem_next, gCells) == true
|
||||
)
|
||||
: (
|
||||
// DLS prefix
|
||||
DLS(gEnd, gEndPrev, pxItem, ?gItem_prev,
|
||||
take(index_of(pxItem, gCells), gCells),
|
||||
take(index_of(pxItem, gCells), gVals),
|
||||
pxList)
|
||||
&*&
|
||||
// item of interest
|
||||
xLIST_ITEM(pxItem, ?gItemVal, ?pxItem_next, gItem_prev, pxList) &*&
|
||||
gItemVal == nth(index_of(pxItem, gCells), gVals)
|
||||
&*&
|
||||
// DLS suffix
|
||||
(pxItem != gEndPrev
|
||||
? DLS(pxItem_next, pxItem, gEnd, gEndPrev,
|
||||
drop(1, drop(index_of(pxItem, gCells), gCells)),
|
||||
drop(1, drop(index_of(pxItem, gCells), gVals)),
|
||||
pxList)
|
||||
: (pxItem_next == gEnd &*&
|
||||
index_of(pxItem, gCells) == length(gCells) - 1
|
||||
)
|
||||
)
|
||||
&*&
|
||||
mem(pxItem_next, gCells) == true
|
||||
);
|
||||
{
|
||||
if( pxItem == gEnd ) {
|
||||
DLS_end_next_open(pxList, pxItem);
|
||||
} else {
|
||||
DLS_nonEndItem_next_open(pxList, pxItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lemma void DLS_next_close(struct xLIST* pxList, struct xLIST_ITEM* pxItem,
|
||||
list<struct xLIST_ITEM*> gCells,
|
||||
list<TickType_t> gVals,
|
||||
struct xLIST_ITEM* gEnd,
|
||||
struct xLIST_ITEM* gEndPrev)
|
||||
requires
|
||||
head(gCells) == gEnd &*&
|
||||
length(gCells) > 1 &*&
|
||||
length(gCells) == length(gVals) &*&
|
||||
pxItem == gEnd
|
||||
? (
|
||||
xLIST_ITEM(gEnd, ?gItemVal, ?gItem_next, gEndPrev, pxList) &*&
|
||||
DLS(gItem_next, gEnd, gEnd, gEndPrev, drop(1, gCells), drop(1, gVals), pxList) &*&
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gCells) > 0 &*&
|
||||
head(gVals) == gItemVal
|
||||
)
|
||||
: (
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gCells) > 1
|
||||
&*&
|
||||
// DLS prefix
|
||||
DLS(gEnd, gEndPrev, pxItem, ?gItem_prev, ?gCellsPrefix, ?gValsPrefix,
|
||||
pxList)
|
||||
&*&
|
||||
mem(pxItem, gCells) == true &*&
|
||||
gCellsPrefix == take(index_of(pxItem, gCells), gCells) &*&
|
||||
gValsPrefix == take(index_of(pxItem, gCells), gVals)
|
||||
&*&
|
||||
// item of interest
|
||||
pxItem != gEnd &*&
|
||||
xLIST_ITEM(pxItem, ?gItemVal, ?gItem_next, gItem_prev, pxList) &*&
|
||||
mem(gItemVal, gVals) == true &*&
|
||||
gItemVal == nth(index_of(pxItem, gCells), gVals)
|
||||
&*&
|
||||
// DLS suffix
|
||||
(pxItem != gEndPrev
|
||||
? DLS(gItem_next, pxItem, gEnd, gEndPrev,
|
||||
drop(1, drop(index_of(pxItem, gCells), gCells)),
|
||||
drop(1, drop(index_of(pxItem, gCells), gVals)),
|
||||
pxList)
|
||||
: (gItem_next == gEnd &*&
|
||||
index_of(pxItem, gCells) == length(gCells) - 1
|
||||
)
|
||||
)
|
||||
&*&
|
||||
mem(gItem_next, gCells) == true
|
||||
);
|
||||
ensures
|
||||
DLS(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, pxList);
|
||||
{
|
||||
if( pxItem == gEnd ) {
|
||||
DLS_end_next_close(pxList, pxItem);
|
||||
|
||||
// why is this necessary?
|
||||
assert( gCells == cons( _, _) );
|
||||
assert( gVals == cons(_, _) );
|
||||
} else {
|
||||
DLS_nonEndItem_next_close(pxList, pxItem, gCells, gVals);
|
||||
}
|
||||
}
|
||||
@*/
|
||||
|
||||
#ifdef IGNORE_DEPRECATED
|
||||
/* By verifying the following function, we can validate that the above lemmas
|
||||
* apply to the use cases they are meant for.
|
||||
*/
|
||||
void lemma_validation__DLS_item_next(struct xLIST_ITEM* pxTaskItem)
|
||||
/* @ requires
|
||||
DLS(?gEnd, ?gEndPrev, gEnd, gEndPrev, ?gCells, ?gVals, ?gList) &*&
|
||||
mem(pxTaskItem, gCells) == true &*&
|
||||
gEnd == head(gCells) &*&
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gCells) > 1;
|
||||
@*/
|
||||
/* @ ensures
|
||||
DLS(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, gList) &*&
|
||||
mem(pxTaskItem, gCells) == true;
|
||||
@*/
|
||||
{
|
||||
//@ struct xLIST_ITEM* gTaskItem_0 = pxTaskItem;
|
||||
|
||||
/* @
|
||||
if( gTaskItem_0 == gEnd ) {
|
||||
DLS_end_next_open(gList, gTaskItem_0);
|
||||
} else {
|
||||
DLS_nonEndItem_next_open(gList, gTaskItem_0);
|
||||
}
|
||||
@*/
|
||||
|
||||
//@ DLS_next_open(gList, gTaskItem_0);
|
||||
|
||||
pxTaskItem = pxTaskItem->pxNext;
|
||||
//@ struct xLIST_ITEM* pxItem_1 = pxTaskItem;
|
||||
|
||||
|
||||
//@ close xLIST_ITEM(gTaskItem_0, ?gTaskItemVal, _, _, gList);
|
||||
|
||||
//@ DLS_next_close(gList, gTaskItem_0, gCells, gVals, gEnd, gEndPrev);
|
||||
|
||||
/* @
|
||||
if( gTaskItem_0 == gEnd ) {
|
||||
DLS_end_next_close(gList, gTaskItem_0);
|
||||
assert( DLS(gEnd, gEndPrev, gEnd, gEndPrev, ?gCells2, ?gVals2, gList) );
|
||||
|
||||
// why is this necessary?
|
||||
assert( gCells == cons( _, _) );
|
||||
assert( gVals == cons(_, _) );
|
||||
} else {
|
||||
DLS_nonEndItem_next_close(gList, gTaskItem_0, gCells, gVals);
|
||||
}
|
||||
@*/
|
||||
|
||||
//@ assert( mem(pxItem_1, gCells) == true );
|
||||
}
|
||||
#endif I/* GNORE_DEPRECATED */
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------
|
||||
* The folling lemmas aim to simpilfy the lemmas above and reduce
|
||||
* the number of case distinctions that are introduced by applying them.
|
||||
*/
|
||||
|
||||
|
||||
/*@
|
||||
// Splitting a full DLS of the form
|
||||
// DLS(end, endPrev, end, endPrev, cells, vals, list)
|
||||
// at item `I` should result in a prefix, the item of interest and a suffix.
|
||||
// Both prefix and suffix can be empty, which the standard DLS predicate does
|
||||
// not allow
|
||||
predicate DLS_prefix(
|
||||
// prefix args
|
||||
list<struct xLIST_ITEM*> prefCells,
|
||||
list<TickType_t> prefVals,
|
||||
list<void*> prefOwners,
|
||||
struct xLIST_ITEM* item,
|
||||
struct xLIST_ITEM* itemPrev,
|
||||
// unsplit DLS args
|
||||
struct xLIST_ITEM *end,
|
||||
struct xLIST_ITEM *endPrev,
|
||||
struct xLIST *pxContainer) =
|
||||
length(prefCells) == length(prefVals) &*&
|
||||
length(prefOwners) == length(prefCells) &*&
|
||||
switch(prefCells) {
|
||||
case nil: return
|
||||
prefVals == nil &*&
|
||||
prefOwners == nil &*&
|
||||
item == end &*&
|
||||
itemPrev == endPrev;
|
||||
case cons(headItem, tailCells): return
|
||||
item != end &*&
|
||||
// itemPrev != endPrev &*& // do we need to know this?
|
||||
headItem == end &*&
|
||||
DLS(end, endPrev, item, itemPrev, prefCells, prefVals, prefOwners,
|
||||
pxContainer);
|
||||
};
|
||||
|
||||
predicate DLS_suffix(
|
||||
// suffix args
|
||||
list<struct xLIST_ITEM*> sufCells,
|
||||
list<TickType_t> sufVals,
|
||||
list<void*> sufOwners,
|
||||
struct xLIST_ITEM* item,
|
||||
struct xLIST_ITEM* itemNext,
|
||||
// unsplit DLS args
|
||||
struct xLIST_ITEM *end,
|
||||
struct xLIST_ITEM *endPrev,
|
||||
struct xLIST *pxContainer) =
|
||||
length(sufCells) == length(sufVals) &*&
|
||||
length(sufOwners) == length(sufCells) &*&
|
||||
switch(sufCells) {
|
||||
case nil: return
|
||||
sufVals == nil &*&
|
||||
sufOwners == nil &*&
|
||||
item == endPrev &*&
|
||||
itemNext == end;
|
||||
case cons(headItem, tailCells): return
|
||||
item != endPrev &*&
|
||||
mem(endPrev, sufCells) == true &*&
|
||||
index_of(endPrev, sufCells) == length(sufCells)-1 &*&
|
||||
DLS(itemNext, item, end, endPrev, sufCells, sufVals, sufOwners,
|
||||
pxContainer);
|
||||
};
|
||||
|
||||
|
||||
lemma void DLS_open_2(struct xLIST_ITEM* pxItem)
|
||||
requires
|
||||
DLS(?gEnd, ?gEndPrev, gEnd, gEndPrev, ?gCells, ?gVals, ?gOwners, ?gList) &*&
|
||||
mem(pxItem, gCells) == true &*&
|
||||
gEnd == head(gCells) &*&
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gOwners) == length(gCells) &*&
|
||||
length(gCells) > 1;
|
||||
ensures
|
||||
DLS_prefix(?gPrefCells, ?gPrefVals, ?gPrefOwners, pxItem, ?gItemPrev,
|
||||
gEnd, gEndPrev, gList)
|
||||
&*&
|
||||
xLIST_ITEM(pxItem, ?gItemVal, ?gItemNext, gItemPrev, ?gOw, gList)
|
||||
&*&
|
||||
DLS_suffix(?gSufCells, ?gSufVals, ?gSufOwners, pxItem, gItemNext,
|
||||
gEnd, gEndPrev, gList)
|
||||
&*&
|
||||
// lists have form "prefix + element + suffix"
|
||||
gCells == append(gPrefCells, append(singleton(pxItem), gSufCells)) &*&
|
||||
gVals == append(gPrefVals, append(singleton(gItemVal), gSufVals)) &*&
|
||||
gOwners == append(gPrefOwners, append(singleton(gOw), gSufOwners))
|
||||
&*&
|
||||
// next in cells
|
||||
mem(gItemNext, gCells) == true &*&
|
||||
// prev in cells
|
||||
mem(gItemPrev, gCells) == true
|
||||
;
|
||||
{
|
||||
if(pxItem == gEnd) {
|
||||
// pxItem is first/ left-most item in the list
|
||||
// -> empty prefix
|
||||
|
||||
open DLS(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, gOwners, gList);
|
||||
assert( xLIST_ITEM(pxItem, ?gItemVal, ?gItemNext, ?gItemPrev, ?gOw, gList) );
|
||||
assert( DLS(gItemNext, pxItem, gEnd, gEndPrev,
|
||||
?gSufCells, ?gSufVals, ?gSufOwners, gList) );
|
||||
close DLS_prefix(nil, nil, nil, pxItem, gItemPrev,
|
||||
gEnd, gEndPrev, gList);
|
||||
|
||||
// Prove: `mem(gItemNext, gCells) == true`
|
||||
open DLS(gItemNext, pxItem, gEnd, gEndPrev,
|
||||
gSufCells, gSufVals, gSufOwners, gList);
|
||||
assert( mem(gItemNext, gCells) == true );
|
||||
close DLS(gItemNext, pxItem, gEnd, gEndPrev,
|
||||
gSufCells, gSufVals, gSufOwners, gList);
|
||||
|
||||
// Prove: `mem(gItemPrev, gCells) == true `
|
||||
assert( gItemPrev == gEndPrev );
|
||||
dls_last_mem(gItemNext, pxItem, gEnd, gEndPrev, gSufCells);
|
||||
assert( mem(gItemPrev, gCells) == true );
|
||||
|
||||
close DLS_suffix(gSufCells, gSufVals, gSufOwners, pxItem, gItemNext,
|
||||
gEnd, gEndPrev, gList);
|
||||
} else {
|
||||
// pxItem is not the first/ left-most item in the list
|
||||
// -> non-empty prefix
|
||||
// (potentially empty suffix)
|
||||
|
||||
int gItemIndex = index_of(pxItem, gCells);
|
||||
split(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, pxItem, gItemIndex);
|
||||
|
||||
assert( DLS(gEnd, gEndPrev, pxItem, ?gItemPrev,
|
||||
?gPrefCells, ?gPrefVals, ?gPrefOwners, gList) );
|
||||
// -> Will be wrapped inside the prefix constructed at the end of this
|
||||
// lemma.
|
||||
|
||||
assert( DLS(pxItem, gItemPrev, gEnd, gEndPrev,
|
||||
?gPartCells, ?gPartVals, ?gPartOwners, gList) );
|
||||
// -> The tail of this DLS will make up the suffix constructed at the
|
||||
// end of this lemma.
|
||||
|
||||
// Notes on cell and val lists:
|
||||
assert( length(gPartCells) == length(gPartVals) );
|
||||
assert( gPartCells == drop(gItemIndex, gCells) );
|
||||
assert( gPartVals == drop(gItemIndex, gVals) );
|
||||
|
||||
// Prove: `head(gPrefCells) == gEnd`
|
||||
// Necessary to construct prefix later.
|
||||
// Implies `mem(gItemPrev, gCells) == true`.
|
||||
open DLS(gEnd, gEndPrev, pxItem, gItemPrev,
|
||||
gPrefCells, gPrefVals, gPrefOwners, gList);
|
||||
assert( head(gPrefCells) == gEnd );
|
||||
close DLS(gEnd, gEndPrev, pxItem, gItemPrev,
|
||||
gPrefCells, gPrefVals, gPrefOwners, gList);
|
||||
assert( mem(gItemPrev, gCells) == true );
|
||||
|
||||
open DLS(pxItem, gItemPrev, gEnd, gEndPrev,
|
||||
gPartCells, gPartVals, gPartOwners, gList);
|
||||
assert( xLIST_ITEM(pxItem, ?gItemVal, ?gItemNext, gItemPrev, ?gOw, gList) );
|
||||
|
||||
if( pxItem == gEndPrev ) {
|
||||
// pxItem is the last/ right-most item in the list.
|
||||
// -> empty suffix
|
||||
assert( gItemNext == gEnd );
|
||||
|
||||
// prove: `mem(gItemNext, gCells) == true`
|
||||
dls_first_mem(gEnd, gEndPrev, pxItem, gItemPrev, gPrefCells);
|
||||
assert( mem(gItemNext, gPrefCells) == true );
|
||||
assert( gPrefCells == take(gItemIndex, gCells) );
|
||||
mem_prefix_implies_mem(gItemNext, gCells, gItemIndex);
|
||||
assert( mem(gItemNext, gCells) == true );
|
||||
|
||||
|
||||
// prove: mem(gItemNext, gCells) == true
|
||||
open xLIST_ITEM(pxItem, gItemVal, gItemNext, gItemPrev, gOw,
|
||||
gList);
|
||||
assert( gItemNext == gEnd );
|
||||
assert( mem(gItemNext, gCells) == true );
|
||||
close xLIST_ITEM(pxItem, gItemVal, gItemNext, gItemPrev, gOw,
|
||||
gList);
|
||||
|
||||
close DLS_prefix(gPrefCells, gPrefVals, gPrefOwners, pxItem,
|
||||
gItemPrev, gEnd, gEndPrev, gList);
|
||||
close DLS_suffix(nil, nil, nil, pxItem, gItemNext,
|
||||
gEnd, gEndPrev, gList);
|
||||
} else {
|
||||
// pxItem is not the last/ right-most item in the list.
|
||||
// -> non-empty suffix
|
||||
|
||||
assert( DLS(gItemNext, pxItem, gEnd, gEndPrev,
|
||||
?gSufCells, ?gSufVals, ?gSufOwners, gList) );
|
||||
assert( gSufCells == drop(1, gPartCells) );
|
||||
|
||||
// Prove: - `drop(gItemIndex+1, gCells) == gSufCells`
|
||||
// - `drop(gItemIndex+1, gVals) == gSufVals`
|
||||
// - `drop(gItemIndex+1, gOwners) == gSufOwners`
|
||||
// -> Required to prove `mem(gItemNext, gCells) == true` and also to
|
||||
// prove relationship between gCells/gVals and their segmentation.
|
||||
assert( drop(1, drop(gItemIndex, gCells)) == gSufCells );
|
||||
assert( drop(1, drop(gItemIndex, gVals)) == gSufVals );
|
||||
assert( drop(1, drop(gItemIndex, gOwners)) == gSufOwners );
|
||||
drop_n_plus_m(gCells, 1, gItemIndex);
|
||||
drop_n_plus_m(gVals, 1, gItemIndex);
|
||||
drop_n_plus_m(gOwners, 1, gItemIndex);
|
||||
assert( drop(gItemIndex+1, gCells) == gSufCells );
|
||||
assert( drop(gItemIndex+1, gVals) == gSufVals );
|
||||
assert( drop(gItemIndex+1, gOwners) == gSufOwners );
|
||||
|
||||
// Prove: `mem(gItemNext, gCells) == true`
|
||||
open DLS(gItemNext, pxItem, gEnd, gEndPrev,
|
||||
gSufCells, gSufVals, gSufOwners, gList);
|
||||
assert( mem(gItemNext, gSufCells) == true );
|
||||
mem_suffix_implies_mem(gItemNext, gCells, gItemIndex+1);
|
||||
assert( mem(gItemNext, gCells) == true );
|
||||
close DLS(gItemNext, pxItem, gEnd, gEndPrev,
|
||||
gSufCells, gSufVals, gSufOwners, gList);
|
||||
|
||||
close DLS_prefix(gPrefCells, gPrefVals, gPrefOwners,
|
||||
pxItem, gItemPrev, gEnd, gEndPrev, gList);
|
||||
dls_last_mem(gItemNext, pxItem, gEnd, gEndPrev, gSufCells);
|
||||
close DLS_suffix(gSufCells, gSufVals, gSufOwners, pxItem, gItemNext,
|
||||
gEnd, gEndPrev, gList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void DLS_close_2(struct xLIST_ITEM* pxItem,
|
||||
list<struct xLIST_ITEM*> gCells,
|
||||
list<TickType_t> gVals,
|
||||
list<void*> gOwners)
|
||||
requires
|
||||
length(gCells) == length(gVals) &*&
|
||||
DLS_prefix(?gPrefCells, ?gPrefVals, ?gPrefOwners, pxItem, ?gItemPrev,
|
||||
?gEnd, ?gEndPrev, ?gList)
|
||||
&*&
|
||||
gEnd == head(gCells)
|
||||
&*&
|
||||
xLIST_ITEM(pxItem, ?gItemVal, ?gItemNext, gItemPrev, ?gOw, gList)
|
||||
&*&
|
||||
DLS_suffix(?gSufCells, ?gSufVals, ?gSufOwners, pxItem, gItemNext,
|
||||
gEnd, gEndPrev, gList)
|
||||
&*&
|
||||
// lists have form "prefix + element + suffix"
|
||||
gCells == append(gPrefCells, append(singleton(pxItem), gSufCells)) &*&
|
||||
gVals == append(gPrefVals, append(singleton(gItemVal), gSufVals)) &*&
|
||||
gOwners == append(gPrefOwners, append(singleton(gOw), gSufOwners))
|
||||
&*&
|
||||
// next in cells
|
||||
mem(gItemNext, gCells) == true &*&
|
||||
// prev in cells
|
||||
mem(gItemPrev, gCells) == true
|
||||
;
|
||||
ensures
|
||||
DLS(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, gOwners, gList) &*&
|
||||
mem(pxItem, gCells) == true &*&
|
||||
mem(gItemNext, gCells) == true &*&
|
||||
mem(gItemPrev, gCells) == true &*&
|
||||
// length(gCells) == length(gVals) &*&
|
||||
// length(gCells) > 1;
|
||||
true;
|
||||
{
|
||||
if( gPrefCells == nil ) {
|
||||
// pxItem is first/ left-most item in the list
|
||||
// -> empty prefix
|
||||
|
||||
open DLS_prefix(gPrefCells, gPrefVals, gPrefOwners, pxItem, gItemPrev,
|
||||
gEnd, gEndPrev, gList);
|
||||
assert( pxItem == gEnd );
|
||||
assert( gPrefVals == nil );
|
||||
|
||||
if( gSufCells == nil ) {
|
||||
// pxItem is last/ right-most item in the list
|
||||
|
||||
open DLS_suffix(gSufCells, gSufVals, gSufOwners, pxItem, gItemNext,
|
||||
gEnd, gEndPrev, gList);
|
||||
assert( pxItem == gEndPrev );
|
||||
assert( gSufVals == nil );
|
||||
|
||||
close DLS(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, gOwners,
|
||||
gList);
|
||||
} else {
|
||||
// pxItem is not last/ right-most item in the list
|
||||
|
||||
open DLS_suffix(gSufCells, gSufVals, gSufOwners, pxItem, gItemNext,
|
||||
gEnd, gEndPrev, gList);
|
||||
close DLS(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, gOwners,
|
||||
gList);
|
||||
}
|
||||
} else {
|
||||
// pxItem is not the first/ left-most item in the list
|
||||
// -> non-empty prefix
|
||||
// (potentially empty suffix)
|
||||
|
||||
open DLS_prefix(gPrefCells, gPrefVals, gPrefOwners, pxItem, gItemPrev,
|
||||
gEnd, gEndPrev, gList);
|
||||
|
||||
if( gSufCells == nil ) {
|
||||
// pxItem is the last/ right-most item in the list
|
||||
// -> empty suffix
|
||||
|
||||
open DLS_suffix(gSufCells, gSufVals, gSufOwners, pxItem, gItemNext,
|
||||
gEnd, gEndPrev, gList);
|
||||
assert( pxItem == gEndPrev );
|
||||
close DLS(pxItem, gItemPrev, gEnd, gEndPrev,
|
||||
singleton(pxItem), singleton(gItemVal), singleton(gOw),
|
||||
gList);
|
||||
join(gEnd, gEndPrev, pxItem, gItemPrev, gPrefCells, gPrefVals,
|
||||
pxItem, gItemPrev, gEnd, gEndPrev,
|
||||
singleton(pxItem), singleton(gItemVal));
|
||||
} else {
|
||||
// pxItem is not the last/ right-most item in the list
|
||||
// -> non-empty suffix
|
||||
|
||||
open DLS_suffix(gSufCells, gSufVals, gSufOwners, pxItem, gItemNext,
|
||||
gEnd, gEndPrev, gList);
|
||||
close DLS(pxItem, gItemPrev, gEnd, gEndPrev,
|
||||
cons(pxItem, gSufCells), cons(gItemVal, gSufVals),
|
||||
cons(gOw, gSufOwners),
|
||||
gList);
|
||||
join(gEnd, gEndPrev, pxItem, gItemPrev, gPrefCells, gPrefVals,
|
||||
pxItem, gItemPrev, gEnd, gEndPrev,
|
||||
cons(pxItem, gSufCells), cons(gItemVal, gSufVals));
|
||||
}
|
||||
}
|
||||
}
|
||||
@*/
|
||||
|
||||
struct xLIST_ITEM* lemma_validation__DLS_item_next_2(struct xLIST_ITEM* pxTaskItem)
|
||||
/*@ requires
|
||||
DLS(?gEnd, ?gEndPrev, gEnd, gEndPrev, ?gCells, ?gVals, ?gOwners, ?gList) &*&
|
||||
mem(pxTaskItem, gCells) == true &*&
|
||||
gEnd == head(gCells) &*&
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gOwners) == length(gCells) &*&
|
||||
length(gCells) > 1;
|
||||
@*/
|
||||
/*@ ensures
|
||||
DLS(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, gOwners, gList) &*&
|
||||
mem(pxTaskItem, gCells) == true &*&
|
||||
mem(result, gCells) == true;
|
||||
@*/
|
||||
{
|
||||
//@ struct xLIST_ITEM* gTaskItem_0 = pxTaskItem;
|
||||
|
||||
// first iteration step
|
||||
|
||||
//@ DLS_open_2(gTaskItem_0);
|
||||
/*@ assert( xLIST_ITEM(gTaskItem_0, ?gTaskItem_0_val,
|
||||
?gTaskItem_0_next, ?gTaskItem_0_prev, ?gTaskItem_0_owner,
|
||||
gList) );
|
||||
@*/
|
||||
pxTaskItem = pxTaskItem->pxNext;
|
||||
//@ struct xLIST_ITEM* gTaskItem_1 = pxTaskItem;
|
||||
|
||||
/*@ close xLIST_ITEM(gTaskItem_0, gTaskItem_0_val,
|
||||
gTaskItem_0_next, gTaskItem_0_prev, gTaskItem_0_owner,
|
||||
gList);
|
||||
@*/
|
||||
//@ DLS_close_2(gTaskItem_0, gCells, gVals, gOwners);
|
||||
|
||||
|
||||
// second iteration step
|
||||
|
||||
//@ DLS_open_2(gTaskItem_1);
|
||||
/*@ assert( xLIST_ITEM(gTaskItem_1, ?gTaskItem_1_val,
|
||||
?gTaskItem_1_next, ?gTaskItem_1_prev, ?gTaskItem_1_owner,
|
||||
gList) );
|
||||
@*/
|
||||
pxTaskItem = pxTaskItem->pxNext;
|
||||
//@ struct xLIST_ITEM* gTaskItem_2 = pxTaskItem;
|
||||
|
||||
/*@ close xLIST_ITEM(gTaskItem_1, gTaskItem_1_val,
|
||||
gTaskItem_1_next, gTaskItem_1_prev, gTaskItem_1_owner,
|
||||
gList);
|
||||
@*/
|
||||
//@ DLS_close_2(gTaskItem_1, gCells, gVals, gOwners);
|
||||
|
||||
|
||||
//@ assert( mem(gTaskItem_2, gCells) == true );
|
||||
return pxTaskItem;
|
||||
}
|
||||
|
||||
|
||||
struct xLIST_ITEM* lemma_validation__DLS_item_prev_2(struct xLIST_ITEM* pxTaskItem)
|
||||
/*@ requires
|
||||
DLS(?gEnd, ?gEndPrev, gEnd, gEndPrev, ?gCells, ?gVals, ?gOwners, ?gList) &*&
|
||||
mem(pxTaskItem, gCells) == true &*&
|
||||
gEnd == head(gCells) &*&
|
||||
length(gCells) == length(gVals) &*&
|
||||
length(gOwners) == length(gCells) &*&
|
||||
length(gCells) > 1;
|
||||
@*/
|
||||
/*@ ensures
|
||||
DLS(gEnd, gEndPrev, gEnd, gEndPrev, gCells, gVals, gOwners, gList) &*&
|
||||
mem(pxTaskItem, gCells) == true &*&
|
||||
mem(result, gCells) == true;
|
||||
@*/
|
||||
{
|
||||
//@ struct xLIST_ITEM* gTaskItem_0 = pxTaskItem;
|
||||
|
||||
// first iteration step
|
||||
|
||||
//@ DLS_open_2(gTaskItem_0);
|
||||
/*@ assert( xLIST_ITEM(gTaskItem_0, ?gTaskItem_0_val,
|
||||
?gTaskItem_0_next, ?gTaskItem_0_prev, ?gTaskItem_0_owner,
|
||||
gList) );
|
||||
@*/
|
||||
pxTaskItem = pxTaskItem->pxPrevious;
|
||||
//@ struct xLIST_ITEM* gTaskItem_1 = pxTaskItem;
|
||||
|
||||
/*@ close xLIST_ITEM(gTaskItem_0, gTaskItem_0_val,
|
||||
gTaskItem_0_next, gTaskItem_0_prev, gTaskItem_0_owner,
|
||||
gList);
|
||||
@*/
|
||||
//@ DLS_close_2(gTaskItem_0, gCells, gVals, gOwners);
|
||||
|
||||
|
||||
// second iteration step
|
||||
|
||||
//@ DLS_open_2(gTaskItem_1);
|
||||
/*@ assert( xLIST_ITEM(gTaskItem_1, ?gTaskItem_1_val,
|
||||
?gTaskItem_1_next, ?gTaskItem_1_prev, ?gTaskItem_1_owner,
|
||||
gList) );
|
||||
@*/
|
||||
pxTaskItem = pxTaskItem->pxPrevious;
|
||||
//@ struct xLIST_ITEM* gTaskItem_2 = pxTaskItem;
|
||||
|
||||
/*@ close xLIST_ITEM(gTaskItem_1, gTaskItem_1_val,
|
||||
gTaskItem_1_next, gTaskItem_1_prev,gTaskItem_1_owner,
|
||||
gList);
|
||||
@*/
|
||||
//@ DLS_close_2(gTaskItem_1, gCells, gVals, gOwners);
|
||||
|
||||
|
||||
//@ assert( mem(gTaskItem_2, gCells) == true );
|
||||
return pxTaskItem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* SCP_LIST_PREDICATES_EXTENDED_H */
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef STACK_PREDICATES
|
||||
#define STACK_PREDICATES
|
||||
|
||||
|
||||
/*@
|
||||
// Represents a stack that grows down (cf. RP2040 stack)
|
||||
predicate stack_p(StackType_t * pxStack,
|
||||
uint32_t ulStackDepth,
|
||||
StackType_t * pxTopOfStack,
|
||||
uint32_t ulFreeBytes,
|
||||
uint32_t ulUsedCells,
|
||||
uint32_t ulUnalignedBytes) =
|
||||
malloc_block_chars((char*) pxStack, ulStackDepth * sizeof(StackType_t)) &*&
|
||||
// Free stack cells. The size of this memory block is not necessarily a
|
||||
// multiple of sizeof(StackType_t), due to bitvector arithmetic.
|
||||
// At least, we cannot prove it.
|
||||
chars((char*) pxStack, ulFreeBytes, _) &*&
|
||||
//integer_(pxTopOfStack + sizeof(StackType_t), sizeof(StackType_t), false, _) &*&;
|
||||
|
||||
// If there is any free memory left in this stack,
|
||||
// pxTopOfStack points to the last sizeof(StackType_t) number of bytes.
|
||||
(char*) pxStack + ulFreeBytes == (char*) pxTopOfStack + sizeof(StackType_t) &*&
|
||||
// Used stack cells
|
||||
integers_(pxTopOfStack + 1, sizeof(StackType_t), false, ulUsedCells, _) &*&
|
||||
// Unaligned rest
|
||||
unalignedRestOfStack_p((char*) pxStack + ulFreeBytes + sizeof(StackType_t) * ulUsedCells,
|
||||
ulUnalignedBytes) &*&
|
||||
// `taskCHECK_FOR_STACK_OVERFLOW` macro on RP2040 port expects minimal stack size
|
||||
ulFreeBytes >= 0 &*&
|
||||
ulUsedCells >= 0 &*&
|
||||
ulFreeBytes + ulUsedCells * sizeof(StackType_t) >= 4 * sizeof(StackType_t);
|
||||
|
||||
predicate unalignedRestOfStack_p(char* p, uint32_t ulUnalignedBytes) =
|
||||
chars(p, ulUnalignedBytes, _);
|
||||
@*/
|
||||
|
||||
|
||||
|
||||
#endif /* STACK_PREDICATES */
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef TASKS_GH
|
||||
|
||||
#define TASKS_GH
|
||||
|
||||
#include "single_core_proofs/scp_list_predicates.h"
|
||||
|
||||
|
||||
/*@
|
||||
// This predicate represents the memory corresponding to an
|
||||
// initialised instance of type `TCB_t` aka `tskTaskControlBlock`.
|
||||
// The predicate itself is not used during the verification of
|
||||
// `vTaskSwitchContext`. However, we keep it around to allow proof authors to
|
||||
// validate that the predicates below indeed capture specific segments of a TCB.
|
||||
predicate TCB_p(TCB_t * tcb, uint32_t ulFreeBytesOnStack) =
|
||||
malloc_block_tskTaskControlBlock(tcb) &*&
|
||||
tcb->pxStack |-> ?stackPtr &*&
|
||||
tcb->pxTopOfStack |-> ?topPtr &*&
|
||||
stack_p(stackPtr, ?ulStackDepth, topPtr,
|
||||
ulFreeBytesOnStack, ?ulUsedCells, ?ulUnalignedBytes) &*&
|
||||
|
||||
xLIST_ITEM(&tcb->xStateListItem, _, _, _, _, _) &*&
|
||||
struct_xLIST_ITEM_padding(&tcb->xStateListItem) &*&
|
||||
xLIST_ITEM(&tcb->xEventListItem, _, _, _, _, _) &*&
|
||||
struct_xLIST_ITEM_padding(&tcb->xEventListItem) &*&
|
||||
|
||||
tcb->uxPriority |-> _ &*&
|
||||
|
||||
tcb->xTaskRunState |-> ?gTaskRunState &*&
|
||||
tcb->xIsIdle |-> _ &*&
|
||||
|
||||
// Assumes macro `configMAX_TASK_NAME_LEN` evaluates to 16.
|
||||
chars_(tcb->pcTaskName, 16, _) &*&
|
||||
|
||||
tcb->uxCriticalNesting |-> ?uxCriticalNesting &*&
|
||||
tcb->uxTCBNumber |-> _ &*&
|
||||
tcb->uxTaskNumber |-> _ &*&
|
||||
tcb->uxBasePriority |-> _ &*&
|
||||
tcb->uxMutexesHeld |-> _ &*&
|
||||
|
||||
// void * pvThreadLocalStoragePointers[ 5 ];
|
||||
pointers(tcb->pvThreadLocalStoragePointers, 5, _) &*&
|
||||
|
||||
// We assume that the macro `configTASK_NOTIFICATION_ARRAY_ENTRIES`
|
||||
// evaluates to 1.
|
||||
integers_(tcb->ulNotifiedValue, 4, false, 1, _) &*&
|
||||
uchars((unsigned char*) tcb->ucNotifyState, 1, _) &*&
|
||||
|
||||
tcb->ucDelayAborted |-> _;
|
||||
@*/
|
||||
|
||||
/*@
|
||||
// This predicate represents write access to a TCB's stack.
|
||||
predicate TCB_stack_p(TCB_t* tcb, uint32_t ulFreeBytesOnStack) =
|
||||
tcb->pxStack |-> ?stackPtr &*&
|
||||
tcb->pxTopOfStack |-> ?topPtr &*&
|
||||
stack_p(stackPtr, ?ulStackDepth, topPtr,
|
||||
ulFreeBytesOnStack, ?ulUsedCells, ?ulUnalignedBytes);
|
||||
|
||||
// This predicate represents write access to the run state of a TCB.
|
||||
predicate TCB_runState_p(TCB_t* tcb, TaskRunning_t state;) =
|
||||
tcb->xTaskRunState |-> state;
|
||||
|
||||
// This predicate represents write access to the nesting level of a TCB.
|
||||
// Entering a critical section increases the nesting level. Leaving it,
|
||||
// decreases it.
|
||||
predicate TCB_criticalNesting_p(TCB_t* tcb, UBaseType_t uxCriticalNesting) =
|
||||
tcb->uxCriticalNesting |-> uxCriticalNesting;
|
||||
@*/
|
||||
|
||||
#endif /* TASKS_GH */
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef TASK_RUNNING_STATES_H
|
||||
#define TASK_RUNNING_STATES_H
|
||||
|
||||
/* The source file `tasks.c` defines macros to denote the running states of
|
||||
* tasks:
|
||||
* - `taskTASK_NOT_RUNNING` == -1
|
||||
* - `taskTASK_YIELDING` == -2
|
||||
* - state >= 0 => task is running on core with ID `state`
|
||||
* We cannot import theses definitions into our proof headers. Hence, we define
|
||||
* our own macros and proof in `tasks.c` that they match.
|
||||
*/
|
||||
|
||||
#include "portmacro.h" // defines `BaseType_t`
|
||||
|
||||
/* Indicates that the task is not actively running on any core. */
|
||||
//VF_macro #define taskTASK_NOT_RUNNING ( BaseType_t ) ( -1 )
|
||||
|
||||
/* Indicates that the task is actively running but scheduled to yield. */
|
||||
//VF_macro #define taskTASK_YIELDING ( BaseType_t ) ( -2 )
|
||||
|
||||
|
||||
/* Verify that the preprocessor and our VeriFast proofs evaluate
|
||||
* `taskTASK_NOT_RUNNING` to the same values.
|
||||
*/
|
||||
void validate_taskTASK_NOT_RUNNING_value()
|
||||
//@ requires true;
|
||||
//@ ensures true;
|
||||
{
|
||||
//@ TaskRunning_t gVal = taskTASK_NOT_RUNNING;
|
||||
TaskRunning_t val = taskTASK_NOT_RUNNING;
|
||||
//@ assert( gVal == val );
|
||||
}
|
||||
|
||||
/* Verify that the preprocessor and our VeriFast proofs evaluate
|
||||
* `taskTASK_YIELDING` to the same values.
|
||||
*/
|
||||
void validate_taskTASK_YIELDING_value()
|
||||
//@ requires true;
|
||||
//@ ensures true;
|
||||
{
|
||||
//@ TaskRunning_t gVal = taskTASK_YIELDING;
|
||||
TaskRunning_t val = taskTASK_YIELDING;
|
||||
//@ assert( gVal == val );
|
||||
}
|
||||
|
||||
#endif /* TASK_RUNNING_STATES_H */
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
#ifndef VERIFAST_LISTS_EXTENDED_H
|
||||
#define VERIFAST_LISTS_EXTENDED_H
|
||||
|
||||
/* This file contains lemmas that would fit `list.gh` which is part
|
||||
* of VeriFast's standard library.
|
||||
*/
|
||||
|
||||
// Most of the following lemmas are axioms.
|
||||
|
||||
|
||||
/*@
|
||||
lemma void head_drop_n_equals_nths<t>(list<t> xs, int n);
|
||||
requires n >= 0;
|
||||
ensures head(drop(n, xs)) == nth(n, xs);
|
||||
|
||||
lemma void drop_index_equals_singleton_implies_last_element<t>(list<t> xs, t x);
|
||||
requires drop(index_of(x, xs), xs) == cons(x, nil);
|
||||
ensures index_of(x, xs) == length(xs) - 1;
|
||||
|
||||
lemma void nth_index<t>(list<t> xs, t x);
|
||||
requires mem(x, xs) == true;
|
||||
ensures nth(index_of(x, xs), xs) == x;
|
||||
|
||||
lemma void mem_prefix_implies_mem<t>(t x, list<t> xs, int n);
|
||||
requires mem(x, take(n, xs)) == true;
|
||||
ensures mem(x, xs) == true;
|
||||
|
||||
lemma void mem_suffix_implies_mem<t>(t x, list<t> xs, int n);
|
||||
requires mem(x, drop(n, xs)) == true;
|
||||
ensures mem(x, xs) == true;
|
||||
|
||||
lemma void drop_n_plus_m<t>(list<t> xs, int n, int m);
|
||||
requires true;
|
||||
ensures drop(n, drop(m, xs)) == drop(n + m, xs);
|
||||
|
||||
|
||||
fixpoint bool superset<t>(list<t> super, list<t> sub) {
|
||||
return subset(sub, super);
|
||||
}
|
||||
|
||||
|
||||
lemma void update_out_of_bounds<t>(int index, t x, list<t> xs)
|
||||
requires (index < 0 || index >= length(xs));
|
||||
ensures update(index, x, xs) == xs;
|
||||
{
|
||||
switch(xs) {
|
||||
case nil: // nothing to do
|
||||
case cons(h, rest): {
|
||||
update_out_of_bounds(index-1, x, rest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void index_of_different<t>(t x1, t x2, list<t> xs)
|
||||
requires x1 != x2 &*& mem(x1, xs) == true &*& mem(x2, xs) == true;
|
||||
ensures index_of(x1, xs) != index_of(x2, xs);
|
||||
{
|
||||
switch(xs) {
|
||||
case nil:
|
||||
case cons(h, rest):
|
||||
if(h != x1 && h != x2) {
|
||||
index_of_different(x1, x2, rest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lemma void remove_result_subset<t>(t x, list<t> xs);
|
||||
requires true;
|
||||
ensures subset(remove(x, xs), xs) == true;
|
||||
|
||||
lemma void append_take_nth_drop<t>(int n, list<t> xs);
|
||||
requires 0 <= n &*& n < length(xs);
|
||||
ensures xs == append( take(n, xs), cons(nth(n, xs), drop(n+1, xs)) );
|
||||
|
||||
// Note: `listex.gh` contains lemma `forall_drop` but no corresponding
|
||||
// `forall_take`.
|
||||
lemma void forall_take<t>(list<t> xs, fixpoint(t, bool) p, int i);
|
||||
requires forall(xs, p) == true;
|
||||
ensures forall(take(i, xs), p) == true;
|
||||
|
||||
lemma void forall_mem_implies_superset<t>(list<t> super, list<t> sub);
|
||||
requires forall(sub, (mem_list_elem)(super)) == true;
|
||||
ensures superset(super, sub) == true;
|
||||
|
||||
lemma void subset_implies_forall_mem<t>(list<t> sub, list<t> super);
|
||||
requires subset(sub, super) == true;
|
||||
ensures forall(sub, (mem_list_elem)(super)) == true;
|
||||
|
||||
lemma void forall_remove<t>(t x, list<t> xs, fixpoint(t, bool) p);
|
||||
requires forall(xs, p) == true;
|
||||
ensures forall(remove(x, xs), p) == true;
|
||||
|
||||
lemma void forall_remove_nth<t>(int n, list<t> xs, fixpoint(t, bool) p);
|
||||
requires forall(xs, p) == true;
|
||||
ensures forall(remove_nth(n, xs), p) == true;
|
||||
|
||||
lemma void nth_implies_mem<t>(int n, list<t> xs);
|
||||
requires 0 <= n &*& n < length(xs);
|
||||
ensures mem(nth(n, xs), xs) == true;
|
||||
|
||||
lemma void subset_append<t>(list<t> sub1, list<t> sub2, list<t> super);
|
||||
requires subset(sub1, super) == true &*& subset(sub2, super) == true;
|
||||
ensures subset(append(sub1, sub2), super) == true;
|
||||
|
||||
lemma void subset_take<t>(int i, list<t> xs);
|
||||
requires true;
|
||||
ensures subset(take(i, xs), xs) == true;
|
||||
|
||||
lemma void subset_drop<t>(int i, list<t> xs);
|
||||
requires true;
|
||||
ensures subset(drop(i, xs), xs) == true;
|
||||
@*/
|
||||
|
||||
|
||||
|
||||
#endif /* VERIFAST_LISTS_EXTENDED_H */
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
/* This is a stub used for the VeriFast proof. */
|
||||
|
||||
/*
|
||||
* FreeRTOS V202107.00
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef FREERTOS_CONFIG_H
|
||||
#define FREERTOS_CONFIG_H
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Application specific definitions.
|
||||
*
|
||||
* These definitions should be adjusted for your particular hardware and
|
||||
* application requirements.
|
||||
*
|
||||
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
|
||||
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
|
||||
*
|
||||
* See http://www.freertos.org/a00110.html
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
/* Scheduler Related */
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_TICKLESS_IDLE 0
|
||||
#define configUSE_IDLE_HOOK 0
|
||||
#define configUSE_TICK_HOOK 1
|
||||
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
|
||||
#define configMAX_PRIORITIES 32
|
||||
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
|
||||
/* Synchronization Related */
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configUSE_RECURSIVE_MUTEXES 1
|
||||
#define configUSE_APPLICATION_TASK_TAG 0
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
#define configQUEUE_REGISTRY_SIZE 8
|
||||
#define configUSE_QUEUE_SETS 1
|
||||
#define configUSE_TIME_SLICING 1
|
||||
#define configUSE_NEWLIB_REENTRANT 0
|
||||
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
||||
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
|
||||
|
||||
/* System */
|
||||
#define configSTACK_DEPTH_TYPE uint32_t
|
||||
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
|
||||
|
||||
/* Memory allocation related definitions. */
|
||||
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#define configTOTAL_HEAP_SIZE (128*1024)
|
||||
#define configAPPLICATION_ALLOCATED_HEAP 0
|
||||
|
||||
/* Hook function related definitions. */
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 2
|
||||
#define configUSE_MALLOC_FAILED_HOOK 1
|
||||
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
|
||||
|
||||
/* Run time and task stats gathering related definitions. */
|
||||
#define configGENERATE_RUN_TIME_STATS 0
|
||||
#define configUSE_TRACE_FACILITY 1
|
||||
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
|
||||
|
||||
/* Co-routine related definitions. */
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES 1
|
||||
|
||||
/* Software timer related definitions. */
|
||||
#define configUSE_TIMERS 1
|
||||
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
|
||||
#define configTIMER_QUEUE_LENGTH 10
|
||||
#define configTIMER_TASK_STACK_DEPTH 1024
|
||||
|
||||
/* Interrupt nesting behaviour configuration. */
|
||||
/*
|
||||
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
|
||||
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
|
||||
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
|
||||
*/
|
||||
|
||||
/* SMP port only */
|
||||
#define configNUM_CORES 100
|
||||
#define configTICK_CORE 1
|
||||
#define configRUN_MULTIPLE_PRIORITIES 1
|
||||
|
||||
/* RP2040 specific */
|
||||
#define configSUPPORT_PICO_SYNC_INTEROP 1
|
||||
#define configSUPPORT_PICO_TIME_INTEROP 1
|
||||
|
||||
#ifndef VERIFAST
|
||||
/* Reason for rewrite: VeriFast does not accept duplicate fct prototypes. */
|
||||
#include <assert.h>
|
||||
#endif /* VERIFAST */
|
||||
/* Define to trap errors during development. */
|
||||
#define configASSERT(x) assert(x)
|
||||
|
||||
/* Set the following definitions to 1 to include the API function, or zero
|
||||
to exclude the API function. */
|
||||
#define INCLUDE_vTaskPrioritySet 1
|
||||
#define INCLUDE_uxTaskPriorityGet 1
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_xTaskGetSchedulerState 1
|
||||
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
||||
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||
#define INCLUDE_xTaskGetIdleTaskHandle 1
|
||||
#define INCLUDE_eTaskGetState 1
|
||||
#define INCLUDE_xTimerPendFunctionCall 1
|
||||
#define INCLUDE_xTaskAbortDelay 1
|
||||
#define INCLUDE_xTaskGetHandle 1
|
||||
#define INCLUDE_xTaskResumeFromISR 1
|
||||
#define INCLUDE_xQueueGetMutexHolder 1
|
||||
|
||||
/* A header file that defines trace macro can be included here. */
|
||||
|
||||
#endif /* FREERTOS_CONFIG_H */
|
||||
35
Test/VeriFast/tasks/vTaskSwitchContext/proof_setup/asm.h
Normal file
35
Test/VeriFast/tasks/vTaskSwitchContext/proof_setup/asm.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef ASM_H
|
||||
#define ASM_H
|
||||
|
||||
/* VeriFast does not support inline assembler.
|
||||
* The following definitions replace macros that would normally evaluate to
|
||||
* inline assember by failing assertions.
|
||||
*/
|
||||
|
||||
/* VeriFast treats `assert` as keyword and does not support calling it
|
||||
* in many contexts where function calls are permitted. */
|
||||
bool assert_fct(bool b, const char*)
|
||||
{
|
||||
assert(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
// Port macros were originally defined in `portmacro.h`.
|
||||
|
||||
#undef portCHECK_IF_IN_ISR
|
||||
#define portCHECK_IF_IN_ISR() assert_fct(false, "portCHECK_IF_IN_ISR")
|
||||
|
||||
/* Additional reason for rewrite:
|
||||
* VeriFast does not support embedding block statements that consist of
|
||||
* multiple elemts in expression contexts, e.g., `({e1; e2})`.
|
||||
*/
|
||||
#undef portSET_INTERRUPT_MASK_FROM_ISR
|
||||
#define portSET_INTERRUPT_MASK_FROM_ISR() assert_fct(false, "portSET_INTERRUPT_MASK_FROM_ISR")
|
||||
|
||||
#undef portRESTORE_INTERRUPTS
|
||||
#define portRESTORE_INTERRUPTS(ulState) assert_fct(false, "portRESTORE_INTERRUPTS")
|
||||
|
||||
//#undef portDISABLE_INTERRUPTS
|
||||
//#define portDISABLE_INTERRUPTS() assert_fct(false, "portDISABLE_INTERRUPTS")
|
||||
|
||||
#endif /* ASM_H */
|
||||
|
|
@ -0,0 +1 @@
|
|||
This directory contains files that would normally be generated during the build.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
This directory contains files that would normally be generated during the build
|
||||
and placed into
|
||||
`$FREERTOS_SMP_DEMO_DIR/FreeRTOS/Demo/CORTEX_M0+_RP2040/build/generated/pico_base/pico`
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/* This is a stub used for the VeriFast proof. */
|
||||
|
||||
// AUTOGENERATED FROM PICO_CONFIG_HEADER_FILES and then PICO_<PLATFORM>_CONFIG_HEADER_FILES
|
||||
// DO NOT EDIT!
|
||||
|
||||
|
||||
// based on PICO_CONFIG_HEADER_FILES:
|
||||
|
||||
#ifdef VERIFAST
|
||||
/* Reason for rewrite: VeriFast cannot handle absolute include paths. */
|
||||
#include "freertos_sdk_config.h"
|
||||
#include "boards/pico.h"
|
||||
|
||||
// based on PICO_RP2040_CONFIG_HEADER_FILES:
|
||||
|
||||
#include "cmsis/rename_exceptions.h"
|
||||
#else
|
||||
// Generated include directives with absolute paths.
|
||||
#endif
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/* This is a stub used for the VeriFast proof. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
// ---------------------------------------
|
||||
// THIS FILE IS AUTOGENERATED; DO NOT EDIT
|
||||
// ---------------------------------------
|
||||
|
||||
#ifndef _PICO_VERSION_H
|
||||
#define _PICO_VERSION_H
|
||||
|
||||
#define PICO_SDK_VERSION_MAJOR 1
|
||||
#define PICO_SDK_VERSION_MINOR 4
|
||||
#define PICO_SDK_VERSION_REVISION 0
|
||||
#define PICO_SDK_VERSION_STRING "1.4.0"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* This file contains defines to configure the VeriFast proof setup.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PROOF_DEFS_H
|
||||
// Delete keywords VeriFast canot parse (in some contexts)
|
||||
#define inline
|
||||
#define __always_inline
|
||||
|
||||
/* `projdefs.h` defines `pdFALSE` and `pdTRUE` as 0 and 1 of type
|
||||
* `BaseType_t`. Both are assigned to variables smaller or
|
||||
* unsigned types. While that's safe in practice, it is not
|
||||
* type safe. Hence we define
|
||||
*/
|
||||
#undef pdFALSE
|
||||
#undef pdTRUE
|
||||
#define pdFALSE ( ( char ) 0 )
|
||||
#define pdTRUE ( ( char ) 1 )
|
||||
#define pd_U_FALSE ( ( unsigned char ) pdFALSE )
|
||||
#define pd_U_TRUE ( ( unsigned char ) pdTRUE )
|
||||
|
||||
#undef assert
|
||||
#undef configASSERT
|
||||
#define configASSERT(x) assert(x)
|
||||
#endif /* PROOF_DEFS_H */
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
This directory contains files copied from:
|
||||
`/Library/Developer/CommandLineTools/SDKs/MacOSX12.3.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers`
|
||||
We cannot put this directory on VeriFast's include path because it contains
|
||||
the file `stdbool.h` which VeriFast cannot parse.
|
||||
|
||||
More specifically, VeriFast cannot parse the defines `#define false 0` and
|
||||
`#define true 1` contained in the header `stdbool.h`.
|
||||
Therefore, by default, it skips all includes of `stdbool.h` and
|
||||
uses its builtin definitions of `true` and `false`. However, if we manually
|
||||
specify an include path (via VeriFast's `-I` option) that contains `stdbool.h`,
|
||||
this behaviour changes. It stops skipping these includes which leads to parse
|
||||
errors.
|
||||
924
Test/VeriFast/tasks/vTaskSwitchContext/proof_setup/sys/cdefs.h
Normal file
924
Test/VeriFast/tasks/vTaskSwitchContext/proof_setup/sys/cdefs.h
Normal file
|
|
@ -0,0 +1,924 @@
|
|||
/* This is a stub used for the VeriFast proof. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000-2018 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. The rights granted to you under the License
|
||||
* may not be used to create, or enable the creation or redistribution of,
|
||||
* unlawful or unlicensed copies of an Apple operating system, or to
|
||||
* circumvent, violate, or enable the circumvention or violation of, any
|
||||
* terms of an Apple operating system software license agreement.
|
||||
*
|
||||
* Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
|
||||
*/
|
||||
/* Copyright 1995 NeXT Computer, Inc. All rights reserved. */
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Berkeley Software Design, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)cdefs.h 8.8 (Berkeley) 1/9/95
|
||||
*/
|
||||
|
||||
#ifndef _CDEFS_H_
|
||||
#define _CDEFS_H_
|
||||
|
||||
/* Verifast proof setup */
|
||||
#ifdef VERIFAST
|
||||
/*
|
||||
* The proof setup header is already included at the top of the proof target,
|
||||
* e.g., `tasks.c`. But it seems like the contained defines are not propagated
|
||||
* to this file.
|
||||
*/
|
||||
#include "proof_defs.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#define __BEGIN_DECLS extern "C" {
|
||||
#define __END_DECLS }
|
||||
#else
|
||||
#define __BEGIN_DECLS
|
||||
#define __END_DECLS
|
||||
#endif
|
||||
|
||||
/* This SDK is designed to work with clang and specific versions of
|
||||
* gcc >= 4.0 with Apple's patch sets */
|
||||
#if !defined(__GNUC__) || __GNUC__ < 4
|
||||
#warning "Unsupported compiler detected"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compatibility with compilers and environments that don't support compiler
|
||||
* feature checking function-like macros.
|
||||
*/
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
#ifndef __has_include
|
||||
#define __has_include(x) 0
|
||||
#endif
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
#ifndef __has_attribute
|
||||
#define __has_attribute(x) 0
|
||||
#endif
|
||||
#ifndef __has_extension
|
||||
#define __has_extension(x) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The __CONCAT macro is used to concatenate parts of symbol names, e.g.
|
||||
* with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
|
||||
* The __CONCAT macro is a bit tricky -- make sure you don't put spaces
|
||||
* in between its arguments. __CONCAT can also concatenate double-quoted
|
||||
* strings produced by the __STRING macro, but this only works with ANSI C.
|
||||
*/
|
||||
#if defined(__STDC__) || defined(__cplusplus)
|
||||
#define __P(protos) protos /* full-blown ANSI C */
|
||||
#define __CONCAT(x, y) x ## y
|
||||
#define __STRING(x) #x
|
||||
|
||||
#define __const const /* define reserved names to standard */
|
||||
#define __signed signed
|
||||
#define __volatile volatile
|
||||
#if defined(__cplusplus)
|
||||
#define __inline inline /* convert to C++ keyword */
|
||||
#else
|
||||
#ifndef __GNUC__
|
||||
#define __inline /* delete GCC keyword */
|
||||
#endif /* !__GNUC__ */
|
||||
#endif /* !__cplusplus */
|
||||
|
||||
#else /* !(__STDC__ || __cplusplus) */
|
||||
#define __P(protos) () /* traditional C preprocessor */
|
||||
#define __CONCAT(x, y) x /**/ y
|
||||
#define __STRING(x) "x"
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __const /* delete pseudo-ANSI C keywords */
|
||||
#define __inline
|
||||
#define __signed
|
||||
#define __volatile
|
||||
#endif /* !__GNUC__ */
|
||||
|
||||
/*
|
||||
* In non-ANSI C environments, new programs will want ANSI-only C keywords
|
||||
* deleted from the program and old programs will want them left alone.
|
||||
* When using a compiler other than gcc, programs using the ANSI C keywords
|
||||
* const, inline etc. as normal identifiers should define -DNO_ANSI_KEYWORDS.
|
||||
* When using "gcc -traditional", we assume that this is the intent; if
|
||||
* __GNUC__ is defined but __STDC__ is not, we leave the new keywords alone.
|
||||
*/
|
||||
#ifndef NO_ANSI_KEYWORDS
|
||||
#define const __const /* convert ANSI C keywords */
|
||||
#define inline __inline
|
||||
#define signed __signed
|
||||
#define volatile __volatile
|
||||
#endif /* !NO_ANSI_KEYWORDS */
|
||||
#endif /* !(__STDC__ || __cplusplus) */
|
||||
|
||||
/*
|
||||
* __pure2 can be used for functions that are only a function of their scalar
|
||||
* arguments (meaning they can't dereference pointers).
|
||||
*
|
||||
* __stateful_pure can be used for functions that have no side effects,
|
||||
* but depend on the state of the memory.
|
||||
*/
|
||||
#define __dead2 __attribute__((__noreturn__))
|
||||
#define __pure2 __attribute__((__const__))
|
||||
#define __stateful_pure __attribute__((__pure__))
|
||||
|
||||
/* __unused denotes variables and functions that may not be used, preventing
|
||||
* the compiler from warning about it if not used.
|
||||
*/
|
||||
#define __unused __attribute__((__unused__))
|
||||
|
||||
/* __used forces variables and functions to be included even if it appears
|
||||
* to the compiler that they are not used (and would thust be discarded).
|
||||
*/
|
||||
#define __used __attribute__((__used__))
|
||||
|
||||
/* __cold marks code used for debugging or that is rarely taken
|
||||
* and tells the compiler to optimize for size and outline code.
|
||||
*/
|
||||
#if __has_attribute(cold)
|
||||
#define __cold __attribute__((__cold__))
|
||||
#else
|
||||
#define __cold
|
||||
#endif
|
||||
|
||||
/* __exported denotes symbols that should be exported even when symbols
|
||||
* are hidden by default.
|
||||
* __exported_push/_exported_pop are pragmas used to delimit a range of
|
||||
* symbols that should be exported even when symbols are hidden by default.
|
||||
*/
|
||||
#define __exported __attribute__((__visibility__("default")))
|
||||
#define __exported_push _Pragma("GCC visibility push(default)")
|
||||
#define __exported_pop _Pragma("GCC visibility pop")
|
||||
|
||||
/* __deprecated causes the compiler to produce a warning when encountering
|
||||
* code using the deprecated functionality.
|
||||
* __deprecated_msg() does the same, and compilers that support it will print
|
||||
* a message along with the deprecation warning.
|
||||
* This may require turning on such warning with the -Wdeprecated flag.
|
||||
* __deprecated_enum_msg() should be used on enums, and compilers that support
|
||||
* it will print the deprecation warning.
|
||||
* __kpi_deprecated() specifically indicates deprecation of kernel programming
|
||||
* interfaces in Kernel.framework used by KEXTs.
|
||||
*/
|
||||
#define __deprecated __attribute__((__deprecated__))
|
||||
|
||||
#if __has_extension(attribute_deprecated_with_message) || \
|
||||
(defined(__GNUC__) && ((__GNUC__ >= 5) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5))))
|
||||
#define __deprecated_msg(_msg) __attribute__((__deprecated__(_msg)))
|
||||
#else
|
||||
#define __deprecated_msg(_msg) __attribute__((__deprecated__))
|
||||
#endif
|
||||
|
||||
#if __has_extension(enumerator_attributes)
|
||||
#define __deprecated_enum_msg(_msg) __deprecated_msg(_msg)
|
||||
#else
|
||||
#define __deprecated_enum_msg(_msg)
|
||||
#endif
|
||||
|
||||
#define __kpi_deprecated(_msg) __deprecated_msg(_msg)
|
||||
|
||||
/* __unavailable causes the compiler to error out when encountering
|
||||
* code using the tagged function
|
||||
*/
|
||||
#if __has_attribute(unavailable)
|
||||
#define __unavailable __attribute__((__unavailable__))
|
||||
#else
|
||||
#define __unavailable
|
||||
#endif
|
||||
|
||||
#define __kpi_unavailable __unavailable
|
||||
|
||||
#if defined(__arm64__)
|
||||
#define __kpi_deprecated_arm64_macos_unavailable __unavailable
|
||||
#else
|
||||
#define __kpi_deprecated_arm64_macos_unavailable __deprecated
|
||||
#endif /* XNU_KERNEL_PRIVATE */
|
||||
|
||||
/* Delete pseudo-keywords wherever they are not available or needed. */
|
||||
#ifndef __dead
|
||||
#define __dead
|
||||
#define __pure
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We use `__restrict' as a way to define the `restrict' type qualifier
|
||||
* without disturbing older software that is unaware of C99 keywords.
|
||||
*/
|
||||
#if __STDC_VERSION__ < 199901
|
||||
#define __restrict
|
||||
#else
|
||||
#define __restrict restrict
|
||||
#endif
|
||||
|
||||
/* Compatibility with compilers and environments that don't support the
|
||||
* nullability feature.
|
||||
*/
|
||||
|
||||
#if !__has_feature(nullability)
|
||||
#ifndef __nullable
|
||||
#define __nullable
|
||||
#endif
|
||||
#ifndef __nonnull
|
||||
#define __nonnull
|
||||
#endif
|
||||
#ifndef __null_unspecified
|
||||
#define __null_unspecified
|
||||
#endif
|
||||
#ifndef _Nullable
|
||||
#define _Nullable
|
||||
#endif
|
||||
#ifndef _Nonnull
|
||||
#define _Nonnull
|
||||
#endif
|
||||
#ifndef _Null_unspecified
|
||||
#define _Null_unspecified
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __disable_tail_calls causes the compiler to not perform tail call
|
||||
* optimization inside the marked function.
|
||||
*/
|
||||
#if __has_attribute(disable_tail_calls)
|
||||
#define __disable_tail_calls __attribute__((__disable_tail_calls__))
|
||||
#else
|
||||
#define __disable_tail_calls
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __not_tail_called causes the compiler to prevent tail call optimization
|
||||
* on statically bound calls to the function. It has no effect on indirect
|
||||
* calls. Virtual functions, objective-c methods, and functions marked as
|
||||
* "always_inline" cannot be marked as __not_tail_called.
|
||||
*/
|
||||
#if __has_attribute(not_tail_called)
|
||||
#define __not_tail_called __attribute__((__not_tail_called__))
|
||||
#else
|
||||
#define __not_tail_called
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __result_use_check warns callers of a function that not using the function
|
||||
* return value is a bug, i.e. dismissing malloc() return value results in a
|
||||
* memory leak.
|
||||
*/
|
||||
#if __has_attribute(warn_unused_result)
|
||||
#define __result_use_check __attribute__((__warn_unused_result__))
|
||||
#else
|
||||
#define __result_use_check
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __swift_unavailable causes the compiler to mark a symbol as specifically
|
||||
* unavailable in Swift, regardless of any other availability in C.
|
||||
*/
|
||||
#if __has_feature(attribute_availability_swift)
|
||||
#define __swift_unavailable(_msg) __attribute__((__availability__(swift, unavailable, message=_msg)))
|
||||
#else
|
||||
#define __swift_unavailable(_msg)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __abortlike is the attribute to put on functions like abort() that are
|
||||
* typically used to mark assertions. These optimize the codegen
|
||||
* for outlining while still maintaining debugability.
|
||||
*/
|
||||
#ifndef __abortlike
|
||||
#define __abortlike __dead2 __cold __not_tail_called
|
||||
#endif
|
||||
|
||||
/* Declaring inline functions within headers is error-prone due to differences
|
||||
* across various versions of the C language and extensions. __header_inline
|
||||
* can be used to declare inline functions within system headers. In cases
|
||||
* where you want to force inlining instead of letting the compiler make
|
||||
* the decision, you can use __header_always_inline.
|
||||
*
|
||||
* Be aware that using inline for functions which compilers may also provide
|
||||
* builtins can behave differently under various compilers. If you intend to
|
||||
* provide an inline version of such a function, you may want to use a macro
|
||||
* instead.
|
||||
*
|
||||
* The check for !__GNUC__ || __clang__ is because gcc doesn't correctly
|
||||
* support c99 inline in some cases:
|
||||
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55965
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus) || \
|
||||
(__STDC_VERSION__ >= 199901L && \
|
||||
!defined(__GNUC_GNU_INLINE__) && \
|
||||
(!defined(__GNUC__) || defined(__clang__)))
|
||||
# define __header_inline inline
|
||||
#elif defined(__GNUC__) && defined(__GNUC_STDC_INLINE__)
|
||||
# define __header_inline extern __inline __attribute__((__gnu_inline__))
|
||||
#elif defined(__GNUC__)
|
||||
# define __header_inline extern __inline
|
||||
#else
|
||||
/* If we land here, we've encountered an unsupported compiler,
|
||||
* so hopefully it understands static __inline as a fallback.
|
||||
*/
|
||||
# define __header_inline static __inline
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define __header_always_inline __header_inline __attribute__ ((__always_inline__))
|
||||
#else
|
||||
/* Unfortunately, we're using a compiler that we don't know how to force to
|
||||
* inline. Oh well.
|
||||
*/
|
||||
# define __header_always_inline __header_inline
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compiler-dependent macros that bracket portions of code where the
|
||||
* "-Wunreachable-code" warning should be ignored. Please use sparingly.
|
||||
*/
|
||||
#if defined(__clang__)
|
||||
# define __unreachable_ok_push \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wunreachable-code\"")
|
||||
# define __unreachable_ok_pop \
|
||||
_Pragma("clang diagnostic pop")
|
||||
#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
# define __unreachable_ok_push \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wunreachable-code\"")
|
||||
# define __unreachable_ok_pop \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
# define __unreachable_ok_push
|
||||
# define __unreachable_ok_pop
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compiler-dependent macros to declare that functions take printf-like
|
||||
* or scanf-like arguments. They are null except for versions of gcc
|
||||
* that are known to support the features properly. Functions declared
|
||||
* with these attributes will cause compilation warnings if there is a
|
||||
* mismatch between the format string and subsequent function parameter
|
||||
* types.
|
||||
*/
|
||||
#define __printflike(fmtarg, firstvararg) \
|
||||
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
||||
#define __printf0like(fmtarg, firstvararg) \
|
||||
__attribute__((__format__ (__printf0__, fmtarg, firstvararg)))
|
||||
#define __scanflike(fmtarg, firstvararg) \
|
||||
__attribute__((__format__ (__scanf__, fmtarg, firstvararg)))
|
||||
#define __osloglike(fmtarg, firstvararg) \
|
||||
__attribute__((__format__ (__os_log__, fmtarg, firstvararg)))
|
||||
|
||||
#define __IDSTRING(name, string) static const char name[] __used = string
|
||||
|
||||
#ifndef __COPYRIGHT
|
||||
#define __COPYRIGHT(s) __IDSTRING(copyright,s)
|
||||
#endif
|
||||
|
||||
#ifndef __RCSID
|
||||
#define __RCSID(s) __IDSTRING(rcsid,s)
|
||||
#endif
|
||||
|
||||
#ifndef __SCCSID
|
||||
#define __SCCSID(s) __IDSTRING(sccsid,s)
|
||||
#endif
|
||||
|
||||
#ifndef __PROJECT_VERSION
|
||||
#define __PROJECT_VERSION(s) __IDSTRING(project_version,s)
|
||||
#endif
|
||||
|
||||
/* Source compatibility only, ID string not emitted in object file */
|
||||
#ifndef __FBSDID
|
||||
#define __FBSDID(s)
|
||||
#endif
|
||||
|
||||
#ifndef __DECONST
|
||||
#define __DECONST(type, var) __CAST_AWAY_QUALIFIER(var, const, type)
|
||||
#endif
|
||||
|
||||
#ifndef __DEVOLATILE
|
||||
#define __DEVOLATILE(type, var) __CAST_AWAY_QUALIFIER(var, volatile, type)
|
||||
#endif
|
||||
|
||||
#ifndef __DEQUALIFY
|
||||
#define __DEQUALIFY(type, var) __CAST_AWAY_QUALIFIER(var, const volatile, type)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __alloc_size can be used to label function arguments that represent the
|
||||
* size of memory that the function allocates and returns. The one-argument
|
||||
* form labels a single argument that gives the allocation size (where the
|
||||
* arguments are numbered from 1):
|
||||
*
|
||||
* void *malloc(size_t __size) __alloc_size(1);
|
||||
*
|
||||
* The two-argument form handles the case where the size is calculated as the
|
||||
* product of two arguments:
|
||||
*
|
||||
* void *calloc(size_t __count, size_t __size) __alloc_size(1,2);
|
||||
*/
|
||||
#ifndef __alloc_size
|
||||
#if __has_attribute(alloc_size)
|
||||
#define __alloc_size(...) __attribute__((alloc_size(__VA_ARGS__)))
|
||||
#else
|
||||
#define __alloc_size(...)
|
||||
#endif
|
||||
#endif // __alloc_size
|
||||
|
||||
/*
|
||||
* COMPILATION ENVIRONMENTS -- see compat(5) for additional detail
|
||||
*
|
||||
* DEFAULT By default newly complied code will get POSIX APIs plus
|
||||
* Apple API extensions in scope.
|
||||
*
|
||||
* Most users will use this compilation environment to avoid
|
||||
* behavioral differences between 32 and 64 bit code.
|
||||
*
|
||||
* LEGACY Defining _NONSTD_SOURCE will get pre-POSIX APIs plus Apple
|
||||
* API extensions in scope.
|
||||
*
|
||||
* This is generally equivalent to the Tiger release compilation
|
||||
* environment, except that it cannot be applied to 64 bit code;
|
||||
* its use is discouraged.
|
||||
*
|
||||
* We expect this environment to be deprecated in the future.
|
||||
*
|
||||
* STRICT Defining _POSIX_C_SOURCE or _XOPEN_SOURCE restricts the
|
||||
* available APIs to exactly the set of APIs defined by the
|
||||
* corresponding standard, based on the value defined.
|
||||
*
|
||||
* A correct, portable definition for _POSIX_C_SOURCE is 200112L.
|
||||
* A correct, portable definition for _XOPEN_SOURCE is 600L.
|
||||
*
|
||||
* Apple API extensions are not visible in this environment,
|
||||
* which can cause Apple specific code to fail to compile,
|
||||
* or behave incorrectly if prototypes are not in scope or
|
||||
* warnings about missing prototypes are not enabled or ignored.
|
||||
*
|
||||
* In any compilation environment, for correct symbol resolution to occur,
|
||||
* function prototypes must be in scope. It is recommended that all Apple
|
||||
* tools users add either the "-Wall" or "-Wimplicit-function-declaration"
|
||||
* compiler flags to their projects to be warned when a function is being
|
||||
* used without a prototype in scope.
|
||||
*/
|
||||
|
||||
/* These settings are particular to each product. */
|
||||
#define __DARWIN_ONLY_64_BIT_INO_T 0
|
||||
#define __DARWIN_ONLY_UNIX_CONFORMANCE 0
|
||||
#define __DARWIN_ONLY_VERS_1050 0
|
||||
#if defined(__x86_64__)
|
||||
#define __DARWIN_SUF_DARWIN14 "_darwin14"
|
||||
#define __DARWIN14_ALIAS(sym) __asm("_" __STRING(sym) __DARWIN_SUF_DARWIN14)
|
||||
#else
|
||||
#define __DARWIN14_ALIAS(sym)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The __DARWIN_ALIAS macros are used to do symbol renaming; they allow
|
||||
* legacy code to use the old symbol, thus maintaining binary compatibility
|
||||
* while new code can use a standards compliant version of the same function.
|
||||
*
|
||||
* __DARWIN_ALIAS is used by itself if the function signature has not
|
||||
* changed, it is used along with a #ifdef check for __DARWIN_UNIX03
|
||||
* if the signature has changed. Because the __LP64__ environment
|
||||
* only supports UNIX03 semantics it causes __DARWIN_UNIX03 to be
|
||||
* defined, but causes __DARWIN_ALIAS to do no symbol mangling.
|
||||
*
|
||||
* As a special case, when XCode is used to target a specific version of the
|
||||
* OS, the manifest constant __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
|
||||
* will be defined by the compiler, with the digits representing major version
|
||||
* time 100 + minor version times 10 (e.g. 10.5 := 1050). If we are targeting
|
||||
* pre-10.5, and it is the default compilation environment, revert the
|
||||
* compilation environment to pre-__DARWIN_UNIX03.
|
||||
*/
|
||||
#if !defined(__DARWIN_UNIX03)
|
||||
# define __DARWIN_UNIX03 0
|
||||
#endif /* !__DARWIN_UNIX03 */
|
||||
|
||||
#if !defined(__DARWIN_64_BIT_INO_T)
|
||||
# define __DARWIN_64_BIT_INO_T 0
|
||||
#endif /* !__DARWIN_64_BIT_INO_T */
|
||||
|
||||
#if !defined(__DARWIN_VERS_1050)
|
||||
# define __DARWIN_VERS_1050 0
|
||||
#endif /* !__DARWIN_VERS_1050 */
|
||||
|
||||
#if !defined(__DARWIN_NON_CANCELABLE)
|
||||
# define __DARWIN_NON_CANCELABLE 0
|
||||
#endif /* !__DARWIN_NON_CANCELABLE */
|
||||
|
||||
/*
|
||||
* symbol suffixes used for symbol versioning
|
||||
*/
|
||||
#if __DARWIN_UNIX03
|
||||
# if __DARWIN_ONLY_UNIX_CONFORMANCE
|
||||
# define __DARWIN_SUF_UNIX03 /* nothing */
|
||||
# else /* !__DARWIN_ONLY_UNIX_CONFORMANCE */
|
||||
# define __DARWIN_SUF_UNIX03 "$UNIX2003"
|
||||
# endif /* __DARWIN_ONLY_UNIX_CONFORMANCE */
|
||||
|
||||
# if __DARWIN_64_BIT_INO_T
|
||||
# if __DARWIN_ONLY_64_BIT_INO_T
|
||||
# define __DARWIN_SUF_64_BIT_INO_T /* nothing */
|
||||
# else /* !__DARWIN_ONLY_64_BIT_INO_T */
|
||||
# define __DARWIN_SUF_64_BIT_INO_T "$INODE64"
|
||||
# endif /* __DARWIN_ONLY_64_BIT_INO_T */
|
||||
# else /* !__DARWIN_64_BIT_INO_T */
|
||||
# define __DARWIN_SUF_64_BIT_INO_T /* nothing */
|
||||
# endif /* __DARWIN_64_BIT_INO_T */
|
||||
|
||||
# if __DARWIN_VERS_1050
|
||||
# if __DARWIN_ONLY_VERS_1050
|
||||
# define __DARWIN_SUF_1050 /* nothing */
|
||||
# else /* !__DARWIN_ONLY_VERS_1050 */
|
||||
# define __DARWIN_SUF_1050 "$1050"
|
||||
# endif /* __DARWIN_ONLY_VERS_1050 */
|
||||
# else /* !__DARWIN_VERS_1050 */
|
||||
# define __DARWIN_SUF_1050 /* nothing */
|
||||
# endif /* __DARWIN_VERS_1050 */
|
||||
|
||||
# if __DARWIN_NON_CANCELABLE
|
||||
# define __DARWIN_SUF_NON_CANCELABLE "$NOCANCEL"
|
||||
# else /* !__DARWIN_NON_CANCELABLE */
|
||||
# define __DARWIN_SUF_NON_CANCELABLE /* nothing */
|
||||
# endif /* __DARWIN_NON_CANCELABLE */
|
||||
|
||||
#else /* !__DARWIN_UNIX03 */
|
||||
# define __DARWIN_SUF_UNIX03 /* nothing */
|
||||
# define __DARWIN_SUF_64_BIT_INO_T /* nothing */
|
||||
# define __DARWIN_SUF_NON_CANCELABLE /* nothing */
|
||||
# define __DARWIN_SUF_1050 /* nothing */
|
||||
#endif /* __DARWIN_UNIX03 */
|
||||
|
||||
#define __DARWIN_SUF_EXTSN "$DARWIN_EXTSN"
|
||||
|
||||
/*
|
||||
* symbol versioning macros
|
||||
*/
|
||||
#define __DARWIN_ALIAS(sym) __asm("_" __STRING(sym) __DARWIN_SUF_UNIX03)
|
||||
#define __DARWIN_ALIAS_C(sym) __asm("_" __STRING(sym) __DARWIN_SUF_NON_CANCELABLE __DARWIN_SUF_UNIX03)
|
||||
#define __DARWIN_ALIAS_I(sym) __asm("_" __STRING(sym) __DARWIN_SUF_64_BIT_INO_T __DARWIN_SUF_UNIX03)
|
||||
#define __DARWIN_NOCANCEL(sym) __asm("_" __STRING(sym) __DARWIN_SUF_NON_CANCELABLE)
|
||||
#define __DARWIN_INODE64(sym) __asm("_" __STRING(sym) __DARWIN_SUF_64_BIT_INO_T)
|
||||
|
||||
#define __DARWIN_1050(sym) __asm("_" __STRING(sym) __DARWIN_SUF_1050)
|
||||
#define __DARWIN_1050ALIAS(sym) __asm("_" __STRING(sym) __DARWIN_SUF_1050 __DARWIN_SUF_UNIX03)
|
||||
#define __DARWIN_1050ALIAS_C(sym) __asm("_" __STRING(sym) __DARWIN_SUF_1050 __DARWIN_SUF_NON_CANCELABLE __DARWIN_SUF_UNIX03)
|
||||
#define __DARWIN_1050ALIAS_I(sym) __asm("_" __STRING(sym) __DARWIN_SUF_1050 __DARWIN_SUF_64_BIT_INO_T __DARWIN_SUF_UNIX03)
|
||||
#define __DARWIN_1050INODE64(sym) __asm("_" __STRING(sym) __DARWIN_SUF_1050 __DARWIN_SUF_64_BIT_INO_T)
|
||||
|
||||
#define __DARWIN_EXTSN(sym) __asm("_" __STRING(sym) __DARWIN_SUF_EXTSN)
|
||||
#define __DARWIN_EXTSN_C(sym) __asm("_" __STRING(sym) __DARWIN_SUF_EXTSN __DARWIN_SUF_NON_CANCELABLE)
|
||||
|
||||
/*
|
||||
* symbol release macros
|
||||
*/
|
||||
#define __DARWIN_ALIAS_STARTING(_mac, _iphone, x)
|
||||
|
||||
|
||||
/*
|
||||
* POSIX.1 requires that the macros we test be defined before any standard
|
||||
* header file is included. This permits us to convert values for feature
|
||||
* testing, as necessary, using only _POSIX_C_SOURCE.
|
||||
*
|
||||
* Here's a quick run-down of the versions:
|
||||
* defined(_POSIX_SOURCE) 1003.1-1988
|
||||
* _POSIX_C_SOURCE == 1L 1003.1-1990
|
||||
* _POSIX_C_SOURCE == 2L 1003.2-1992 C Language Binding Option
|
||||
* _POSIX_C_SOURCE == 199309L 1003.1b-1993
|
||||
* _POSIX_C_SOURCE == 199506L 1003.1c-1995, 1003.1i-1995,
|
||||
* and the omnibus ISO/IEC 9945-1: 1996
|
||||
* _POSIX_C_SOURCE == 200112L 1003.1-2001
|
||||
* _POSIX_C_SOURCE == 200809L 1003.1-2008
|
||||
*
|
||||
* In addition, the X/Open Portability Guide, which is now the Single UNIX
|
||||
* Specification, defines a feature-test macro which indicates the version of
|
||||
* that specification, and which subsumes _POSIX_C_SOURCE.
|
||||
*/
|
||||
|
||||
/* Deal with IEEE Std. 1003.1-1990, in which _POSIX_C_SOURCE == 1L. */
|
||||
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE == 1L
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 199009L
|
||||
#endif
|
||||
|
||||
/* Deal with IEEE Std. 1003.2-1992, in which _POSIX_C_SOURCE == 2L. */
|
||||
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE == 2L
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 199209L
|
||||
#endif
|
||||
|
||||
/* Deal with various X/Open Portability Guides and Single UNIX Spec. */
|
||||
#ifdef _XOPEN_SOURCE
|
||||
#if _XOPEN_SOURCE - 0L >= 700L && (!defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE - 0L < 200809L)
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#elif _XOPEN_SOURCE - 0L >= 600L && (!defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE - 0L < 200112L)
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
#elif _XOPEN_SOURCE - 0L >= 500L && (!defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE - 0L < 199506L)
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 199506L
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Deal with all versions of POSIX. The ordering relative to the tests above is
|
||||
* important.
|
||||
*/
|
||||
#if defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE)
|
||||
#define _POSIX_C_SOURCE 198808L
|
||||
#endif
|
||||
|
||||
/* POSIX C deprecation macros */
|
||||
#define __POSIX_C_DEPRECATED(ver)
|
||||
|
||||
/*
|
||||
* Set a single macro which will always be defined and can be used to determine
|
||||
* the appropriate namespace. For POSIX, these values will correspond to
|
||||
* _POSIX_C_SOURCE value. Currently there are two additional levels corresponding
|
||||
* to ANSI (_ANSI_SOURCE) and Darwin extensions (_DARWIN_C_SOURCE)
|
||||
*/
|
||||
#define __DARWIN_C_ANSI 010000L
|
||||
#define __DARWIN_C_FULL 900000L
|
||||
|
||||
#if defined(_ANSI_SOURCE)
|
||||
#define __DARWIN_C_LEVEL __DARWIN_C_ANSI
|
||||
#elif defined(_POSIX_C_SOURCE) && !defined(_DARWIN_C_SOURCE) && !defined(_NONSTD_SOURCE)
|
||||
#define __DARWIN_C_LEVEL _POSIX_C_SOURCE
|
||||
#else
|
||||
#define __DARWIN_C_LEVEL __DARWIN_C_FULL
|
||||
#endif
|
||||
|
||||
/* If the developer has neither requested a strict language mode nor a version
|
||||
* of POSIX, turn on functionality provided by __STDC_WANT_LIB_EXT1__ as part
|
||||
* of __DARWIN_C_FULL.
|
||||
*/
|
||||
#if !defined(__STDC_WANT_LIB_EXT1__) && !defined(__STRICT_ANSI__) && __DARWIN_C_LEVEL >= __DARWIN_C_FULL
|
||||
#define __STDC_WANT_LIB_EXT1__ 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* long long is not supported in c89 (__STRICT_ANSI__), but g++ -ansi and
|
||||
* c99 still want long longs. While not perfect, we allow long longs for
|
||||
* g++.
|
||||
*/
|
||||
#if (defined(__STRICT_ANSI__) && (__STDC_VERSION__ - 0 < 199901L) && !defined(__GNUG__))
|
||||
#define __DARWIN_NO_LONG_LONG 1
|
||||
#else
|
||||
#define __DARWIN_NO_LONG_LONG 0
|
||||
#endif
|
||||
|
||||
/*****************************************
|
||||
* Public darwin-specific feature macros
|
||||
*****************************************/
|
||||
|
||||
/*
|
||||
* _DARWIN_FEATURE_64_BIT_INODE indicates that the ino_t type is 64-bit, and
|
||||
* structures modified for 64-bit inodes (like struct stat) will be used.
|
||||
*/
|
||||
#if __DARWIN_64_BIT_INO_T
|
||||
#define _DARWIN_FEATURE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _DARWIN_FEATURE_64_ONLY_BIT_INODE indicates that the ino_t type may only
|
||||
* be 64-bit; there is no support for 32-bit ino_t when this macro is defined
|
||||
* (and non-zero). There is no struct stat64 either, as the regular
|
||||
* struct stat will already be the 64-bit version.
|
||||
*/
|
||||
#if __DARWIN_ONLY_64_BIT_INO_T
|
||||
#define _DARWIN_FEATURE_ONLY_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _DARWIN_FEATURE_ONLY_VERS_1050 indicates that only those APIs updated
|
||||
* in 10.5 exists; no pre-10.5 variants are available.
|
||||
*/
|
||||
#if __DARWIN_ONLY_VERS_1050
|
||||
#define _DARWIN_FEATURE_ONLY_VERS_1050 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _DARWIN_FEATURE_ONLY_UNIX_CONFORMANCE indicates only UNIX conforming API
|
||||
* are available (the legacy BSD APIs are not available)
|
||||
*/
|
||||
#if __DARWIN_ONLY_UNIX_CONFORMANCE
|
||||
#define _DARWIN_FEATURE_ONLY_UNIX_CONFORMANCE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _DARWIN_FEATURE_UNIX_CONFORMANCE indicates whether UNIX conformance is on,
|
||||
* and specifies the conformance level (3 is SUSv3)
|
||||
*/
|
||||
#if __DARWIN_UNIX03
|
||||
#define _DARWIN_FEATURE_UNIX_CONFORMANCE 3
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* This macro casts away the qualifier from the variable
|
||||
*
|
||||
* Note: use at your own risk, removing qualifiers can result in
|
||||
* catastrophic run-time failures.
|
||||
*/
|
||||
#ifndef __CAST_AWAY_QUALIFIER
|
||||
#define __CAST_AWAY_QUALIFIER(variable, qualifier, type) (type) (long)(variable)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __XNU_PRIVATE_EXTERN is a linkage decoration indicating that a symbol can be
|
||||
* used from other compilation units, but not other libraries or executables.
|
||||
*/
|
||||
#ifndef __XNU_PRIVATE_EXTERN
|
||||
#define __XNU_PRIVATE_EXTERN __attribute__((visibility("hidden")))
|
||||
#endif
|
||||
|
||||
#if __has_include(<ptrcheck.h>)
|
||||
#include <ptrcheck.h>
|
||||
#else
|
||||
/*
|
||||
* We intentionally define to nothing pointer attributes which do not have an
|
||||
* impact on the ABI. __indexable and __bidi_indexable are not defined because
|
||||
* of the ABI incompatibility that makes the diagnostic preferable.
|
||||
*/
|
||||
#define __has_ptrcheck 0
|
||||
#define __single
|
||||
#define __unsafe_indexable
|
||||
#define __counted_by(N)
|
||||
#define __sized_by(N)
|
||||
#define __ended_by(E)
|
||||
|
||||
/*
|
||||
* Similarly, we intentionally define to nothing the
|
||||
* __ptrcheck_abi_assume_single and __ptrcheck_abi_assume_unsafe_indexable
|
||||
* macros because they do not lead to an ABI incompatibility. However, we do not
|
||||
* define the indexable and unsafe_indexable ones because the diagnostic is
|
||||
* better than the silent ABI break.
|
||||
*/
|
||||
#define __ptrcheck_abi_assume_single()
|
||||
#define __ptrcheck_abi_assume_unsafe_indexable()
|
||||
|
||||
/* __unsafe_forge intrinsics are defined as regular C casts. */
|
||||
#define __unsafe_forge_bidi_indexable(T, P, S) ((T)(P))
|
||||
#define __unsafe_forge_single(T, P) ((T)(P))
|
||||
|
||||
/* decay operates normally; attribute is meaningless without pointer checks. */
|
||||
#define __array_decay_dicards_count_in_parameters
|
||||
#endif /* !__has_include(<ptrcheck.h>) */
|
||||
|
||||
#define __ASSUME_PTR_ABI_SINGLE_BEGIN __ptrcheck_abi_assume_single()
|
||||
#define __ASSUME_PTR_ABI_SINGLE_END __ptrcheck_abi_assume_unsafe_indexable()
|
||||
|
||||
#if __has_ptrcheck
|
||||
#define __header_indexable __indexable
|
||||
#define __header_bidi_indexable __bidi_indexable
|
||||
#else
|
||||
#define __header_indexable
|
||||
#define __header_bidi_indexable
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Architecture validation for current SDK
|
||||
*/
|
||||
#if !defined(__sys_cdefs_arch_unknown__) && defined(__i386__)
|
||||
#elif !defined(__sys_cdefs_arch_unknown__) && defined(__x86_64__)
|
||||
#elif !defined(__sys_cdefs_arch_unknown__) && defined(__arm__)
|
||||
#elif !defined(__sys_cdefs_arch_unknown__) && defined(__arm64__)
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Check if __probable and __improbable have already been defined elsewhere.
|
||||
* These macros inform the compiler (and humans) about which branches are likely
|
||||
* to be taken.
|
||||
*/
|
||||
#if !defined(__probable) && !defined(__improbable)
|
||||
#define __probable(x) __builtin_expect(!!(x), 1)
|
||||
#define __improbable(x) __builtin_expect(!!(x), 0)
|
||||
#endif /* !defined(__probable) && !defined(__improbable) */
|
||||
|
||||
#define __container_of(ptr, type, field) __extension__({ \
|
||||
const __typeof__(((type *)NULL)->field) *__ptr = (ptr); \
|
||||
(type *)((uintptr_t)__ptr - offsetof(type, field)); \
|
||||
})
|
||||
|
||||
|
||||
#define __compiler_barrier() __asm__ __volatile__("" ::: "memory")
|
||||
|
||||
#if __has_attribute(enum_extensibility)
|
||||
#define __enum_open __attribute__((__enum_extensibility__(open)))
|
||||
#define __enum_closed __attribute__((__enum_extensibility__(closed)))
|
||||
#else
|
||||
#define __enum_open
|
||||
#define __enum_closed
|
||||
#endif // __has_attribute(enum_extensibility)
|
||||
|
||||
#if __has_attribute(flag_enum)
|
||||
#define __enum_options __attribute__((__flag_enum__))
|
||||
#else
|
||||
#define __enum_options
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Similar to OS_ENUM/OS_CLOSED_ENUM/OS_OPTIONS/OS_CLOSED_OPTIONS
|
||||
*
|
||||
* This provides more advanced type checking on compilers supporting
|
||||
* the proper extensions, even in C.
|
||||
*/
|
||||
#if __has_feature(objc_fixed_enum) || __has_extension(cxx_fixed_enum) || \
|
||||
__has_extension(cxx_strong_enums)
|
||||
#define __enum_decl(_name, _type, ...) \
|
||||
typedef enum : _type __VA_ARGS__ __enum_open _name
|
||||
#define __enum_closed_decl(_name, _type, ...) \
|
||||
typedef enum : _type __VA_ARGS__ __enum_closed _name
|
||||
#define __options_decl(_name, _type, ...) \
|
||||
typedef enum : _type __VA_ARGS__ __enum_open __enum_options _name
|
||||
#define __options_closed_decl(_name, _type, ...) \
|
||||
typedef enum : _type __VA_ARGS__ __enum_closed __enum_options _name
|
||||
#else
|
||||
#define __enum_decl(_name, _type, ...) \
|
||||
typedef _type _name; enum __VA_ARGS__ __enum_open
|
||||
#define __enum_closed_decl(_name, _type, ...) \
|
||||
typedef _type _name; enum __VA_ARGS__ __enum_closed
|
||||
#define __options_decl(_name, _type, ...) \
|
||||
typedef _type _name; enum __VA_ARGS__ __enum_open __enum_options
|
||||
#define __options_closed_decl(_name, _type, ...) \
|
||||
typedef _type _name; enum __VA_ARGS__ __enum_closed __enum_options
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(KERNEL) && __has_attribute(xnu_usage_semantics)
|
||||
/*
|
||||
* These macros can be used to annotate type definitions or scalar structure
|
||||
* fields to inform the compiler about which semantic they have with regards
|
||||
* to the content of the underlying memory represented by such type or field.
|
||||
*
|
||||
* This information is used in the analysis of the types performed by the
|
||||
* signature based type segregation implemented in kalloc.
|
||||
*/
|
||||
#define __kernel_ptr_semantics __attribute__((xnu_usage_semantics("pointer")))
|
||||
#define __kernel_data_semantics __attribute__((xnu_usage_semantics("data")))
|
||||
#define __kernel_dual_semantics __attribute__((xnu_usage_semantics("pointer", "data")))
|
||||
|
||||
#else /* defined(KERNEL) && __has_attribute(xnu_usage_semantics) */
|
||||
|
||||
#define __kernel_ptr_semantics
|
||||
#define __kernel_data_semantics
|
||||
#define __kernel_dual_semantics
|
||||
|
||||
#endif /* defined(KERNEL) && __has_attribute(xnu_usage_semantics) */
|
||||
|
||||
#endif /* !_CDEFS_H_ */
|
||||
85
Test/VeriFast/tasks/vTaskSwitchContext/run-verifast.sh
Executable file
85
Test/VeriFast/tasks/vTaskSwitchContext/run-verifast.sh
Executable file
|
|
@ -0,0 +1,85 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script runs the preprocesses the annotated 'tasks.c' file
|
||||
# and checks the resulting proof file with VeriFast.
|
||||
#
|
||||
# This script expects the following arguments:
|
||||
# $1 : Absolute path to the base directory of this repository.
|
||||
# $2 : Absolute path to the VeriFast installation directory.
|
||||
|
||||
|
||||
# Checking validity of command line arguments.
|
||||
HELP="false"
|
||||
if [ $1 == "-h" ] || [ $1 == "--help" ]; then
|
||||
HELP="true"
|
||||
else
|
||||
if [ $# != 2 ] ; then
|
||||
echo Wrong number of arguments. Found $#, expected 2.
|
||||
HELP="true"
|
||||
fi
|
||||
|
||||
if [ ! -d "$1" ]; then
|
||||
echo "Directory (\$1) '$1' does not exist."
|
||||
HELP="true"
|
||||
fi
|
||||
|
||||
if [ ! -d "$2" ]; then
|
||||
echo "Directory (\$2) '$2' does not exist."
|
||||
HELP="true"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$HELP" != "false" ]; then
|
||||
echo Expected call of the form
|
||||
echo "run-verifast.sh <REPO_BASE_DIR> <VERIFAST_DIR>"
|
||||
echo "where"
|
||||
echo "<REPO_BASE_DIR> is the absolute path to the base directory of this repository and"
|
||||
echo "<VERIFAST_DIR> is the absolute path to the VeriFast installation directory."
|
||||
exit
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Relative or absolute path to the directory this script and `paths.sh` reside in.
|
||||
PREFIX=`dirname $0`
|
||||
# Absolute path to the base of this repository.
|
||||
REPO_BASE_DIR="$1"
|
||||
# Absolute path the VeriFast installation directory
|
||||
VF_DIR="$2"
|
||||
|
||||
# Load functions used to compute paths.
|
||||
. "$PREFIX/paths.sh"
|
||||
|
||||
|
||||
VF_PROOF_BASE_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
|
||||
PP_SCRIPT_DIR=`pp_script_dir $REPO_BASE_DIR`
|
||||
PREP="$PP_SCRIPT_DIR/prepare_file_for_VeriFast.sh"
|
||||
TASK_C=`vf_annotated_tasks_c $REPO_BASE_DIR`
|
||||
PP_TASK_C=`pp_vf_tasks_c $REPO_BASE_DIR`
|
||||
|
||||
PROOF_SETUP_DIR=`vf_proof_setup_dir $REPO_BASE_DIR`
|
||||
PROOF_FILES_DIR=`vf_proof_dir $REPO_BASE_DIR`
|
||||
|
||||
PP_ERR_LOG="`pp_log_dir $REPO_BASE_DIR`/preprocessing_errors.txt"
|
||||
|
||||
|
||||
ensure_output_dirs_exist $REPO_BASE_DIR
|
||||
|
||||
"$PREP" "$TASK_C" "$PP_TASK_C" "$PP_ERR_LOG" \
|
||||
"$REPO_BASE_DIR" "$VF_PROOF_BASE_DIR" "$VF_DIR"
|
||||
|
||||
# Remarks:
|
||||
# - Recently, provenance checks have been added to VF that break old proofs
|
||||
# involving pointer comparisons. The flag `-assume_no_provenance` turns them
|
||||
# off.
|
||||
|
||||
"$VF_DIR/bin/verifast" \
|
||||
-I $PROOF_SETUP_DIR \
|
||||
-I $PROOF_FILES_DIR \
|
||||
-assume_no_provenance \
|
||||
-disable_overflow_check \
|
||||
-allow_dead_code \
|
||||
-c \
|
||||
"$PP_TASK_C" \
|
||||
99
Test/VeriFast/tasks/vTaskSwitchContext/run-vfide.sh
Executable file
99
Test/VeriFast/tasks/vTaskSwitchContext/run-vfide.sh
Executable file
|
|
@ -0,0 +1,99 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script runs the preprocesses the annotated 'tasks.c' file
|
||||
# and loads the result into the VeriFast IDE.
|
||||
#
|
||||
# This script expects the following arguments:
|
||||
# $1 : Absolute path to the base directory of this repository.
|
||||
# $2 : Absolute path to the VeriFast installation directory.
|
||||
# $3 (Optional) : Font size
|
||||
|
||||
|
||||
|
||||
# Checking validity of command line arguments.
|
||||
HELP="false"
|
||||
if [ $1 == "-h" ] || [ $1 == "--help" ]; then
|
||||
HELP="true"
|
||||
else
|
||||
if [[ $# < 2 || $# > 3 ]] ; then
|
||||
echo Wrong number of arguments. Found $#, expected 2 or 3.
|
||||
HELP="true"
|
||||
fi
|
||||
|
||||
if [ ! -d "$1" ]; then
|
||||
echo "Directory (\$1) '$1' does not exist."
|
||||
HELP="true"
|
||||
fi
|
||||
|
||||
if [ ! -d "$2" ]; then
|
||||
echo "Directory (\$2) '$2' does not exist."
|
||||
HELP="true"
|
||||
fi
|
||||
|
||||
if ! [[ "$3" =~ ^[1-9]*$ ]] ; then
|
||||
echo "Argument (\$3) '$3' is not a number."
|
||||
HELP="true"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$HELP" != "false" ]; then
|
||||
echo Expected call of the form
|
||||
echo "run-vfide.sh <REPO_BASE_DIR> <VERIFAST_DIR> [<FONT_SIZE>]"
|
||||
echo "where:"
|
||||
echo "- <REPO_BASE_DIR> is the absolute path to the base directory of this repository"
|
||||
echo "- <VERIFAST_DIR> is the absolute path to the VeriFast installation directory"
|
||||
echo "- <FONT_SIZE> is an optional argument specifying the font size"
|
||||
exit
|
||||
fi
|
||||
|
||||
|
||||
# Relative or absolute path to the directory this script and `paths.sh` reside in.
|
||||
PREFIX=`dirname $0`
|
||||
# Absolute path to the base of this repository.
|
||||
REPO_BASE_DIR="$1"
|
||||
# Absolute path the VeriFast installation directory
|
||||
VF_DIR="$2"
|
||||
|
||||
FONT_SIZE=17
|
||||
if [ "$3" != "" ]
|
||||
then
|
||||
FONT_SIZE="$3"
|
||||
fi
|
||||
|
||||
# Load functions used to compute paths.
|
||||
. "$PREFIX/paths.sh"
|
||||
|
||||
|
||||
VF_PROOF_BASE_DIR=`vf_proof_base_dir $REPO_BASE_DIR`
|
||||
|
||||
|
||||
PP_SCRIPT_DIR=`pp_script_dir $REPO_BASE_DIR`
|
||||
PREP="$PP_SCRIPT_DIR/prepare_file_for_VeriFast.sh"
|
||||
TASK_C=`vf_annotated_tasks_c $REPO_BASE_DIR`
|
||||
PP_TASK_C=`pp_vf_tasks_c $REPO_BASE_DIR`
|
||||
|
||||
PROOF_SETUP_DIR=`vf_proof_setup_dir $REPO_BASE_DIR`
|
||||
PROOF_FILES_DIR=`vf_proof_dir $REPO_BASE_DIR`
|
||||
|
||||
PP_ERR_LOG="`pp_log_dir $REPO_BASE_DIR`/preprocessing_errors.txt"
|
||||
|
||||
|
||||
|
||||
|
||||
ensure_output_dirs_exist $REPO_BASE_DIR
|
||||
|
||||
"$PREP" "$TASK_C" "$PP_TASK_C" "$PP_ERR_LOG" \
|
||||
"$REPO_BASE_DIR" "$VF_PROOF_BASE_DIR" "$VF_DIR"
|
||||
|
||||
# Remarks:
|
||||
# - Recently, provenance checks have been added to VF that break old proofs
|
||||
# involving pointer comparisons. The flag `-assume_no_provenance` turns them
|
||||
# off.
|
||||
|
||||
"$VF_DIR/bin/vfide" "$PP_TASK_C" \
|
||||
-I $PROOF_SETUP_DIR \
|
||||
-I $PROOF_FILES_DIR \
|
||||
-assume_no_provenance \
|
||||
-disable_overflow_check \
|
||||
"$PP_TASK_C" \
|
||||
-codeFont "$FONT_SIZE" -traceFont "$FONT_SIZE" \
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 780173e22f197ec7481001f45a5daa1ae5d1788a
|
||||
1081
Test/VeriFast/tasks/vTaskSwitchContext/src/list.c
Normal file
1081
Test/VeriFast/tasks/vTaskSwitchContext/src/list.c
Normal file
File diff suppressed because it is too large
Load diff
6999
Test/VeriFast/tasks/vTaskSwitchContext/src/tasks.c
Normal file
6999
Test/VeriFast/tasks/vTaskSwitchContext/src/tasks.c
Normal file
File diff suppressed because it is too large
Load diff
26
Test/VeriFast/tasks/vTaskSwitchContext/stats/stats.md
Normal file
26
Test/VeriFast/tasks/vTaskSwitchContext/stats/stats.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#lines of code verified
|
||||
tasks.c:
|
||||
vTaskSwitchContext: 22
|
||||
prvSelectHighestPriorityTask: 68
|
||||
xTaskGetCurrentTaskHandle: 9
|
||||
global definitions and variables: 103
|
||||
|
||||
stack_macros.h:
|
||||
taskCHECK_FOR_STACK_OVERFLOW: 13
|
||||
|
||||
list.c:
|
||||
vListInitialiseItem: 4
|
||||
vListInsertEnd: 11
|
||||
uxListRemove: 17
|
||||
|
||||
list.h:
|
||||
global definitions: 23
|
||||
|
||||
FreeRTOSConfig.h: 65
|
||||
|
||||
total: 335
|
||||
|
||||
|
||||
#lines of annotation
|
||||
|
||||
tasks_vf_pp.c: 2328
|
||||
|
|
@ -1274,6 +1274,10 @@ typedef struct xSTATIC_TCB
|
|||
* users will recognise that it would be unwise to make direct use of the
|
||||
* structure members.
|
||||
*/
|
||||
#ifndef VERIFAST
|
||||
/* Reason for rewrite:
|
||||
* VeriFast does not support nested union definitions.
|
||||
*/
|
||||
typedef struct xSTATIC_QUEUE
|
||||
{
|
||||
void * pvDummy1[ 3 ];
|
||||
|
|
@ -1302,6 +1306,7 @@ typedef struct xSTATIC_QUEUE
|
|||
#endif
|
||||
} StaticQueue_t;
|
||||
typedef StaticQueue_t StaticSemaphore_t;
|
||||
#endif /* VERIFAST */
|
||||
|
||||
/*
|
||||
* In line with software engineering best practice, especially when supplying a
|
||||
|
|
|
|||
|
|
@ -28,6 +28,20 @@
|
|||
#ifndef TIMERS_H
|
||||
#define TIMERS_H
|
||||
|
||||
|
||||
#ifdef VERIFAST
|
||||
/* Reason for rewrite:
|
||||
* VeriFast bug:
|
||||
* Both `#ifdef INC_FREERTOS_H` and its negation `#ifdef INC_FREERTOS_H`
|
||||
* evaluate to true. See minimal example `define_name`.
|
||||
*/
|
||||
#define INC_FREERTOS_H
|
||||
/* Remember that this header is included indirectly `tasks.c` after it
|
||||
* includes `FreeRTOS.h`.
|
||||
*/
|
||||
// TODO: Remove this work-around once VF has been fixed.
|
||||
#endif /* VERIFAST */
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
#error "include FreeRTOS.h must appear in source files before include timers.h"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -77,7 +77,13 @@
|
|||
#define portSTACK_GROWTH ( -1 )
|
||||
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
|
||||
#define portBYTE_ALIGNMENT 8
|
||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||
#ifdef VERIFAST
|
||||
/* Reason for rewrite: VeriFast does not support the attriibute `used`.
|
||||
*/
|
||||
#define portDONT_DISCARD
|
||||
#else
|
||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||
#endif
|
||||
/* We have to use PICO_DIVIDER_DISABLE_INTERRUPTS as the source of truth rathern than our config,
|
||||
* as our FreeRTOSConfig.h header cannot be included by ASM code - which is what this affects in the SDK */
|
||||
#define portUSE_DIVIDER_SAVE_RESTORE !PICO_DIVIDER_DISABLE_INTERRUPTS
|
||||
|
|
@ -172,40 +178,45 @@
|
|||
/* Note this is a single method with uxAcquire parameter since we have
|
||||
* static vars, the method is always called with a compile time constant for
|
||||
* uxAcquire, and the compiler should dothe right thing! */
|
||||
static inline void vPortRecursiveLock(uint32_t ulLockNum, spin_lock_t *pxSpinLock, BaseType_t uxAcquire) {
|
||||
static uint8_t ucOwnedByCore[ portMAX_CORE_COUNT ];
|
||||
static uint8_t ucRecursionCountByLock[ portRTOS_SPINLOCK_COUNT ];
|
||||
configASSERT(ulLockNum >= 0 && ulLockNum < portRTOS_SPINLOCK_COUNT );
|
||||
uint32_t ulCoreNum = get_core_num();
|
||||
uint32_t ulLockBit = 1u << ulLockNum;
|
||||
configASSERT(ulLockBit < 256u );
|
||||
if( uxAcquire )
|
||||
{
|
||||
if( __builtin_expect( !*pxSpinLock, 0 ) )
|
||||
#ifdef VERIFAST
|
||||
/* Reason for rewrite: VeriFast does not support local static variables.
|
||||
*/
|
||||
#else
|
||||
static inline void vPortRecursiveLock(uint32_t ulLockNum, spin_lock_t *pxSpinLock, BaseType_t uxAcquire) {
|
||||
static uint8_t ucOwnedByCore[ portMAX_CORE_COUNT ];
|
||||
static uint8_t ucRecursionCountByLock[ portRTOS_SPINLOCK_COUNT ];
|
||||
configASSERT(ulLockNum >= 0 && ulLockNum < portRTOS_SPINLOCK_COUNT );
|
||||
uint32_t ulCoreNum = get_core_num();
|
||||
uint32_t ulLockBit = 1u << ulLockNum;
|
||||
configASSERT(ulLockBit < 256u );
|
||||
if( uxAcquire )
|
||||
{
|
||||
if( ucOwnedByCore[ulCoreNum] & ulLockBit )
|
||||
if( __builtin_expect( !*pxSpinLock, 0 ) )
|
||||
{
|
||||
configASSERT(ucRecursionCountByLock[ulLockNum] != 255u );
|
||||
ucRecursionCountByLock[ulLockNum]++;
|
||||
return;
|
||||
if( ucOwnedByCore[ulCoreNum] & ulLockBit )
|
||||
{
|
||||
configASSERT(ucRecursionCountByLock[ulLockNum] != 255u );
|
||||
ucRecursionCountByLock[ulLockNum]++;
|
||||
return;
|
||||
}
|
||||
while ( __builtin_expect( !*pxSpinLock, 0 ) );
|
||||
}
|
||||
__mem_fence_acquire();
|
||||
configASSERT(ucRecursionCountByLock[ulLockNum] == 0 );
|
||||
ucRecursionCountByLock[ulLockNum] = 1;
|
||||
ucOwnedByCore[ulCoreNum] |= ulLockBit;
|
||||
} else {
|
||||
configASSERT((ucOwnedByCore[ulCoreNum] & ulLockBit) != 0 );
|
||||
configASSERT(ucRecursionCountByLock[ulLockNum] != 0 );
|
||||
if( !--ucRecursionCountByLock[ulLockNum] )
|
||||
{
|
||||
ucOwnedByCore[ulCoreNum] &= ~ulLockBit;
|
||||
__mem_fence_release();
|
||||
*pxSpinLock = 1;
|
||||
}
|
||||
while ( __builtin_expect( !*pxSpinLock, 0 ) );
|
||||
}
|
||||
__mem_fence_acquire();
|
||||
configASSERT(ucRecursionCountByLock[ulLockNum] == 0 );
|
||||
ucRecursionCountByLock[ulLockNum] = 1;
|
||||
ucOwnedByCore[ulCoreNum] |= ulLockBit;
|
||||
} else {
|
||||
configASSERT((ucOwnedByCore[ulCoreNum] & ulLockBit) != 0 );
|
||||
configASSERT(ucRecursionCountByLock[ulLockNum] != 0 );
|
||||
if( !--ucRecursionCountByLock[ulLockNum] )
|
||||
{
|
||||
ucOwnedByCore[ulCoreNum] &= ~ulLockBit;
|
||||
__mem_fence_release();
|
||||
*pxSpinLock = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* VERIFAST */
|
||||
|
||||
#define portGET_ISR_LOCK() vPortRecursiveLock(0, spin_lock_instance(configSMP_SPINLOCK_0), pdTRUE)
|
||||
#define portRELEASE_ISR_LOCK() vPortRecursiveLock(0, spin_lock_instance(configSMP_SPINLOCK_0), pdFALSE)
|
||||
|
|
|
|||
2
portable/ThirdParty/GCC/RP2040/port.c
vendored
2
portable/ThirdParty/GCC/RP2040/port.c
vendored
|
|
@ -170,6 +170,8 @@ static uint8_t ucPrimaryCoreNum = INVALID_PRIMARY_CORE_NUM;
|
|||
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
|
||||
TaskFunction_t pxCode,
|
||||
void * pvParameters )
|
||||
//@ requires true;
|
||||
//@ ensures true;
|
||||
{
|
||||
/* Simulate the stack frame as it would be created by a context switch
|
||||
* interrupt. */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue