Skip to content

Commit d55b92a

Browse files
committed
extmod/zephyr_kernel: NSI investigation - preserved for reference.
This commit contains an investigation into using Zephyr's Native Simulator Infrastructure (NSI) for the POSIX/Unix threading layer. This work is being preserved for future reference, but NSI is not suitable for MicroPython's Unix port due to fundamental architectural incompatibility. ## What is NSI? NSI (Native Simulator Infrastructure) is Zephyr's official POSIX threading implementation, using cooperative threading to accurately simulate single- core microcontroller behavior on native (Unix/Linux) systems. ## How NSI Works NSI's nct.c (Native CPU Threading) module: - Creates pthreads that immediately block on semaphores (nct_wait_until_allowed) - Threads only execute when explicitly swapped in via nct_swap_threads() - Only one thread runs at a time (enforced single-core MCU simulation) - Requires explicit scheduler calls for any thread to make progress ## Why NSI Doesn't Work for MicroPython Unix Port **Architectural Mismatch:** - NSI: Cooperative threading (explicit scheduler swaps required) - MicroPython: Expects preemptive threading (OS scheduler manages threads) **Result:** - Threads created successfully via nct_new_thread() - Threads immediately blocked on semaphore waiting for nct_swap_threads() - MicroPython never calls swap functions (expects automatic scheduling) - All created threads hung indefinitely, never executed **Unix Port Benefits:** The Unix port should leverage true concurrent multi-threading: - Multi-core CPUs can run threads in parallel - C library calls can execute concurrently (coordinated by GIL) - Better utilization of native system resources NSI artificially restricts to single-threaded execution (MCU simulation), which defeats these advantages. ## Files in This Commit - extmod/zephyr_kernel/posix_nsi_board.c: NSI-based board layer - extmod/zephyr_kernel/zephyr_kernel.mk: Build config for NSI - ZEPHYR_POC_FINDINGS.md: Research findings document - ZEPHYR_THREADING_RESEARCH.md: Investigation notes ## Decision Continue with minimal pthread adapter (posix_minimal_board.c) that provides true preemptive threading while adapting Zephyr primitives to pthreads. This preserves Unix port benefits while enabling Zephyr threading API. Signed-off-by: Andrew Leech <[email protected]>
1 parent 5905e8d commit d55b92a

File tree

4 files changed

+1050
-3
lines changed

4 files changed

+1050
-3
lines changed

ZEPHYR_POC_FINDINGS.md

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# Zephyr Threading POC - Findings and Blockers
2+
3+
## Summary
4+
5+
Initial Proof of Concept attempt to integrate Zephyr kernel for threading in Unix port revealed significant integration challenges. While the concept is sound, the implementation complexity is higher than anticipated.
6+
7+
## Work Completed
8+
9+
### Infrastructure Created
10+
1.`extmod/zephyr_kernel/` directory structure
11+
2.`extmod/zephyr_kernel/zephyr_config.h` - Fixed CONFIG_ definitions (161 lines)
12+
3.`extmod/zephyr_kernel/zephyr_kernel.h` - Integration API
13+
4.`extmod/zephyr_kernel/kernel/mpthread_zephyr.c` - MicroPython threading API implementation (320 lines)
14+
5.`ports/unix/zephyr_arch_unix.c` - Unix architecture layer (150 lines)
15+
6. ✅ Modified `ports/unix/Makefile` - Added MICROPY_ZEPHYR_THREADING build option
16+
7. ✅ Modified `ports/unix/mpthreadport.h` - Conditional compilation for Zephyr
17+
8. ✅ Modified `ports/unix/main.c` - Handle different mp_thread_init signatures
18+
19+
### Code Statistics
20+
- Total new code: ~700 lines
21+
- Modified existing code: ~50 lines
22+
- Identified 18 Zephyr kernel files needed for minimal threading
23+
24+
## Build Issues Encountered
25+
26+
### Issue 1: Architecture Detection
27+
**Problem**: Zephyr's `toolchain/gcc.h` didn't recognize x86_64 architecture.
28+
29+
**Solution Attempted**: Added CONFIG_X86_64 and CONFIG_64BIT definitions to zephyr_config.h
30+
31+
**Status**: ✅ Partially resolved (still some edge cases)
32+
33+
### Issue 2: Missing Generated Headers
34+
**Problem**: Zephyr build system generates several header files that don't exist in source:
35+
- `zephyr/syscall_list.h`
36+
- `zephyr/syscalls/time_units.h`
37+
- `zephyr/syscalls/*.h` (various syscall headers)
38+
39+
**Impact**: These are core to Zephyr's header structure. Stubbing them out causes cascading issues.
40+
41+
**Root Cause**: Zephyr's header files are tightly coupled to the build system's code generation.
42+
43+
**Status**: ⚠️ Partial workaround attempted, not fully resolved
44+
45+
### Issue 3: Syscall System Integration
46+
**Problem**: Zephyr uses a complex syscall system with:
47+
- Macro-based syscall definitions
48+
- Generated wrapper code
49+
- Architecture-specific trampolines
50+
- Userspace/kernel space separation
51+
52+
**Attempted Solutions**:
53+
1. Define `__syscall` as empty macro → Conflicts with Zephyr's definitions
54+
2. Stub out syscall_list.h → Missing dependent generated files
55+
3. Use `-D` to redefine includes → ISO C99 macro naming issues
56+
57+
**Status**: ❌ Blocked - Syscall system deeply integrated into headers
58+
59+
### Issue 4: Header Include Order Dependencies
60+
**Problem**: Zephyr headers have complex include dependencies:
61+
```
62+
kernel.h → kernel_includes.h → syscall.h → syscall_list.h (generated)
63+
→ toolchain.h → arch-specific headers
64+
→ sys/atomic.h → time_units.h → syscalls/time_units.h (generated)
65+
```
66+
67+
**Impact**: Can't include `<zephyr/kernel.h>` without full build system
68+
69+
**Status**: ❌ Fundamental architectural issue
70+
71+
## Technical Analysis
72+
73+
### Why Integration is Difficult
74+
75+
1. **Generated Code Dependency**
76+
- Zephyr build generates ~20+ header files
77+
- These files contain syscall wrappers, device trees, Kconfig output
78+
- Not feasible to manually stub all of them
79+
80+
2. **Tight Coupling to Build System**
81+
- CMake introspects source files to generate syscall lists
82+
- Kconfig generates configuration headers
83+
- Device tree compiler generates hardware definitions
84+
- Build system is not just configuration - it's code generation
85+
86+
3. **Userspace/Kernel Separation**
87+
- Zephyr designed for userspace/kernel separation
88+
- Syscall mechanism is core architecture
89+
- Can't easily bypass for "kernel-only" use
90+
91+
4. **Architecture-Specific Code**
92+
- Each arch has different header requirements
93+
- Context switching depends on arch-specific types
94+
- Atomic operations vary by architecture
95+
96+
### What Would Be Needed for Success
97+
98+
To make this work, would need:
99+
100+
1. **Minimal Zephyr Build**
101+
- Run CMake to generate required headers
102+
- Extract only kernel .c files and generated headers
103+
- Package as pre-built component
104+
105+
2. **Alternative: Header-Only Wrapper**
106+
- Don't use Zephyr headers at all
107+
- Manually reimplement minimal thread/mutex/sem types
108+
- Link against pre-compiled Zephyr kernel library
109+
110+
3. **Alternative: Fork and Simplify**
111+
- Fork Zephyr kernel sources
112+
- Remove syscall system completely
113+
- Create standalone kernel library
114+
- High maintenance burden
115+
116+
## Recommendations
117+
118+
### Short Term: Alternative Approaches
119+
120+
#### Option A: Pre-Generated Zephyr Build
121+
1. Use Zephyr build system to compile kernel for each architecture
122+
2. Package as static library + minimal headers
123+
3. MicroPython ports link against pre-built library
124+
4. **Pros**: Gets Zephyr functionality, avoids header issues
125+
5. **Cons**: Adds binary dependency, complicates build
126+
127+
#### Option B: Minimal Kernel Reimplementation
128+
1. Study Zephyr's thread.c, sched.c, mutex.c implementations
129+
2. Extract core algorithms
130+
3. Reimplement in standalone files without Zephyr dependencies
131+
4. **Pros**: Clean integration, no Zephyr coupling
132+
5. **Cons**: Significant development effort, loses Zephyr updates
133+
134+
#### Option C: Use Different RTOS
135+
1. Consider lighter-weight RTOS (FreeRTOS, ThreadX, RT-Thread)
136+
2. These have simpler header structures
137+
3. **Pros**: Might integrate easier
138+
4. **Cons**: Different feature set, less mature than Zephyr
139+
140+
### Long Term: Unified Threading API
141+
142+
Regardless of backend choice, create abstraction layer:
143+
144+
```c
145+
// extmod/mpthread_rtos.h - Unified RTOS threading API
146+
typedef struct mp_rtos_thread mp_rtos_thread_t;
147+
typedef struct mp_rtos_mutex mp_rtos_mutex_t;
148+
149+
mp_rtos_thread_t* mp_rtos_thread_create(void *(*entry)(void*), void *arg);
150+
void mp_rtos_mutex_init(mp_rtos_mutex_t *mutex);
151+
// ... etc
152+
```
153+
154+
Then implement for:
155+
- Zephyr (if feasible)
156+
- FreeRTOS
157+
- ThreadX
158+
- Pthreads (Unix/POSIX)
159+
- Custom (STM32, RP2)
160+
161+
## Lessons Learned
162+
163+
1. **Header-Only Integration is Insufficient**
164+
- Modern RTOS frameworks rely on code generation
165+
- Can't just "include headers" without build system
166+
167+
2. **Build System Complexity**
168+
- Zephyr's build system is integral, not optional
169+
- This was underestimated in initial research
170+
171+
3. **Syscall System is Core**
172+
- Can't be easily disabled or stubbed
173+
- Permeates all Zephyr APIs
174+
175+
4. **POC Validated Concerns**
176+
- Research document correctly identified this as high-risk
177+
- Build system integration was flagged as key challenge
178+
- Findings confirm need for different approach
179+
180+
## Next Steps
181+
182+
### Immediate Actions
183+
184+
1. **Document Findings** ✅ (this document)
185+
2. **Update Research Document** with lessons learned
186+
3. **Propose Alternative Strategy** to user
187+
188+
### Options for User
189+
190+
**Option 1**: Accept limited scope
191+
- Proceed with Unix POC using pthread-backed Zephyr API
192+
- Don't use actual Zephyr kernel
193+
- Just standardize API shape
194+
- ~2 hours additional work
195+
196+
**Option 2**: Use pre-built Zephyr libraries
197+
- Set up proper Zephyr builds for each port
198+
- Export as static libraries
199+
- Higher complexity but gets real Zephyr
200+
- ~1-2 days additional work
201+
202+
**Option 3**: Pivot to different approach
203+
- Abandon Zephyr integration
204+
- Either keep port-specific threading OR
205+
- Use simpler RTOS (FreeRTOS already used in ESP32)
206+
- Design unified API over existing implementations
207+
208+
**Option 4**: Minimal Zephyr fork
209+
- Fork just kernel/ directory from Zephyr
210+
- Strip out syscall dependencies
211+
- Maintain as separate library
212+
- ~2-3 days initial, ongoing maintenance
213+
214+
## Conclusion
215+
216+
The POC successfully demonstrated:
217+
- ✅ API design is sound
218+
- ✅ Integration points identified correctly
219+
- ✅ Code structure is reasonable
220+
- ⚠️ Build integration is more complex than anticipated
221+
- ❌ Cannot use Zephyr headers without build system
222+
223+
**Recommendation**: Either commit to full Zephyr build integration (Option 2) or pivot to alternative approach (Options 3 or 4).
224+
225+
The "minimal extraction" approach (original plan) is not viable due to generated header dependencies.

0 commit comments

Comments
 (0)