blob: 90ee3b9d0fcad3840c153e896c937242807dfcd7 [file] [log] [blame] [view] [edit]
`pincputest` shall verify that a peer thread being pinned to a new cpu is
rescheduled properly; particular attention shall be given to situations
where the thread can be rescheduled right away.
In order to cover all cases, the test shall ensure that the peer thread
rescheduling happens:
1. in any possible state of the peer thread (running, ready, blocked, sleeping),
2. whether the newly pinned cpu is the current cpu or another cpu
3. whether the thread from which the peer thread is pinned is a higher
or lower priority than the peer thread
4. and finally whether the involved threads are standard or real-time threads.
Note: the real-time threads are not collaboratively time-sliced with other threads
on their current cpu. This implies that a real-time thread will have to become
BLOCKED or SLEEPING before it can be interrupted.
In order to be able to set the peer thread in a given state, we need to use
a control thread with same or higher priority than the peer thread.
This control thread will be the `unittest thread`. The thread responsible
for pinning the `peer` thread is called the `main` thread.
Below sections illustrates the interactions between the `unittest` thread, the `main` thread and the `peer` thread to reach the expected `peer` thread state in the various
cases described above.
## Testing `thread_set_pinned_cpu` on a `[RUNNING]` peer
```mermaid
sequenceDiagram
participant U as unitest thread (priority peer+1)
participant M as main thread (priority peer+/-1)
participant P as peer thread (priority peer)
Note over U, P: Testing thread_set_pinned_cpu on a [RUNNING] peer
Note over M: main [BLOCKED]
Note over P: peer [BLOCKED]
U->>U:thread_set_pinned_cpu(get_current_thread(), p)
U->>P:thread_set_pinned_cpu(peer.thread, p)
U->>M:thread_set_pinned_cpu(peer.thread, p+1 or p+2)
Note over M: main is pinned to another or same cpu than peer will be<br/> allowing to test cases where<br/> 1) either current cpu needs to be rescheduled<br/> or 2) another cpu than current
U->>U: spin_lock(&peer.lock)
U->>+P: event_signal(&peer.ev_req)
P->>P: spin_lock(&peer.lock)
Note over P: peer [READY] until unittest in [BLOCKED]
U->>+M: event_signal(&main.ev_req)
U->>+U: event_wait(&main.ev_resp)
Note over U: unittest [BLOCKED]
U-->>P: peer thread scheduled on cpu p
Note over P: peer [RUNNING]
M->>M: loop until peer is [RUNNING]
M->>P: thread_set_pinned_cpu(p+1 or p+2)
M-->>P: peer thread scheduled on p+1 or p+2
Note over P: peer in [RUNNING] on the spin_lock
M->>U: event_signal(&main.ev_resp)
M-->>U: unitest unblocked by main
Note over U: unittest [RUNNING]
U->>U: spin_unlock(&peer.lock)
U-->>P: peer is unlocked by unittest
Note over P: peer is [RUNNING] unlocked from spin
U->>U: wait(&peer.ev_resp)
Note over U: unittest [BLOCKED]
P->>P: set actual_cpu
P->>U: event_signal(&peer.ev_resp)
P->>P: ev_wait(peer.ev_req)
P-->>U: unittest unblocked by peer
Note over P: peer [BLOCKED]
M->>M: ev_wait(peer.ev_req)
Note over M: main [BLOCKED]
U->>U: check actual_cpu == p+1 or p+2
```
## Testing `thread_set_pinned_cpu` on a `[READY]` peer
```mermaid
sequenceDiagram
participant U as unitest thread (priority peer+1)
participant M as main thread (priority peer+/-1)
participant P as peer thread (priority peer)
Note over U, P: Testing thread_set_pinned_cpu on a [READY] peer
Note over M: main [BLOCKED]
Note over P: peer [BLOCKED]
U->>U:thread_set_pinned_cpu(get_current_thread(), p)
U->>P:thread_set_pinned_cpu(peer.thread, p)
U->>M:thread_set_pinned_cpu(peer.thread, p+1 or p+2)
Note over M: main is pinned to another or same cpu than peer will be<br/> allowing to test cases where<br/> 1) either current cpu needs to be rescheduled<br/> or 2) another cpu than current
U->>U: spin_lock(&peer.lock)
U->>+P: event_signal(&peer.ev_req)
P->>P: spin_lock(&peer.lock)
Note over P: peer [READY] until unittest in [BLOCKED]
U->>+M: event_signal(&main.ev_req)
U->>+U: event_wait(&main.ev_resp)
Note over U: unittest [BLOCKED]
U-->>P: peer thread scheduled on cpu p
Note over P: peer [RUNNING]
M->>M: spin_lock(&main.lock)
M->>-U: event_signal(&main.ev_resp)
M->>M: loop until peer is [READY]
Note over U: unittest [RUNNING]
U-->>P: peer thread scheduled out of cpu p
Note over P: peer [READY]
U->>U: spin_lock(&main.lock)
Note over U: unittest [RUNNING] in busy loop due to locked lock
M->>P: thread_set_pinned_cpu(p+1)
Note over P: peer thread still spin locked in [READY]
M->>M: spin_unlock(&main.lock)
M-->>U: unittest unlocked
U->>P: spin_unlock(&peer.lock)
Note over P: peer thread [RUNNING] but still locked on spin_lock
U->>U: event_wait(&peer_ev_resp)
U-->>P: peer thread unlocked
Note over P: peer thread [RUNNING]
M-->>P: peer thread scheduled on p+1
P->>P: set actual_cpu
P->>U: event_signal(&peer.ev_resp)
P->>P: ev_wait(peer.ev_req)
Note over P: peer [BLOCKED]
M->>M: ev_wait(peer.ev_req)
Note over M: main [BLOCKED]
U->>U: check actual_cpu == p+1
```
## Testing `thread_set_pinned_cpu` on a `[BLOCKED]` peer
```mermaid
sequenceDiagram
participant U as unitest thread (priority peer+1)
participant M as main thread (priority peer+/-1)
participant P as peer thread (priority peer)
Note over U, P: Testing thread_set_pinned_cpu on a [BLOCKED] peer
Note over M: main [BLOCKED]
Note over P: peer [BLOCKED]
U->>U:thread_set_pinned_cpu(get_current_thread(), p)
U->>P:thread_set_pinned_cpu(peer.thread, p)
U->>M:thread_set_pinned_cpu(peer.thread, p+1 or p+2)
Note over M: main is pinned to another or same cpu than peer will be<br/> allowing to test cases where<br/> 1) either current cpu needs to be rescheduled<br/> or 2) another cpu than current
U->>+P: event_signal(&peer.ev_req)
P->>P: event_wait(&peer.blocked_ev)
Note over P: peer [BLOCKED]
U->>+M: event_signal(&main.ev_req)
U->>+U: event_wait(&main.ev_resp)
Note over U: unittest [BLOCKED]
M->>M: loop until peer is [BLOCKED]
M->>P: thread_set_pinned_cpu(p+1 or p+2)
M->>U: event_signal(&main.ev_resp)
M-->>U: unittest unblocked by main
Note over U: unittest [RUNNING]
U->>P: event_signal(&peer.blocked_ev)
U-->>P: peer unblocked by unittest
M-->>P: peer thread scheduled on p+1 or p+2
Note over P: peer [RUNNING]
P->>P: set actual_cpu
P->>U: event_signal(&peer.ev_resp)
P->>P: ev_wait(peer.ev_req)
Note over P: peer [BLOCKED]
M->>M: ev_wait(peer.ev_req)
Note over M: main [BLOCKED]
U->>U: wait(&peer.ev_resp)
U->>U: check actual_cpu == p+1 or p+2
```
## Testing `thread_set_pinned_cpu` on a `[SLEEPING]` peer
```mermaid
sequenceDiagram
participant U as unitest thread (priority peer+1)
participant M as main thread (priority peer+/-1)
participant P as peer thread (priority peer)
Note over U, P: Testing thread_set_pinned_cpu on a [SLEEPING] peer
Note over M: main [BLOCKED]
Note over P: peer [BLOCKED]
U->>U:thread_set_pinned_cpu(get_current_thread(), p)
U->>P:thread_set_pinned_cpu(peer.thread, p)
U->>M:thread_set_pinned_cpu(peer.thread, p+1 or p+2)
Note over M: main is pinned to another or same cpu than peer will be<br/> allowing to test cases where<br/> 1) either current cpu needs to be rescheduled<br/> or 2) another cpu than current
U->>+P: event_signal(&peer.ev_req)
P->>P: thread_sleep_ns(100ms)
Note over P: peer [SLEEPING]
U->>+M: event_signal(&main.ev_req)
U->>+U: event_wait(&main.ev_resp)
Note over U: unittest [BLOCKED]
M->>M: loop until peer is [SLEEPING]
M->>P: thread_set_pinned_cpu(p+1 or p+2)
M->>U: event_signal(&main.ev_resp)
M-->>U: unittest unblocked by main
Note over U: unittest [RUNNING]
M->>M: ev_wait(peer.ev_req)
Note over M: main [BLOCKED]
U->>U: wait(&peer.ev_resp)
Note over U: unittest [BLOCKING]
P-->>P: timer interrupt: waking-up peer
M-->>P: peer thread scheduled on p+1 or p+2
Note over P: peer [RUNNING]
P->>P: set actual_cpu
P->>U: event_signal(&peer.ev_resp)
P->>P: ev_wait(peer.ev_req)
Note over P: peer [BLOCKED]
P-->>U: unittest unblocked by peer
U->>U: check actual_cpu == p+1 or p+2
```