blob: d1b74c3833fa0d9e2a2c690611f4a3f09d6e50d6 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.5).
// Some portions generated by GitHub Copilot (claude-sonnet-4.6).
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
VOID _tx_thread_context_restore(VOID)
{
TX_THREAD *current_thread;
TX_THREAD *execute_thread;
_tx_win32_debug_entry_insert("CONTEXT_RESTORE", __FILE__, __LINE__);
_tx_thread_system_state[0]--;
current_thread = _tx_thread_current_ptr[0];
execute_thread = _tx_thread_execute_ptr[0];
if (_tx_thread_system_state[0] == 0UL)
{
if (current_thread != TX_NULL)
{
if ((_tx_thread_preempt_disable == 0U) && (current_thread != execute_thread))
{
/* If context_save skipped SuspendThread because the thread was spinning
* on the Win32 CS (suspension_type == 4), suspend it now. The ISR still
* holds the CS so the spinning thread cannot make forward progress, making
* SuspendThread safe to call here. mutex_access remains TRUE; the thread
* will clear it naturally when it acquires the CS after being resumed. */
if (current_thread -> tx_thread_win32_suspension_type == 4U)
{
_tx_win32_thread_suspend(current_thread -> tx_thread_win32_thread_handle);
}
current_thread -> tx_thread_win32_suspension_type = 1U;
if (_tx_timer_time_slice[0] != 0U)
{
current_thread -> tx_thread_time_slice = _tx_timer_time_slice[0];
_tx_timer_time_slice[0] = 0U;
}
_tx_thread_current_ptr[0] = TX_NULL;
_tx_win32_virtual_cores[0].tx_thread_smp_core_mapping_thread_handle = NULL;
_tx_win32_virtual_cores[0].tx_thread_smp_core_mapping_thread_id = 0U;
_tx_win32_virtual_cores[0].tx_thread_smp_core_mapping_thread = TX_NULL;
current_thread -> tx_thread_smp_core_control = 1U;
/* Signal the scheduler to assign the next execute_thread. Wait for the
* scheduler to signal isr_semaphore before returning: the scheduler holds
* the CS while waiting for start_ack from the execute_thread, which forces
* any thread calling TX_DISABLE to spin with mutex_access=TRUE while
* preempt_disable may be non-zero — exactly the window needed to satisfy
* the condition in tests such as wait_abort_and_isr. */
_tx_win32_timer_waiting = 1U;
MemoryBarrier();
if (SetEvent(_tx_win32_scheduler_event) == 0)
{
_tx_win32_system_error++;
}
if ((execute_thread != TX_NULL) &&
(execute_thread -> tx_thread_win32_suspension_type == 2U))
{
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
_tx_win32_wait_for_isr_rendezvous();
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
_tx_win32_semaphore_reset(_tx_win32_isr_semaphore);
}
_tx_win32_timer_waiting = 0U;
}
else
{
if ((current_thread -> tx_thread_win32_suspension_type == 3U) ||
(current_thread -> tx_thread_win32_suspension_type == 4U))
{
/* context_save did not call SuspendThread (type 3: preempt_disable≠0;
* type 4: thread was spinning on Win32 CS). Clear the flag; do not
* issue a matching ResumeThread. The thread will continue
* automatically once the ISR releases the Win32 critical section. */
current_thread -> tx_thread_win32_suspension_type = 0U;
}
else
{
/* suspension_type 0: context_save called SuspendThread. Always issue
* the matching ResumeThread here, regardless of mutex_access.
*
* Do NOT gate this on mutex_access: a thread on a different virtual core
* that happens to share the same stale TLS slot can momentarily stamp
* mutex_access = TRUE on this thread's struct while it is OS-suspended,
* which would otherwise cause context_restore to skip ResumeThread and
* leave the thread permanently suspended (deadlock). */
_tx_win32_thread_resume(current_thread -> tx_thread_win32_thread_handle);
}
}
}
else if (execute_thread != TX_NULL)
{
_tx_win32_timer_waiting = 1U;
MemoryBarrier();
if (SetEvent(_tx_win32_scheduler_event) == 0)
{
_tx_win32_system_error++;
}
if (execute_thread -> tx_thread_win32_suspension_type == 2U)
{
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
_tx_win32_wait_for_isr_rendezvous();
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
_tx_win32_semaphore_reset(_tx_win32_isr_semaphore);
}
_tx_win32_timer_waiting = 0U;
}
}
_tx_thread_smp_unprotect(TX_INT_ENABLE);
}
|