Skip to content

Commit e308aa3

Browse files
committed
📝 Add ascii art of stack layout
1 parent 729c047 commit e308aa3

File tree

1 file changed

+45
-10
lines changed

1 file changed

+45
-10
lines changed

README.md

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ resource-constrained environments. Built with stack-based allocation to avoid
55
heap usage and designed to fit within a single cache line for optimal
66
performance.
77

8+
> [!CAUTION]
9+
>
10+
> 🚧 This project is still under construction! 🚧
11+
812
## Features
913

1014
- **Stack-based coroutine allocation** - No heap allocations; coroutine frames are allocated from a user-provided stack buffer
@@ -22,22 +26,52 @@ performance.
2226
## Requirements
2327

2428
- C++23 compiler with coroutine support
25-
- Tested with Clang 18+
29+
- Tested with Clang 20+
30+
- Usage of C++20 modules
2631

2732
## Stack-Based Allocation
2833

2934
Unlike typical coroutine implementations that allocate frames on the heap,
3035
`async_context` uses a stack-based allocation scheme. Each context owns a
3136
contiguous buffer of memory that grows upward as coroutines are called.
3237

33-
### Memory Layout
34-
35-
> [!NOTE]
36-
>
37-
> Will add a diagram here later
38-
3938
### How Allocation Works
4039

40+
```ascii
41+
┌─────────────────────────────┐ Address 0
42+
│ &context::m_stack_pointer │
43+
├─────────────────────────────┤
44+
│ Coroutine Frame A │
45+
│ (promise + locals) │
46+
| (96 B) │
47+
├─────────────────────────────┤
48+
│ &context::m_stack_pointer │
49+
├─────────────────────────────┤
50+
│ Coroutine Frame B │
51+
| (192 B) │
52+
│ (promise + locals) │
53+
│ │
54+
│ │
55+
│ │
56+
├─────────────────────────────┤
57+
│ Stack pointer address │
58+
├─────────────────────────────┤
59+
│ Coroutine Frame C │
60+
| (128 B) │
61+
│ (promise + locals) │
62+
│ │
63+
├─────────────────────────────┤
64+
│ Unused Memory │ <-- context::m_stack_pointer
65+
│ │
66+
│ │
67+
│ │
68+
│ │
69+
│ │
70+
│ │
71+
│ │
72+
└─────────────────────────────┘ Address N (bytes of stack memory)
73+
```
74+
4175
1. **Allocation**: When a coroutine is created, the promise's `operator new`
4276
requests memory from the context. The context:
4377
- Stores the address of `m_stack_pointer` at the current position
@@ -48,13 +82,14 @@ contiguous buffer of memory that grows upward as coroutines are called.
4882
- Reads the stored `&m_stack_pointer` from just before the frame
4983
- Resets `m_stack_pointer` back to that position
5084

51-
This creates a strict LIFO (stack) discipline—coroutines must complete in
52-
reverse order of their creation, which naturally matches how `co_await` chains
85+
This creates a strict LIFO stack where coroutines must complete in reverse
86+
order of their creation, which naturally matches how `co_await` chains
5387
work.
5488

5589
### Benefits
5690

57-
- **No heap allocation**: Ideal for embedded systems without dynamic memory
91+
- **No heap allocation on frame creation**: Ideal for embedded systems without
92+
dynamic memory
5893
- **Deterministic**: Memory usage is bounded by the stack buffer size
5994
- **Cache-friendly**: Coroutine frames are contiguous in memory
6095
- **Fast**: Simple pointer arithmetic instead of malloc/free

0 commit comments

Comments
 (0)