diff --git a/CMakeLists.txt b/CMakeLists.txt
index 29a86eb..293bb92 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -213,6 +213,7 @@ set(TESTS
test_yafl_suspend_resume
test_yafl_guard
test_yafl_many
+ test_yafl_watermark
)
# Create static library
@@ -233,18 +234,12 @@ endforeach()
# Testing
# ============================================================================
-enable_testing()
+include(CTest)
# Ensure all test-related output goes to the build directory only
set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED TRUE)
foreach(test ${TESTS})
- # Skip guard page test on macOS when coverage is enabled (coverage instrumentation changes signal behavior)
- if(ENABLE_COVERAGE AND APPLE AND "${test}" STREQUAL "test_yafl_guard")
- message(STATUS "Skipping ${test} on macOS (coverage enabled)")
- continue()
- endif()
-
# Use absolute path to binary so tests run from build directory
add_test(NAME ${test} COMMAND ${test})
endforeach()
diff --git a/docs/coverage.svg b/docs/coverage.svg
index f737a95..235b19e 100644
--- a/docs/coverage.svg
+++ b/docs/coverage.svg
@@ -15,6 +15,6 @@
font-family="DejaVu Sans,Verdana,Geneva,sans-serif"
font-size="11">
coverage
- 86.1%
+ 89.3%
diff --git a/docs/coverage/gcov.css b/docs/coverage/gcov.css
index f329042..1cacc83 100644
--- a/docs/coverage/gcov.css
+++ b/docs/coverage/gcov.css
@@ -36,6 +36,20 @@ td.title
font-style: italic;
font-weight: bold;
}
+/* table footnote */
+td.footnote
+{
+ text-align: left;
+ padding-left: 100px;
+ padding-right: 10px;
+ background-color: #dae7fe; /* light blue table background color */
+ /* dark blue table header color
+ background-color: #6688d4; */
+ white-space: nowrap;
+ font-family: sans-serif;
+ font-style: italic;
+ font-size:70%;
+}
/* "Line coverage date bins" leader */
td.subTableHeader
{
@@ -187,6 +201,17 @@ td.coverFile
font-family: monospace;
}
+/* Directory view/File view (all): directory name entry format */
+td.coverDirectory
+{
+ text-align: left;
+ padding-left: 10px;
+ padding-right: 20px;
+ color: #284fa8;
+ background-color: #b8d0ff;
+ font-family: monospace;
+}
+
/* Directory view/File view (all): filename entry format */
td.overallOwner
{
@@ -528,12 +553,29 @@ pre.source
margin-top: 2px;
}
+/* elided/removed code */
+span.elidedSource
+{
+ font-family: sans-serif;
+ /*font-size: 8pt; */
+ font-style: italic;
+ background-color: lightgrey;
+}
+
/* Source code view: line number format */
span.lineNum
{
background-color: #efe383;
}
+/* Source code view: line number format when there are deleted
+ lines in the corresponding location */
+span.lineNumWithDelete
+{
+ foreground-color: #efe383;
+ background-color: lightgrey;
+}
+
/* Source code view: format for Cov legend */
span.coverLegendCov
{
@@ -634,7 +676,17 @@ a.branchTla:visited
color: #000000;
}
-/* Source code view/table entry backround: format for lines classified as "Uncovered New Code (+ => 0):
+a.mcdcTla:link
+{
+ color: #000000;
+}
+
+a.mcdcTla:visited
+{
+ color: #000000;
+}
+
+/* Source code view/table entry background: format for lines classified as "Uncovered New Code (+ => 0):
Newly added code is not tested" */
td.tlaUNC
{
@@ -645,7 +697,7 @@ td.tlaBgUNC {
background-color: #FF6230;
}
-/* Source code view/table entry backround: format for lines classified as "Uncovered New Code (+ => 0):
+/* Source code view/table entry background: format for lines classified as "Uncovered New Code (+ => 0):
Newly added code is not tested" */
span.tlaUNC
{
@@ -670,7 +722,7 @@ td.headerCovTableHeadUNC {
background-color: #FF6230;
}
-/* Source code view/table entry backround: format for lines classified as "Lost Baseline Coverage (1 => 0):
+/* Source code view/table entry background: format for lines classified as "Lost Baseline Coverage (1 => 0):
Unchanged code is no longer tested" */
td.tlaLBC
{
@@ -681,7 +733,7 @@ td.tlaBgLBC {
background-color: #FF6230;
}
-/* Source code view/table entry backround: format for lines classified as "Lost Baseline Coverage (1 => 0):
+/* Source code view/table entry background: format for lines classified as "Lost Baseline Coverage (1 => 0):
Unchanged code is no longer tested" */
span.tlaLBC
{
@@ -706,7 +758,7 @@ td.headerCovTableHeadLBC {
background-color: #FF6230;
}
-/* Source code view/table entry backround: format for lines classified as "Uncovered Included Code (# => 0):
+/* Source code view/table entry background: format for lines classified as "Uncovered Included Code (# => 0):
Previously unused code is untested" */
td.tlaUIC
{
@@ -717,7 +769,7 @@ td.tlaBgUIC {
background-color: #FF6230;
}
-/* Source code view/table entry backround: format for lines classified as "Uncovered Included Code (# => 0):
+/* Source code view/table entry background: format for lines classified as "Uncovered Included Code (# => 0):
Previously unused code is untested" */
span.tlaUIC
{
@@ -742,7 +794,7 @@ td.headerCovTableHeadUIC {
background-color: #FF6230;
}
-/* Source code view/table entry backround: format for lines classified as "Uncovered Baseline Code (0 => 0):
+/* Source code view/table entry background: format for lines classified as "Uncovered Baseline Code (0 => 0):
Unchanged code was untested before, is untested now" */
td.tlaUBC
{
@@ -753,7 +805,7 @@ td.tlaBgUBC {
background-color: #FF6230;
}
-/* Source code view/table entry backround: format for lines classified as "Uncovered Baseline Code (0 => 0):
+/* Source code view/table entry background: format for lines classified as "Uncovered Baseline Code (0 => 0):
Unchanged code was untested before, is untested now" */
span.tlaUBC
{
@@ -778,7 +830,7 @@ td.headerCovTableHeadUBC {
background-color: #FF6230;
}
-/* Source code view/table entry backround: format for lines classified as "Gained Baseline Coverage (0 => 1):
+/* Source code view/table entry background: format for lines classified as "Gained Baseline Coverage (0 => 1):
Unchanged code is tested now" */
td.tlaGBC
{
@@ -789,7 +841,7 @@ td.tlaBgGBC {
background-color: #CAD7FE;
}
-/* Source code view/table entry backround: format for lines classified as "Gained Baseline Coverage (0 => 1):
+/* Source code view/table entry background: format for lines classified as "Gained Baseline Coverage (0 => 1):
Unchanged code is tested now" */
span.tlaGBC
{
@@ -814,7 +866,7 @@ td.headerCovTableHeadGBC {
background-color: #CAD7FE;
}
-/* Source code view/table entry backround: format for lines classified as "Gained Included Coverage (# => 1):
+/* Source code view/table entry background: format for lines classified as "Gained Included Coverage (# => 1):
Previously unused code is tested now" */
td.tlaGIC
{
@@ -825,7 +877,7 @@ td.tlaBgGIC {
background-color: #CAD7FE;
}
-/* Source code view/table entry backround: format for lines classified as "Gained Included Coverage (# => 1):
+/* Source code view/table entry background: format for lines classified as "Gained Included Coverage (# => 1):
Previously unused code is tested now" */
span.tlaGIC
{
@@ -850,7 +902,7 @@ td.headerCovTableHeadGIC {
background-color: #CAD7FE;
}
-/* Source code view/table entry backround: format for lines classified as "Gained New Coverage (+ => 1):
+/* Source code view/table entry background: format for lines classified as "Gained New Coverage (+ => 1):
Newly added code is tested" */
td.tlaGNC
{
@@ -861,7 +913,7 @@ td.tlaBgGNC {
background-color: #CAD7FE;
}
-/* Source code view/table entry backround: format for lines classified as "Gained New Coverage (+ => 1):
+/* Source code view/table entry background: format for lines classified as "Gained New Coverage (+ => 1):
Newly added code is tested" */
span.tlaGNC
{
@@ -886,7 +938,7 @@ td.headerCovTableHeadGNC {
background-color: #CAD7FE;
}
-/* Source code view/table entry backround: format for lines classified as "Covered Baseline Code (1 => 1):
+/* Source code view/table entry background: format for lines classified as "Covered Baseline Code (1 => 1):
Unchanged code was tested before and is still tested" */
td.tlaCBC
{
@@ -897,7 +949,7 @@ td.tlaBgCBC {
background-color: #CAD7FE;
}
-/* Source code view/table entry backround: format for lines classified as "Covered Baseline Code (1 => 1):
+/* Source code view/table entry background: format for lines classified as "Covered Baseline Code (1 => 1):
Unchanged code was tested before and is still tested" */
span.tlaCBC
{
@@ -922,7 +974,7 @@ td.headerCovTableHeadCBC {
background-color: #CAD7FE;
}
-/* Source code view/table entry backround: format for lines classified as "Excluded Uncovered Baseline (0 => #):
+/* Source code view/table entry background: format for lines classified as "Excluded Uncovered Baseline (0 => #):
Previously untested code is unused now" */
td.tlaEUB
{
@@ -933,7 +985,7 @@ td.tlaBgEUB {
background-color: #FFFFFF;
}
-/* Source code view/table entry backround: format for lines classified as "Excluded Uncovered Baseline (0 => #):
+/* Source code view/table entry background: format for lines classified as "Excluded Uncovered Baseline (0 => #):
Previously untested code is unused now" */
span.tlaEUB
{
@@ -958,7 +1010,7 @@ td.headerCovTableHeadEUB {
background-color: #FFFFFF;
}
-/* Source code view/table entry backround: format for lines classified as "Excluded Covered Baseline (1 => #):
+/* Source code view/table entry background: format for lines classified as "Excluded Covered Baseline (1 => #):
Previously tested code is unused now" */
td.tlaECB
{
@@ -969,7 +1021,7 @@ td.tlaBgECB {
background-color: #FFFFFF;
}
-/* Source code view/table entry backround: format for lines classified as "Excluded Covered Baseline (1 => #):
+/* Source code view/table entry background: format for lines classified as "Excluded Covered Baseline (1 => #):
Previously tested code is unused now" */
span.tlaECB
{
@@ -994,7 +1046,7 @@ td.headerCovTableHeadECB {
background-color: #FFFFFF;
}
-/* Source code view/table entry backround: format for lines classified as "Deleted Uncovered Baseline (0 => -):
+/* Source code view/table entry background: format for lines classified as "Deleted Uncovered Baseline (0 => -):
Previously untested code has been deleted" */
td.tlaDUB
{
@@ -1005,7 +1057,7 @@ td.tlaBgDUB {
background-color: #FFFFFF;
}
-/* Source code view/table entry backround: format for lines classified as "Deleted Uncovered Baseline (0 => -):
+/* Source code view/table entry background: format for lines classified as "Deleted Uncovered Baseline (0 => -):
Previously untested code has been deleted" */
span.tlaDUB
{
@@ -1030,7 +1082,7 @@ td.headerCovTableHeadDUB {
background-color: #FFFFFF;
}
-/* Source code view/table entry backround: format for lines classified as "Deleted Covered Baseline (1 => -):
+/* Source code view/table entry background: format for lines classified as "Deleted Covered Baseline (1 => -):
Previously tested code has been deleted" */
td.tlaDCB
{
@@ -1041,7 +1093,7 @@ td.tlaBgDCB {
background-color: #FFFFFF;
}
-/* Source code view/table entry backround: format for lines classified as "Deleted Covered Baseline (1 => -):
+/* Source code view/table entry background: format for lines classified as "Deleted Covered Baseline (1 => -):
Previously tested code has been deleted" */
span.tlaDCB
{
diff --git a/docs/coverage/index-sort-f.html b/docs/coverage/index-sort-f.html
index add076a..2eb7a84 100644
--- a/docs/coverage/index-sort-f.html
+++ b/docs/coverage/index-sort-f.html
@@ -28,21 +28,21 @@
-
+
|
-
-
-
+
+
+
-
+
|
-
-
-
+
+
+
 |
@@ -80,28 +80,28 @@
Hit |
- | src |
+ src/ |
-
+
|
- 83.2 % |
- 137 |
- 114 |
- 87.5 % |
- 8 |
- 7 |
+ 89.2 % |
+ 139 |
+ 124 |
+ 84.6 % |
+ 13 |
+ 11 |
- | tests |
+ tests/ |
-
+
|
- 87.1 % |
- 402 |
- 350 |
- 90.0 % |
- 30 |
- 27 |
+ 89.3 % |
+ 503 |
+ 449 |
+ 92.1 % |
+ 38 |
+ 35 |
@@ -109,7 +109,7 @@
diff --git a/docs/coverage/index-sort-l.html b/docs/coverage/index-sort-l.html
index ce23a23..e410472 100644
--- a/docs/coverage/index-sort-l.html
+++ b/docs/coverage/index-sort-l.html
@@ -28,21 +28,21 @@
-
+
|
-
-
-
+
+
+
-
+
|
-
-
-
+
+
+
 |
@@ -80,28 +80,28 @@
Hit |
- | src |
+ src/ |
-
+
|
- 83.2 % |
- 137 |
- 114 |
- 87.5 % |
- 8 |
- 7 |
+ 89.2 % |
+ 139 |
+ 124 |
+ 84.6 % |
+ 13 |
+ 11 |
- | tests |
+ tests/ |
-
+
|
- 87.1 % |
- 402 |
- 350 |
- 90.0 % |
- 30 |
- 27 |
+ 89.3 % |
+ 503 |
+ 449 |
+ 92.1 % |
+ 38 |
+ 35 |
@@ -109,7 +109,7 @@
diff --git a/docs/coverage/index.html b/docs/coverage/index.html
index 8c51e48..577c07f 100644
--- a/docs/coverage/index.html
+++ b/docs/coverage/index.html
@@ -28,21 +28,21 @@
-
+
|
-
-
-
+
+
+
-
+
|
-
-
-
+
+
+
 |
@@ -80,28 +80,28 @@
Hit |
- | src |
+ src/ |
-
+
|
- 83.2 % |
- 137 |
- 114 |
- 87.5 % |
- 8 |
- 7 |
+ 89.2 % |
+ 139 |
+ 124 |
+ 84.6 % |
+ 13 |
+ 11 |
- | tests |
+ tests/ |
-
+
|
- 87.1 % |
- 402 |
- 350 |
- 90.0 % |
- 30 |
- 27 |
+ 89.3 % |
+ 503 |
+ 449 |
+ 92.1 % |
+ 38 |
+ 35 |
@@ -109,7 +109,7 @@
diff --git a/docs/coverage/src/index.html b/docs/coverage/src/index.html
index 0f2c5f4..999849e 100644
--- a/docs/coverage/src/index.html
+++ b/docs/coverage/src/index.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,21 +28,21 @@
-
+
|
-
-
-
+
+
+
-
+
|
-
-
-
+
+
+
 |
@@ -67,9 +67,9 @@
- Filename  |
- Line Coverage  |
- Function Coverage  |
+ File  |
+ Line Coverage  |
+ Function Coverage  |
| Rate |
@@ -80,16 +80,16 @@
Hit |
- | yafl.c |
+ yafl.c |
-
+
|
- 83.2 % |
- 137 |
- 114 |
- 87.5 % |
- 8 |
- 7 |
+ 89.2 % |
+ 139 |
+ 124 |
+ 84.6 % |
+ 13 |
+ 11 |
@@ -97,7 +97,7 @@
diff --git a/docs/coverage/src/yafl.c.func-c.html b/docs/coverage/src/yafl.c.func-c.html
index c46b48b..42a3410 100644
--- a/docs/coverage/src/yafl.c.func-c.html
+++ b/docs/coverage/src/yafl.c.func-c.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,21 +28,21 @@
-
+
|
-
-
-
+
+
+
-
+
|
-
-
-
+
+
+
 |
@@ -61,60 +61,109 @@
Hit count  |
+
+
+
+ | fiber_entry_trampoline |
+
+ 0 |
+
+
+
- | yafl_get_page_size |
+ yafl_get_page_size |
0 |
+
+
+
+ | reinitialize_fiber_context_with_watermark |
+
+ 24 |
+
+
+
+
+
+ | yafl_fiber_stack_high_watermark |
+
+ 45 |
+
+
+
+
+
+ | get_page_size |
+
+ 321 |
+
+
+
+
+
+ | align_stack_pointer |
+
+ 366 |
+
+
+
- | yafl_fiber_stack_high_watermark |
+ free_fiber_stack |
+
+ 366 |
- 4 |
- | fiber_entry_trampoline |
+ yafl_fiber_destroy |
+
+ 372 |
- 112 |
- | yafl_fiber_destroy |
+ yafl_fiber_create |
+
+ 378 |
- 118 |
- | yafl_fiber_create |
+ initialize_fiber_context |
+
+ 390 |
- 120 |
- | yafl_fiber_suspend |
+ yafl_fiber_suspend |
+
+ 3075 |
- 1023 |
- | yafl_fiber_resume |
+ yafl_fiber_resume |
+
+ 3435 |
- 1137 |
- | yafl_fiber_status |
+ yafl_fiber_status |
+
+ 4296 |
- 1426 |
@@ -123,7 +172,7 @@
diff --git a/docs/coverage/src/yafl.c.func.html b/docs/coverage/src/yafl.c.func.html
index afb0852..c970366 100644
--- a/docs/coverage/src/yafl.c.func.html
+++ b/docs/coverage/src/yafl.c.func.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,21 +28,21 @@
-
+
|
-
-
-
+
+
+
-
+
|
-
-
-
+
+
+
 |
@@ -61,69 +61,118 @@
Hit count  |
+
+
+
+ | align_stack_pointer |
+
+ 366 |
+
+
+
+
+
+ | fiber_entry_trampoline |
+
+ 0 |
+
+
+
+
+
+ | free_fiber_stack |
+
+ 366 |
+
+
+
- | fiber_entry_trampoline |
+ get_page_size |
+
+ 321 |
+
+
+
+
+
+ | initialize_fiber_context |
+
+ 390 |
+
+
+
+
+
+ | reinitialize_fiber_context_with_watermark |
+
+ 24 |
- 112 |
- | yafl_fiber_create |
+ yafl_fiber_create |
+
+ 378 |
- 120 |
- | yafl_fiber_destroy |
+ yafl_fiber_destroy |
+
+ 372 |
- 118 |
- | yafl_fiber_resume |
+ yafl_fiber_resume |
+
+ 3435 |
- 1137 |
- | yafl_fiber_stack_high_watermark |
+ yafl_fiber_stack_high_watermark |
+
+ 45 |
- 4 |
- | yafl_fiber_status |
+ yafl_fiber_status |
+
+ 4296 |
- 1426 |
- | yafl_fiber_suspend |
+ yafl_fiber_suspend |
+
+ 3075 |
- 1023 |
- | yafl_get_page_size |
+ yafl_get_page_size |
0 |
+
diff --git a/docs/coverage/src/yafl.c.gcov.html b/docs/coverage/src/yafl.c.gcov.html
index e606534..f4e72ab 100644
--- a/docs/coverage/src/yafl.c.gcov.html
+++ b/docs/coverage/src/yafl.c.gcov.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,21 +28,21 @@
-
+
|
-
-
-
+
+
+
-
+
|
-
-
-
+
+
+
 |
@@ -95,394 +95,328 @@
33 : /* Raw context handle - opaque pointer to saved machine state */
34 : typedef struct yafl_opaque_t *yafl_t;
35 :
- 36 : /* Raw transfer between contexts */
- 37 : typedef struct {
- 38 : yafl_t prev_context;
- 39 : void *data;
- 40 : } yafl_transfer_t;
- 41 :
- 42 : /* Raw entry function type for low-level API */
- 43 : typedef void (*yafl_entry_t)(yafl_transfer_t);
- 44 :
- 45 : /* Low-level assembly-implemented functions */
- 46 : extern yafl_t make_fcontext(void *sp, size_t size, yafl_entry_t fn);
- 47 : extern yafl_transfer_t jump_fcontext(yafl_t const to, void *vp);
- 48 :
- 49 : /* ========================================================================
- 50 : * Constants and Types
- 51 : * ======================================================================== */
- 52 :
- 53 : #define FCONTEXT_FIBER_MAGIC 0xF1BE7001
- 54 : #define FCONTEXT_STACK_WATERMARK 0xA5
- 55 : #define FCONTEXT_STACK_ALIGNMENT 16
- 56 :
- 57 : typedef enum {
- 58 : FCONTEXT_ALLOC_MALLOC,
- 59 : FCONTEXT_ALLOC_VMEM
- 60 : } yafl_alloc_type_t;
- 61 :
- 62 : /* Internal fiber structure */
- 63 : struct yafl_fiber {
- 64 : uint32_t magic;
- 65 : yafl_alloc_type_t alloc_type;
- 66 : yafl_fiber_status_t status;
- 67 :
- 68 : /* Stack management */
- 69 : void *stack_region;
- 70 : size_t stack_total_size;
- 71 : void *stack_top;
- 72 : size_t stack_size;
- 73 : bool watermark_filled;
- 74 :
- 75 : /* Context tracking */
- 76 : yafl_t context; /* Fiber's saved context */
- 77 : yafl_t resumer_context; /* Context to return to */
+ 36 : /* Raw entry function type for low-level API */
+ 37 : typedef void (*yafl_entry_t)(void *);
+ 38 :
+ 39 : /* Low-level assembly-implemented functions */
+ 40 : /* Creates the initial saved context for a fiber stack. */
+ 41 : extern yafl_t yafl_make_context(void *sp, size_t size, yafl_entry_t fn);
+ 42 : extern void *yafl_switch(yafl_t *save, yafl_t target, void *data);
+ 43 :
+ 44 : /* ========================================================================
+ 45 : * Constants and Types
+ 46 : * ======================================================================== */
+ 47 :
+ 48 : #define FCONTEXT_FIBER_MAGIC 0xF1BE7001
+ 49 : #define FCONTEXT_STACK_WATERMARK 0xA5
+ 50 : #define FCONTEXT_STACK_ALIGNMENT 16
+ 51 :
+ 52 : typedef enum { FCONTEXT_ALLOC_MALLOC, FCONTEXT_ALLOC_VMEM } yafl_alloc_type_t;
+ 53 :
+ 54 : /* Internal fiber structure */
+ 55 : struct yafl_fiber {
+ 56 : uint32_t magic;
+ 57 : yafl_alloc_type_t alloc_type;
+ 58 : yafl_fiber_status_t status;
+ 59 :
+ 60 : /* Stack management */
+ 61 : void *stack_region;
+ 62 : size_t stack_total_size;
+ 63 : void *stack_top;
+ 64 : size_t stack_size;
+ 65 : bool watermark_filled;
+ 66 :
+ 67 : /* Context tracking */
+ 68 : yafl_t context; /* Fiber's saved context */
+ 69 : yafl_t resumer_context; /* Context to return to */
+ 70 :
+ 71 : /* User entry and result */
+ 72 : yafl_fiber_fn user_entry;
+ 73 : void *cached_result;
+ 74 : };
+ 75 :
+ 76 : /* Typedef for internal use */
+ 77 : typedef struct yafl_fiber yafl_fiber_t;
78 :
- 79 : /* User entry and result */
- 80 : yafl_fiber_fn user_entry;
- 81 : void *cached_result;
- 82 : void *pending_arg; /* Argument for next resume */
- 83 : };
- 84 :
- 85 : /* Typedef for internal use */
- 86 : typedef struct yafl_fiber yafl_fiber_t;
- 87 :
- 88 : /* Thread-local storage */
- 89 : static _Thread_local yafl_fiber_t *tls_current_fiber = NULL;
- 90 :
- 91 : /* ========================================================================
- 92 : * Utility Functions
- 93 : * ======================================================================== */
- 94 :
- 95 104 : static size_t get_page_size(void) {
- 96 : #ifdef _WIN32
- 97 : SYSTEM_INFO si;
- 98 : GetSystemInfo(&si);
- 99 : return (size_t)si.dwPageSize;
- 100 : #else
- 101 208 : long page_size = sysconf(_SC_PAGE_SIZE);
- 102 104 : if (page_size <= 0) {
- 103 : return 4096;
- 104 : }
- 105 104 : return (size_t)page_size;
- 106 : #endif
- 107 : }
- 108 :
- 109 116 : static void *align_stack_pointer(void *ptr) {
- 110 116 : uintptr_t addr = (uintptr_t)ptr;
- 111 116 : return (void *)(addr & ~(FCONTEXT_STACK_ALIGNMENT - 1));
- 112 : }
- 113 :
- 114 : /* ========================================================================
- 115 : * Trampoline: Adapts Low-Level API to High-Level Fiber API
- 116 : * ======================================================================== */
- 117 :
- 118 : /*
- 119 : * This is called as the entry function by make_fcontext().
- 120 : * It wraps the user's entry function, manages state, and handles the result.
- 121 : */
- 122 112 : static void fiber_entry_trampoline(yafl_transfer_t t) {
- 123 112 : yafl_fiber_t *fiber = (yafl_fiber_t *)t.data;
- 124 :
- 125 : /* Save resumer's context (who called resume on us) */
- 126 112 : fiber->resumer_context = t.prev_context;
- 127 :
- 128 : /* Update status and TLS */
- 129 112 : fiber->status = YAFL_FIBER_STATUS_RUNNING;
- 130 112 : tls_current_fiber = fiber;
- 131 :
- 132 : /* Call user entry with argument from first resume */
- 133 112 : void *result = fiber->user_entry(fiber->pending_arg);
- 134 :
- 135 : /* Mark complete and cache result */
- 136 112 : fiber->status = YAFL_FIBER_STATUS_COMPLETE;
- 137 112 : fiber->cached_result = result;
- 138 112 : tls_current_fiber = NULL;
- 139 :
- 140 : /* Return to resumer with final result */
- 141 112 : jump_fcontext(fiber->resumer_context, result);
- 142 :
- 143 : /* Should never reach here */
- 144 0 : }
+ 79 : /* Thread-local storage */
+ 80 : static _Thread_local yafl_fiber_t *tls_current_fiber = NULL;
+ 81 :
+ 82 : static void fiber_entry_trampoline(void *arg);
+ 83 :
+ 84 366 : static void free_fiber_stack(yafl_fiber_t *fiber) {
+ 85 366 : if(fiber == NULL || fiber->stack_region == NULL) { return; }
+ 86 :
+ 87 366 : if(fiber->alloc_type == FCONTEXT_ALLOC_MALLOC) {
+ 88 45 : free(fiber->stack_region);
+ 89 366 : } else if(fiber->alloc_type == FCONTEXT_ALLOC_VMEM) {
+ 90 : #ifdef _WIN32
+ 91 : VirtualFree(fiber->stack_region, 0, MEM_RELEASE);
+ 92 : #else
+ 93 321 : munmap(fiber->stack_region, fiber->stack_total_size);
+ 94 : #endif
+ 95 321 : }
+ 96 :
+ 97 366 : fiber->stack_region = NULL;
+ 98 366 : fiber->stack_total_size = 0;
+ 99 366 : fiber->stack_top = NULL;
+ 100 366 : fiber->stack_size = 0;
+ 101 366 : }
+ 102 :
+ 103 390 : static bool initialize_fiber_context(yafl_fiber_t *fiber) {
+ 104 390 : fiber->context = yafl_make_context(fiber->stack_top, fiber->stack_size, fiber_entry_trampoline);
+ 105 390 : return fiber->context != NULL;
+ 106 : }
+ 107 :
+ 108 24 : static bool reinitialize_fiber_context_with_watermark(yafl_fiber_t *fiber) {
+ 109 24 : memset((char *)fiber->stack_top - fiber->stack_size, FCONTEXT_STACK_WATERMARK, fiber->stack_size);
+ 110 24 : return initialize_fiber_context(fiber);
+ 111 : }
+ 112 :
+ 113 : /* ========================================================================
+ 114 : * Utility Functions
+ 115 : * ======================================================================== */
+ 116 :
+ 117 321 : static size_t get_page_size(void) {
+ 118 : #ifdef _WIN32
+ 119 : SYSTEM_INFO si;
+ 120 : GetSystemInfo(&si);
+ 121 : return (size_t)si.dwPageSize;
+ 122 : #else
+ 123 321 : long page_size = sysconf(_SC_PAGE_SIZE);
+ 124 321 : if(page_size <= 0) { return 4096; }
+ 125 321 : return (size_t)page_size;
+ 126 : #endif
+ 127 321 : }
+ 128 :
+ 129 366 : static void *align_stack_pointer(void *ptr) {
+ 130 366 : uintptr_t addr = (uintptr_t)ptr;
+ 131 732 : return (void *)(addr & ~((uintptr_t)FCONTEXT_STACK_ALIGNMENT - 1));
+ 132 366 : }
+ 133 :
+ 134 : /* ========================================================================
+ 135 : * Trampoline: Adapts Low-Level API to High-Level Fiber API
+ 136 : * ======================================================================== */
+ 137 :
+ 138 : /*
+ 139 : * This is called as the entry function by yafl_make_context().
+ 140 : * It wraps the user's entry function, manages state, and handles the result.
+ 141 : */
+ 142 0 : static void fiber_entry_trampoline(void *arg) {
+ 143 0 : yafl_fiber_t *fiber = tls_current_fiber;
+ 144 0 : if(fiber == NULL) { abort(); }
145 :
- 146 : /* ========================================================================
- 147 : * Fiber Creation
- 148 : * ======================================================================== */
+ 146 : /* Update status and TLS */
+ 147 0 : fiber->status = YAFL_FIBER_STATUS_RUNNING;
+ 148 0 : tls_current_fiber = fiber;
149 :
- 150 120 : extern yafl_fiber_t *yafl_fiber_create(yafl_fiber_fn fiber_fn, size_t stack_size,
- 151 : yafl_stack_flags_t flags) {
- 152 : /* Validate fiber function is not NULL */
- 153 120 : if (fiber_fn == NULL) {
- 154 : return NULL;
- 155 : }
- 156 :
- 157 : /* Validate exactly one allocation type is set */
- 158 119 : int alloc_flags = flags & (YAFL_STACK_FLAGS_MALLOC | YAFL_STACK_FLAGS_VMEM);
- 159 119 : if (alloc_flags != YAFL_STACK_FLAGS_MALLOC && alloc_flags != YAFL_STACK_FLAGS_VMEM) {
- 160 : return NULL;
- 161 : }
- 162 :
- 163 116 : bool use_vmem = (flags & YAFL_STACK_FLAGS_VMEM) != 0;
- 164 116 : bool use_watermark = (flags & YAFL_STACK_FLAGS_WATERMARK) != 0;
- 165 :
- 166 : /* Allocate fiber structure */
- 167 116 : yafl_fiber_t *fiber = malloc(sizeof(yafl_fiber_t));
- 168 116 : if (fiber == NULL) {
- 169 : return NULL;
- 170 : }
- 171 :
- 172 : /* Initialize fiber structure */
- 173 116 : fiber->magic = FCONTEXT_FIBER_MAGIC;
- 174 116 : fiber->alloc_type = use_vmem ? FCONTEXT_ALLOC_VMEM : FCONTEXT_ALLOC_MALLOC;
- 175 116 : fiber->status = YAFL_FIBER_STATUS_SUSPENDED;
- 176 116 : fiber->user_entry = fiber_fn;
- 177 116 : fiber->cached_result = NULL;
- 178 116 : fiber->pending_arg = NULL;
- 179 116 : fiber->watermark_filled = use_watermark;
- 180 116 : fiber->context = NULL;
- 181 116 : fiber->resumer_context = NULL;
- 182 :
- 183 : /* Use default stack size if not specified */
- 184 116 : if (stack_size == 0) {
- 185 1 : stack_size = FCONTEXT_DEFAULT_STACK_SIZE;
- 186 : }
- 187 :
- 188 : /* Allocate stack based on allocation type */
- 189 116 : if (use_vmem) {
- 190 104 : size_t page_size = get_page_size();
- 191 104 : size_t stack_with_overhead = stack_size + 256;
- 192 104 : size_t aligned_stack_size = ((stack_with_overhead + page_size - 1) / page_size) * page_size;
- 193 104 : size_t guard_size = page_size;
- 194 104 : size_t total_size = guard_size + aligned_stack_size + guard_size;
- 195 :
- 196 104 : void *region = NULL;
- 197 : #ifdef _WIN32
- 198 : region = VirtualAlloc(NULL, total_size, MEM_RESERVE, PAGE_NOACCESS);
- 199 : if (region == NULL) {
- 200 : free(fiber);
- 201 : return NULL;
- 202 : }
- 203 : void *stack_base = (char *)region + guard_size;
- 204 : if (!VirtualAlloc(stack_base, aligned_stack_size, MEM_COMMIT, PAGE_READWRITE)) {
- 205 : VirtualFree(region, 0, MEM_RELEASE);
- 206 : free(fiber);
- 207 : return NULL;
- 208 : }
- 209 : #else
- 210 104 : region = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- 211 104 : if (region == MAP_FAILED) {
- 212 0 : free(fiber);
- 213 0 : return NULL;
- 214 : }
- 215 104 : if (mprotect(region, guard_size, PROT_NONE) == -1) {
- 216 0 : munmap(region, total_size);
- 217 0 : free(fiber);
- 218 0 : return NULL;
- 219 : }
- 220 104 : if (mprotect((char *)region + guard_size + aligned_stack_size, guard_size, PROT_NONE) == -1) {
- 221 0 : munmap(region, total_size);
- 222 0 : free(fiber);
- 223 0 : return NULL;
- 224 : }
- 225 104 : void *stack_base = (char *)region + guard_size;
- 226 : #endif
- 227 :
- 228 104 : void *stack_region_end = (char *)stack_base + aligned_stack_size;
- 229 104 : void *stack_top = (char *)stack_region_end - 256;
- 230 104 : stack_top = align_stack_pointer(stack_top);
- 231 104 : size_t actual_stack_size = (char *)stack_top - (char *)stack_base;
- 232 :
- 233 104 : fiber->stack_region = region;
- 234 104 : fiber->stack_total_size = total_size;
- 235 104 : fiber->stack_top = stack_top;
- 236 104 : fiber->stack_size = actual_stack_size;
- 237 : } else {
- 238 : /* malloc allocation */
- 239 12 : size_t allocated_size = stack_size + 256;
- 240 12 : void *block = malloc(allocated_size);
- 241 12 : if (block == NULL) {
- 242 0 : free(fiber);
- 243 0 : return NULL;
- 244 : }
+ 150 : /* Call user entry with argument from first resume */
+ 151 0 : void *result = fiber->user_entry(arg);
+ 152 :
+ 153 : /* Mark complete and cache result */
+ 154 0 : fiber->status = YAFL_FIBER_STATUS_COMPLETE;
+ 155 0 : fiber->cached_result = result;
+ 156 0 : tls_current_fiber = NULL;
+ 157 :
+ 158 : /* Return to resumer with final result */
+ 159 0 : yafl_switch(&fiber->context, fiber->resumer_context, result);
+ 160 :
+ 161 : /* Should never reach here */
+ 162 0 : abort();
+ 163 : }
+ 164 :
+ 165 : /* ========================================================================
+ 166 : * Fiber Creation
+ 167 : * ======================================================================== */
+ 168 :
+ 169 378 : extern yafl_fiber_t *yafl_fiber_create(yafl_fiber_fn fiber_fn, size_t stack_size, yafl_stack_flags_t flags) {
+ 170 : /* Validate fiber function is not NULL */
+ 171 378 : if(fiber_fn == NULL) { return NULL; }
+ 172 :
+ 173 : /* Validate exactly one allocation type is set */
+ 174 375 : int alloc_flags = flags & (YAFL_STACK_FLAGS_MALLOC | YAFL_STACK_FLAGS_VMEM);
+ 175 375 : if(alloc_flags != YAFL_STACK_FLAGS_MALLOC && alloc_flags != YAFL_STACK_FLAGS_VMEM) { return NULL; }
+ 176 :
+ 177 366 : bool use_vmem = (flags & YAFL_STACK_FLAGS_VMEM) != 0;
+ 178 366 : bool use_watermark = (flags & YAFL_STACK_FLAGS_WATERMARK) != 0;
+ 179 :
+ 180 : /* Allocate fiber structure */
+ 181 366 : yafl_fiber_t *fiber = malloc(sizeof(yafl_fiber_t));
+ 182 366 : if(fiber == NULL) { return NULL; }
+ 183 :
+ 184 : /* Initialize fiber structure */
+ 185 366 : fiber->magic = FCONTEXT_FIBER_MAGIC;
+ 186 366 : fiber->alloc_type = use_vmem ? FCONTEXT_ALLOC_VMEM : FCONTEXT_ALLOC_MALLOC;
+ 187 366 : fiber->status = YAFL_FIBER_STATUS_SUSPENDED;
+ 188 366 : fiber->user_entry = fiber_fn;
+ 189 366 : fiber->cached_result = NULL;
+ 190 366 : fiber->watermark_filled = use_watermark;
+ 191 366 : fiber->context = NULL;
+ 192 366 : fiber->resumer_context = NULL;
+ 193 366 : fiber->stack_region = NULL;
+ 194 366 : fiber->stack_total_size = 0;
+ 195 366 : fiber->stack_top = NULL;
+ 196 366 : fiber->stack_size = 0;
+ 197 :
+ 198 : /* Use default stack size if not specified */
+ 199 366 : if(stack_size == 0) { stack_size = FCONTEXT_DEFAULT_STACK_SIZE; }
+ 200 :
+ 201 : /* Allocate stack based on allocation type */
+ 202 366 : if(use_vmem) {
+ 203 321 : size_t page_size = get_page_size();
+ 204 321 : size_t stack_with_overhead = stack_size + 256;
+ 205 321 : size_t aligned_stack_size = ((stack_with_overhead + page_size - 1) / page_size) * page_size;
+ 206 321 : size_t guard_size = page_size;
+ 207 321 : size_t total_size = guard_size + aligned_stack_size + guard_size;
+ 208 :
+ 209 321 : void *region = NULL;
+ 210 : #ifdef _WIN32
+ 211 : region = VirtualAlloc(NULL, total_size, MEM_RESERVE, PAGE_NOACCESS);
+ 212 : if(region == NULL) { goto create_fail; }
+ 213 : fiber->stack_region = region;
+ 214 : fiber->stack_total_size = total_size;
+ 215 : void *stack_base = (char *)region + guard_size;
+ 216 : if(!VirtualAlloc(stack_base, aligned_stack_size, MEM_COMMIT, PAGE_READWRITE)) { goto create_fail; }
+ 217 : #else
+ 218 321 : region = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ 219 321 : if(region == MAP_FAILED) { goto create_fail; }
+ 220 321 : fiber->stack_region = region;
+ 221 321 : fiber->stack_total_size = total_size;
+ 222 321 : if(mprotect(region, guard_size, PROT_NONE) == -1) { goto create_fail; }
+ 223 321 : if(mprotect((char *)region + guard_size + aligned_stack_size, guard_size, PROT_NONE) == -1) { goto create_fail; }
+ 224 321 : void *stack_base = (char *)region + guard_size;
+ 225 : #endif
+ 226 :
+ 227 321 : void *stack_region_end = (char *)stack_base + aligned_stack_size;
+ 228 321 : void *stack_top = (char *)stack_region_end - 256;
+ 229 321 : stack_top = align_stack_pointer(stack_top);
+ 230 321 : size_t actual_stack_size = (uintptr_t)(intptr_t)((char *)stack_top - (char *)stack_base);
+ 231 :
+ 232 321 : fiber->stack_top = stack_top;
+ 233 321 : fiber->stack_size = actual_stack_size;
+ 234 321 : } else {
+ 235 : /* malloc allocation */
+ 236 45 : size_t allocated_size = stack_size + 256;
+ 237 45 : void *block = malloc(allocated_size);
+ 238 45 : if(block == NULL) { goto create_fail; }
+ 239 45 : fiber->stack_region = block;
+ 240 45 : fiber->stack_total_size = allocated_size;
+ 241 :
+ 242 45 : void *block_end = (char *)block + allocated_size;
+ 243 45 : void *stack_top = (char *)block_end - 256;
+ 244 45 : stack_top = align_stack_pointer(stack_top);
245 :
- 246 12 : void *block_end = (char *)block + allocated_size;
- 247 12 : void *stack_top = (char *)block_end - 256;
- 248 12 : stack_top = align_stack_pointer(stack_top);
- 249 :
- 250 12 : size_t actual_stack_size = (char *)stack_top - (char *)block;
+ 246 45 : size_t actual_stack_size = (uintptr_t)(intptr_t)((char *)stack_top - (char *)block);
+ 247 :
+ 248 45 : fiber->stack_top = stack_top;
+ 249 45 : fiber->stack_size = actual_stack_size;
+ 250 45 : }
251 :
- 252 12 : fiber->stack_region = block;
- 253 12 : fiber->stack_total_size = allocated_size;
- 254 12 : fiber->stack_top = stack_top;
- 255 12 : fiber->stack_size = actual_stack_size;
- 256 : }
- 257 :
- 258 : /* Initialize the low-level context with trampoline as entry */
- 259 116 : fiber->context = make_fcontext(fiber->stack_top, fiber->stack_size, fiber_entry_trampoline);
- 260 116 : if (fiber->context == NULL) {
- 261 0 : if (use_vmem) {
- 262 : #ifdef _WIN32
- 263 : VirtualFree(fiber->stack_region, 0, MEM_RELEASE);
- 264 : #else
- 265 0 : munmap(fiber->stack_region, fiber->stack_total_size);
- 266 : #endif
- 267 : } else {
- 268 0 : free(fiber->stack_region);
- 269 : }
- 270 0 : free(fiber);
- 271 0 : return NULL;
- 272 : }
- 273 :
- 274 : /* Apply watermark if requested */
- 275 116 : if (use_watermark) {
- 276 4 : memset((char *)fiber->stack_top - fiber->stack_size, FCONTEXT_STACK_WATERMARK, fiber->stack_size);
- 277 : /* Reinitialize context after watermark (overwrites filled area) */
- 278 4 : fiber->context = make_fcontext(fiber->stack_top, fiber->stack_size, fiber_entry_trampoline);
- 279 4 : if (fiber->context == NULL) {
- 280 0 : if (use_vmem) {
- 281 : #ifdef _WIN32
- 282 : VirtualFree(fiber->stack_region, 0, MEM_RELEASE);
- 283 : #else
- 284 0 : munmap(fiber->stack_region, fiber->stack_total_size);
- 285 : #endif
- 286 : } else {
- 287 0 : free(fiber->stack_region);
- 288 : }
- 289 0 : free(fiber);
- 290 0 : return NULL;
- 291 : }
- 292 : }
- 293 :
- 294 : return fiber;
- 295 : }
- 296 :
- 297 : /* ========================================================================
- 298 : * Fiber Control Flow
- 299 : * ======================================================================== */
+ 252 : /* Initialize the low-level context with trampoline as entry */
+ 253 366 : if(!initialize_fiber_context(fiber)) { goto create_fail; }
+ 254 :
+ 255 : /* Apply watermark if requested */
+ 256 366 : if(use_watermark) {
+ 257 24 : if(!reinitialize_fiber_context_with_watermark(fiber)) { goto create_fail; }
+ 258 24 : }
+ 259 :
+ 260 366 : return fiber;
+ 261 :
+ 262 : create_fail:
+ 263 0 : free_fiber_stack(fiber);
+ 264 0 : free(fiber);
+ 265 0 : return NULL;
+ 266 378 : }
+ 267 :
+ 268 : /* ========================================================================
+ 269 : * Fiber Control Flow
+ 270 : * ======================================================================== */
+ 271 :
+ 272 3435 : extern void *yafl_fiber_resume(yafl_fiber_t *fiber, void *arg) {
+ 273 : /* Validation */
+ 274 3435 : if(fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC) { return NULL; }
+ 275 :
+ 276 : /* If complete, return cached result (idempotent) */
+ 277 3432 : if(fiber->status == YAFL_FIBER_STATUS_COMPLETE) { return fiber->cached_result; }
+ 278 :
+ 279 : /* Cannot resume running fiber */
+ 280 3429 : if(fiber->status == YAFL_FIBER_STATUS_RUNNING) { return NULL; }
+ 281 :
+ 282 : /* Update status and TLS */
+ 283 3429 : fiber->status = YAFL_FIBER_STATUS_RUNNING;
+ 284 3429 : tls_current_fiber = fiber;
+ 285 :
+ 286 : /* Perform context switch */
+ 287 3429 : void *result = yafl_switch(&fiber->resumer_context, fiber->context, arg);
+ 288 :
+ 289 : /* Back in resumer */
+ 290 3429 : tls_current_fiber = NULL;
+ 291 :
+ 292 3429 : return result;
+ 293 3435 : }
+ 294 :
+ 295 3075 : extern void *yafl_fiber_suspend(void *result) {
+ 296 3075 : yafl_fiber_t *current = tls_current_fiber;
+ 297 :
+ 298 : /* Must be in a fiber */
+ 299 3075 : if(current == NULL) { return NULL; }
300 :
- 301 1137 : extern void *yafl_fiber_resume(yafl_fiber_t *fiber, void *arg) {
- 302 : /* Validation */
- 303 1137 : if (fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC) {
- 304 : return NULL;
- 305 : }
+ 301 : /* Update status */
+ 302 3075 : current->status = YAFL_FIBER_STATUS_SUSPENDED;
+ 303 :
+ 304 : /* Switch back to resumer */
+ 305 3075 : void *arg = yafl_switch(¤t->context, current->resumer_context, result);
306 :
- 307 : /* If complete, return cached result (idempotent) */
- 308 1136 : if (fiber->status == YAFL_FIBER_STATUS_COMPLETE) {
- 309 1 : return fiber->cached_result;
- 310 : }
- 311 :
- 312 : /* Cannot resume running fiber */
- 313 1135 : if (fiber->status == YAFL_FIBER_STATUS_RUNNING) {
- 314 : return NULL;
- 315 : }
- 316 :
- 317 : /* Store argument for delivery */
- 318 1135 : fiber->pending_arg = arg;
- 319 :
- 320 : /* Update status and TLS */
- 321 1135 : fiber->status = YAFL_FIBER_STATUS_RUNNING;
- 322 1135 : tls_current_fiber = fiber;
+ 307 : /* When resumed - restore state */
+ 308 3075 : current->status = YAFL_FIBER_STATUS_RUNNING;
+ 309 3075 : tls_current_fiber = current;
+ 310 :
+ 311 : /* Return argument passed to resume */
+ 312 3075 : return arg;
+ 313 3075 : }
+ 314 :
+ 315 : /* ========================================================================
+ 316 : * Fiber Status and Monitoring
+ 317 : * ======================================================================== */
+ 318 :
+ 319 4296 : extern yafl_fiber_status_t yafl_fiber_status(yafl_fiber_t *fiber) {
+ 320 4296 : if(fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC) { return YAFL_FIBER_STATUS_ERR; }
+ 321 4293 : return fiber->status;
+ 322 4296 : }
323 :
- 324 : /* Pass fiber pointer to trampoline on first resume */
- 325 1135 : void *transfer_data = (void *)fiber;
+ 324 45 : extern size_t yafl_fiber_stack_high_watermark(yafl_fiber_t *fiber) {
+ 325 45 : if(fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC || !fiber->watermark_filled) { return 0; }
326 :
- 327 : /* Perform context switch */
- 328 1135 : yafl_transfer_t t = jump_fcontext(fiber->context, transfer_data);
- 329 :
- 330 : /* Back in resumer - update fiber's context for next resume */
- 331 1135 : fiber->context = t.prev_context;
- 332 1135 : tls_current_fiber = NULL;
- 333 :
- 334 1135 : return t.data;
- 335 : }
- 336 :
- 337 1023 : extern void *yafl_fiber_suspend(void *result) {
- 338 1023 : yafl_fiber_t *current = tls_current_fiber;
+ 327 : /* Scan from stack base for watermark bytes */
+ 328 24 : unsigned char *stack_base = (unsigned char *)fiber->stack_top - fiber->stack_size;
+ 329 24 : size_t unused = 0;
+ 330 :
+ 331 580440 : while(unused < fiber->stack_size && stack_base[unused] == FCONTEXT_STACK_WATERMARK) { unused++; }
+ 332 :
+ 333 24 : return fiber->stack_size - unused;
+ 334 45 : }
+ 335 :
+ 336 : /* ========================================================================
+ 337 : * Cleanup
+ 338 : * ======================================================================== */
339 :
- 340 : /* Must be in a fiber */
- 341 1023 : if (current == NULL) {
- 342 : return NULL;
- 343 : }
- 344 :
- 345 : /* Update status */
- 346 1023 : current->status = YAFL_FIBER_STATUS_SUSPENDED;
+ 340 372 : extern void yafl_fiber_destroy(yafl_fiber_t *fiber) {
+ 341 372 : if(fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC) { return; }
+ 342 :
+ 343 : /* Cannot destroy running fiber */
+ 344 366 : if(fiber->status == YAFL_FIBER_STATUS_RUNNING) { return; }
+ 345 :
+ 346 366 : free_fiber_stack(fiber);
347 :
- 348 : /* Switch back to resumer */
- 349 1023 : yafl_transfer_t t = jump_fcontext(current->resumer_context, result);
- 350 :
- 351 : /* When resumed - restore state */
- 352 1023 : current->status = YAFL_FIBER_STATUS_RUNNING;
- 353 1023 : current->resumer_context = t.prev_context;
- 354 1023 : tls_current_fiber = current;
- 355 :
- 356 : /* Return argument passed to resume */
- 357 1023 : return current->pending_arg;
- 358 : }
- 359 :
- 360 : /* ========================================================================
- 361 : * Fiber Status and Monitoring
- 362 : * ======================================================================== */
- 363 :
- 364 1426 : extern yafl_fiber_status_t yafl_fiber_status(yafl_fiber_t *fiber) {
- 365 1426 : if (fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC) {
- 366 : return YAFL_FIBER_STATUS_ERR;
- 367 : }
- 368 1425 : return fiber->status;
- 369 : }
- 370 :
- 371 4 : extern size_t yafl_fiber_stack_high_watermark(yafl_fiber_t *fiber) {
- 372 4 : if (fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC || !fiber->watermark_filled) {
- 373 : return 0;
- 374 : }
- 375 :
- 376 : /* Scan from stack base for watermark bytes */
- 377 2 : unsigned char *stack_base = (unsigned char *)fiber->stack_top - fiber->stack_size;
- 378 2 : size_t unused = 0;
- 379 :
- 380 36434 : while (unused < fiber->stack_size && stack_base[unused] == FCONTEXT_STACK_WATERMARK) {
- 381 36432 : unused++;
- 382 : }
- 383 :
- 384 2 : return fiber->stack_size - unused;
- 385 : }
- 386 :
- 387 : /* ========================================================================
- 388 : * Cleanup
- 389 : * ======================================================================== */
- 390 :
- 391 118 : extern void yafl_fiber_destroy(yafl_fiber_t *fiber) {
- 392 118 : if (fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC) {
- 393 : return;
- 394 : }
- 395 :
- 396 : /* Cannot destroy running fiber */
- 397 116 : if (fiber->status == YAFL_FIBER_STATUS_RUNNING) {
- 398 : return;
- 399 : }
- 400 :
- 401 : /* Free stack based on allocation type */
- 402 116 : if (fiber->alloc_type == FCONTEXT_ALLOC_MALLOC) {
- 403 12 : free(fiber->stack_region);
- 404 104 : } else if (fiber->alloc_type == FCONTEXT_ALLOC_VMEM) {
- 405 : #ifdef _WIN32
- 406 : VirtualFree(fiber->stack_region, 0, MEM_RELEASE);
- 407 : #else
- 408 104 : munmap(fiber->stack_region, fiber->stack_total_size);
- 409 : #endif
- 410 : }
- 411 :
- 412 : /* Invalidate and free */
- 413 116 : fiber->magic = 0;
- 414 116 : free(fiber);
- 415 : }
- 416 :
- 417 : /* ========================================================================
- 418 : * Utilities
- 419 : * ======================================================================== */
- 420 :
- 421 0 : extern size_t yafl_get_page_size(void) {
- 422 0 : return get_page_size();
- 423 : }
+ 348 : /* Invalidate and free */
+ 349 366 : fiber->magic = 0;
+ 350 366 : free(fiber);
+ 351 372 : }
+ 352 :
+ 353 : /* ========================================================================
+ 354 : * Utilities
+ 355 : * ======================================================================== */
+ 356 :
+ 357 0 : extern size_t yafl_get_page_size(void) { return get_page_size(); }
@@ -491,7 +425,7 @@
diff --git a/docs/coverage/tests/index-sort-f.html b/docs/coverage/tests/index-sort-f.html
index 7e2b0c5..152700d 100644
--- a/docs/coverage/tests/index-sort-f.html
+++ b/docs/coverage/tests/index-sort-f.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,21 +28,21 @@
-
+
|
-
-
-
+
+
+
-
+
|
-
-
-
+
+
+
 |
@@ -67,7 +67,7 @@
- Filename  |
+ File  |
Line Coverage  |
Function Coverage  |
@@ -80,49 +80,61 @@
Hit |
- | test_yafl_guard.c |
+ test_yafl_guard.c |
-
+
|
- 32.5 % |
- 77 |
- 25 |
+ 34.1 % |
+ 82 |
+ 28 |
25.0 % |
4 |
1 |
- | test_yafl_many.c |
+ test_yafl_many.c |
|
100.0 % |
- 65 |
- 65 |
+ 78 |
+ 78 |
100.0 % |
2 |
2 |
- | test_yafl_suspend_resume.c |
+ test_yafl_watermark.c |
|
100.0 % |
- 107 |
- 107 |
+ 76 |
+ 76 |
+ 100.0 % |
+ 8 |
+ 8 |
+
+
+ | test_yafl_suspend_resume.c |
+
+
+ |
+ 100.0 % |
+ 111 |
+ 111 |
100.0 % |
11 |
11 |
- | test_yafl_basic.c |
+ test_yafl_basic.c |
|
100.0 % |
- 153 |
- 153 |
+ 156 |
+ 156 |
100.0 % |
13 |
13 |
@@ -133,7 +145,7 @@
diff --git a/docs/coverage/tests/index-sort-l.html b/docs/coverage/tests/index-sort-l.html
index 2ee6554..15ca397 100644
--- a/docs/coverage/tests/index-sort-l.html
+++ b/docs/coverage/tests/index-sort-l.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,21 +28,21 @@
-
+
|
-
-
-
+
+
+
-
+
|
-
-
-
+
+
+
 |
@@ -67,7 +67,7 @@
- Filename  |
+ File  |
Line Coverage  |
Function Coverage  |
@@ -80,49 +80,61 @@
Hit |
- | test_yafl_guard.c |
+ test_yafl_guard.c |
-
+
|
- 32.5 % |
- 77 |
- 25 |
+ 34.1 % |
+ 82 |
+ 28 |
25.0 % |
4 |
1 |
- | test_yafl_many.c |
+ test_yafl_watermark.c |
|
100.0 % |
- 65 |
- 65 |
+ 76 |
+ 76 |
+ 100.0 % |
+ 8 |
+ 8 |
+
+
+ | test_yafl_many.c |
+
+
+ |
+ 100.0 % |
+ 78 |
+ 78 |
100.0 % |
2 |
2 |
- | test_yafl_suspend_resume.c |
+ test_yafl_suspend_resume.c |
|
100.0 % |
- 107 |
- 107 |
+ 111 |
+ 111 |
100.0 % |
11 |
11 |
- | test_yafl_basic.c |
+ test_yafl_basic.c |
|
100.0 % |
- 153 |
- 153 |
+ 156 |
+ 156 |
100.0 % |
13 |
13 |
@@ -133,7 +145,7 @@
diff --git a/docs/coverage/tests/index.html b/docs/coverage/tests/index.html
index c06ba1a..03b1152 100644
--- a/docs/coverage/tests/index.html
+++ b/docs/coverage/tests/index.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,21 +28,21 @@
-
+
|
-
-
-
+
+
+
-
+
|
-
-
-
+
+
+
 |
@@ -67,7 +67,7 @@
- Filename  |
+ File  |
Line Coverage  |
Function Coverage  |
@@ -80,60 +80,72 @@
Hit |
- | test_yafl_basic.c |
+ test_yafl_basic.c |
|
100.0 % |
- 153 |
- 153 |
+ 156 |
+ 156 |
100.0 % |
13 |
13 |
- | test_yafl_guard.c |
+ test_yafl_guard.c |
-
+
|
- 32.5 % |
- 77 |
- 25 |
+ 34.1 % |
+ 82 |
+ 28 |
25.0 % |
4 |
1 |
- | test_yafl_many.c |
+ test_yafl_many.c |
|
100.0 % |
- 65 |
- 65 |
+ 78 |
+ 78 |
100.0 % |
2 |
2 |
- | test_yafl_suspend_resume.c |
+ test_yafl_suspend_resume.c |
|
100.0 % |
- 107 |
- 107 |
+ 111 |
+ 111 |
100.0 % |
11 |
11 |
+
+ | test_yafl_watermark.c |
+
+
+ |
+ 100.0 % |
+ 76 |
+ 76 |
+ 100.0 % |
+ 8 |
+ 8 |
+
diff --git a/docs/coverage/tests/test_yafl_basic.c.func-c.html b/docs/coverage/tests/test_yafl_basic.c.func-c.html
index ed2a718..78f35ae 100644
--- a/docs/coverage/tests/test_yafl_basic.c.func-c.html
+++ b/docs/coverage/tests/test_yafl_basic.c.func-c.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
+
+
-
+
|
@@ -61,95 +61,109 @@
Hit count  |
+
| cycling_fiber_func |
- 1 |
+ 3 |
+
| main |
- 1 |
+ 3 |
+
| test_default_stack_size |
- 1 |
+ 3 |
+
| test_flag_combinations |
- 1 |
+ 3 |
+
| test_null_entry_function |
- 1 |
+ 3 |
+
| test_null_fiber_pointer |
- 1 |
+ 3 |
+
| test_simple_execution |
- 1 |
+ 3 |
+
| test_status_query |
- 1 |
+ 3 |
+
| test_suspend_resume_cycles |
- 1 |
+ 3 |
+
| test_watermark |
- 1 |
+ 3 |
+
| test_watermark_without_flag |
- 1 |
+ 3 |
+
| watermarked_fiber_func |
- 2 |
+ 6 |
+
| simple_fiber_func |
- 4 |
+ 12 |
+
@@ -158,7 +172,7 @@
diff --git a/docs/coverage/tests/test_yafl_basic.c.func.html b/docs/coverage/tests/test_yafl_basic.c.func.html
index d1af4b8..d0f5bdf 100644
--- a/docs/coverage/tests/test_yafl_basic.c.func.html
+++ b/docs/coverage/tests/test_yafl_basic.c.func.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
+
+
-
+
|
@@ -61,95 +61,109 @@
Hit count  |
+
| cycling_fiber_func |
- 1 |
+ 3 |
+
| main |
- 1 |
+ 3 |
+
| simple_fiber_func |
- 4 |
+ 12 |
+
| test_default_stack_size |
- 1 |
+ 3 |
+
| test_flag_combinations |
- 1 |
+ 3 |
+
| test_null_entry_function |
- 1 |
+ 3 |
+
| test_null_fiber_pointer |
- 1 |
+ 3 |
+
| test_simple_execution |
- 1 |
+ 3 |
+
| test_status_query |
- 1 |
+ 3 |
+
| test_suspend_resume_cycles |
- 1 |
+ 3 |
+
| test_watermark |
- 1 |
+ 3 |
+
| test_watermark_without_flag |
- 1 |
+ 3 |
+
| watermarked_fiber_func |
- 2 |
+ 6 |
+
@@ -158,7 +172,7 @@
diff --git a/docs/coverage/tests/test_yafl_basic.c.gcov.html b/docs/coverage/tests/test_yafl_basic.c.gcov.html
index 52bb335..75ff469 100644
--- a/docs/coverage/tests/test_yafl_basic.c.gcov.html
+++ b/docs/coverage/tests/test_yafl_basic.c.gcov.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
+
+
-
+
|
@@ -79,313 +79,313 @@
17 : * Test: Simple Fiber Execution
18 : * ======================================================================== */
19 :
- 20 4 : static void *simple_fiber_func(void *arg) {
- 21 4 : return arg;
+ 20 12 : static void *simple_fiber_func(void *arg) {
+ 21 12 : return arg;
22 : }
23 :
- 24 1 : static void test_simple_execution(void) {
- 25 1 : printf("test_simple_execution: ");
- 26 1 : fflush(stdout);
+ 24 3 : static void test_simple_execution(void) {
+ 25 3 : printf("test_simple_execution: ");
+ 26 3 : fflush(stdout);
27 :
28 : /* Create fiber with malloc allocation */
- 29 1 : yafl_fiber_t *fiber = yafl_fiber_create(simple_fiber_func, 16 * 1024,
+ 29 3 : yafl_fiber_t *fiber = yafl_fiber_create(simple_fiber_func, 16 * 1024,
30 : YAFL_STACK_FLAGS_MALLOC);
- 31 1 : assert(fiber != NULL);
- 32 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
+ 31 3 : assert(fiber != NULL);
+ 32 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
33 :
34 : /* Resume fiber */
- 35 1 : void *result = yafl_fiber_resume(fiber, (void *)0x1234);
- 36 1 : assert(result == (void *)0x1234);
- 37 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
+ 35 3 : void *result = yafl_fiber_resume(fiber, (void *)0x1234);
+ 36 3 : assert(result == (void *)0x1234);
+ 37 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
38 :
39 : /* Resuming completed fiber returns cached result */
- 40 1 : void *result2 = yafl_fiber_resume(fiber, (void *)0x5678);
- 41 1 : assert(result2 == (void *)0x1234);
+ 40 3 : void *result2 = yafl_fiber_resume(fiber, (void *)0x5678);
+ 41 3 : assert(result2 == (void *)0x1234);
42 :
43 : /* Cleanup */
- 44 1 : yafl_fiber_destroy(fiber);
- 45 1 : yafl_fiber_destroy(NULL); /* Safe to call on NULL */
+ 44 3 : yafl_fiber_destroy(fiber);
+ 45 3 : yafl_fiber_destroy(NULL); /* Safe to call on NULL */
46 :
- 47 1 : printf("PASS\n");
- 48 1 : }
+ 47 3 : printf("PASS\n");
+ 48 3 : }
49 :
50 : /* ========================================================================
51 : * Test: Flag Combinations
52 : * ======================================================================== */
53 :
- 54 1 : static void test_flag_combinations(void) {
- 55 1 : printf("test_flag_combinations: ");
- 56 1 : fflush(stdout);
+ 54 3 : static void test_flag_combinations(void) {
+ 55 3 : printf("test_flag_combinations: ");
+ 56 3 : fflush(stdout);
57 :
58 : /* Valid: MALLOC alone */
- 59 1 : yafl_fiber_t *f1 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
+ 59 3 : yafl_fiber_t *f1 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
60 : YAFL_STACK_FLAGS_MALLOC);
- 61 1 : assert(f1 != NULL);
- 62 1 : yafl_fiber_destroy(f1);
+ 61 3 : assert(f1 != NULL);
+ 62 3 : yafl_fiber_destroy(f1);
63 :
64 : /* Valid: VMEM alone */
- 65 1 : yafl_fiber_t *f2 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
+ 65 3 : yafl_fiber_t *f2 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
66 : YAFL_STACK_FLAGS_VMEM);
- 67 1 : assert(f2 != NULL);
- 68 1 : yafl_fiber_destroy(f2);
+ 67 3 : assert(f2 != NULL);
+ 68 3 : yafl_fiber_destroy(f2);
69 :
70 : /* Valid: MALLOC with WATERMARK */
- 71 1 : yafl_fiber_t *f3 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
+ 71 3 : yafl_fiber_t *f3 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
72 : YAFL_STACK_FLAGS_MALLOC | YAFL_STACK_FLAGS_WATERMARK);
- 73 1 : assert(f3 != NULL);
- 74 1 : yafl_fiber_destroy(f3);
+ 73 3 : assert(f3 != NULL);
+ 74 3 : yafl_fiber_destroy(f3);
75 :
76 : /* Valid: VMEM with WATERMARK */
- 77 1 : yafl_fiber_t *f4 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
+ 77 3 : yafl_fiber_t *f4 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
78 : YAFL_STACK_FLAGS_VMEM | YAFL_STACK_FLAGS_WATERMARK);
- 79 1 : assert(f4 != NULL);
- 80 1 : yafl_fiber_destroy(f4);
+ 79 3 : assert(f4 != NULL);
+ 80 3 : yafl_fiber_destroy(f4);
81 :
82 : /* Invalid: NONE */
- 83 1 : yafl_fiber_t *f5 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
+ 83 3 : yafl_fiber_t *f5 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
84 : YAFL_STACK_FLAGS_NONE);
- 85 1 : assert(f5 == NULL);
+ 85 3 : assert(f5 == NULL);
86 :
87 : /* Invalid: MALLOC | VMEM both set */
- 88 1 : yafl_fiber_t *f6 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
+ 88 3 : yafl_fiber_t *f6 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
89 : YAFL_STACK_FLAGS_MALLOC | YAFL_STACK_FLAGS_VMEM);
- 90 1 : assert(f6 == NULL);
+ 90 3 : assert(f6 == NULL);
91 :
92 : /* Invalid: Neither allocation type */
- 93 1 : yafl_fiber_t *f7 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
+ 93 3 : yafl_fiber_t *f7 = yafl_fiber_create(simple_fiber_func, 16 * 1024,
94 : YAFL_STACK_FLAGS_WATERMARK);
- 95 1 : assert(f7 == NULL);
+ 95 3 : assert(f7 == NULL);
96 :
- 97 1 : printf("PASS\n");
- 98 1 : }
+ 97 3 : printf("PASS\n");
+ 98 3 : }
99 :
100 : /* ========================================================================
101 : * Test: Suspend/Resume Cycles
102 : * ======================================================================== */
103 :
- 104 1 : static void *cycling_fiber_func(void *arg) {
- 105 1 : void *result = arg;
+ 104 3 : static void *cycling_fiber_func(void *arg) {
+ 105 3 : void *result = arg;
106 :
- 107 6 : for (int i = 0; i < 5; i++) {
- 108 5 : result = yafl_fiber_suspend(result);
- 109 : }
+ 107 18 : for (int i = 0; i < 5; i++) {
+ 108 15 : result = yafl_fiber_suspend(result);
+ 109 15 : }
110 :
- 111 1 : return result;
- 112 : }
+ 111 6 : return result;
+ 112 3 : }
113 :
- 114 1 : static void test_suspend_resume_cycles(void) {
- 115 1 : printf("test_suspend_resume_cycles: ");
- 116 1 : fflush(stdout);
+ 114 3 : static void test_suspend_resume_cycles(void) {
+ 115 3 : printf("test_suspend_resume_cycles: ");
+ 116 3 : fflush(stdout);
117 :
- 118 1 : yafl_fiber_t *fiber = yafl_fiber_create(cycling_fiber_func, 16 * 1024,
+ 118 3 : yafl_fiber_t *fiber = yafl_fiber_create(cycling_fiber_func, 16 * 1024,
119 : YAFL_STACK_FLAGS_MALLOC);
- 120 1 : assert(fiber != NULL);
+ 120 3 : assert(fiber != NULL);
121 :
122 : /* Cycle 1 */
- 123 1 : void *result = yafl_fiber_resume(fiber, (void *)0x1);
- 124 1 : assert(result == (void *)0x1);
- 125 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
+ 123 3 : void *result = yafl_fiber_resume(fiber, (void *)0x1);
+ 124 3 : assert(result == (void *)0x1);
+ 125 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
126 :
127 : /* Cycle 2 */
- 128 1 : result = yafl_fiber_resume(fiber, (void *)0x2);
- 129 1 : assert(result == (void *)0x2);
- 130 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
+ 128 3 : result = yafl_fiber_resume(fiber, (void *)0x2);
+ 129 3 : assert(result == (void *)0x2);
+ 130 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
131 :
132 : /* Cycle 3 */
- 133 1 : result = yafl_fiber_resume(fiber, (void *)0x3);
- 134 1 : assert(result == (void *)0x3);
+ 133 3 : result = yafl_fiber_resume(fiber, (void *)0x3);
+ 134 3 : assert(result == (void *)0x3);
135 :
136 : /* Cycle 4 */
- 137 1 : result = yafl_fiber_resume(fiber, (void *)0x4);
- 138 1 : assert(result == (void *)0x4);
+ 137 3 : result = yafl_fiber_resume(fiber, (void *)0x4);
+ 138 3 : assert(result == (void *)0x4);
139 :
140 : /* Cycle 5 */
- 141 1 : result = yafl_fiber_resume(fiber, (void *)0x5);
- 142 1 : assert(result == (void *)0x5);
+ 141 3 : result = yafl_fiber_resume(fiber, (void *)0x5);
+ 142 3 : assert(result == (void *)0x5);
143 :
144 : /* Final cycle - fiber completes */
- 145 1 : result = yafl_fiber_resume(fiber, (void *)0x6);
- 146 1 : assert(result == (void *)0x6);
- 147 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
+ 145 3 : result = yafl_fiber_resume(fiber, (void *)0x6);
+ 146 3 : assert(result == (void *)0x6);
+ 147 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
148 :
- 149 1 : yafl_fiber_destroy(fiber);
+ 149 3 : yafl_fiber_destroy(fiber);
150 :
- 151 1 : printf("PASS\n");
- 152 1 : }
+ 151 3 : printf("PASS\n");
+ 152 3 : }
153 :
154 : /* ========================================================================
155 : * Test: Status Query
156 : * ======================================================================== */
157 :
- 158 1 : static void test_status_query(void) {
- 159 1 : printf("test_status_query: ");
- 160 1 : fflush(stdout);
+ 158 3 : static void test_status_query(void) {
+ 159 3 : printf("test_status_query: ");
+ 160 3 : fflush(stdout);
161 :
- 162 1 : yafl_fiber_t *fiber = yafl_fiber_create(simple_fiber_func, 16 * 1024,
+ 162 3 : yafl_fiber_t *fiber = yafl_fiber_create(simple_fiber_func, 16 * 1024,
163 : YAFL_STACK_FLAGS_MALLOC);
164 :
165 : /* Check initial status */
- 166 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
+ 166 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
167 :
168 : /* Check status of NULL */
- 169 1 : assert(yafl_fiber_status(NULL) == YAFL_FIBER_STATUS_ERR);
+ 169 3 : assert(yafl_fiber_status(NULL) == YAFL_FIBER_STATUS_ERR);
170 :
171 : /* Resume and check completion */
- 172 1 : yafl_fiber_resume(fiber, (void *)0x99);
- 173 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
+ 172 3 : yafl_fiber_resume(fiber, (void *)0x99);
+ 173 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
174 :
- 175 1 : yafl_fiber_destroy(fiber);
+ 175 3 : yafl_fiber_destroy(fiber);
176 :
- 177 1 : printf("PASS\n");
- 178 1 : }
+ 177 3 : printf("PASS\n");
+ 178 3 : }
179 :
180 : /* ========================================================================
181 : * Test: Watermark Measurement
182 : * ======================================================================== */
183 :
- 184 2 : static void *watermarked_fiber_func(void *arg) {
+ 184 6 : static void *watermarked_fiber_func(void *arg) {
185 : /* Allocate some stack space to trigger watermark usage */
- 186 2 : volatile char stack_buffer[1024];
+ 186 6 : volatile char stack_buffer[1024];
187 : /* Use memset to ensure compiler can't optimize the buffer away */
- 188 2 : memset((char *)stack_buffer, 0xAA, sizeof(stack_buffer));
- 189 2 : return arg;
- 190 : }
+ 188 6 : memset((char *)stack_buffer, 0xAA, sizeof(stack_buffer));
+ 189 12 : return arg;
+ 190 6 : }
191 :
- 192 1 : static void test_watermark(void) {
- 193 1 : printf("test_watermark_malloc: ");
- 194 1 : fflush(stdout);
+ 192 3 : static void test_watermark(void) {
+ 193 3 : printf("test_watermark_malloc: ");
+ 194 3 : fflush(stdout);
195 :
196 : /* Test with malloc + watermark */
- 197 1 : yafl_fiber_t *fiber = yafl_fiber_create(watermarked_fiber_func, 16 * 1024,
+ 197 3 : yafl_fiber_t *fiber = yafl_fiber_create(watermarked_fiber_func, 16 * 1024,
198 : YAFL_STACK_FLAGS_MALLOC | YAFL_STACK_FLAGS_WATERMARK);
- 199 1 : assert(fiber != NULL);
+ 199 3 : assert(fiber != NULL);
200 :
201 : /* Resume and check watermark */
- 202 1 : yafl_fiber_resume(fiber, NULL);
- 203 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
+ 202 3 : yafl_fiber_resume(fiber, NULL);
+ 203 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
204 :
- 205 1 : size_t usage = yafl_fiber_stack_high_watermark(fiber);
- 206 1 : assert(usage > 0); /* Should have used some stack */
+ 205 3 : size_t usage = yafl_fiber_stack_high_watermark(fiber);
+ 206 3 : assert(usage > 0); /* Should have used some stack */
207 :
- 208 1 : yafl_fiber_destroy(fiber);
+ 208 3 : yafl_fiber_destroy(fiber);
209 :
- 210 1 : printf("PASS\n");
+ 210 3 : printf("PASS\n");
211 :
- 212 1 : printf("test_watermark_vmem: ");
- 213 1 : fflush(stdout);
+ 212 3 : printf("test_watermark_vmem: ");
+ 213 3 : fflush(stdout);
214 :
215 : /* Test with vmem + watermark */
- 216 1 : yafl_fiber_t *fiber2 = yafl_fiber_create(watermarked_fiber_func, 16 * 1024,
+ 216 3 : yafl_fiber_t *fiber2 = yafl_fiber_create(watermarked_fiber_func, 16 * 1024,
217 : YAFL_STACK_FLAGS_VMEM | YAFL_STACK_FLAGS_WATERMARK);
- 218 1 : assert(fiber2 != NULL);
+ 218 3 : assert(fiber2 != NULL);
219 :
- 220 1 : yafl_fiber_resume(fiber2, NULL);
- 221 1 : assert(yafl_fiber_status(fiber2) == YAFL_FIBER_STATUS_COMPLETE);
+ 220 3 : yafl_fiber_resume(fiber2, NULL);
+ 221 3 : assert(yafl_fiber_status(fiber2) == YAFL_FIBER_STATUS_COMPLETE);
222 :
- 223 1 : size_t usage2 = yafl_fiber_stack_high_watermark(fiber2);
- 224 1 : assert(usage2 > 0);
+ 223 3 : size_t usage2 = yafl_fiber_stack_high_watermark(fiber2);
+ 224 3 : assert(usage2 > 0);
225 :
- 226 1 : yafl_fiber_destroy(fiber2);
+ 226 3 : yafl_fiber_destroy(fiber2);
227 :
- 228 1 : printf("PASS\n");
- 229 1 : }
+ 228 3 : printf("PASS\n");
+ 229 3 : }
230 :
231 : /* ========================================================================
232 : * Test: Watermark Without Flag
233 : * ======================================================================== */
234 :
- 235 1 : static void test_watermark_without_flag(void) {
- 236 1 : printf("test_watermark_without_flag: ");
- 237 1 : fflush(stdout);
+ 235 3 : static void test_watermark_without_flag(void) {
+ 236 3 : printf("test_watermark_without_flag: ");
+ 237 3 : fflush(stdout);
238 :
- 239 1 : yafl_fiber_t *fiber = yafl_fiber_create(simple_fiber_func, 16 * 1024,
+ 239 3 : yafl_fiber_t *fiber = yafl_fiber_create(simple_fiber_func, 16 * 1024,
240 : YAFL_STACK_FLAGS_MALLOC);
- 241 1 : assert(fiber != NULL);
+ 241 3 : assert(fiber != NULL);
242 :
243 : /* Without watermark flag, should return 0 */
- 244 1 : assert(yafl_fiber_stack_high_watermark(fiber) == 0);
+ 244 3 : assert(yafl_fiber_stack_high_watermark(fiber) == 0);
245 :
- 246 1 : yafl_fiber_resume(fiber, NULL);
+ 246 3 : yafl_fiber_resume(fiber, NULL);
247 :
248 : /* Still 0 because no watermark was applied */
- 249 1 : assert(yafl_fiber_stack_high_watermark(fiber) == 0);
+ 249 3 : assert(yafl_fiber_stack_high_watermark(fiber) == 0);
250 :
- 251 1 : yafl_fiber_destroy(fiber);
+ 251 3 : yafl_fiber_destroy(fiber);
252 :
- 253 1 : printf("PASS\n");
- 254 1 : }
+ 253 3 : printf("PASS\n");
+ 254 3 : }
255 :
256 : /* ========================================================================
257 : * Test: NULL Fiber Pointer
258 : * ======================================================================== */
259 :
- 260 1 : static void test_null_fiber_pointer(void) {
- 261 1 : printf("test_null_fiber_pointer: ");
- 262 1 : fflush(stdout);
+ 260 3 : static void test_null_fiber_pointer(void) {
+ 261 3 : printf("test_null_fiber_pointer: ");
+ 262 3 : fflush(stdout);
263 :
264 : /* Resume NULL fiber */
- 265 1 : void *result = yafl_fiber_resume(NULL, (void *)0x1);
- 266 1 : assert(result == NULL);
+ 265 3 : void *result = yafl_fiber_resume(NULL, (void *)0x1);
+ 266 3 : assert(result == NULL);
267 :
268 : /* Destroy NULL fiber (safe no-op) */
- 269 1 : yafl_fiber_destroy(NULL);
+ 269 3 : yafl_fiber_destroy(NULL);
270 :
- 271 1 : printf("PASS\n");
- 272 1 : }
+ 271 3 : printf("PASS\n");
+ 272 3 : }
273 :
274 : /* ========================================================================
275 : * Test: NULL Entry Function
276 : * ======================================================================== */
277 :
- 278 1 : static void test_null_entry_function(void) {
- 279 1 : printf("test_null_entry_function: ");
- 280 1 : fflush(stdout);
+ 278 3 : static void test_null_entry_function(void) {
+ 279 3 : printf("test_null_entry_function: ");
+ 280 3 : fflush(stdout);
281 :
- 282 1 : yafl_fiber_t *fiber = yafl_fiber_create(NULL, 16 * 1024,
+ 282 3 : yafl_fiber_t *fiber = yafl_fiber_create(NULL, 16 * 1024,
283 : YAFL_STACK_FLAGS_MALLOC);
- 284 1 : assert(fiber == NULL);
+ 284 3 : assert(fiber == NULL);
285 :
- 286 1 : printf("PASS\n");
- 287 1 : }
+ 286 3 : printf("PASS\n");
+ 287 3 : }
288 :
289 : /* ========================================================================
290 : * Test: Default Stack Size
291 : * ======================================================================== */
292 :
- 293 1 : static void test_default_stack_size(void) {
- 294 1 : printf("test_default_stack_size: ");
- 295 1 : fflush(stdout);
+ 293 3 : static void test_default_stack_size(void) {
+ 294 3 : printf("test_default_stack_size: ");
+ 295 3 : fflush(stdout);
296 :
297 : /* Create with 0 stack size (uses default) */
- 298 1 : yafl_fiber_t *fiber = yafl_fiber_create(simple_fiber_func, 0,
+ 298 3 : yafl_fiber_t *fiber = yafl_fiber_create(simple_fiber_func, 0,
299 : YAFL_STACK_FLAGS_MALLOC);
- 300 1 : assert(fiber != NULL);
+ 300 3 : assert(fiber != NULL);
301 :
- 302 1 : yafl_fiber_resume(fiber, (void *)0x42);
- 303 1 : yafl_fiber_destroy(fiber);
+ 302 3 : yafl_fiber_resume(fiber, (void *)0x42);
+ 303 3 : yafl_fiber_destroy(fiber);
304 :
- 305 1 : printf("PASS\n");
- 306 1 : }
+ 305 3 : printf("PASS\n");
+ 306 3 : }
307 :
308 : /* ========================================================================
309 : * Main
310 : * ======================================================================== */
311 :
- 312 1 : int main(void) {
- 313 1 : printf("Running YAFL basic tests...\n");
+ 312 3 : int main(void) {
+ 313 3 : printf("Running YAFL basic tests...\n");
314 :
- 315 1 : test_simple_execution();
- 316 1 : test_flag_combinations();
- 317 1 : test_suspend_resume_cycles();
- 318 1 : test_status_query();
- 319 1 : test_watermark();
- 320 1 : test_watermark_without_flag();
- 321 1 : test_null_fiber_pointer();
- 322 1 : test_null_entry_function();
- 323 1 : test_default_stack_size();
+ 315 3 : test_simple_execution();
+ 316 3 : test_flag_combinations();
+ 317 3 : test_suspend_resume_cycles();
+ 318 3 : test_status_query();
+ 319 3 : test_watermark();
+ 320 3 : test_watermark_without_flag();
+ 321 3 : test_null_fiber_pointer();
+ 322 3 : test_null_entry_function();
+ 323 3 : test_default_stack_size();
324 :
- 325 1 : printf("\nAll tests passed!\n");
- 326 1 : return 0;
+ 325 3 : printf("\nAll tests passed!\n");
+ 326 3 : return 0;
327 : }
@@ -395,7 +395,7 @@
diff --git a/docs/coverage/tests/test_yafl_guard.c.func-c.html b/docs/coverage/tests/test_yafl_guard.c.func-c.html
index 5479975..7d5bd7c 100644
--- a/docs/coverage/tests/test_yafl_guard.c.func-c.html
+++ b/docs/coverage/tests/test_yafl_guard.c.func-c.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
-
+
+
+
-
+
|
@@ -61,6 +61,7 @@
Hit count  |
+
| guard_test_fiber |
@@ -68,6 +69,7 @@
0 |
+
| overflow_stack |
@@ -75,6 +77,7 @@
0 |
+
| run_child_test |
@@ -82,11 +85,13 @@
0 |
+
| main |
- 1 |
+ 4 |
+
@@ -95,7 +100,7 @@
diff --git a/docs/coverage/tests/test_yafl_guard.c.func.html b/docs/coverage/tests/test_yafl_guard.c.func.html
index f456f8b..6732e17 100644
--- a/docs/coverage/tests/test_yafl_guard.c.func.html
+++ b/docs/coverage/tests/test_yafl_guard.c.func.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
-
+
+
+
-
+
|
@@ -61,6 +61,7 @@
Hit count  |
+
| guard_test_fiber |
@@ -68,11 +69,13 @@
0 |
+
| main |
- 1 |
+ 4 |
+
@@ -82,6 +85,7 @@
0 |
+
| run_child_test |
@@ -89,13 +93,14 @@
0 |
+
diff --git a/docs/coverage/tests/test_yafl_guard.c.gcov.html b/docs/coverage/tests/test_yafl_guard.c.gcov.html
index 43892bd..bc4925f 100644
--- a/docs/coverage/tests/test_yafl_guard.c.gcov.html
+++ b/docs/coverage/tests/test_yafl_guard.c.gcov.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
-
+
+
+
-
+
|
@@ -86,7 +86,7 @@
24 : #endif
25 :
26 : /* Recursive function to overflow the stack */
- 27 0 : static void overflow_stack(int depth) {
+ 27 0 : static void overflow_stack(int depth) {
28 0 : volatile char buffer[128];
29 :
30 : /* Touch the buffer to prevent optimization */
@@ -98,7 +98,7 @@
36 : /* Recurse to build up stack usage to trigger guard page */
37 0 : if (depth < 250) {
38 0 : overflow_stack(depth + 1);
- 39 : }
+ 39 0 : }
40 0 : }
41 :
42 0 : static void *guard_test_fiber(void *data) {
@@ -139,16 +139,16 @@
77 0 : fflush(stderr);
78 0 : yafl_fiber_destroy(fiber);
79 0 : return 1;
- 80 : }
+ 80 0 : }
81 :
- 82 1 : int main(int argc, char *argv[]) {
- 83 1 : fprintf(stderr, "=== yafl Guard Page Test ===\n");
- 84 1 : fflush(stderr);
+ 82 4 : int main(int argc, char *argv[]) {
+ 83 4 : fprintf(stderr, "=== yafl Guard Page Test ===\n");
+ 84 4 : fflush(stderr);
85 :
86 : /* argc and argv only used on Windows */
87 : #ifndef _WIN32
- 88 1 : (void)argc;
- 89 1 : (void)argv;
+ 88 4 : (void)argc;
+ 89 4 : (void)argv;
90 : #endif
91 :
92 : #ifdef _WIN32
@@ -210,49 +210,49 @@
148 :
149 : #else
150 : /* POSIX: use fork */
- 151 1 : fprintf(stderr, "[main] spawning child process\n");
- 152 1 : fflush(stderr);
+ 151 4 : fprintf(stderr, "[main] spawning child process\n");
+ 152 4 : fflush(stderr);
153 :
- 154 1 : pid_t pid = fork();
- 155 1 : if (pid == -1) {
- 156 0 : fprintf(stderr, "[main] ERROR: fork failed\n");
+ 154 4 : pid_t pid = fork();
+ 155 4 : if (pid == -1) {
+ 156 0 : fprintf(stderr, "[main] ERROR: fork failed\n");
157 0 : fflush(stderr);
158 0 : return 1;
159 : }
160 :
- 161 1 : if (pid == 0) {
+ 161 4 : if (pid == 0) {
162 : /* Child process - run test and exit */
- 163 0 : exit(run_child_test());
+ 163 0 : exit(run_child_test());
164 : }
165 :
166 : /* Parent process - wait for child */
- 167 1 : fprintf(stderr, "[main] waiting for child process (PID: %d)\n", (int)pid);
- 168 1 : fflush(stderr);
+ 167 4 : fprintf(stderr, "[main] waiting for child process (PID: %d)\n", (int)pid);
+ 168 4 : fflush(stderr);
169 :
- 170 1 : int status;
- 171 1 : pid_t result = waitpid(pid, &status, 0);
- 172 1 : if (result == -1) {
- 173 0 : fprintf(stderr, "[main] ERROR: waitpid failed\n");
+ 170 4 : int status;
+ 171 4 : pid_t result = waitpid(pid, &status, 0);
+ 172 4 : if (result == -1) {
+ 173 0 : fprintf(stderr, "[main] ERROR: waitpid failed\n");
174 0 : fflush(stderr);
175 0 : return 1;
176 : }
177 :
178 : /* Check how the child terminated */
- 179 1 : if (WIFSIGNALED(status)) {
- 180 1 : int sig = WTERMSIG(status);
- 181 1 : fprintf(stderr, "[main] child killed by signal %d\n", sig);
- 182 1 : fflush(stderr);
+ 179 4 : if (WIFSIGNALED(status)) {
+ 180 4 : int sig = WTERMSIG(status);
+ 181 4 : fprintf(stderr, "[main] child killed by signal %d\n", sig);
+ 182 4 : fflush(stderr);
183 :
- 184 : /* Expect SIGSEGV (11) or SIGBUS (7) for guard page fault */
- 185 1 : if (sig == SIGSEGV || sig == SIGBUS) {
- 186 1 : fprintf(stderr, "[main] guard page successfully detected stack overflow\n");
- 187 1 : fflush(stderr);
- 188 : } else {
- 189 0 : fprintf(stderr, "[main] FAIL: child killed by unexpected signal %d\n", sig);
+ 184 : /* Expect SIGSEGV (11) or SIGBUS (7) SIGILL (4) for guard page fault */
+ 185 4 : if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL) {
+ 186 4 : fprintf(stderr, "[main] guard page successfully detected stack overflow\n");
+ 187 4 : fflush(stderr);
+ 188 4 : } else {
+ 189 0 : fprintf(stderr, "[main] FAIL: child killed by unexpected signal %d\n", sig);
190 0 : fflush(stderr);
191 0 : return 1;
192 : }
- 193 0 : } else if (WIFEXITED(status)) {
+ 193 4 : } else if (WIFEXITED(status)) {
194 0 : int exit_code = WEXITSTATUS(status);
195 0 : fprintf(stderr, "[main] child exited with code %d\n", exit_code);
196 0 : fflush(stderr);
@@ -262,7 +262,7 @@
200 0 : fflush(stderr);
201 0 : return 1;
202 : }
- 203 : } else {
+ 203 0 : } else {
204 0 : fprintf(stderr, "[main] FAIL: unexpected child termination\n");
205 0 : fflush(stderr);
206 0 : return 1;
@@ -270,10 +270,10 @@
208 :
209 : #endif
210 :
- 211 1 : fprintf(stderr, "\nPASS: Guard page detected stack overflow\n");
- 212 1 : fflush(stderr);
- 213 1 : return 0;
- 214 : }
+ 211 4 : fprintf(stderr, "\nPASS: Guard page detected stack overflow\n");
+ 212 4 : fflush(stderr);
+ 213 4 : return 0;
+ 214 4 : }
@@ -282,7 +282,7 @@
diff --git a/docs/coverage/tests/test_yafl_many.c.func-c.html b/docs/coverage/tests/test_yafl_many.c.func-c.html
index 1126f91..0077423 100644
--- a/docs/coverage/tests/test_yafl_many.c.func-c.html
+++ b/docs/coverage/tests/test_yafl_many.c.func-c.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
+
+
-
+
|
@@ -61,18 +61,21 @@
Hit count  |
+
| main |
- 1 |
+ 3 |
+
| fiber_entry |
- 100 |
+ 300 |
+
@@ -81,7 +84,7 @@
diff --git a/docs/coverage/tests/test_yafl_many.c.func.html b/docs/coverage/tests/test_yafl_many.c.func.html
index b9d9b9e..c78779d 100644
--- a/docs/coverage/tests/test_yafl_many.c.func.html
+++ b/docs/coverage/tests/test_yafl_many.c.func.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
+
+
-
+
|
@@ -61,18 +61,21 @@
Hit count  |
+
| fiber_entry |
- 100 |
+ 300 |
+
| main |
- 1 |
+ 3 |
+
@@ -81,7 +84,7 @@
diff --git a/docs/coverage/tests/test_yafl_many.c.gcov.html b/docs/coverage/tests/test_yafl_many.c.gcov.html
index 931072c..dc970ae 100644
--- a/docs/coverage/tests/test_yafl_many.c.gcov.html
+++ b/docs/coverage/tests/test_yafl_many.c.gcov.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
+
+
-
+
|
@@ -85,111 +85,111 @@
23 : static int counters[NUM_FIBERS];
24 : static yafl_fiber_t *fibers[NUM_FIBERS];
25 :
- 26 100 : static void *fiber_entry(void *data) {
- 27 100 : int id = (int)(uintptr_t)data;
+ 26 300 : static void *fiber_entry(void *data) {
+ 27 300 : int id = (int)(uintptr_t)data;
28 :
- 29 100 : fprintf(stderr, "[fiber %d] entered\n", id);
- 30 100 : fflush(stderr);
+ 29 300 : fprintf(stderr, "[fiber %d] entered\n", id);
+ 30 300 : fflush(stderr);
31 :
- 32 1100 : for (int i = 0; i < ITERATIONS; i++) {
- 33 1000 : fprintf(stderr, "[fiber %d] iteration %d/%d\n", id, i + 1, ITERATIONS);
- 34 1000 : fflush(stderr);
+ 32 3300 : for (int i = 0; i < ITERATIONS; i++) {
+ 33 3000 : fprintf(stderr, "[fiber %d] iteration %d/%d\n", id, i + 1, ITERATIONS);
+ 34 3000 : fflush(stderr);
35 :
- 36 1000 : counters[id]++;
+ 36 3000 : counters[id]++;
37 :
- 38 1000 : fprintf(stderr, "[fiber %d] suspending\n", id);
- 39 1000 : fflush(stderr);
- 40 1000 : yafl_fiber_suspend(NULL);
+ 38 3000 : fprintf(stderr, "[fiber %d] suspending\n", id);
+ 39 3000 : fflush(stderr);
+ 40 3000 : yafl_fiber_suspend(NULL);
41 :
- 42 1000 : fprintf(stderr, "[fiber %d] resumed\n", id);
- 43 1000 : fflush(stderr);
- 44 : }
+ 42 3000 : fprintf(stderr, "[fiber %d] resumed\n", id);
+ 43 3000 : fflush(stderr);
+ 44 3000 : }
45 :
- 46 100 : fprintf(stderr, "[fiber %d] finishing with result %d\n", id, id + 1000);
- 47 100 : fflush(stderr);
- 48 100 : return (void *)(uintptr_t)(id + 1000);
- 49 : }
+ 46 300 : fprintf(stderr, "[fiber %d] finishing with result %d\n", id, id + 1000);
+ 47 300 : fflush(stderr);
+ 48 300 : return (void *)(uintptr_t)(id + 1000);
+ 49 300 : }
50 :
- 51 1 : int main(void) {
- 52 1 : fprintf(stderr, "=== yafl Many Fibers Test ===\n");
- 53 1 : fprintf(stderr, "[main] testing with %d fibers, %d iterations each\n", NUM_FIBERS, ITERATIONS);
- 54 1 : fflush(stderr);
+ 51 3 : int main(void) {
+ 52 3 : fprintf(stderr, "=== yafl Many Fibers Test ===\n");
+ 53 3 : fprintf(stderr, "[main] testing with %d fibers, %d iterations each\n", NUM_FIBERS, ITERATIONS);
+ 54 3 : fflush(stderr);
55 :
56 : /* Create 100 fibers */
- 57 1 : fprintf(stderr, "[main] creating %d fibers\n", NUM_FIBERS);
- 58 1 : fflush(stderr);
- 59 101 : for (int i = 0; i < NUM_FIBERS; i++) {
- 60 100 : counters[i] = 0;
- 61 100 : fibers[i] = yafl_fiber_create(fiber_entry, 24 * 1024, YAFL_STACK_FLAGS_VMEM);
- 62 100 : assert(fibers[i] != NULL);
+ 57 3 : fprintf(stderr, "[main] creating %d fibers\n", NUM_FIBERS);
+ 58 3 : fflush(stderr);
+ 59 303 : for (int i = 0; i < NUM_FIBERS; i++) {
+ 60 300 : counters[i] = 0;
+ 61 300 : fibers[i] = yafl_fiber_create(fiber_entry, 24 * 1024, YAFL_STACK_FLAGS_VMEM);
+ 62 300 : assert(fibers[i] != NULL);
63 :
64 : /* Test status on created fiber */
- 65 100 : yafl_fiber_status_t status = yafl_fiber_status(fibers[i]);
- 66 100 : assert(status == YAFL_FIBER_STATUS_SUSPENDED);
+ 65 300 : yafl_fiber_status_t status = yafl_fiber_status(fibers[i]);
+ 66 300 : assert(status == YAFL_FIBER_STATUS_SUSPENDED);
67 :
- 68 100 : if (i == 0 || i == NUM_FIBERS - 1) {
- 69 2 : fprintf(stderr, "[main] fiber %d: created, status=%d\n", i, status);
- 70 2 : fflush(stderr);
- 71 : }
- 72 : }
- 73 1 : fprintf(stderr, "[main] all %d fibers created successfully\n", NUM_FIBERS);
- 74 1 : fflush(stderr);
+ 68 300 : if (i == 0 || i == NUM_FIBERS - 1) {
+ 69 6 : fprintf(stderr, "[main] fiber %d: created, status=%d\n", i, status);
+ 70 6 : fflush(stderr);
+ 71 6 : }
+ 72 300 : }
+ 73 3 : fprintf(stderr, "[main] all %d fibers created successfully\n", NUM_FIBERS);
+ 74 3 : fflush(stderr);
75 :
76 : /* Round-robin scheduling until all done */
- 77 1 : fprintf(stderr, "[main] starting round-robin scheduling\n");
- 78 1 : fflush(stderr);
+ 77 3 : fprintf(stderr, "[main] starting round-robin scheduling\n");
+ 78 3 : fflush(stderr);
79 :
- 80 1 : int round = 0;
- 81 1 : bool all_done = false;
- 82 13 : while (!all_done) {
- 83 : all_done = true;
- 84 : int active_count = 0;
+ 80 3 : int round = 0;
+ 81 3 : bool all_done = false;
+ 82 39 : while (!all_done) {
+ 83 36 : all_done = true;
+ 84 36 : int active_count = 0;
85 :
- 86 1212 : for (int i = 0; i < NUM_FIBERS; i++) {
- 87 1200 : yafl_fiber_status_t status = yafl_fiber_status(fibers[i]);
- 88 1200 : if (status != YAFL_FIBER_STATUS_COMPLETE) {
- 89 1100 : yafl_fiber_resume(fibers[i], (void *)(uintptr_t)i);
- 90 1100 : all_done = false;
- 91 1100 : active_count++;
- 92 : }
- 93 : }
+ 86 3636 : for (int i = 0; i < NUM_FIBERS; i++) {
+ 87 3600 : yafl_fiber_status_t status = yafl_fiber_status(fibers[i]);
+ 88 3600 : if (status != YAFL_FIBER_STATUS_COMPLETE) {
+ 89 3300 : yafl_fiber_resume(fibers[i], (void *)(uintptr_t)i);
+ 90 3300 : all_done = false;
+ 91 3300 : active_count++;
+ 92 3300 : }
+ 93 3600 : }
94 :
- 95 12 : round++;
- 96 12 : if (round <= 3 || all_done) {
- 97 4 : fprintf(stderr, "[main] round %d: %d fibers still active\n", round, active_count);
- 98 4 : fflush(stderr);
- 99 : }
- 100 : }
+ 95 36 : round++;
+ 96 36 : if (round <= 3 || all_done) {
+ 97 12 : fprintf(stderr, "[main] round %d: %d fibers still active\n", round, active_count);
+ 98 12 : fflush(stderr);
+ 99 12 : }
+ 100 36 : }
101 :
- 102 1 : fprintf(stderr, "[main] all fibers finished after %d rounds\n", round);
- 103 1 : fflush(stderr);
+ 102 3 : fprintf(stderr, "[main] all fibers finished after %d rounds\n", round);
+ 103 3 : fflush(stderr);
104 :
105 : /* Verify all fibers ran exactly ITERATIONS times */
- 106 1 : fprintf(stderr, "[main] verifying all fibers completed %d iterations\n", ITERATIONS);
- 107 1 : fflush(stderr);
+ 106 3 : fprintf(stderr, "[main] verifying all fibers completed %d iterations\n", ITERATIONS);
+ 107 3 : fflush(stderr);
108 :
- 109 101 : for (int i = 0; i < NUM_FIBERS; i++) {
- 110 100 : assert(counters[i] == ITERATIONS);
+ 109 303 : for (int i = 0; i < NUM_FIBERS; i++) {
+ 110 300 : assert(counters[i] == ITERATIONS);
111 :
- 112 100 : yafl_fiber_status_t status = yafl_fiber_status(fibers[i]);
- 113 100 : assert(status == YAFL_FIBER_STATUS_COMPLETE);
+ 112 300 : yafl_fiber_status_t status = yafl_fiber_status(fibers[i]);
+ 113 300 : assert(status == YAFL_FIBER_STATUS_COMPLETE);
114 :
- 115 100 : if (i == 0 || i == NUM_FIBERS - 1) {
- 116 2 : fprintf(stderr, "[main] fiber %d: counter=%d, status=%d\n", i, counters[i], status);
- 117 2 : fflush(stderr);
- 118 : }
+ 115 300 : if (i == 0 || i == NUM_FIBERS - 1) {
+ 116 6 : fprintf(stderr, "[main] fiber %d: counter=%d, status=%d\n", i, counters[i], status);
+ 117 6 : fflush(stderr);
+ 118 6 : }
119 :
- 120 100 : yafl_fiber_destroy(fibers[i]);
- 121 : }
+ 120 300 : yafl_fiber_destroy(fibers[i]);
+ 121 300 : }
122 :
- 123 1 : fprintf(stderr, "[main] all fibers verified and destroyed\n");
- 124 1 : fflush(stderr);
+ 123 3 : fprintf(stderr, "[main] all fibers verified and destroyed\n");
+ 124 3 : fflush(stderr);
125 :
- 126 1 : fprintf(stderr, "\nPASS: %d fibers x %d iterations = %d total context switches\n", NUM_FIBERS,
+ 126 3 : fprintf(stderr, "\nPASS: %d fibers x %d iterations = %d total context switches\n", NUM_FIBERS,
127 : ITERATIONS, NUM_FIBERS * ITERATIONS);
- 128 1 : fflush(stderr);
- 129 1 : return 0;
- 130 : }
+ 128 3 : fflush(stderr);
+ 129 3 : return 0;
+ 130 3 : }
@@ -198,7 +198,7 @@
diff --git a/docs/coverage/tests/test_yafl_suspend_resume.c.func-c.html b/docs/coverage/tests/test_yafl_suspend_resume.c.func-c.html
index d40870e..db20129 100644
--- a/docs/coverage/tests/test_yafl_suspend_resume.c.func-c.html
+++ b/docs/coverage/tests/test_yafl_suspend_resume.c.func-c.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
+
+
-
+
|
@@ -61,81 +61,93 @@
Hit count  |
+
| conditional_suspend_fiber_func |
- 1 |
+ 3 |
+
| echo_fiber_func |
- 1 |
+ 3 |
+
| main |
- 1 |
+ 3 |
+
| multi_suspend_fiber_func |
- 1 |
+ 3 |
+
| null_data_fiber_func |
- 1 |
+ 3 |
+
| test_bidirectional_data_passing |
- 1 |
+ 3 |
+
| test_conditional_suspension |
- 1 |
+ 3 |
+
| test_multiple_suspend_points |
- 1 |
+ 3 |
+
| test_null_data_passing |
- 1 |
+ 3 |
+
| test_vmem_suspend_resume |
- 1 |
+ 3 |
+
| vmem_test_func |
- 1 |
+ 3 |
+
@@ -144,7 +156,7 @@
diff --git a/docs/coverage/tests/test_yafl_suspend_resume.c.func.html b/docs/coverage/tests/test_yafl_suspend_resume.c.func.html
index 6704222..d30db38 100644
--- a/docs/coverage/tests/test_yafl_suspend_resume.c.func.html
+++ b/docs/coverage/tests/test_yafl_suspend_resume.c.func.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
+
+
-
+
|
@@ -61,81 +61,93 @@
Hit count  |
+
| conditional_suspend_fiber_func |
- 1 |
+ 3 |
+
| echo_fiber_func |
- 1 |
+ 3 |
+
| main |
- 1 |
+ 3 |
+
| multi_suspend_fiber_func |
- 1 |
+ 3 |
+
| null_data_fiber_func |
- 1 |
+ 3 |
+
| test_bidirectional_data_passing |
- 1 |
+ 3 |
+
| test_conditional_suspension |
- 1 |
+ 3 |
+
| test_multiple_suspend_points |
- 1 |
+ 3 |
+
| test_null_data_passing |
- 1 |
+ 3 |
+
| test_vmem_suspend_resume |
- 1 |
+ 3 |
+
| vmem_test_func |
- 1 |
+ 3 |
+
@@ -144,7 +156,7 @@
diff --git a/docs/coverage/tests/test_yafl_suspend_resume.c.gcov.html b/docs/coverage/tests/test_yafl_suspend_resume.c.gcov.html
index a015f7e..abfcab5 100644
--- a/docs/coverage/tests/test_yafl_suspend_resume.c.gcov.html
+++ b/docs/coverage/tests/test_yafl_suspend_resume.c.gcov.html
@@ -19,7 +19,7 @@
-
+
|
|
@@ -28,16 +28,16 @@
-
+
|
-
-
+
+
-
+
|
@@ -78,201 +78,201 @@
16 : * Test: Bidirectional Data Passing
17 : * ======================================================================== */
18 :
- 19 1 : static void *echo_fiber_func(void *arg) {
+ 19 3 : static void *echo_fiber_func(void *arg) {
20 : /* Fiber receives initial arg, suspends with it */
- 21 1 : arg = yafl_fiber_suspend(arg);
+ 21 3 : arg = yafl_fiber_suspend(arg);
22 :
23 : /* Receives new arg, suspends with it */
- 24 1 : arg = yafl_fiber_suspend(arg);
+ 24 3 : arg = yafl_fiber_suspend(arg);
25 :
26 : /* Receives final arg, returns it */
- 27 1 : return arg;
+ 27 3 : return arg;
28 : }
29 :
- 30 1 : static void test_bidirectional_data_passing(void) {
- 31 1 : printf("test_bidirectional_data_passing: ");
- 32 1 : fflush(stdout);
+ 30 3 : static void test_bidirectional_data_passing(void) {
+ 31 3 : printf("test_bidirectional_data_passing: ");
+ 32 3 : fflush(stdout);
33 :
- 34 1 : yafl_fiber_t *fiber = yafl_fiber_create(echo_fiber_func, 16 * 1024,
+ 34 3 : yafl_fiber_t *fiber = yafl_fiber_create(echo_fiber_func, 16 * 1024,
35 : YAFL_STACK_FLAGS_MALLOC);
- 36 1 : assert(fiber != NULL);
+ 36 3 : assert(fiber != NULL);
37 :
38 : /* First resume: send 0x1111, receive 0x1111 back */
- 39 1 : void *result = yafl_fiber_resume(fiber, (void *)0x1111);
- 40 1 : assert(result == (void *)0x1111);
- 41 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
+ 39 3 : void *result = yafl_fiber_resume(fiber, (void *)0x1111);
+ 40 3 : assert(result == (void *)0x1111);
+ 41 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
42 :
43 : /* Second resume: send 0x2222, receive 0x2222 back */
- 44 1 : result = yafl_fiber_resume(fiber, (void *)0x2222);
- 45 1 : assert(result == (void *)0x2222);
- 46 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
+ 44 3 : result = yafl_fiber_resume(fiber, (void *)0x2222);
+ 45 3 : assert(result == (void *)0x2222);
+ 46 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
47 :
48 : /* Third resume: send 0x3333, receive 0x3333 back (fiber completes) */
- 49 1 : result = yafl_fiber_resume(fiber, (void *)0x3333);
- 50 1 : assert(result == (void *)0x3333);
- 51 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
+ 49 3 : result = yafl_fiber_resume(fiber, (void *)0x3333);
+ 50 3 : assert(result == (void *)0x3333);
+ 51 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
52 :
- 53 1 : yafl_fiber_destroy(fiber);
+ 53 3 : yafl_fiber_destroy(fiber);
54 :
- 55 1 : printf("PASS\n");
- 56 1 : }
+ 55 3 : printf("PASS\n");
+ 56 3 : }
57 :
58 : /* ========================================================================
59 : * Test: Multiple Suspend Points
60 : * ======================================================================== */
61 :
- 62 1 : static void *multi_suspend_fiber_func(void *arg) {
- 63 11 : for (int i = 0; i < 10; i++) {
- 64 10 : arg = yafl_fiber_suspend((void *)(uintptr_t)(0x1000 + i));
- 65 : }
- 66 1 : return arg;
+ 62 3 : static void *multi_suspend_fiber_func(void *arg) {
+ 63 33 : for (int i = 0; i < 10; i++) {
+ 64 30 : arg = yafl_fiber_suspend((void *)(uintptr_t)(0x1000 + i));
+ 65 30 : }
+ 66 3 : return arg;
67 : }
68 :
- 69 1 : static void test_multiple_suspend_points(void) {
- 70 1 : printf("test_multiple_suspend_points: ");
- 71 1 : fflush(stdout);
+ 69 3 : static void test_multiple_suspend_points(void) {
+ 70 3 : printf("test_multiple_suspend_points: ");
+ 71 3 : fflush(stdout);
72 :
- 73 1 : yafl_fiber_t *fiber = yafl_fiber_create(multi_suspend_fiber_func, 16 * 1024,
+ 73 3 : yafl_fiber_t *fiber = yafl_fiber_create(multi_suspend_fiber_func, 16 * 1024,
74 : YAFL_STACK_FLAGS_MALLOC);
- 75 1 : assert(fiber != NULL);
+ 75 3 : assert(fiber != NULL);
76 :
- 77 11 : for (int i = 0; i < 10; i++) {
- 78 10 : void *result = yafl_fiber_resume(fiber, (void *)(uintptr_t)(0x2000 + i));
- 79 10 : assert(result == (void *)(uintptr_t)(0x1000 + i));
- 80 10 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
- 81 : }
+ 77 33 : for (int i = 0; i < 10; i++) {
+ 78 30 : void *result = yafl_fiber_resume(fiber, (void *)(uintptr_t)(0x2000 + i));
+ 79 30 : assert(result == (void *)(uintptr_t)(0x1000 + i));
+ 80 30 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
+ 81 30 : }
82 :
83 : /* Final resume to complete - should return the last arg passed to resume */
- 84 1 : void *final = yafl_fiber_resume(fiber, (void *)0x3000);
- 85 1 : assert(final == (void *)0x3000);
- 86 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
+ 84 3 : void *final = yafl_fiber_resume(fiber, (void *)0x3000);
+ 85 3 : assert(final == (void *)0x3000);
+ 86 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
87 :
- 88 1 : yafl_fiber_destroy(fiber);
+ 88 3 : yafl_fiber_destroy(fiber);
89 :
- 90 1 : printf("PASS\n");
- 91 1 : }
+ 90 3 : printf("PASS\n");
+ 91 3 : }
92 :
93 : /* ========================================================================
94 : * Test: Conditional Suspension
95 : * ======================================================================== */
96 :
- 97 1 : static void *conditional_suspend_fiber_func(void *arg) {
- 98 6 : for (int i = 0; i < 5; i++) {
- 99 5 : if (i % 2 == 0) {
- 100 3 : arg = yafl_fiber_suspend((void *)(uintptr_t)(0x100 + i));
- 101 : }
- 102 : }
- 103 1 : return arg;
+ 97 3 : static void *conditional_suspend_fiber_func(void *arg) {
+ 98 18 : for (int i = 0; i < 5; i++) {
+ 99 15 : if (i % 2 == 0) {
+ 100 9 : arg = yafl_fiber_suspend((void *)(uintptr_t)(0x100 + i));
+ 101 9 : }
+ 102 15 : }
+ 103 3 : return arg;
104 : }
105 :
- 106 1 : static void test_conditional_suspension(void) {
- 107 1 : printf("test_conditional_suspension: ");
- 108 1 : fflush(stdout);
+ 106 3 : static void test_conditional_suspension(void) {
+ 107 3 : printf("test_conditional_suspension: ");
+ 108 3 : fflush(stdout);
109 :
- 110 1 : yafl_fiber_t *fiber = yafl_fiber_create(conditional_suspend_fiber_func, 16 * 1024,
+ 110 3 : yafl_fiber_t *fiber = yafl_fiber_create(conditional_suspend_fiber_func, 16 * 1024,
111 : YAFL_STACK_FLAGS_MALLOC);
- 112 1 : assert(fiber != NULL);
+ 112 3 : assert(fiber != NULL);
113 :
114 : /* Suspend at i=0 */
- 115 1 : void *result = yafl_fiber_resume(fiber, (void *)0x1);
- 116 1 : assert(result == (void *)0x100);
+ 115 3 : void *result = yafl_fiber_resume(fiber, (void *)0x1);
+ 116 3 : assert(result == (void *)0x100);
117 :
118 : /* Suspend at i=2 */
- 119 1 : result = yafl_fiber_resume(fiber, (void *)0x2);
- 120 1 : assert(result == (void *)0x102);
+ 119 3 : result = yafl_fiber_resume(fiber, (void *)0x2);
+ 120 3 : assert(result == (void *)0x102);
121 :
122 : /* Suspend at i=4 */
- 123 1 : result = yafl_fiber_resume(fiber, (void *)0x3);
- 124 1 : assert(result == (void *)0x104);
+ 123 3 : result = yafl_fiber_resume(fiber, (void *)0x3);
+ 124 3 : assert(result == (void *)0x104);
125 :
126 : /* Complete */
- 127 1 : result = yafl_fiber_resume(fiber, (void *)0x4);
- 128 1 : assert(result == (void *)0x4);
- 129 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
+ 127 3 : result = yafl_fiber_resume(fiber, (void *)0x4);
+ 128 3 : assert(result == (void *)0x4);
+ 129 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
130 :
- 131 1 : yafl_fiber_destroy(fiber);
+ 131 3 : yafl_fiber_destroy(fiber);
132 :
- 133 1 : printf("PASS\n");
- 134 1 : }
+ 133 3 : printf("PASS\n");
+ 134 3 : }
135 :
136 : /* ========================================================================
137 : * Test: NULL Data Passing
138 : * ======================================================================== */
139 :
- 140 1 : static void *null_data_fiber_func(void *arg) {
- 141 1 : assert(arg == NULL); /* First resume passes NULL */
- 142 1 : arg = yafl_fiber_suspend(NULL);
- 143 1 : assert(arg == NULL); /* Second resume passes NULL */
- 144 1 : return arg;
+ 140 3 : static void *null_data_fiber_func(void *arg) {
+ 141 3 : assert(arg == NULL); /* First resume passes NULL */
+ 142 3 : arg = yafl_fiber_suspend(NULL);
+ 143 3 : assert(arg == NULL); /* Second resume passes NULL */
+ 144 3 : return arg;
145 : }
146 :
- 147 1 : static void test_null_data_passing(void) {
- 148 1 : printf("test_null_data_passing: ");
- 149 1 : fflush(stdout);
+ 147 3 : static void test_null_data_passing(void) {
+ 148 3 : printf("test_null_data_passing: ");
+ 149 3 : fflush(stdout);
150 :
- 151 1 : yafl_fiber_t *fiber = yafl_fiber_create(null_data_fiber_func, 16 * 1024,
+ 151 3 : yafl_fiber_t *fiber = yafl_fiber_create(null_data_fiber_func, 16 * 1024,
152 : YAFL_STACK_FLAGS_MALLOC);
- 153 1 : assert(fiber != NULL);
+ 153 3 : assert(fiber != NULL);
154 :
- 155 1 : void *result = yafl_fiber_resume(fiber, NULL);
- 156 1 : assert(result == NULL);
+ 155 3 : void *result = yafl_fiber_resume(fiber, NULL);
+ 156 3 : assert(result == NULL);
157 :
- 158 1 : result = yafl_fiber_resume(fiber, NULL);
- 159 1 : assert(result == NULL);
+ 158 3 : result = yafl_fiber_resume(fiber, NULL);
+ 159 3 : assert(result == NULL);
160 :
- 161 1 : yafl_fiber_destroy(fiber);
+ 161 3 : yafl_fiber_destroy(fiber);
162 :
- 163 1 : printf("PASS\n");
- 164 1 : }
+ 163 3 : printf("PASS\n");
+ 164 3 : }
165 :
166 : /* ========================================================================
167 : * Test: VMEM Allocation with Suspend/Resume
168 : * ======================================================================== */
169 :
- 170 1 : static void *vmem_test_func(void *arg) {
- 171 1 : arg = yafl_fiber_suspend((void *)0xAAAA);
- 172 1 : arg = yafl_fiber_suspend((void *)0xBBBB);
- 173 1 : return arg;
+ 170 3 : static void *vmem_test_func(void *arg) {
+ 171 3 : arg = yafl_fiber_suspend((void *)0xAAAA);
+ 172 3 : arg = yafl_fiber_suspend((void *)0xBBBB);
+ 173 3 : return arg;
174 : }
175 :
- 176 1 : static void test_vmem_suspend_resume(void) {
- 177 1 : printf("test_vmem_suspend_resume: ");
- 178 1 : fflush(stdout);
+ 176 3 : static void test_vmem_suspend_resume(void) {
+ 177 3 : printf("test_vmem_suspend_resume: ");
+ 178 3 : fflush(stdout);
179 :
- 180 1 : yafl_fiber_t *fiber = yafl_fiber_create(vmem_test_func, 16 * 1024,
+ 180 3 : yafl_fiber_t *fiber = yafl_fiber_create(vmem_test_func, 16 * 1024,
181 : YAFL_STACK_FLAGS_VMEM);
- 182 1 : assert(fiber != NULL);
+ 182 3 : assert(fiber != NULL);
183 :
- 184 1 : void *result = yafl_fiber_resume(fiber, (void *)0x1111);
- 185 1 : assert(result == (void *)0xAAAA);
+ 184 3 : void *result = yafl_fiber_resume(fiber, (void *)0x1111);
+ 185 3 : assert(result == (void *)0xAAAA);
186 :
- 187 1 : result = yafl_fiber_resume(fiber, (void *)0x2222);
- 188 1 : assert(result == (void *)0xBBBB);
+ 187 3 : result = yafl_fiber_resume(fiber, (void *)0x2222);
+ 188 3 : assert(result == (void *)0xBBBB);
189 :
- 190 1 : result = yafl_fiber_resume(fiber, (void *)0x3333);
- 191 1 : assert(result == (void *)0x3333);
- 192 1 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
+ 190 3 : result = yafl_fiber_resume(fiber, (void *)0x3333);
+ 191 3 : assert(result == (void *)0x3333);
+ 192 3 : assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
193 :
- 194 1 : yafl_fiber_destroy(fiber);
+ 194 3 : yafl_fiber_destroy(fiber);
195 :
- 196 1 : printf("PASS\n");
- 197 1 : }
+ 196 3 : printf("PASS\n");
+ 197 3 : }
198 :
199 : /* ========================================================================
200 : * Main
201 : * ======================================================================== */
202 :
- 203 1 : int main(void) {
- 204 1 : printf("Running YAFL suspend/resume tests...\n");
+ 203 3 : int main(void) {
+ 204 3 : printf("Running YAFL suspend/resume tests...\n");
205 :
- 206 1 : test_bidirectional_data_passing();
- 207 1 : test_multiple_suspend_points();
- 208 1 : test_conditional_suspension();
- 209 1 : test_null_data_passing();
- 210 1 : test_vmem_suspend_resume();
+ 206 3 : test_bidirectional_data_passing();
+ 207 3 : test_multiple_suspend_points();
+ 208 3 : test_conditional_suspension();
+ 209 3 : test_null_data_passing();
+ 210 3 : test_vmem_suspend_resume();
211 :
- 212 1 : printf("\nAll tests passed!\n");
- 213 1 : return 0;
+ 212 3 : printf("\nAll tests passed!\n");
+ 213 3 : return 0;
214 : }
@@ -282,7 +282,7 @@
diff --git a/docs/coverage_linux_aarch64.svg b/docs/coverage_linux_aarch64.svg
index f737a95..156293b 100644
--- a/docs/coverage_linux_aarch64.svg
+++ b/docs/coverage_linux_aarch64.svg
@@ -8,13 +8,13 @@
-
+
coverage
- 86.1%
+ 90.5%
diff --git a/docs/coverage_linux_x86_64.svg b/docs/coverage_linux_x86_64.svg
index f737a95..156293b 100644
--- a/docs/coverage_linux_x86_64.svg
+++ b/docs/coverage_linux_x86_64.svg
@@ -8,13 +8,13 @@
-
+
coverage
- 86.1%
+ 90.5%
diff --git a/docs/coverage_macos_aarch64.svg b/docs/coverage_macos_aarch64.svg
index efd1237..5371a6c 100644
--- a/docs/coverage_macos_aarch64.svg
+++ b/docs/coverage_macos_aarch64.svg
@@ -8,13 +8,13 @@
-
+
coverage
- 94.3%
+ 89.4%
diff --git a/docs/coverage_macos_x86_64.svg b/docs/coverage_macos_x86_64.svg
index efd1237..156293b 100644
--- a/docs/coverage_macos_x86_64.svg
+++ b/docs/coverage_macos_x86_64.svg
@@ -15,6 +15,6 @@
font-family="DejaVu Sans,Verdana,Geneva,sans-serif"
font-size="11">
coverage
- 94.3%
+ 90.5%
diff --git a/docs/coverage_windows_x86_64.svg b/docs/coverage_windows_x86_64.svg
index 0d26668..42ec6a0 100644
--- a/docs/coverage_windows_x86_64.svg
+++ b/docs/coverage_windows_x86_64.svg
@@ -8,13 +8,13 @@
-
+
coverage
- 87%
+ 96%
diff --git a/docs/streamline-plan.md b/docs/streamline-plan.md
new file mode 100644
index 0000000..ec875d1
--- /dev/null
+++ b/docs/streamline-plan.md
@@ -0,0 +1,96 @@
+# Streamlining Summary
+
+## Summary
+
+The coroutine-layer streamlining work is implemented across the C runtime, assembly backends, and toolchain selection files. YAFL now uses `yafl_switch(yafl_t *save, yafl_t target, void *data)` and `yafl_make_context()` internally, which removes `transfer_t`, removes `pending_arg`, and keeps the hot path at a save/restore plus direct data handoff.
+
+The public API in `include/yafl.h` stays unchanged. All of the streamlining work remains below that surface.
+
+## Status
+
+- `src/yafl.c` now uses direct `void *` handoff through `yafl_switch`.
+- Assembly sources and exported symbols are renamed to `switch_*` / `make_context_*` and `yafl_switch` / `yafl_make_context`.
+- Toolchain `ASM_FILES` lists point at the renamed files.
+- The host arm64 build and test suite pass after the refactor.
+
+## Implemented Design
+
+### Low-level switch primitive
+
+The internal switch ABI is now:
+
+`void *yafl_switch(yafl_t *save, yafl_t target, void *data)`
+
+- `*save` receives the current suspended context.
+- `target` is the context to resume.
+- `data` is delivered directly both as the resumed return value and as the first-entry argument.
+
+This removes the synthetic transport struct and the Windows-specific hidden struct-return plumbing that existed in the old backend model.
+
+### Initial context creation
+
+The initial saved context is created by:
+
+`yafl_t yafl_make_context(void *sp, size_t size, yafl_entry_t fn)`
+
+Each backend-specific `make_context_*` file prepares the initial stack/register image for a new fiber and installs the `finish:` fallback path that terminates the process if a fiber entry function unexpectedly returns through the raw frame.
+
+### C runtime changes
+
+- `yafl_transfer_t` is removed.
+- `pending_arg` is removed from `struct yafl_fiber`.
+- `fiber_entry_trampoline()` now receives the first resume argument directly and discovers the active fiber through TLS.
+- `yafl_fiber_resume()` and `yafl_fiber_suspend()` use direct `void *` handoff through `yafl_switch()`.
+- Fiber stack cleanup and watermark reinitialization are both routed through helpers so failure paths stay linear.
+
+### Assembly and naming changes
+
+- All internal switch-family files are renamed from `jump_*` to `switch_*`.
+- All initial-context files are renamed from `make_*` to `make_context_*`.
+- Exported assembly symbols are renamed from `jump_fcontext` / `make_fcontext` to `yafl_switch` / `yafl_make_context`.
+- Toolchain `ASM_FILES` lists in `toolchains/*.cmake` point at the renamed files.
+
+### Backend scope
+
+The direct-data `yafl_switch` model is implemented across the maintained backends in the tree, including x86_64, arm64, i386, arm, riscv64, loongarch64, mips32, mips64, ppc32, ppc64, s390x, and sparc64.
+
+The guiding backend rule is unchanged across architectures: save-via-pointer, restore-target-from-second-argument, and pass `data` directly.
+
+## Validation
+
+- Host arm64 library build succeeds.
+- Host tests pass: `test_yafl_basic`, `test_yafl_suspend_resume`, `test_yafl_guard`, `test_yafl_many`, and `test_yafl_watermark`.
+- Maintained sources no longer carry live `transfer_t`, `pending_arg`, `jump_fcontext`, or `make_fcontext` implementation references.
+- Non-host assembly validation is opportunistic and depends on the locally available target assemblers.
+
+## Remaining Follow-up
+
+- Keep generated coverage artifacts in sync with the source tree when coverage is regenerated.
+- Expand cross-target validation when additional target toolchains are available.
+
+## Decisions
+
+1. **Do not move the C trampoline into assembly**
+ - That would hardcode `struct yafl_fiber` offsets into every backend.
+ - The resulting code would be harder to audit and not meaningfully faster.
+
+2. **Do not collapse the initial-context primitive and the switch primitive into one assembly entry point**
+ - `yafl_switch` is the hot path.
+ - `yafl_make_context` runs only during fiber creation.
+ - Combining them would trade a tiny amount of source reduction for a branchier and less legible hot path.
+
+3. **Do not merge ELF and Mach-O assembly files even when they currently match**
+ - OS-level context requirements may diverge later, including support for wider architectural state such as AVX or other OS-managed register state.
+ - Keep separate per-OS source files so those changes can land without re-splitting shared assembly later.
+
+4. **Do not introduce runtime architecture dispatch to reduce file count**
+ - The current per-target selection in the toolchain files keeps the build explicit and predictable.
+ - Runtime selection would increase complexity without helping performance.
+
+## Relevant Files
+
+- `src/yafl.c` — current C runtime implementation of the streamlined switch semantics.
+- `include/yafl.h` — no public API changes are required.
+- `src/asm/*/switch_*` — backend switch-family sources implementing `yafl_switch`.
+- `src/asm/*/make_context_*` — backend entry-context sources implementing `yafl_make_context`.
+- `toolchains/*.cmake` — backend selection for the renamed assembly sources.
diff --git a/include/yafl.h b/include/yafl.h
index 1ed2097..28195c6 100644
--- a/include/yafl.h
+++ b/include/yafl.h
@@ -24,8 +24,8 @@ extern "C" {
* Configuration
* ======================================================================== */
-#ifndef FCONTEXT_DEFAULT_STACK_SIZE
- #define FCONTEXT_DEFAULT_STACK_SIZE (24 * 1024)
+#ifndef YAFL_DEFAULT_STACK_SIZE
+ #define YAFL_DEFAULT_STACK_SIZE (24 * 1024)
#endif
/* ========================================================================
@@ -77,8 +77,7 @@ typedef void *(*yafl_fiber_fn)(void *arg);
* - YAFL_STACK_FLAGS_WATERMARK is optional
* - YAFL_STACK_FLAGS_NONE (no flags) is invalid
*/
-extern yafl_fiber_t *yafl_fiber_create(yafl_fiber_fn fiber_fn, size_t stack_size,
- yafl_stack_flags_t flags);
+extern yafl_fiber_t *yafl_fiber_create(yafl_fiber_fn fiber_fn, size_t stack_size, yafl_stack_flags_t flags);
/* ========================================================================
diff --git a/scripts/generate_coverage.sh b/scripts/generate_coverage.sh
index f4a5634..17abd7b 100755
--- a/scripts/generate_coverage.sh
+++ b/scripts/generate_coverage.sh
@@ -54,7 +54,7 @@ lcov --capture --directory build --output-file coverage.info
echo
echo -e "${GREEN}Step 5: Filtering system files from coverage...${NC}"
-lcov --remove coverage.info '/usr/*' --output-file coverage.info
+lcov --remove coverage.info '/usr/*' --output-file coverage.info --ignore-errors unused
echo
echo -e "${GREEN}Step 6: Generating HTML report...${NC}"
diff --git a/scripts/make_coverage_badge.sh b/scripts/make_coverage_badge.sh
old mode 100644
new mode 100755
diff --git a/src/asm/README.md b/src/asm/README.md
index 5646ed6..6064360 100644
--- a/src/asm/README.md
+++ b/src/asm/README.md
@@ -4,49 +4,70 @@ This directory contains architecture-specific assembly code for context switchin
## File Organization
-```
+```text
asm/
-├── x86_64/ # 64-bit Intel/AMD
+├── arm/ # 32-bit ARM
├── arm64/ # 64-bit ARM (AArch64)
├── i386/ # 32-bit Intel
-└── arm/ # 32-bit ARM
+├── loongarch64/ # 64-bit LoongArch
+├── mips/ # 32-bit MIPS
+├── mips64/ # 64-bit MIPS N64 ABI
+├── ppc32/ # 32-bit PowerPC
+├── ppc64/ # 64-bit PowerPC
+├── riscv32/ # 32-bit RISC-V notes
+├── riscv64/ # 64-bit RISC-V
+├── s390x/ # IBM Z / s390x
+├── sparc64/ # 64-bit SPARC
+└── x86_64/ # 64-bit Intel/AMD
```
## File Naming Convention
-Each architecture has three types of functions:
+Each architecture has two low-level entry points:
-1. **make_*_*.S** - Create/initialize a context
+1. **make_context_*_*.S** - Create/initialize a context
- Sets up stack frame and instruction pointer
- Called once per new context
- - Maps to: `yafl_t make_yafl(void *sp, size_t size, yafl_fn_t fn)`
+ - Maps to: `yafl_t yafl_make_context(void *sp, size_t size, yafl_fn_t fn)`
-2. **jump_*_*.S** - Switch to a context
+2. **switch_*_*.S** - Switch to a context
- Saves current state, restores new context
- Called frequently (on every context switch)
- - Maps to: `yafl_transfer_t jump_yafl(yafl_t const to, void *vp)`
+ - Maps to: `void *yafl_switch(yafl_t *save, yafl_t target, void *data)`
## ABI and OS-Specific Suffixes
Filenames follow the pattern: `[function]_[arch]_[abi]_[os]_[asm].S`
### Architectures
+
- `x86_64` - Intel/AMD 64-bit
- `arm64` - ARM 64-bit (AArch64)
- `i386` - Intel/AMD 32-bit
- `arm` - ARM 32-bit
+- `loongarch64` - LoongArch 64-bit
+- `mips` - MIPS 32-bit O32 ABI
+- `mips64` - MIPS 64-bit N64 ABI
+- `ppc32` - PowerPC 32-bit SysV ABI
+- `ppc64` - PowerPC 64-bit SysV ABI
+- `riscv64` - RISC-V 64-bit SysV ABI
+- `s390x` - IBM Z / s390x SysV ABI
+- `sparc64` - SPARC V9 64-bit SysV ABI
### Application Binary Interface (ABI)
+
- `sysv` - System V ABI (Linux, BSD, older UNIX)
- `aapcs` - ARM EABI / ARM Architecture Procedure Call Standard (ARM systems)
- `ms` - Microsoft x64 ABI (Windows - not used in this project)
### Operating System / Format
+
- `elf` - ELF executable format (Linux)
- `macho` - Mach-O executable format (macOS)
- `xcoff` - XCOFF executable format (IBM PowerPC AIX - not in tier 1)
### Assembler
+
- `gas` - GNU Assembler syntax
- `masm` - Microsoft Assembler (MASM) syntax - not used in this project
- `armasm` - ARM Assembler syntax - not used in this project
@@ -56,21 +77,26 @@ Filenames follow the pattern: `[function]_[arch]_[abi]_[os]_[asm].S`
The build system automatically selects the correct files based on `uname -s` and `uname -m`:
### macOS (Darwin)
-- **arm64**: `*_arm64_aapcs_macho_gas.S`
-- **x86_64**: `*_x86_64_sysv_macho_gas.S`
-- **i386**: `*_i386_sysv_macho_gas.S`
-- **arm**: `*_arm_aapcs_macho_gas.S`
+
+- **arm64**: `make_context_arm64_aapcs_macho_gas.S`, `switch_arm64_aapcs_macho_gas.S`
+- **x86_64**: `make_context_x86_64_sysv_macho_gas.S`, `switch_x86_64_sysv_macho_gas.S`
+- **i386**: `make_context_i386_sysv_macho_gas.S`, `switch_i386_sysv_macho_gas.S`
+- **arm**: `make_context_arm_aapcs_macho_gas.S`, `switch_arm_aapcs_macho_gas.S`
### Linux
-- **x86_64**: `*_x86_64_sysv_elf_gas.S`
-- **aarch64**: `*_arm64_aapcs_elf_gas.S`
-- **i386**: `*_i386_sysv_elf_gas.S`
-- **armv7l**: `*_arm_aapcs_elf_gas.S`
+
+- **x86_64**: `make_context_x86_64_sysv_elf_gas.S`, `switch_x86_64_sysv_elf_gas.S`
+- **aarch64**: `make_context_arm64_aapcs_elf_gas.S`, `switch_arm64_aapcs_elf_gas.S`
+- **i386**: `make_context_i386_sysv_elf_gas.S`, `switch_i386_sysv_elf_gas.S`
+- **armv7l**: `make_context_arm_aapcs_elf_gas.S`, `switch_arm_aapcs_elf_gas.S`
+
+Additional Linux-targeted toolchain files in this repository select backend pairs for `mipsel`, `mips64el`, `powerpc`, `powerpc64le`, `riscv64`, `s390x`, and `sparc64`.
## Source and License
All files are extracted directly from Boost.Context repository:
-https://github.com/boostorg/context/tree/develop/src/asm
+
+
Each file retains its original Boost Software License 1.0 header:
@@ -86,23 +112,28 @@ Each file retains its original Boost Software License 1.0 header:
## How They Work (High Level)
-### make_* Functions
+### make_context_* Functions
+
Create a new execution context by:
+
1. Storing the stack pointer and context metadata
2. Setting up the instruction pointer to the entry function
3. Initializing CPU registers to safe values
4. Returning an opaque handle to the new context
-### jump_* Functions
+### switch_* Functions
+
Context switch by:
+
1. Saving all CPU registers to current stack
2. Restoring all CPU registers from target context's stack
3. Returning to execution at target context's saved instruction pointer
-4. The "return value" includes the previous context and user data
+4. Returning the caller-supplied `data` pointer directly while saving the previous context through the `save` pointer
### Calling Convention Details
-The entry function for a new context receives `yafl_transfer_t` in:
+The entry function for a new context receives the first resume argument directly in:
+
- **x86_64**: `rdi` register (System V ABI first argument)
- **arm64**: `x0` register (AAPCS first argument)
- **i386**: Stack parameter (32-bit calling convention)
@@ -111,9 +142,12 @@ The entry function for a new context receives `yafl_transfer_t` in:
## Testing and Validation
All assembly files are tested by:
+
1. `test_yafl_basic` - Basic context creation and switching
-2. `test_yafl_simple` - Simple entry point execution
-3. `test_yafl_transfer` - Data passing through context switches
+2. `test_yafl_suspend_resume` - Suspend/resume handoff behavior
+3. `test_yafl_guard` - Guard-page stack protection
+4. `test_yafl_many` - Repeated fiber creation and switching
+5. `test_yafl_watermark` - Watermark-based stack usage tracking
Tests are compiled with the selected architecture's assembly files and run on the target platform.
@@ -123,16 +157,21 @@ To add a new architecture (e.g., RISC-V):
1. Create new subdirectory: `riscv64/`
2. Copy assembly files from Boost.Context:
- - `make_riscv64_sysv_elf_gas.S`
- - `jump_riscv64_sysv_elf_gas.S`
+ - `make_context_riscv64_sysv_elf_gas.S`
+ - `switch_riscv64_sysv_elf_gas.S`
3. Update `Makefile` to detect the new architecture
4. Update `CMakeLists.txt` similarly
5. Test on actual hardware or in emulation
+## Current Repository Notes
+
+- `riscv32/` currently contains notes only and is not selected by any checked-in toolchain file.
+- Several backend directories beyond the host architecture are maintained primarily through assembly syntax checks and cross-target builds when the corresponding toolchains are available.
+
## References
-- **Boost.Context Source**: https://github.com/boostorg/context
-- **System V ABI**: https://software.intel.com/en-us/sites/default/files/article/2016-08/x86-64-abi-0.99.pdf
-- **ARM EABI**: https://github.com/ARM-software/abi-aa
-- **ELF Format**: https://refspecs.linuxbase.org/elf/elf.pdf
-- **Mach-O Format**: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/MachORuntime/
+- **Boost.Context Source**:
+- **System V ABI**:
+- **ARM EABI**:
+- **ELF Format**:
+- **Mach-O Format**:
diff --git a/src/asm/arm/make_arm_aapcs_elf_gas.S b/src/asm/arm/make_context_arm_aapcs_elf_gas.S
similarity index 90%
rename from src/asm/arm/make_arm_aapcs_elf_gas.S
rename to src/asm/arm/make_context_arm_aapcs_elf_gas.S
index 9616e56..f9993db 100644
--- a/src/asm/arm/make_arm_aapcs_elf_gas.S
+++ b/src/asm/arm/make_context_arm_aapcs_elf_gas.S
@@ -40,26 +40,21 @@
.file "make_arm_aapcs_elf_gas.S"
.text
-.globl make_fcontext
-.hidden make_fcontext
+.globl yafl_make_context
+.hidden yafl_make_context
.align 2
-.type make_fcontext,%function
+.type yafl_make_context,%function
.syntax unified
-make_fcontext:
+yafl_make_context:
@ shift address in A1 to lower 16 byte boundary
bic a1, a1, #15
@ reserve space for context-data on context-stack
sub a1, a1, #124
- @ third arg of make_fcontext() == address of context-function
+ @ third arg of yafl_make_context() == address of context-function
str a3, [a1, #104]
- @ compute address of returned transfer_t
- add a2, a1, #108
- mov a3, a2
- str a3, [a1, #64]
-
@ compute abs address of label finish
adr a2, finish
@ save address of finish as return-address for context-function
@@ -76,7 +71,7 @@ finish:
mov a1, #0
@ exit application
bl _exit@PLT
-.size make_fcontext,.-make_fcontext
+.size yafl_make_context,.-yafl_make_context
@ Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/arm/make_arm_aapcs_macho_gas.S b/src/asm/arm/make_context_arm_aapcs_macho_gas.S
similarity index 91%
rename from src/asm/arm/make_arm_aapcs_macho_gas.S
rename to src/asm/arm/make_context_arm_aapcs_macho_gas.S
index de93407..ef71cc7 100644
--- a/src/asm/arm/make_arm_aapcs_macho_gas.S
+++ b/src/asm/arm/make_context_arm_aapcs_macho_gas.S
@@ -39,24 +39,19 @@
*******************************************************/
.text
-.private_extern _make_fcontext
-.globl _make_fcontext
+.private_extern _yafl_make_context
+.globl _yafl_make_context
.align 2
-_make_fcontext:
+_yafl_make_context:
@ shift address in A1 to lower 16 byte boundary
bic a1, a1, #15
@ reserve space for context-data on context-stack
sub a1, a1, #124
- @ third arg of make_fcontext() == address of context-function
+ @ third arg of yafl_make_context() == address of context-function
str a3, [a1, #108]
- @ compute address of returned transfer_t
- add a2, a1, #112
- mov a3, a2
- str a3, [a1, #68]
-
@ compute abs address of label finish
adr a2, finish
@ save address of finish as return-address for context-function
diff --git a/src/asm/arm/jump_arm_aapcs_elf_gas.S b/src/asm/arm/switch_arm_aapcs_elf_gas.S
similarity index 84%
rename from src/asm/arm/jump_arm_aapcs_elf_gas.S
rename to src/asm/arm/switch_arm_aapcs_elf_gas.S
index 9934c08..f449b17 100644
--- a/src/asm/arm/jump_arm_aapcs_elf_gas.S
+++ b/src/asm/arm/switch_arm_aapcs_elf_gas.S
@@ -40,15 +40,15 @@
.file "jump_arm_aapcs_elf_gas.S"
.text
-.globl jump_fcontext
-.hidden jump_fcontext
+.globl yafl_switch
+.hidden yafl_switch
.align 2
-.type jump_fcontext,%function
+.type yafl_switch,%function
.syntax unified
-jump_fcontext:
+yafl_switch:
@ save LR as PC
push {lr}
- @ save hidden,V1-V8,LR
+ @ save V1-V8,LR and preserve layout slot for the old hidden pointer
push {a1,v1-v8,lr}
@ prepare stack for FPU
@@ -58,10 +58,10 @@ jump_fcontext:
vstmia sp, {d8-d15}
#endif
- @ store RSP (pointing to context-data) in A1
- mov a1, sp
+ @ save current context through the first argument pointer
+ str sp, [a1]
- @ restore RSP (pointing to context-data) from A2
+ @ restore target context from the second argument
mov sp, a2
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
@@ -71,19 +71,15 @@ jump_fcontext:
@ prepare stack for FPU
add sp, sp, #64
- @ restore hidden,V1-V8,LR
+ @ restore V1-V8,LR
pop {a4,v1-v8,lr}
- @ return transfer_t from jump
- str a1, [a4, #0]
- str a3, [a4, #4]
- @ pass transfer_t as first arg in context function
- @ A1 == FCTX, A2 == DATA
- mov a2, a3
+ @ return and pass data directly
+ mov a1, a3
@ restore PC
pop {pc}
-.size jump_fcontext,.-jump_fcontext
+.size yafl_switch,.-yafl_switch
@ Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/arm/jump_arm_aapcs_macho_gas.S b/src/asm/arm/switch_arm_aapcs_macho_gas.S
similarity index 86%
rename from src/asm/arm/jump_arm_aapcs_macho_gas.S
rename to src/asm/arm/switch_arm_aapcs_macho_gas.S
index 44e7f2a..5ee3456 100644
--- a/src/asm/arm/jump_arm_aapcs_macho_gas.S
+++ b/src/asm/arm/switch_arm_aapcs_macho_gas.S
@@ -39,13 +39,13 @@
*******************************************************/
.text
-.private_extern _jump_fcontext
-.globl _jump_fcontext
+.private_extern _yafl_switch
+.globl _yafl_switch
.align 2
-_jump_fcontext:
+_yafl_switch:
@ save LR as PC
push {lr}
- @ save hidden,V1-V8,LR
+ @ save V1-V8,LR and preserve layout slot for the old hidden pointer
push {a1,v1-v8,lr}
@ locate TLS to save/restore SjLj handler
@@ -64,10 +64,10 @@ _jump_fcontext:
vstmia sp, {d8-d15}
#endif
- @ store RSP (pointing to context-data) in A1
- mov a1, sp
+ @ save current context through the first argument pointer
+ str sp, [a1]
- @ restore RSP (pointing to context-data) from A2
+ @ restore target context from the second argument
mov sp, a2
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
@@ -82,15 +82,11 @@ _jump_fcontext:
@ store SjLj handler in TLS
str v1, [v2, #72]
- @ restore hidden,V1-V8,LR
+ @ restore V1-V8,LR
pop {a4,v1-v8,lr}
- @ return transfer_t from jump
- str a1, [a4, #0]
- str a3, [a4, #4]
- @ pass transfer_t as first arg in context function
- @ A1 == FCTX, A2 == DATA
- mov a2, a3
+ @ return and pass data directly
+ mov a1, a3
@ restore PC
pop {pc}
diff --git a/src/asm/arm64/make_arm64_aapcs_elf_gas.S b/src/asm/arm64/make_context_arm64_aapcs_elf_gas.S
similarity index 95%
rename from src/asm/arm64/make_arm64_aapcs_elf_gas.S
rename to src/asm/arm64/make_context_arm64_aapcs_elf_gas.S
index 2465254..335247f 100644
--- a/src/asm/arm64/make_arm64_aapcs_elf_gas.S
+++ b/src/asm/arm64/make_context_arm64_aapcs_elf_gas.S
@@ -69,10 +69,10 @@
.popsection
#endif
.align 2
-.global make_fcontext
-.hidden make_fcontext
-.type make_fcontext, %function
-make_fcontext:
+.global yafl_make_context
+.hidden yafl_make_context
+.type yafl_make_context, %function
+yafl_make_context:
#if defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT == 1)
hint #34 /* bti c */
#endif
@@ -82,7 +82,7 @@ make_fcontext:
# reserve space for context-data on context-stack
sub x0, x0, #0xb0
- # third arg of make_fcontext() == address of context-function
+ # third arg of yafl_make_context() == address of context-function
# store address as a PC to jump in
str x2, [x0, #0xa0]
@@ -99,6 +99,6 @@ finish:
# exit application
bl _exit
-.size make_fcontext,.-make_fcontext
+.size yafl_make_context,.-yafl_make_context
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/arm64/make_arm64_aapcs_macho_gas.S b/src/asm/arm64/make_context_arm64_aapcs_macho_gas.S
similarity index 95%
rename from src/asm/arm64/make_arm64_aapcs_macho_gas.S
rename to src/asm/arm64/make_context_arm64_aapcs_macho_gas.S
index a6a1314..e6c5db9 100644
--- a/src/asm/arm64/make_arm64_aapcs_macho_gas.S
+++ b/src/asm/arm64/make_context_arm64_aapcs_macho_gas.S
@@ -52,18 +52,18 @@
*******************************************************/
.text
-.private_extern _make_fcontext
-.globl _make_fcontext
+.private_extern _yafl_make_context
+.globl _yafl_make_context
.balign 16
-_make_fcontext:
+_yafl_make_context:
; shift address in x0 (allocated stack) to lower 16 byte boundary
and x0, x0, ~0xF
; reserve space for context-data on context-stack
sub x0, x0, #0xb0
- ; third arg of make_fcontext() == address of context-function
+ ; third arg of yafl_make_context() == address of context-function
; store address as a PC to jump in
str x2, [x0, #0xa0]
diff --git a/src/asm/arm64/make_arm64_aapcs_pe_armasm.asm b/src/asm/arm64/make_context_arm64_aapcs_pe_armasm.asm
similarity index 97%
rename from src/asm/arm64/make_arm64_aapcs_pe_armasm.asm
rename to src/asm/arm64/make_context_arm64_aapcs_pe_armasm.asm
index c384af0..232bdd7 100644
--- a/src/asm/arm64/make_arm64_aapcs_pe_armasm.asm
+++ b/src/asm/arm64/make_context_arm64_aapcs_pe_armasm.asm
@@ -58,10 +58,10 @@
;*******************************************************
AREA |.text|, CODE, READONLY, ALIGN=4, CODEALIGN
- EXPORT make_fcontext
+ EXPORT yafl_make_context
IMPORT _exit
-make_fcontext proc
+yafl_make_context proc
; save stack top address to x3
mov x3, x0
@@ -79,7 +79,7 @@ make_fcontext proc
; save 0 as 'fiber data'
str xzr, [x0, #0xb8]
- ; third arg of make_fcontext() == address of context-function
+ ; third arg of yafl_make_context() == address of context-function
; store address as x19 for trampoline
str x2, [x0, #0x40]
; store trampoline address as pc
diff --git a/src/asm/arm64/make_arm64_aapcs_pe_armclang.S b/src/asm/arm64/make_context_arm64_aapcs_pe_armclang.S
similarity index 95%
rename from src/asm/arm64/make_arm64_aapcs_pe_armclang.S
rename to src/asm/arm64/make_context_arm64_aapcs_pe_armclang.S
index 761092f..105cccb 100644
--- a/src/asm/arm64/make_arm64_aapcs_pe_armclang.S
+++ b/src/asm/arm64/make_context_arm64_aapcs_pe_armclang.S
@@ -63,10 +63,10 @@
.text
.balign 4
-.globl make_fcontext
-.def make_fcontext; .scl 2; .type 32; .endef
-.seh_proc make_fcontext
-make_fcontext:
+.globl yafl_make_context
+.def yafl_make_context; .scl 2; .type 32; .endef
+.seh_proc yafl_make_context
+yafl_make_context:
.seh_endprologue
// save stack top address to x3
mov x3, x0
@@ -85,7 +85,7 @@ make_fcontext:
// save 0 as 'fiber data'
str xzr, [x0, #0xb8]
- // third arg of make_fcontext() == address of context-function
+ // third arg of yafl_make_context() == address of context-function
// store address as x19 for trampoline
str x2, [x0, #0x40]
// store trampoline address as pc
@@ -115,4 +115,4 @@ finish:
.def _exit; .scl 2; .type 32; .endef /* standard C library function */
.section .drectve
-.ascii " -export:\"make_fcontext\""
+.ascii " -export:\"yafl_make_context\""
diff --git a/src/asm/arm64/jump_arm64_aapcs_elf_gas.S b/src/asm/arm64/switch_arm64_aapcs_elf_gas.S
similarity index 92%
rename from src/asm/arm64/jump_arm64_aapcs_elf_gas.S
rename to src/asm/arm64/switch_arm64_aapcs_elf_gas.S
index b8abb2e..f2cfd01 100644
--- a/src/asm/arm64/jump_arm64_aapcs_elf_gas.S
+++ b/src/asm/arm64/switch_arm64_aapcs_elf_gas.S
@@ -69,10 +69,10 @@
.popsection
#endif
.align 2
-.global jump_fcontext
-.hidden jump_fcontext
-.type jump_fcontext, %function
-jump_fcontext:
+.global yafl_switch
+.hidden yafl_switch
+.type yafl_switch, %function
+yafl_switch:
#if defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT == 1)
hint #34 /* bti c: valid indirect-entry target */
#endif
@@ -96,11 +96,13 @@ jump_fcontext:
# save LR as PC
str x30, [sp, #0xa0]
- # store RSP (pointing to context-data) in X0
- mov x4, sp
+ # save current context through the first argument pointer
+ mov x4, x2
+ mov x5, sp
+ str x5, [x0]
- # restore RSP (pointing to context-data) from X1
- mov sp, x0
+ # restore target context from the second argument
+ mov sp, x1
# load d8 - d15
ldp d8, d9, [sp, #0x00]
@@ -116,9 +118,7 @@ jump_fcontext:
ldp x27, x28, [sp, #0x80]
ldp x29, x30, [sp, #0x90]
- # return transfer_t from jump
- # pass transfer_t as first arg in context function
- # X0 == FCTX, X1 == DATA
+ # return and pass data directly
mov x0, x4
# load pc
@@ -128,6 +128,6 @@ jump_fcontext:
add sp, sp, #0xb0
ret x4
-.size jump_fcontext,.-jump_fcontext
+.size yafl_switch,.-yafl_switch
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/arm64/jump_arm64_aapcs_macho_gas.S b/src/asm/arm64/switch_arm64_aapcs_macho_gas.S
similarity index 92%
rename from src/asm/arm64/jump_arm64_aapcs_macho_gas.S
rename to src/asm/arm64/switch_arm64_aapcs_macho_gas.S
index 12cc021..eef7d50 100644
--- a/src/asm/arm64/jump_arm64_aapcs_macho_gas.S
+++ b/src/asm/arm64/switch_arm64_aapcs_macho_gas.S
@@ -52,10 +52,10 @@
*******************************************************/
.text
-.private_extern _jump_fcontext
-.globl _jump_fcontext
+.private_extern _yafl_switch
+.globl _yafl_switch
.balign 16
-_jump_fcontext:
+_yafl_switch:
; prepare stack for GP + FPU
sub sp, sp, #0xb0
@@ -76,11 +76,12 @@ _jump_fcontext:
; save LR as PC
str lr, [sp, #0xa0]
- ; store RSP (pointing to context-data) in X0
+ ; save current SP (pointing to context-data) through X0
mov x4, sp
+ str x4, [x0]
- ; restore RSP (pointing to context-data) from X1
- mov sp, x0
+ ; restore SP (pointing to context-data) from X1
+ mov sp, x1
; load d8 - d15
ldp d8, d9, [sp, #0x00]
@@ -96,10 +97,8 @@ _jump_fcontext:
ldp x27, x28, [sp, #0x80]
ldp fp, lr, [sp, #0x90]
- ; return transfer_t from jump
- ; pass transfer_t as first arg in context function
- ; X0 == FCTX, X1 == DATA
- mov x0, x4
+ ; return data as the resumed function result and first argument
+ mov x0, x2
; load pc
ldr x4, [sp, #0xa0]
diff --git a/src/asm/arm64/jump_arm64_aapcs_pe_armasm.asm b/src/asm/arm64/switch_arm64_aapcs_pe_armasm.asm
similarity index 94%
rename from src/asm/arm64/jump_arm64_aapcs_pe_armasm.asm
rename to src/asm/arm64/switch_arm64_aapcs_pe_armasm.asm
index afb6d2b..f1b058c 100644
--- a/src/asm/arm64/jump_arm64_aapcs_pe_armasm.asm
+++ b/src/asm/arm64/switch_arm64_aapcs_pe_armasm.asm
@@ -58,9 +58,9 @@
;*******************************************************
AREA |.text|, CODE, READONLY, ALIGN=4, CODEALIGN
- EXPORT jump_fcontext
+ EXPORT yafl_switch
-jump_fcontext proc
+yafl_switch proc
; prepare stack for GP + FPU
sub sp, sp, #0xd0
@@ -89,11 +89,13 @@ jump_fcontext proc
ldr x6, [x18, #0x20] ; TeFiberData at ksarm64.h
stp x5, x6, [sp, #0xb0]
- ; store RSP (pointing to context-data) in X0
- mov x4, sp
+ ; save current context through the first argument pointer
+ mov x4, x2
+ mov x7, sp
+ str x7, [x0]
- ; restore RSP (pointing to context-data) from X1
- mov sp, x0
+ ; restore target context from the second argument
+ mov sp, x1
; restore stack base and limit
ldp x5, x6, [sp, #0xa0]
@@ -117,9 +119,7 @@ jump_fcontext proc
ldp x27, x28, [sp, #0x80]
ldp x29, x30, [sp, #0x90]
- ; return transfer_t from jump
- ; pass transfer_t as first arg in context function
- ; X0 == FCTX, X1 == DATA
+ ; return and pass data directly
mov x0, x4
; load pc
diff --git a/src/asm/arm64/jump_arm64_aapcs_pe_armclang.S b/src/asm/arm64/switch_arm64_aapcs_pe_armclang.S
similarity index 92%
rename from src/asm/arm64/jump_arm64_aapcs_pe_armclang.S
rename to src/asm/arm64/switch_arm64_aapcs_pe_armclang.S
index 3a62562..8cb5134 100644
--- a/src/asm/arm64/jump_arm64_aapcs_pe_armclang.S
+++ b/src/asm/arm64/switch_arm64_aapcs_pe_armclang.S
@@ -63,9 +63,9 @@
.text
.balign 4
-.def jump_fcontext; .scl 2; .type 32; .endef
-.seh_proc jump_fcontext
-jump_fcontext:
+.def yafl_switch; .scl 2; .type 32; .endef
+.seh_proc yafl_switch
+yafl_switch:
.seh_endprologue
// prepare stack for GP + FPU
sub sp, sp, #0xd0
@@ -95,11 +95,13 @@ jump_fcontext:
ldr x6, [x18, #0x20] // TeFiberData at ksarm64.h
stp x5, x6, [sp, #0xb0]
- // store RSP (pointing to context-data) in X0
- mov x4, sp
+ // save current context through the first argument pointer
+ mov x4, x2
+ mov x7, sp
+ str x7, [x0]
- // restore RSP (pointing to context-data) from X1
- mov sp, x0
+ // restore target context from the second argument
+ mov sp, x1
// restore stack base and limit
ldp x5, x6, [sp, #0xa0]
@@ -123,9 +125,7 @@ jump_fcontext:
ldp x27, x28, [sp, #0x80]
ldp x29, x30, [sp, #0x90]
- // return transfer_t from jump
- // pass transfer_t as first arg in context function
- // X0 == FCTX, X1 == DATA
+ // return and pass data directly
mov x0, x4
// load pc
@@ -138,4 +138,4 @@ jump_fcontext:
.seh_endproc
.section .drectve
-.ascii " -export:\"jump_fcontext\""
+.ascii " -export:\"yafl_switch\""
diff --git a/src/asm/i386/make_i386_sysv_elf_gas.S b/src/asm/i386/make_context_i386_sysv_elf_gas.S
similarity index 86%
rename from src/asm/i386/make_i386_sysv_elf_gas.S
rename to src/asm/i386/make_context_i386_sysv_elf_gas.S
index 56c3bdc..430cf93 100644
--- a/src/asm/i386/make_i386_sysv_elf_gas.S
+++ b/src/asm/i386/make_context_i386_sysv_elf_gas.S
@@ -26,12 +26,12 @@
.file "make_i386_sysv_elf_gas.S"
.text
-.globl make_fcontext
-.hidden make_fcontext
+.globl yafl_make_context
+.hidden yafl_make_context
.align 2
-.type make_fcontext,@function
-make_fcontext:
- /* first arg of make_fcontext() == top of context-stack */
+.type yafl_make_context,@function
+yafl_make_context:
+ /* first arg of yafl_make_context() == top of context-stack */
movl 0x4(%esp), %eax
/* reserve space for first argument of context-function
@@ -42,9 +42,9 @@ make_fcontext:
andl $-16, %eax
/* reserve space for context-data on context-stack, and align the stack */
- leal -0x34(%eax), %eax
+ leal -0x30(%eax), %eax
- /* third arg of make_fcontext() == address of context-function */
+ /* third arg of yafl_make_context() == address of context-function */
/* stored in EBX */
movl 0xc(%esp), %ecx
movl %ecx, 0x14(%eax)
@@ -60,11 +60,6 @@ make_fcontext:
movl %ecx, 0x8(%eax) /* save stack guard */
#endif
- /* return transport_t */
- /* FCTX == EDI, DATA == ESI */
- leal 0xc(%eax), %ecx
- movl %ecx, 0x20(%eax)
-
/* compute abs address of label trampoline */
call 1f
/* address of trampoline 1 */
@@ -72,7 +67,7 @@ make_fcontext:
/* compute abs address of label trampoline */
addl $trampoline-1b, %ecx
/* save address of trampoline as return address */
- /* will be entered after calling jump_fcontext() first time */
+ /* will be entered after calling yafl_switch() first time */
movl %ecx, 0x1c(%eax)
/* compute abs address of label finish */
@@ -88,9 +83,8 @@ make_fcontext:
ret /* return pointer to context-data */
trampoline:
- /* move transport_t for entering context-function */
- movl %edi, (%esp)
- movl %esi, 0x4(%esp)
+ /* move the first-entry argument into the reserved stack slot */
+ movl %eax, (%esp)
pushl %ebp
/* jump to context-function */
jmp *%ebx
@@ -108,7 +102,7 @@ finish:
/* exit application */
call _exit@PLT
hlt
-.size make_fcontext,.-make_fcontext
+.size yafl_make_context,.-yafl_make_context
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/i386/make_i386_sysv_macho_gas.S b/src/asm/i386/make_context_i386_sysv_macho_gas.S
similarity index 90%
rename from src/asm/i386/make_i386_sysv_macho_gas.S
rename to src/asm/i386/make_context_i386_sysv_macho_gas.S
index 0107612..b3e4fd8 100644
--- a/src/asm/i386/make_i386_sysv_macho_gas.S
+++ b/src/asm/i386/make_context_i386_sysv_macho_gas.S
@@ -25,11 +25,11 @@
****************************************************************************************/
.text
-.private_extern _make_fcontext
-.globl _make_fcontext
+.private_extern _yafl_make_context
+.globl _yafl_make_context
.align 2
-_make_fcontext:
- /* first arg of make_fcontext() == top of context-stack */
+_yafl_make_context:
+ /* first arg of yafl_make_context() == top of context-stack */
movl 0x4(%esp), %eax
/* reserve space for first argument of context-function
@@ -42,7 +42,7 @@ _make_fcontext:
/* reserve space for context-data on context-stack, and align the stack */
leal -0x34(%eax), %eax
- /* third arg of make_fcontext() == address of context-function */
+ /* third arg of yafl_make_context() == address of context-function */
/* stored in EBX */
movl 0xc(%esp), %ecx
movl %ecx, 0x10(%eax)
@@ -59,7 +59,7 @@ _make_fcontext:
/* compute abs address of label trampoline */
addl $trampoline-1b, %ecx
/* save address of trampoline as return address */
- /* will be entered after calling jump_fcontext() first time */
+ /* will be entered after calling yafl_switch() first time */
movl %ecx, 0x18(%eax)
/* compute abs address of label finish */
@@ -75,9 +75,8 @@ _make_fcontext:
ret /* return pointer to context-data */
trampoline:
- /* move transport_t for entering context-function */
+ /* move the first-entry argument into the reserved stack slot */
movl %eax, (%esp)
- movl %edx, 0x4(%esp)
pushl %ebp
/* jump to context-function */
jmp *%ebx
diff --git a/src/asm/i386/jump_i386_sysv_elf_gas.S b/src/asm/i386/switch_i386_sysv_elf_gas.S
similarity index 85%
rename from src/asm/i386/jump_i386_sysv_elf_gas.S
rename to src/asm/i386/switch_i386_sysv_elf_gas.S
index 727d661..28a412e 100644
--- a/src/asm/i386/jump_i386_sysv_elf_gas.S
+++ b/src/asm/i386/switch_i386_sysv_elf_gas.S
@@ -26,11 +26,11 @@
.file "jump_i386_sysv_elf_gas.S"
.text
-.globl jump_fcontext
-.hidden jump_fcontext
+.globl yafl_switch
+.hidden yafl_switch
.align 2
-.type jump_fcontext,@function
-jump_fcontext:
+.type yafl_switch,@function
+yafl_switch:
leal -0x1c(%esp), %esp /* prepare stack */
#if !defined(BOOST_USE_TSX)
@@ -48,25 +48,18 @@ jump_fcontext:
movl %ebx, 0x14(%esp) /* save EBX */
movl %ebp, 0x18(%esp) /* save EBP */
- /* store ESP (pointing to context-data) in ECX */
+ /* save current context through the first argument pointer */
movl %esp, %ecx
+ movl 0x20(%esp), %eax
+ movl %ecx, (%eax)
- /* first arg of jump_fcontext() == fcontext to jump to */
+ /* target context and switch data */
movl 0x24(%esp), %eax
-
- /* second arg of jump_fcontext() == data to be transferred */
movl 0x28(%esp), %edx
- /* restore ESP (pointing to context-data) from EAX */
+ /* restore ESP (pointing to context-data) from target */
movl %eax, %esp
- /* address of returned transport_t */
- movl 0x20(%esp), %eax
- /* return parent fcontext_t */
- movl %ecx, (%eax)
- /* return data */
- movl %edx, 0x4(%eax)
-
movl 0x1c(%esp), %ecx /* restore EIP */
#if !defined(BOOST_USE_TSX)
@@ -84,11 +77,14 @@ jump_fcontext:
movl 0x14(%esp), %ebx /* restore EBX */
movl 0x18(%esp), %ebp /* restore EBP */
- leal 0x24(%esp), %esp /* prepare stack */
+ leal 0x20(%esp), %esp /* prepare stack for direct data return */
+
+ /* return and pass data directly */
+ movl %edx, %eax
/* jump to context */
jmp *%ecx
-.size jump_fcontext,.-jump_fcontext
+.size yafl_switch,.-yafl_switch
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/i386/jump_i386_sysv_macho_gas.S b/src/asm/i386/switch_i386_sysv_macho_gas.S
similarity index 86%
rename from src/asm/i386/jump_i386_sysv_macho_gas.S
rename to src/asm/i386/switch_i386_sysv_macho_gas.S
index 4cae325..9a19c90 100644
--- a/src/asm/i386/jump_i386_sysv_macho_gas.S
+++ b/src/asm/i386/switch_i386_sysv_macho_gas.S
@@ -25,10 +25,10 @@
****************************************************************************************/
.text
-.private_extern _jump_fcontext
-.globl _jump_fcontext
+.private_extern _yafl_switch
+.globl _yafl_switch
.align 2
-_jump_fcontext:
+_yafl_switch:
leal -0x18(%esp), %esp /* prepare stack */
#if !defined(BOOST_USE_TSX)
@@ -41,22 +41,18 @@ _jump_fcontext:
movl %ebx, 0x10(%esp) /* save EBX */
movl %ebp, 0x14(%esp) /* save EBP */
- /* store ESP (pointing to context-data) in ECX */
+ /* save current context through the first argument pointer */
movl %esp, %ecx
-
- /* first arg of jump_fcontext() == fcontext to jump to */
movl 0x1c(%esp), %eax
+ movl %ecx, (%eax)
- /* second arg of jump_fcontext() == data to be transferred */
- movl 0x20(%esp), %edx
+ /* target context and switch data */
+ movl 0x20(%esp), %eax
+ movl 0x24(%esp), %edx
- /* restore ESP (pointing to context-data) from EAX */
+ /* restore ESP (pointing to context-data) from target */
movl %eax, %esp
- /* return parent fcontext_t */
- movl %ecx, %eax
- /* returned data is stored in EDX */
-
movl 0x18(%esp), %ecx /* restore EIP */
#if !defined(BOOST_USE_TSX)
@@ -71,5 +67,8 @@ _jump_fcontext:
leal 0x1c(%esp), %esp /* prepare stack */
+ /* return and pass data directly */
+ movl %edx, %eax
+
/* jump to context */
jmp *%ecx
diff --git a/src/asm/loongarch64/make_loongarch64_sysv_elf_gas.S b/src/asm/loongarch64/make_context_loongarch64_sysv_elf_gas.S
similarity index 92%
rename from src/asm/loongarch64/make_loongarch64_sysv_elf_gas.S
rename to src/asm/loongarch64/make_context_loongarch64_sysv_elf_gas.S
index a067bad..98a5f9e 100644
--- a/src/asm/loongarch64/make_loongarch64_sysv_elf_gas.S
+++ b/src/asm/loongarch64/make_context_loongarch64_sysv_elf_gas.S
@@ -40,18 +40,18 @@
.file "make_loongarch64_sysv_elf_gas.S"
.text
-.globl make_fcontext
-.hidden make_fcontext
+.globl yafl_make_context
+.hidden yafl_make_context
.align 2
-.type make_fcontext,@function
-make_fcontext:
+.type yafl_make_context,@function
+yafl_make_context:
# shift address in A0 to lower 16 byte boundary
bstrins.d $a0, $zero, 3, 0
# reserve space for context-data on context-stack
addi.d $a0, $a0, -160
- # third arg of make_fcontext() == address of context-function
+ # third arg of yafl_make_context() == address of context-function
st.d $a2, $a0, 152
# save address of finish as return-address for context-function
@@ -68,6 +68,6 @@ finish:
# call _exit(0)
b %plt(_exit)
-.size make_fcontext, .-make_fcontext
+.size yafl_make_context, .-yafl_make_context
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/loongarch64/jump_loongarch64_sysv_elf_gas.S b/src/asm/loongarch64/switch_loongarch64_sysv_elf_gas.S
similarity index 89%
rename from src/asm/loongarch64/jump_loongarch64_sysv_elf_gas.S
rename to src/asm/loongarch64/switch_loongarch64_sysv_elf_gas.S
index 6f99e71..7ec0f62 100644
--- a/src/asm/loongarch64/jump_loongarch64_sysv_elf_gas.S
+++ b/src/asm/loongarch64/switch_loongarch64_sysv_elf_gas.S
@@ -40,11 +40,11 @@
.file "jump_loongarch64_sysv_elf_gas.S"
.text
-.globl jump_fcontext
-.hidden jump_fcontext
+.globl yafl_switch
+.hidden yafl_switch
.align 2
-.type jump_fcontext,@function
-jump_fcontext:
+.type yafl_switch,@function
+yafl_switch:
# reserve space on stack
addi.d $sp, $sp, -160
@@ -74,11 +74,12 @@ jump_fcontext:
# save RA as PC
st.d $ra, $sp, 152
- # store SP (pointing to context-data) in A2
- move $a2, $sp
+ # save current context through the first argument pointer
+ move $a3, $a2
+ st.d $sp, $a0, 0
- # restore SP (pointing to context-data) from A0
- move $sp, $a0
+ # restore target context from the second argument
+ move $sp, $a1
# load fs0 - fs7
fld.d $fs0, $sp, 0
@@ -103,10 +104,8 @@ jump_fcontext:
ld.d $fp, $sp, 136
ld.d $ra, $sp, 144
- # return transfer_t from jump
- # pass transfer_t as first arg in context function
- # a0 == FCTX, a1 == DATA
- move $a0, $a2
+ # return and pass data directly
+ move $a0, $a3
# load PC
ld.d $a2, $sp, 152
@@ -116,7 +115,7 @@ jump_fcontext:
# jump to context
jr $a2
-.size jump_fcontext, .-jump_fcontext
+.size yafl_switch, .-yafl_switch
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/mips/make_mips32_o32_elf_gas.S b/src/asm/mips/make_context_mips32_o32_elf_gas.S
similarity index 85%
rename from src/asm/mips/make_mips32_o32_elf_gas.S
rename to src/asm/mips/make_context_mips32_o32_elf_gas.S
index 54742f3..cdb9757 100644
--- a/src/asm/mips/make_mips32_o32_elf_gas.S
+++ b/src/asm/mips/make_context_mips32_o32_elf_gas.S
@@ -40,12 +40,12 @@
.file "make_mips32_o32_elf_gas.S"
.text
-.globl make_fcontext
-.hidden make_fcontext
+.globl yafl_make_context
+.hidden yafl_make_context
.align 2
-.type make_fcontext,@function
-.ent make_fcontext
-make_fcontext:
+.type yafl_make_context,@function
+.ent yafl_make_context
+yafl_make_context:
#ifdef __PIC__
.set noreorder
.cpload $t9
@@ -57,22 +57,16 @@ make_fcontext:
# reserve space for context-data on context-stack
# includes an extra 32 bytes for:
- # - 16-byte incoming argument area required by mips ABI used when
- # jump_context calls the initial function
+ # - 16-byte incoming argument area required by the MIPS ABI on first entry
# - 4 bytes to save our GP register used in finish
- # - 8 bytes to as space for transfer_t returned to finish
- # - 4 bytes for alignment
+ # - 12 bytes of reserved scratch/alignment space retained with the original frame layout
addiu $v0, $v0, -128
- # third arg of make_fcontext() == address of context-function
+ # third arg of yafl_make_context() == address of context-function
sw $a2, 92($v0)
# save global pointer in context-data
sw $gp, 112($v0)
- # compute address of returned transfer_t
- addiu $t0, $v0, 116
- sw $t0, 84($v0)
-
# compute abs address of label finish
la $t9, finish
# save address of finish as return-address for context-function
@@ -91,8 +85,8 @@ finish:
la $t9, _exit
move $a0, $zero
jr $t9
-.end make_fcontext
-.size make_fcontext, .-make_fcontext
+.end yafl_make_context
+.size yafl_make_context, .-yafl_make_context
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/mips/jump_mips32_o32_elf_gas.S b/src/asm/mips/switch_mips32_o32_elf_gas.S
similarity index 84%
rename from src/asm/mips/jump_mips32_o32_elf_gas.S
rename to src/asm/mips/switch_mips32_o32_elf_gas.S
index 38d22d2..cd2e3bb 100644
--- a/src/asm/mips/jump_mips32_o32_elf_gas.S
+++ b/src/asm/mips/switch_mips32_o32_elf_gas.S
@@ -40,12 +40,12 @@
.file "jump_mips32_o32_elf_gas.S"
.text
-.globl jump_fcontext
-.hidden jump_fcontext
+.globl yafl_switch
+.hidden yafl_switch
.align 2
-.type jump_fcontext,@function
-.ent jump_fcontext
-jump_fcontext:
+.type yafl_switch,@function
+.ent yafl_switch
+yafl_switch:
# reserve space on stack
addiu $sp, $sp, -96
@@ -58,7 +58,6 @@ jump_fcontext:
sw $s6, 72($sp) # save S6
sw $s7, 76($sp) # save S7
sw $fp, 80($sp) # save FP
- sw $a0, 84($sp) # save hidden, address of returned transfer_t
sw $ra, 88($sp) # save RA
sw $ra, 92($sp) # save RA as PC
@@ -71,10 +70,10 @@ jump_fcontext:
s.d $f30, 40($sp) # save F30
#endif
- # store SP (pointing to context-data) in A0
- move $a0, $sp
+ # save current context through the first argument pointer
+ sw $sp, 0($a0)
- # restore SP (pointing to context-data) from A1
+ # restore target context from the second argument
move $sp, $a1
#if defined(__mips_hard_float)
@@ -95,7 +94,6 @@ jump_fcontext:
lw $s6, 72($sp) # restore S6
lw $s7, 76($sp) # restore S7
lw $fp, 80($sp) # restore FP
- lw $v0, 84($sp) # restore hidden, address of returned transfer_t
lw $ra, 88($sp) # restore RA
# load PC
@@ -104,17 +102,14 @@ jump_fcontext:
# adjust stack
addiu $sp, $sp, 96
- # return transfer_t from jump
- sw $a0, ($v0) # fctx of transfer_t
- sw $a2, 4($v0) # data of transfer_t
- # pass transfer_t as first arg in context function
- # A0 == fctx, A1 == data
- move $a1, $a2
+ # return and pass data directly
+ move $v0, $a2
+ move $a0, $a2
# jump to context
jr $t9
-.end jump_fcontext
-.size jump_fcontext, .-jump_fcontext
+.end yafl_switch
+.size yafl_switch, .-yafl_switch
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/mips64/README.md b/src/asm/mips64/README.md
index a73c074..9f5ae4f 100644
--- a/src/asm/mips64/README.md
+++ b/src/asm/mips64/README.md
@@ -6,22 +6,22 @@ This directory contains the MIPS64 N64 ABI context switching implementation for
### API Refactoring (2026)
-The original Boost.Context API required fiber functions to explicitly call `jump_fcontext()` at the end to return control. The fcontext library has been refactored to allow fiber functions to return naturally with a `void` return type, eliminating the need for explicit context switches at function end.
+The original Boost.Context API required fiber functions to explicitly call `yafl_switch()` at the end to return control. The fcontext library has been refactored to allow fiber functions to return naturally with a `void` return type, eliminating the need for explicit context switches at function end.
-This required a key fix in `make_mips64_n64_elf_gas.S`:
+This required a key fix in `make_context_mips64_n64_elf_gas.S`:
#### Fix in `finish` Routine - Context Pointer Preservation
**Original Problem:** Early versions tried to reconstruct the context pointer from $sp using fixed offset calculations (`$sp - 160`). This was unreliable because:
-1. `jump_fcontext` adjusts $sp by 160 bytes after restoring the context
+1. `yafl_switch` adjusts $sp by 160 bytes after restoring the context
2. The fiber function then allocates its own stack space, moving $sp even further
3. By the time `finish` is reached, $sp is no longer near the context data
4. This caused segmentation faults when fiber functions did substantial work
**Solution:** Use a callee-saved register (S1) to preserve the context pointer.
-In `make_mips64_n64_elf_gas.S`:
+In `make_context_mips64_n64_elf_gas.S`:
```asm
# Save context pointer in S1 slot within the context
# S1 is callee-saved, so the fiber will preserve it across calls
@@ -31,7 +31,7 @@ sd $v0, 72($v0)
In `finish` routine:
```asm
finish:
- # S1 contains the context pointer (saved during make_fcontext and preserved by fiber)
+ # S1 contains the context pointer (saved during yafl_make_context and preserved by fiber)
# S1 is callee-saved, so it survives the entire fiber execution
ld $gp, 136($s1)
...
@@ -40,7 +40,7 @@ finish:
**Why This Works:**
- The MIPS64 ABI requires S1 to be callee-saved
- We store the context pointer in the S1 register slot at offset 72 during initialization
-- When `jump_fcontext` restores the context, it loads S1 from this slot
+- When `yafl_switch` restores the context, it loads S1 from this slot
- The fiber function must preserve S1 (ABI requirement), so it's still available in `finish`
- By using S1 directly, we avoid relying on $sp which has been moved during fiber execution
@@ -50,8 +50,8 @@ Stack operations ensure 16-byte alignment compliance required by the MIPS64 ABI.
## Files
-- `make_mips64_n64_elf_gas.S` - Context initialization
-- `jump_mips64_n64_elf_gas.S` - Context switching/jumping
+- `make_context_mips64_n64_elf_gas.S` - Context initialization
+- `switch_mips64_n64_elf_gas.S` - Context switching/jumping
## Updating from Boost.Context
diff --git a/src/asm/mips64/make_mips64_n64_elf_gas.S b/src/asm/mips64/make_context_mips64_n64_elf_gas.S
similarity index 94%
rename from src/asm/mips64/make_mips64_n64_elf_gas.S
rename to src/asm/mips64/make_context_mips64_n64_elf_gas.S
index b7bfd2e..eac6b6f 100644
--- a/src/asm/mips64/make_mips64_n64_elf_gas.S
+++ b/src/asm/mips64/make_context_mips64_n64_elf_gas.S
@@ -47,12 +47,12 @@
.file "make_mips64_n64_elf_gas.S"
.text
-.globl make_fcontext
-.hidden make_fcontext
+.globl yafl_make_context
+.hidden yafl_make_context
.align 3
-.type make_fcontext,@function
-.ent make_fcontext
-make_fcontext:
+.type yafl_make_context,@function
+.ent yafl_make_context
+yafl_make_context:
#ifdef __PIC__
.set noreorder
.cpload $t9
@@ -70,7 +70,7 @@ make_fcontext:
# When finish is reached after the fiber returns, S1 will contain the context pointer.
sd $v0, 72($v0)
- # third arg of make_fcontext() == address of context-function
+ # third arg of yafl_make_context() == address of context-function
sd $a2, 152($v0)
# NOTE: $gp (global pointer) is NOT saved here.
@@ -99,8 +99,8 @@ finish:
dla $t9, _exit
move $a0, $zero
jr $t9
-.end make_fcontext
-.size make_fcontext, .-make_fcontext
+.end yafl_make_context
+.size yafl_make_context, .-yafl_make_context
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/mips64/jump_mips64_n64_elf_gas.S b/src/asm/mips64/switch_mips64_n64_elf_gas.S
similarity index 90%
rename from src/asm/mips64/jump_mips64_n64_elf_gas.S
rename to src/asm/mips64/switch_mips64_n64_elf_gas.S
index 60027fe..d8dd367 100644
--- a/src/asm/mips64/jump_mips64_n64_elf_gas.S
+++ b/src/asm/mips64/switch_mips64_n64_elf_gas.S
@@ -47,12 +47,12 @@
.file "jump_mips64_n64_elf_gas.S"
.text
-.globl jump_fcontext
-.hidden jump_fcontext
+.globl yafl_switch
+.hidden yafl_switch
.align 3
-.type jump_fcontext,@function
-.ent jump_fcontext
-jump_fcontext:
+.type yafl_switch,@function
+.ent yafl_switch
+yafl_switch:
# reserve space on stack
daddiu $sp, $sp, -160
@@ -79,11 +79,11 @@ jump_fcontext:
s.d $f31, 56($sp) # save F31
#endif
- # store SP (pointing to old context-data) in v0 as return
- move $v0, $sp
+ # save current context through the first argument pointer
+ sd $sp, 0($a0)
- # get SP (pointing to new context-data) from a0 param
- move $sp, $a0
+ # restore target context from the second argument
+ move $sp, $a1
#if defined(__mips_hard_float)
l.d $f24, 0($sp) # restore F24
@@ -113,13 +113,14 @@ jump_fcontext:
# adjust stack
daddiu $sp, $sp, 160
- move $a0, $v0 # move old sp from v0 to a0 as param
- move $v1, $a1 # move *data from a1 to v1 as return
+ # return and pass data directly
+ move $v0, $a2
+ move $a0, $a2
# jump to context
jr $t9
-.end jump_fcontext
-.size jump_fcontext, .-jump_fcontext
+.end yafl_switch
+.size yafl_switch, .-yafl_switch
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/ppc32/make_ppc32_sysv_elf_gas.S b/src/asm/ppc32/make_context_ppc32_sysv_elf_gas.S
similarity index 81%
rename from src/asm/ppc32/make_ppc32_sysv_elf_gas.S
rename to src/asm/ppc32/make_context_ppc32_sysv_elf_gas.S
index 0dd7771..474cc28 100644
--- a/src/asm/ppc32/make_ppc32_sysv_elf_gas.S
+++ b/src/asm/ppc32/make_context_ppc32_sysv_elf_gas.S
@@ -52,15 +52,15 @@
.file "make_ppc32_sysv_elf_gas.S"
.text
-.globl make_fcontext
-.hidden make_fcontext
+.globl yafl_make_context
+.hidden yafl_make_context
.align 2
-.type make_fcontext,@function
-make_fcontext:
+.type yafl_make_context,@function
+yafl_make_context:
# save return address into R6
mflr %r6
- # first arg of make_fcontext() == top address of context-function
+ # first arg of yafl_make_context() == top address of context-function
# shift address in R3 to lower 16 byte boundary
clrrwi %r3, %r3, 4
@@ -68,14 +68,9 @@ make_fcontext:
# and parameter area + 240 bytes of context-data (R1 % 16 == 0)
subi %r3, %r3, 16 + 240
- # third arg of make_fcontext() == address of context-function
-#ifdef __linux__
+ # third arg of yafl_make_context() == address of context-function
# save context-function as PC
stw %r5, 16(%r3)
-#else
- # save context-function for trampoline
- stw %r5, 248(%r3)
-#endif
# set back-chain to zero
li %r0, 0
@@ -85,20 +80,9 @@ make_fcontext:
mffs %f0
stfd %f0, 8(%r3)
-#ifdef __linux__
- # set hidden pointer for returning transfer_t
- la %r0, 248(%r3)
- stw %r0, 4(%r3)
-#endif
-
# load address of label 1 into R4
bl 1f
1: mflr %r4
-#ifndef __linux__
- # compute abs address of trampoline, use as PC
- addi %r7, %r4, trampoline - 1b
- stw %r7, 16(%r3)
-#endif
# compute abs address of label finish
addi %r4, %r4, finish - 1b
# save address of finish as return-address for context-function
@@ -110,19 +94,6 @@ make_fcontext:
blr # return pointer to context-data
-#ifndef __linux__
-trampoline:
- # On systems other than Linux, jump_fcontext is returning the
- # transfer_t in R3:R4, but we need to pass transfer_t * R3 to
- # our context-function.
- lwz %r0, 8(%r1) # address of context-function
- mtctr %r0
- stw %r3, 8(%r1)
- stw %r4, 12(%r1)
- la %r3, 8(%r1) # address of transfer_t
- bctr
-#endif
-
finish:
# Use the secure PLT for _exit(0). If we use the insecure BSS PLT
# here, then the linker may use the insecure BSS PLT even if the
@@ -137,7 +108,7 @@ finish:
# call _exit(0) with special addend 0x8000 for large model
li %r3, 0
bl _exit + 0x8000@plt
-.size make_fcontext, .-make_fcontext
+.size yafl_make_context, .-yafl_make_context
/* Provide the GOT pointer for secure PLT, large model. */
.section .got2,"aw"
diff --git a/src/asm/ppc32/jump_ppc32_sysv_elf_gas.S b/src/asm/ppc32/switch_ppc32_sysv_elf_gas.S
similarity index 89%
rename from src/asm/ppc32/jump_ppc32_sysv_elf_gas.S
rename to src/asm/ppc32/switch_ppc32_sysv_elf_gas.S
index e313366..fdb16b1 100644
--- a/src/asm/ppc32/jump_ppc32_sysv_elf_gas.S
+++ b/src/asm/ppc32/switch_ppc32_sysv_elf_gas.S
@@ -52,13 +52,11 @@
.file "jump_ppc32_sysv_elf_gas.S"
.text
-.globl jump_fcontext
-.hidden jump_fcontext
+.globl yafl_switch
+.hidden yafl_switch
.align 2
-.type jump_fcontext,@function
-jump_fcontext:
- # Linux: jump_fcontext( hidden transfer_t * R3, R4, R5)
- # Other: transfer_t R3:R4 = jump_fcontext( R3, R4)
+.type yafl_switch,@function
+yafl_switch:
mflr %r0 # return address from LR
mffs %f0 # FPSCR
@@ -67,10 +65,6 @@ jump_fcontext:
stwu %r1, -240(%r1) # allocate stack space, R1 % 16 == 0
stw %r0, 244(%r1) # save LR in caller's frame
-#ifdef __linux__
- stw %r3, 4(%r1) # hidden pointer
-#endif
-
stfd %f0, 8(%r1) # FPSCR
stw %r0, 16(%r1) # LR as PC
stw %r8, 20(%r1) # CR
@@ -119,16 +113,11 @@ jump_fcontext:
stfd %f30, 224(%r1)
stfd %f31, 232(%r1)
- # store RSP (pointing to context-data) in R7/R6
- # restore RSP (pointing to context-data) from R4/R3
-#ifdef __linux__
- mr %r7, %r1
+ # save current context through the first argument pointer
+ stw %r1, 0(%r3)
+
+ # restore target context from the second argument
mr %r1, %r4
- lwz %r3, 4(%r1) # hidden pointer
-#else
- mr %r6, %r1
- mr %r1, %r3
-#endif
lfd %f0, 8(%r1) # FPSCR
lwz %r0, 16(%r1) # PC
@@ -185,18 +174,12 @@ jump_fcontext:
# adjust stack
addi %r1, %r1, 240
- # return transfer_t
-#ifdef __linux__
- stw %r7, 0(%r3)
- stw %r5, 4(%r3)
-#else
- mr %r3, %r6
- # %r4, %r4
-#endif
+ # return and pass data directly
+ mr %r3, %r5
# jump to context
bctr
-.size jump_fcontext, .-jump_fcontext
+.size yafl_switch, .-yafl_switch
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/ppc64/make_ppc64_sysv_elf_gas.S b/src/asm/ppc64/make_context_ppc64_sysv_elf_gas.S
similarity index 86%
rename from src/asm/ppc64/make_ppc64_sysv_elf_gas.S
rename to src/asm/ppc64/make_context_ppc64_sysv_elf_gas.S
index f513d36..46a568a 100644
--- a/src/asm/ppc64/make_ppc64_sysv_elf_gas.S
+++ b/src/asm/ppc64/make_context_ppc64_sysv_elf_gas.S
@@ -67,40 +67,40 @@
*******************************************************/
.file "make_ppc64_sysv_elf_gas.S"
-.globl make_fcontext
-.hidden make_fcontext
+.globl yafl_make_context
+.hidden yafl_make_context
#if _CALL_ELF == 2
.text
.align 2
-make_fcontext:
- addis %r2, %r12, .TOC.-make_fcontext@ha
- addi %r2, %r2, .TOC.-make_fcontext@l
- .localentry make_fcontext, . - make_fcontext
+yafl_make_context:
+ addis %r2, %r12, .TOC.-yafl_make_context@ha
+ addi %r2, %r2, .TOC.-yafl_make_context@l
+ .localentry yafl_make_context, . - yafl_make_context
#else
.section ".opd","aw"
.align 3
-make_fcontext:
+yafl_make_context:
# ifdef _CALL_LINUX
- .quad .L.make_fcontext,.TOC.@tocbase,0
- .type make_fcontext,@function
+ .quad .L.yafl_make_context,.TOC.@tocbase,0
+ .type yafl_make_context,@function
.text
.align 2
-.L.make_fcontext:
+.L.yafl_make_context:
# else
- .hidden .make_fcontext
- .globl .make_fcontext
- .quad .make_fcontext,.TOC.@tocbase,0
- .size make_fcontext,24
- .type .make_fcontext,@function
+ .hidden .yafl_make_context
+ .globl .yafl_make_context
+ .quad .yafl_make_context,.TOC.@tocbase,0
+ .size yafl_make_context,24
+ .type .yafl_make_context,@function
.text
.align 2
-.make_fcontext:
+.yafl_make_context:
# endif
#endif
# save return address into R6
mflr %r6
- # first arg of make_fcontext() == top address of context-stack
+ # first arg of yafl_make_context() == top address of context-stack
# shift address in R3 to lower 16 byte boundary
clrrdi %r3, %r3, 4
@@ -108,7 +108,7 @@ make_fcontext:
# including 64 byte of linkage + parameter area (R1 % 16 == 0)
subi %r3, %r3, 248
- # third arg of make_fcontext() == address of context-function
+ # third arg of yafl_make_context() == address of context-function
# entry point (ELFv2) or descriptor (ELFv1)
#if _CALL_ELF == 2
# save address of context-function entry point
@@ -126,11 +126,6 @@ make_fcontext:
li %r0, 0
std %r0, 184(%r3)
-#if _CALL_ELF != 2
- # zero in r3 indicates first jump to context-function
- std %r0, 152(%r3)
-#endif
-
# load LR
mflr %r0
# jump to label 1
@@ -165,12 +160,12 @@ finish:
bl _exit
nop
#if _CALL_ELF == 2
- .size make_fcontext, .-make_fcontext
+ .size yafl_make_context, .-yafl_make_context
#else
# ifdef _CALL_LINUX
- .size .make_fcontext, .-.L.make_fcontext
+ .size .yafl_make_context, .-.L.yafl_make_context
# else
- .size .make_fcontext, .-.make_fcontext
+ .size .yafl_make_context, .-.yafl_make_context
# endif
#endif
diff --git a/src/asm/ppc64/jump_ppc64_sysv_elf_gas.S b/src/asm/ppc64/switch_ppc64_sysv_elf_gas.S
similarity index 81%
rename from src/asm/ppc64/jump_ppc64_sysv_elf_gas.S
rename to src/asm/ppc64/switch_ppc64_sysv_elf_gas.S
index debeb34..722b8de 100644
--- a/src/asm/ppc64/jump_ppc64_sysv_elf_gas.S
+++ b/src/asm/ppc64/switch_ppc64_sysv_elf_gas.S
@@ -67,34 +67,34 @@
*******************************************************/
.file "jump_ppc64_sysv_elf_gas.S"
-.globl jump_fcontext
-.hidden jump_fcontext
+.globl yafl_switch
+.hidden yafl_switch
#if _CALL_ELF == 2
.text
.align 2
-jump_fcontext:
- addis %r2, %r12, .TOC.-jump_fcontext@ha
- addi %r2, %r2, .TOC.-jump_fcontext@l
- .localentry jump_fcontext, . - jump_fcontext
+yafl_switch:
+ addis %r2, %r12, .TOC.-yafl_switch@ha
+ addi %r2, %r2, .TOC.-yafl_switch@l
+ .localentry yafl_switch, . - yafl_switch
#else
.section ".opd","aw"
.align 3
-jump_fcontext:
+yafl_switch:
# ifdef _CALL_LINUX
- .quad .L.jump_fcontext,.TOC.@tocbase,0
- .type jump_fcontext,@function
+ .quad .L.yafl_switch,.TOC.@tocbase,0
+ .type yafl_switch,@function
.text
.align 2
-.L.jump_fcontext:
+.L.yafl_switch:
# else
- .hidden .jump_fcontext
- .globl .jump_fcontext
- .quad .jump_fcontext,.TOC.@tocbase,0
- .size jump_fcontext,24
- .type .jump_fcontext,@function
+ .hidden .yafl_switch
+ .globl .yafl_switch
+ .quad .yafl_switch,.TOC.@tocbase,0
+ .size yafl_switch,24
+ .type .yafl_switch,@function
.text
.align 2
-.jump_fcontext:
+.yafl_switch:
# endif
#endif
# reserve space on stack
@@ -121,10 +121,6 @@ jump_fcontext:
std %r29, 128(%r1) # save R29
std %r30, 136(%r1) # save R30
std %r31, 144(%r1) # save R31
-#if _CALL_ELF != 2
- std %r3, 152(%r1) # save hidden
-#endif
-
# save CR
mfcr %r0
std %r0, 160(%r1)
@@ -138,16 +134,13 @@ jump_fcontext:
li %r31, 184
stvx %v31, %r1, %r31
- # store RSP (pointing to context-data) in R6
- mr %r6, %r1
+ # save current context through the first argument pointer
+ std %r1, 0(%r3)
-#if _CALL_ELF == 2
- # restore RSP (pointing to context-data) from R3
- mr %r1, %r3
-#else
- # restore RSP (pointing to context-data) from R4
+ # restore target context from the second argument
mr %r1, %r4
+#if _CALL_ELF != 2
ld %r2, 0(%r1) # restore TOC
#endif
@@ -173,10 +166,6 @@ jump_fcontext:
ld %r29, 128(%r1) # restore R29
ld %r30, 136(%r1) # restore R30
ld %r31, 144(%r1) # restore R31
-#if _CALL_ELF != 2
- ld %r3, 152(%r1) # restore hidden
-#endif
-
# restore CR
ld %r0, 160(%r1)
mtcr %r0
@@ -192,37 +181,18 @@ jump_fcontext:
# adjust stack
addi %r1, %r1, 200
-#if _CALL_ELF == 2
- # copy transfer_t into transfer_fn arg registers
- mr %r3, %r6
- # arg pointer already in %r4
+ # return and pass data directly
+ mr %r3, %r5
# jump to context
bctr
- .size jump_fcontext, .-jump_fcontext
+#if _CALL_ELF == 2
+ .size yafl_switch, .-yafl_switch
#else
- # zero in r3 indicates first jump to context-function
- cmpdi %r3, 0
- beq use_entry_arg
-
- # return transfer_t
- std %r6, 0(%r3)
- std %r5, 8(%r3)
-
- # jump to context
- bctr
-
-use_entry_arg:
- # copy transfer_t into transfer_fn arg registers
- mr %r3, %r6
- mr %r4, %r5
-
- # jump to context
- bctr
# ifdef _CALL_LINUX
- .size .jump_fcontext, .-.L.jump_fcontext
+ .size .yafl_switch, .-.L.yafl_switch
# else
- .size .jump_fcontext, .-.jump_fcontext
+ .size .yafl_switch, .-.yafl_switch
# endif
#endif
diff --git a/src/asm/riscv64/make_riscv64_sysv_elf_gas.S b/src/asm/riscv64/make_context_riscv64_sysv_elf_gas.S
similarity index 94%
rename from src/asm/riscv64/make_riscv64_sysv_elf_gas.S
rename to src/asm/riscv64/make_context_riscv64_sysv_elf_gas.S
index 6d97c59..0811f96 100644
--- a/src/asm/riscv64/make_riscv64_sysv_elf_gas.S
+++ b/src/asm/riscv64/make_context_riscv64_sysv_elf_gas.S
@@ -60,17 +60,17 @@
.file "make_riscv64_sysv_elf_gas.S"
.text
.align 1
-.global make_fcontext
-.hidden make_fcontext
-.type make_fcontext, %function
-make_fcontext:
+.global yafl_make_context
+.hidden yafl_make_context
+.type yafl_make_context, %function
+yafl_make_context:
# shift address in a0 (allocated stack) to lower 16 byte boundary
andi a0, a0, ~0xF
# reserve space for context-data on context-stack
addi a0, a0, -0xd0
- # third arg of make_fcontext() == address of context-function
+ # third arg of yafl_make_context() == address of context-function
# store address as a PC to jump in
sd a2, 0xc8(a0)
@@ -87,6 +87,6 @@ finish:
# exit application
tail _exit@plt
-.size make_fcontext,.-make_fcontext
+.size yafl_make_context,.-yafl_make_context
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/riscv64/jump_riscv64_sysv_elf_gas.S b/src/asm/riscv64/switch_riscv64_sysv_elf_gas.S
similarity index 92%
rename from src/asm/riscv64/jump_riscv64_sysv_elf_gas.S
rename to src/asm/riscv64/switch_riscv64_sysv_elf_gas.S
index 879eb7e..fa371a5 100644
--- a/src/asm/riscv64/jump_riscv64_sysv_elf_gas.S
+++ b/src/asm/riscv64/switch_riscv64_sysv_elf_gas.S
@@ -60,10 +60,10 @@
.file "jump_riscv64_sysv_elf_gas.S"
.text
.align 1
-.global jump_fcontext
-.hidden jump_fcontext
-.type jump_fcontext, %function
-jump_fcontext:
+.global yafl_switch
+.hidden yafl_switch
+.type yafl_switch, %function
+yafl_switch:
# prepare stack for GP + FPU
addi sp, sp, -0xd0
@@ -99,11 +99,12 @@ jump_fcontext:
# save RA as PC
sd ra, 0xc8(sp)
- # store SP (pointing to context-data) in A2
- mv a2, sp
+ # save current context through the first argument pointer
+ mv a3, a2
+ sd sp, 0(a0)
- # restore SP (pointing to context-data) from A0
- mv sp, a0
+ # restore target context from the second argument
+ mv sp, a1
# load fs0 - fs11
fld fs0, 0x00(sp)
@@ -134,10 +135,8 @@ jump_fcontext:
ld s11, 0xb8(sp)
ld ra, 0xc0(sp)
- # return transfer_t from jump
- # pass transfer_t as first arg in context function
- # a0 == FCTX, a1 == DATA
- mv a0, a2
+ # return and pass data directly
+ mv a0, a3
# load pc
ld a2, 0xc8(sp)
@@ -146,6 +145,6 @@ jump_fcontext:
addi sp, sp, 0xd0
jr a2
-.size jump_fcontext,.-jump_fcontext
+.size yafl_switch,.-yafl_switch
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/s390x/make_s390x_sysv_elf_gas.S b/src/asm/s390x/make_context_s390x_sysv_elf_gas.S
similarity index 90%
rename from src/asm/s390x/make_s390x_sysv_elf_gas.S
rename to src/asm/s390x/make_context_s390x_sysv_elf_gas.S
index 4d6aa62..b156f9a 100644
--- a/src/asm/s390x/make_s390x_sysv_elf_gas.S
+++ b/src/asm/s390x/make_context_s390x_sysv_elf_gas.S
@@ -45,9 +45,9 @@
.text
.align 8
-.global make_fcontext
-.hidden make_fcontext
-.type make_fcontext, @function
+.global yafl_make_context
+.hidden yafl_make_context
+.type yafl_make_context, @function
#define ARG_OFFSET 0
#define GR_OFFSET 16
@@ -59,7 +59,7 @@
/*
-fcontext_t make_fcontext( void * sp, std::size_t size, void (* fn)( transfer_t) );
+fcontext_t yafl_make_context( void * sp, std::size_t size, void (* fn)( void * ) );
Create and return a context below SP to call FN.
@@ -70,7 +70,7 @@ r4 - The address of the context function
*/
-make_fcontext:
+yafl_make_context:
.machine "z10"
/* Align the stack to an 8 byte boundary. */
nill %r2,0xfff8
@@ -78,10 +78,6 @@ make_fcontext:
/* Allocate stack space for the context. */
aghi %r2,-CONTEXT_SIZE
- /* Set the r2 save slot to zero. This indicates jump_fcontext
- that this is a special context. */
- mvghi GR_OFFSET(%r2),0
-
/* Save the floating point control register. */
stfpc FPC_OFFSET(%r2)
@@ -100,10 +96,10 @@ make_fcontext:
finish:
/* In finish tasks, you load the exit code and exit the
- make_fcontext This is called when the context-function is
+ yafl_make_context This is called when the context-function is
entirely executed. */
lghi %r2,0
brasl %r14,_exit@PLT
-.size make_fcontext,.-make_fcontext
+.size yafl_make_context,.-yafl_make_context
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/s390x/jump_s390x_sysv_elf_gas.S b/src/asm/s390x/switch_s390x_sysv_elf_gas.S
similarity index 78%
rename from src/asm/s390x/jump_s390x_sysv_elf_gas.S
rename to src/asm/s390x/switch_s390x_sysv_elf_gas.S
index 59bc58b..b1e587a 100644
--- a/src/asm/s390x/jump_s390x_sysv_elf_gas.S
+++ b/src/asm/s390x/switch_s390x_sysv_elf_gas.S
@@ -45,9 +45,9 @@
.text
.align 8
-.global jump_fcontext
-.hidden jump_fcontext
-.type jump_fcontext, @function
+.global yafl_switch
+.hidden yafl_switch
+.type yafl_switch, @function
#define ARG_OFFSET 0
#define GR_OFFSET 16
@@ -63,29 +63,22 @@
typedef void* fcontext_t;
-struct transfer_t {
- fcontext_t fctx;
- void * data;
-};
-
-transfer_t jump_fcontext( fcontext_t const to,
- void * data);
+void * yafl_switch( fcontext_t * save,
+ fcontext_t target,
+ void * data);
Incoming args
-r2 - Hidden argument to the location where the return transfer_t needs to be returned
+r2 - Pointer where the current context will be saved
r3 - Context we want to switch to
r4 - Data pointer
*/
-jump_fcontext:
+yafl_switch:
.machine "z10"
/* Reserve stack space to store the current context. */
aghi %r15,-CONTEXT_SIZE
- /* Save the argument register holding the location of the return value. */
- stg %r2,GR_OFFSET(%r15)
-
/* Save the call-saved general purpose registers. */
stmg %r6,%r14,GR_OFFSET+8(%r15)
@@ -105,8 +98,8 @@ jump_fcontext:
/* Save the floating point control register. */
stfpc FPC_OFFSET(%r15)
- /* Backup the stack pointer pointing to the old context-data into r1. */
- lgr %r1,%r15
+ /* Save the current context through the first argument pointer. */
+ stg %r15,0(%r2)
/* Load the new context pointer as stack pointer. */
lgr %r15,%r3
@@ -130,32 +123,15 @@ jump_fcontext:
/* Restore PC - the location where we will jump to at the end. */
lg %r5,PC_OFFSET(%r15)
- ltg %r2,GR_OFFSET(%r15)
- jnz use_return_slot
-
- /* We're restoring a context created by make_fcontext.
- This is going to be the argument of the entry point
- of the fiber. We're placing it on top of the ABI
- defined register save area of the fiber's own stack. */
- la %r2,REG_SAVE_AREA_SIZE(%r15)
-
- /* REG_SAVE_AREA_SIZE + sizeof(transfer_t) */
- aghi %r15,-(REG_SAVE_AREA_SIZE+16)
-
-use_return_slot:
- /* Save the two fields in transfer_t. When calling a
- make_fcontext function this becomes the function argument of
- the target function, otherwise it will be the return value of
- jump_fcontext. */
- stg %r1,0(%r2)
- stg %r4,8(%r2)
-
/* Free the restored context. */
aghi %r15,CONTEXT_SIZE
+ /* Return and pass data directly. */
+ lgr %r2,%r4
+
/* Jump to the PC loaded from the new context. */
br %r5
-.size jump_fcontext,.-jump_fcontext
+.size yafl_switch,.-yafl_switch
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/sparc64/make_sparc64_sysv_elf_gas.S b/src/asm/sparc64/make_context_sparc64_sysv_elf_gas.S
similarity index 81%
rename from src/asm/sparc64/make_sparc64_sysv_elf_gas.S
rename to src/asm/sparc64/make_context_sparc64_sysv_elf_gas.S
index 3d50447..8cc0cf6 100644
--- a/src/asm/sparc64/make_sparc64_sysv_elf_gas.S
+++ b/src/asm/sparc64/make_context_sparc64_sysv_elf_gas.S
@@ -6,7 +6,7 @@
*/
/*
- * fcontext_t *make_fcontext(void *sp, size_t size, void (*fn)(transfer_t));
+ * fcontext_t *yafl_make_context(void *sp, size_t size, void (*fn)(void *));
*/
#define CC64FSZ 176
#define BIAS 2047
@@ -17,9 +17,9 @@
.file "make_sparc64_sysv_elf_gas.S"
.text
.align 4
-.global make_fcontext
-.type make_fcontext, %function
-make_fcontext:
+.global yafl_make_context
+.type yafl_make_context, %function
+yafl_make_context:
save %sp, -CC64FSZ, %sp
# shift address in %i0 (allocated stack) to lower 16 byte boundary
@@ -27,10 +27,10 @@ make_fcontext:
# reserve space for two frames on the stack
# the first frame is for the call the second one holds the data
- # for jump_fcontext
+ # for yafl_switch
sub %i0, 2 * CC64FSZ, %i0
- # third argument of make_fcontext() is the context-function to call
+ # third argument of yafl_make_context() is the context-function to call
# store it in the first stack frame, also clear %fp there to indicate
# the end of the stack.
stx %i2, [%i0 + CC64FSZ + I7]
@@ -56,13 +56,13 @@ make_fcontext:
trampoline:
ldx [%sp + BIAS + I7], %l0
- # no need to setup transfer_t, already in %o0 and %o1
+ # the first-entry argument already arrives in %o0
jmpl %l0, %o7
nop
call _exit
clr %o0
unimp
-.size make_fcontext,.-make_fcontext
+.size yafl_make_context,.-yafl_make_context
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/sparc64/jump_sparc64_sysv_elf_gas.S b/src/asm/sparc64/switch_sparc64_sysv_elf_gas.S
similarity index 65%
rename from src/asm/sparc64/jump_sparc64_sysv_elf_gas.S
rename to src/asm/sparc64/switch_sparc64_sysv_elf_gas.S
index 61101fb..3f47c21 100644
--- a/src/asm/sparc64/jump_sparc64_sysv_elf_gas.S
+++ b/src/asm/sparc64/switch_sparc64_sysv_elf_gas.S
@@ -8,12 +8,7 @@
/*
* typedef void* fcontext_t;
*
- * struct transfer_t {
- * fcontext_t fctx;
- * void * data;
- * };
- *
- * transfer_t jump_fcontext(fcontext_t const to, void *vp);
+ * void *yafl_switch(fcontext_t *save, fcontext_t target, void *data);
*/
#define CC64FSZ 176
#define BIAS 2047
@@ -23,9 +18,9 @@
.file "jump_sparc64_sysv_elf_gas.S"
.text
.align 4
-.global jump_fcontext
-.type jump_fcontext, %function
-jump_fcontext:
+.global yafl_switch
+.type yafl_switch, %function
+yafl_switch:
# prepare stack
save %sp, -CC64FSZ, %sp
@@ -33,19 +28,19 @@ jump_fcontext:
# for arguments
stx %fp, [%sp + BIAS + SP]
stx %i7, [%sp + BIAS + I7]
- mov %sp, %o0
+ mov %sp, %l0
# force flush register windows to stack and with that save context
flushw
- # get SP (pointing to new context-data) from %i0 param
- mov %i0, %sp
+ # save current context through the first argument pointer
+ stx %l0, [%i0]
+ # get SP (pointing to new context-data) from %i1 param
+ mov %i1, %sp
# load framepointer and return address from context
ldx [%sp + BIAS + SP], %fp
ldx [%sp + BIAS + I7], %i7
ret
- restore %o0, %g0, %o0
- # restore old %sp (pointing to old context-data) in %o0
- # *data stored in %o1 was not modified
-.size jump_fcontext,.-jump_fcontext
+ restore %i2, %g0, %o0
+.size yafl_switch,.-yafl_switch
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/x86_64/make_x86_64_ms_pe_gas.S b/src/asm/x86_64/make_context_x86_64_ms_pe_gas.S
similarity index 93%
rename from src/asm/x86_64/make_x86_64_ms_pe_gas.S
rename to src/asm/x86_64/make_context_x86_64_ms_pe_gas.S
index e854c91..370e5b4 100644
--- a/src/asm/x86_64/make_x86_64_ms_pe_gas.S
+++ b/src/asm/x86_64/make_context_x86_64_ms_pe_gas.S
@@ -90,13 +90,13 @@
.file "make_x86_64_ms_pe_gas.S"
.text
.p2align 4,,15
-.globl make_fcontext
-.def make_fcontext; .scl 2; .type 32; .endef
-.seh_proc make_fcontext
-make_fcontext:
+.globl yafl_make_context
+.def yafl_make_context; .scl 2; .type 32; .endef
+.seh_proc yafl_make_context
+yafl_make_context:
.seh_endprologue
- /* first arg of make_fcontext() == top of context-stack */
+ /* first arg of yafl_make_context() == top of context-stack */
movq %rcx, %rax
/* shift address in RAX to lower 16 byte boundary */
@@ -107,13 +107,13 @@ make_fcontext:
/* on context-function entry: (RSP -0x8) % 16 == 0 */
leaq -0x150(%rax), %rax
- /* third arg of make_fcontext() == address of context-function */
+ /* third arg of yafl_make_context() == address of context-function */
movq %r8, 0x100(%rax)
- /* first arg of make_fcontext() == top of context-stack */
+ /* first arg of yafl_make_context() == top of context-stack */
/* save top address of context stack as 'base' */
movq %rcx, 0xc8(%rax)
- /* second arg of make_fcontext() == size of context-stack */
+ /* second arg of yafl_make_context() == size of context-stack */
/* negate stack size for LEA instruction (== subtraction) */
negq %rdx
/* compute bottom address of context stack (limit) */
@@ -131,15 +131,10 @@ make_fcontext:
/* save x87 control-word */
fnstcw 0xa4(%rax)
- /* compute address of transport_t */
- leaq 0x140(%rax), %rcx
- /* store address of transport_t in hidden field */
- movq %rcx, 0x110(%rax)
-
/* compute abs address of label trampoline */
leaq trampoline(%rip), %rcx
/* save address of finish as return-address for context-function */
- /* will be entered after jump_fcontext() first time */
+ /* will be entered after yafl_switch() first time */
movq %rcx, 0x118(%rax)
/* compute abs address of label finish */
@@ -161,7 +156,7 @@ finish:
/* 32byte shadow-space for _exit() */
andq $-32, %rsp
/* 32byte shadow-space for _exit() are */
- /* already reserved by make_fcontext() */
+ /* already reserved by yafl_make_context() */
/* exit code is zero */
xorq %rcx, %rcx
/* exit application */
@@ -172,4 +167,4 @@ finish:
.def _exit; .scl 2; .type 32; .endef /* standard C library function */
.section .drectve
-.ascii " -export:\"make_fcontext\""
+.ascii " -export:\"yafl_make_context\""
diff --git a/src/asm/x86_64/make_x86_64_ms_pe_masm.asm b/src/asm/x86_64/make_context_x86_64_ms_pe_masm.asm
similarity index 94%
rename from src/asm/x86_64/make_x86_64_ms_pe_masm.asm
rename to src/asm/x86_64/make_context_x86_64_ms_pe_masm.asm
index 408f735..09a5685 100644
--- a/src/asm/x86_64/make_x86_64_ms_pe_masm.asm
+++ b/src/asm/x86_64/make_context_x86_64_ms_pe_masm.asm
@@ -92,11 +92,11 @@ EXTERN _exit:PROC
.code
; generate function table entry in .pdata and unwind information in
-make_fcontext PROC BOOST_CONTEXT_EXPORT FRAME
+yafl_make_context PROC BOOST_CONTEXT_EXPORT FRAME
; .xdata for a function's structured exception handling unwind behavior
.endprolog
- ; first arg of make_fcontext() == top of context-stack
+ ; first arg of yafl_make_context() == top of context-stack
mov rax, rcx
; shift address in RAX to lower 16 byte boundary
@@ -107,14 +107,14 @@ make_fcontext PROC BOOST_CONTEXT_EXPORT FRAME
; on context-function entry: (RSP -0x8) % 16 == 0
sub rax, 0150h
- ; third arg of make_fcontext() == address of context-function
+ ; third arg of yafl_make_context() == address of context-function
; stored in RBX
mov [rax+0100h], r8
- ; first arg of make_fcontext() == top of context-stack
+ ; first arg of yafl_make_context() == top of context-stack
; save top address of context stack as 'base'
mov [rax+0c8h], rcx
- ; second arg of make_fcontext() == size of context-stack
+ ; second arg of yafl_make_context() == size of context-stack
; negate stack size for LEA instruction (== subtraction)
neg rdx
; compute bottom address of context stack (limit)
@@ -132,15 +132,10 @@ make_fcontext PROC BOOST_CONTEXT_EXPORT FRAME
; save x87 control-word
fnstcw [rax+0a4h]
- ; compute address of transport_t
- lea rcx, [rax+0140h]
- ; store address of transport_t in hidden field
- mov [rax+0110h], rcx
-
; compute abs address of label trampoline
lea rcx, trampoline
; save address of trampoline as return-address for context-function
- ; will be entered after calling jump_fcontext() first time
+ ; will be entered after calling yafl_switch() first time
mov [rax+0118h], rcx
; compute abs address of label finish
@@ -164,5 +159,5 @@ finish:
; exit application
call _exit
hlt
-make_fcontext ENDP
+yafl_make_context ENDP
END
diff --git a/src/asm/x86_64/make_x86_64_sysv_elf_gas.S b/src/asm/x86_64/make_context_x86_64_sysv_elf_gas.S
similarity index 94%
rename from src/asm/x86_64/make_x86_64_sysv_elf_gas.S
rename to src/asm/x86_64/make_context_x86_64_sysv_elf_gas.S
index cabebff..df5e2a6 100644
--- a/src/asm/x86_64/make_x86_64_sysv_elf_gas.S
+++ b/src/asm/x86_64/make_context_x86_64_sysv_elf_gas.S
@@ -43,11 +43,11 @@
# endif
.file "make_x86_64_sysv_elf_gas.S"
.text
-.globl make_fcontext
-.hidden make_fcontext
-.type make_fcontext,@function
+.globl yafl_make_context
+.hidden yafl_make_context
+.type yafl_make_context,@function
.align 16
-make_fcontext:
+yafl_make_context:
_CET_ENDBR
#if BOOST_CONTEXT_SHADOW_STACK
@@ -55,7 +55,7 @@ make_fcontext:
movq -0x8(%rdi), %r9
#endif
- /* first arg of make_fcontext() == top of context-stack */
+ /* first arg of yafl_make_context() == top of context-stack */
movq %rdi, %rax
/* shift address in RAX to lower 16 byte boundary */
@@ -65,7 +65,7 @@ make_fcontext:
/* on context-function entry: (RSP -0x8) % 16 == 0 */
leaq -0x48(%rax), %rax
- /* third arg of make_fcontext() == address of context-function */
+ /* third arg of yafl_make_context() == address of context-function */
/* stored in RBX */
movq %rdx, 0x30(%rax)
@@ -83,7 +83,7 @@ make_fcontext:
/* compute abs address of label trampoline */
leaq trampoline(%rip), %rcx
/* save address of trampoline as return-address for context-function */
- /* will be entered after calling jump_fcontext() first time */
+ /* will be entered after calling yafl_switch() first time */
movq %rcx, 0x40(%rax)
/* compute abs address of label finish */
@@ -158,7 +158,7 @@ finish:
/* exit application */
call _exit@PLT
hlt
-.size make_fcontext,.-make_fcontext
+.size yafl_make_context,.-yafl_make_context
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/x86_64/make_x86_64_sysv_macho_gas.S b/src/asm/x86_64/make_context_x86_64_sysv_macho_gas.S
similarity index 91%
rename from src/asm/x86_64/make_x86_64_sysv_macho_gas.S
rename to src/asm/x86_64/make_context_x86_64_sysv_macho_gas.S
index 06357f6..113b853 100644
--- a/src/asm/x86_64/make_x86_64_sysv_macho_gas.S
+++ b/src/asm/x86_64/make_context_x86_64_sysv_macho_gas.S
@@ -25,11 +25,11 @@
****************************************************************************************/
.text
-.private_extern _make_fcontext
-.globl _make_fcontext
+.private_extern _yafl_make_context
+.globl _yafl_make_context
.align 8
-_make_fcontext:
- /* first arg of make_fcontext() == top of context-stack */
+_yafl_make_context:
+ /* first arg of yafl_make_context() == top of context-stack */
movq %rdi, %rax
/* shift address in RAX to lower 16 byte boundary */
@@ -39,7 +39,7 @@ _make_fcontext:
/* on context-function entry: (RSP -0x8) % 16 == 0 */
leaq -0x40(%rax), %rax
- /* third arg of make_fcontext() == address of context-function */
+ /* third arg of yafl_make_context() == address of context-function */
/* stored in RBX */
movq %rdx, 0x28(%rax)
@@ -51,7 +51,7 @@ _make_fcontext:
/* compute abs address of label trampoline */
leaq trampoline(%rip), %rcx
/* save address of trampoline as return-address for context-function */
- /* will be entered after calling jump_fcontext() first time */
+ /* will be entered after calling yafl_switch() first time */
movq %rcx, 0x38(%rax)
/* compute abs address of label finish */
diff --git a/src/asm/x86_64/jump_x86_64_ms_pe_gas.S b/src/asm/x86_64/switch_x86_64_ms_pe_gas.S
similarity index 83%
rename from src/asm/x86_64/jump_x86_64_ms_pe_gas.S
rename to src/asm/x86_64/switch_x86_64_ms_pe_gas.S
index 6507c1e..0a96d46 100644
--- a/src/asm/x86_64/jump_x86_64_ms_pe_gas.S
+++ b/src/asm/x86_64/switch_x86_64_ms_pe_gas.S
@@ -10,10 +10,10 @@
.file "jump_x86_64_ms_pe_gas.S"
.text
.p2align 4,,15
-.globl jump_fcontext
-.def jump_fcontext; .scl 2; .type 32; .endef
-.seh_proc jump_fcontext
-jump_fcontext:
+.globl yafl_switch
+.def yafl_switch; .scl 2; .type 32; .endef
+.seh_proc yafl_switch
+yafl_switch:
.seh_endprologue
leaq -0x118(%rsp), %rsp /* prepare stack */
@@ -58,12 +58,12 @@ jump_fcontext:
movq %rbx, 0x100(%rsp) /* save RBX */
movq %rbp, 0x108(%rsp) /* save RBP */
- movq %rcx, 0x110(%rsp) /* save hidden address of transport_t */
+ /* save current context through the first argument pointer */
+ movq %r8, %r9
+ movq %rsp, %rax
+ movq %rax, (%rcx)
- /* preserve RSP (pointing to context-data) in R9 */
- movq %rsp, %r9
-
- /* restore RSP (pointing to context-data) from RDX */
+ /* restore target context from the second argument */
movq %rdx, %rsp
#if !defined(BOOST_USE_TSX)
@@ -106,25 +106,18 @@ jump_fcontext:
movq 0x100(%rsp), %rbx /* restore RBX */
movq 0x108(%rsp), %rbp /* restore RBP */
- movq 0x110(%rsp), %rax /* restore hidden address of transport_t */
-
leaq 0x118(%rsp), %rsp /* prepare stack */
/* restore return-address */
popq %r10
- /* transport_t returned in RAX */
- /* return parent fcontext_t */
- movq %r9, 0x0(%rax)
- /* return data */
- movq %r8, 0x8(%rax)
-
- /* transport_t as 1.arg of context-function */
- movq %rax, %rcx
+ /* return and pass data directly */
+ movq %r9, %rax
+ movq %r9, %rcx
/* indirect jump to context */
jmp *%r10
.seh_endproc
.section .drectve
-.ascii " -export:\"jump_fcontext\""
+.ascii " -export:\"yafl_switch\""
diff --git a/src/asm/x86_64/jump_x86_64_ms_pe_masm.asm b/src/asm/x86_64/switch_x86_64_ms_pe_masm.asm
similarity index 94%
rename from src/asm/x86_64/jump_x86_64_ms_pe_masm.asm
rename to src/asm/x86_64/switch_x86_64_ms_pe_masm.asm
index 4d3980d..3dfaa87 100644
--- a/src/asm/x86_64/jump_x86_64_ms_pe_masm.asm
+++ b/src/asm/x86_64/switch_x86_64_ms_pe_masm.asm
@@ -89,7 +89,7 @@ ENDIF
.code
-jump_fcontext PROC BOOST_CONTEXT_EXPORT FRAME
+yafl_switch PROC BOOST_CONTEXT_EXPORT FRAME
.endprolog
; prepare stack
@@ -137,12 +137,12 @@ ENDIF
mov [rsp+0100h], rbx ; save RBX
mov [rsp+0108h], rbp ; save RBP
- mov [rsp+0110h], rcx ; save hidden address of transport_t
+ ; save current context through the first argument pointer
+ mov r9, r8
+ mov rax, rsp
+ mov [rcx], rax
- ; preserve RSP (pointing to context-data) in R9
- mov r9, rsp
-
- ; restore RSP (pointing to context-data) from RDX
+ ; restore target context from the second argument
mov rsp, rdx
IFNDEF BOOST_USE_TSX
@@ -187,24 +187,17 @@ ENDIF
mov rbx, [rsp+0100h] ; restore RBX
mov rbp, [rsp+0108h] ; restore RBP
- mov rax, [rsp+0110h] ; restore hidden address of transport_t
-
; prepare stack
lea rsp, [rsp+0118h]
; load return-address
pop r10
- ; transport_t returned in RAX
- ; return parent fcontext_t
- mov [rax], r9
- ; return data
- mov [rax+08h], r8
-
- ; transport_t as 1.arg of context-function
- mov rcx, rax
+ ; return and pass data directly
+ mov rax, r9
+ mov rcx, r9
; indirect jump to context
jmp r10
-jump_fcontext ENDP
+yafl_switch ENDP
END
diff --git a/src/asm/x86_64/jump_x86_64_sysv_elf_gas.S b/src/asm/x86_64/switch_x86_64_sysv_elf_gas.S
similarity index 87%
rename from src/asm/x86_64/jump_x86_64_sysv_elf_gas.S
rename to src/asm/x86_64/switch_x86_64_sysv_elf_gas.S
index 2eff59a..03ba81e 100644
--- a/src/asm/x86_64/jump_x86_64_sysv_elf_gas.S
+++ b/src/asm/x86_64/switch_x86_64_sysv_elf_gas.S
@@ -43,11 +43,11 @@
# endif
.file "jump_x86_64_sysv_elf_gas.S"
.text
-.globl jump_fcontext
-.hidden jump_fcontext
-.type jump_fcontext,@function
+.globl yafl_switch
+.hidden yafl_switch
+.type yafl_switch,@function
.align 16
-jump_fcontext:
+yafl_switch:
_CET_ENDBR
leaq -0x40(%rsp), %rsp /* prepare stack */
@@ -76,11 +76,13 @@ jump_fcontext:
movq %rcx, (%rsp)
# endif
- /* store RSP (pointing to context-data) in RAX */
+ /* save current context through the first argument pointer */
+ movq %rdx, %r9
movq %rsp, %rax
+ movq %rax, (%rdi)
- /* restore RSP (pointing to context-data) from RDI */
- movq %rdi, %rsp
+ /* restore target context from the second argument */
+ movq %rsi, %rsp
#if BOOST_CONTEXT_SHADOW_STACK
/* first 8 bytes are SSP */
@@ -93,7 +95,7 @@ jump_fcontext:
/* on previous shadow stack after saveprevssp */
saveprevssp
- /* when return, jump_fcontext jump to restored return address */
+ /* when return, yafl_switch jump to restored return address */
/* (r8) instead of RET. This miss of RET implies us to unwind */
/* shadow stack accordingly. Otherwise mismatch occur */
movq $1, %rcx
@@ -121,26 +123,13 @@ jump_fcontext:
leaq 0x48(%rsp), %rsp /* prepare stack */
- /* return transfer_t from jump */
-#if !defined(_ILP32)
- /* RAX == fctx, RDX == data */
- movq %rsi, %rdx
-#else
- /* RAX == data:fctx */
- salq $32, %rsi
- orq %rsi, %rax
-#endif
- /* pass transfer_t as first arg in context function */
-#if !defined(_ILP32)
- /* RDI == fctx, RSI == data */
-#else
- /* RDI == data:fctx */
-#endif
- movq %rax, %rdi
+ /* return and pass data directly */
+ movq %r9, %rax
+ movq %r9, %rdi
/* indirect jump to context */
jmp *%r8
-.size jump_fcontext,.-jump_fcontext
+.size yafl_switch,.-yafl_switch
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/x86_64/jump_x86_64_sysv_macho_gas.S b/src/asm/x86_64/switch_x86_64_sysv_macho_gas.S
similarity index 87%
rename from src/asm/x86_64/jump_x86_64_sysv_macho_gas.S
rename to src/asm/x86_64/switch_x86_64_sysv_macho_gas.S
index 673daa6..cc41330 100644
--- a/src/asm/x86_64/jump_x86_64_sysv_macho_gas.S
+++ b/src/asm/x86_64/switch_x86_64_sysv_macho_gas.S
@@ -25,10 +25,10 @@
****************************************************************************************/
.text
-.private_extern _jump_fcontext
-.globl _jump_fcontext
+.private_extern _yafl_switch
+.globl _yafl_switch
.align 8
-_jump_fcontext:
+_yafl_switch:
leaq -0x38(%rsp), %rsp /* prepare stack */
#if !defined(BOOST_USE_TSX)
@@ -43,11 +43,13 @@ _jump_fcontext:
movq %rbx, 0x28(%rsp) /* save RBX */
movq %rbp, 0x30(%rsp) /* save RBP */
- /* store RSP (pointing to context-data) in RAX */
+ /* save current context through the first argument pointer */
+ movq %rdx, %r9
movq %rsp, %rax
+ movq %rax, (%rdi)
- /* restore RSP (pointing to context-data) from RDI */
- movq %rdi, %rsp
+ /* restore target context from the second argument */
+ movq %rsi, %rsp
movq 0x38(%rsp), %r8 /* restore return-address */
@@ -65,12 +67,9 @@ _jump_fcontext:
leaq 0x40(%rsp), %rsp /* prepare stack */
- /* return transfer_t from jump */
- /* RAX == fctx, RDX == data */
- movq %rsi, %rdx
- /* pass transfer_t as first arg in context function */
- /* RDI == fctx, RSI == data */
- movq %rax, %rdi
+ /* return and pass data directly */
+ movq %r9, %rax
+ movq %r9, %rdi
/* indirect jump to context */
jmp *%r8
diff --git a/src/yafl.c b/src/yafl.c
index e035ea6..2350b37 100644
--- a/src/yafl.c
+++ b/src/yafl.c
@@ -26,38 +26,41 @@
#include "yafl.h"
-/* ========================================================================
- * Low-Level API (Internal Only)
- * ======================================================================== */
/* Raw context handle - opaque pointer to saved machine state */
typedef struct yafl_opaque_t *yafl_t;
-/* Raw transfer between contexts */
-typedef struct {
- yafl_t prev_context;
- void *data;
-} yafl_transfer_t;
-
/* Raw entry function type for low-level API */
-typedef void (*yafl_entry_t)(yafl_transfer_t);
+typedef void (*yafl_entry_t)(void *);
/* Low-level assembly-implemented functions */
-extern yafl_t make_fcontext(void *sp, size_t size, yafl_entry_t fn);
-extern yafl_transfer_t jump_fcontext(yafl_t const to, void *vp);
-/* ========================================================================
- * Constants and Types
- * ======================================================================== */
+/**
+ * @brief Create the initial saved context for a fiber stack.
+ *
+ * @param sp Top of the stack region.
+ * @param size Size of the usable stack region in bytes.
+ * @param fn Entry function that will run on the new context.
+ * @return Saved low-level context handle, or NULL on failure.
+ */
+extern yafl_t yafl_make_context(void *sp, size_t size, yafl_entry_t fn);
-#define FCONTEXT_FIBER_MAGIC 0xF1BE7001
-#define FCONTEXT_STACK_WATERMARK 0xA5
-#define FCONTEXT_STACK_ALIGNMENT 16
+/**
+ * @brief Switch execution from one context to another.
+ *
+ * @param save Receives the current context before switching away.
+ * @param target Context to resume.
+ * @param data User data passed across the switch.
+ * @return User data returned when control switches back.
+ */
+extern void *yafl_switch(yafl_t *save, yafl_t target, void *data);
+
+/* Constants and types */
+#define YAFL_FIBER_MAGIC 0xF1BE7001
+#define YAFL_STACK_WATERMARK 0xA5
+#define YAFL_STACK_ALIGNMENT 16
-typedef enum {
- FCONTEXT_ALLOC_MALLOC,
- FCONTEXT_ALLOC_VMEM
-} yafl_alloc_type_t;
+typedef enum { YAFL_ALLOC_MALLOC, YAFL_ALLOC_VMEM } yafl_alloc_type_t;
/* Internal fiber structure */
struct yafl_fiber {
@@ -73,13 +76,12 @@ struct yafl_fiber {
bool watermark_filled;
/* Context tracking */
- yafl_t context; /* Fiber's saved context */
- yafl_t resumer_context; /* Context to return to */
+ yafl_t context; /* Fiber's saved context */
+ yafl_t resumer_context; /* Context to return to */
/* User entry and result */
yafl_fiber_fn user_entry;
void *cached_result;
- void *pending_arg; /* Argument for next resume */
};
/* Typedef for internal use */
@@ -88,49 +90,86 @@ typedef struct yafl_fiber yafl_fiber_t;
/* Thread-local storage */
static _Thread_local yafl_fiber_t *tls_current_fiber = NULL;
-/* ========================================================================
- * Utility Functions
- * ======================================================================== */
+static void fiber_entry_trampoline(void *arg);
-static size_t get_page_size(void) {
+/**
+ * @brief Release any stack memory owned by a fiber.
+ *
+ * @param fiber Fiber whose stack allocation should be freed.
+ */
+static void free_fiber_stack(yafl_fiber_t *fiber) {
+ if(fiber == NULL || fiber->stack_region == NULL) { return; }
+
+ if(fiber->alloc_type == YAFL_ALLOC_MALLOC) {
+ free(fiber->stack_region);
+ } else if(fiber->alloc_type == YAFL_ALLOC_VMEM) {
#ifdef _WIN32
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- return (size_t)si.dwPageSize;
+ VirtualFree(fiber->stack_region, 0, MEM_RELEASE);
#else
- long page_size = sysconf(_SC_PAGE_SIZE);
- if (page_size <= 0) {
- return 4096;
- }
- return (size_t)page_size;
+ munmap(fiber->stack_region, fiber->stack_total_size);
#endif
+ }
+
+ fiber->stack_region = NULL;
+ fiber->stack_total_size = 0;
+ fiber->stack_top = NULL;
+ fiber->stack_size = 0;
}
-static void *align_stack_pointer(void *ptr) {
- uintptr_t addr = (uintptr_t)ptr;
- return (void *)(addr & ~(FCONTEXT_STACK_ALIGNMENT - 1));
+/**
+ * @brief Create the initial low-level context for a fiber.
+ *
+ * @param fiber Fiber whose stack should be prepared for first entry.
+ * @return true if the context was created successfully, otherwise false.
+ */
+static bool initialize_fiber_context(yafl_fiber_t *fiber) {
+ fiber->context = yafl_make_context(fiber->stack_top, fiber->stack_size, fiber_entry_trampoline);
+ return fiber->context != NULL;
}
-/* ========================================================================
- * Trampoline: Adapts Low-Level API to High-Level Fiber API
- * ======================================================================== */
-/*
- * This is called as the entry function by make_fcontext().
- * It wraps the user's entry function, manages state, and handles the result.
+/**
+ * @brief Fill a fiber stack with the watermark byte and rebuild its context.
+ *
+ * @param fiber Fiber whose stack should be watermarked.
+ * @return true if the context was rebuilt successfully, otherwise false.
+ */
+static bool reinitialize_fiber_context_with_watermark(yafl_fiber_t *fiber) {
+ memset((char *)fiber->stack_top - fiber->stack_size, YAFL_STACK_WATERMARK, fiber->stack_size);
+ return initialize_fiber_context(fiber);
+}
+
+
+/**
+ * @brief Align a stack pointer down to the required stack alignment.
+ *
+ * @param ptr Unaligned stack pointer candidate.
+ * @return Aligned stack pointer.
*/
-static void fiber_entry_trampoline(yafl_transfer_t t) {
- yafl_fiber_t *fiber = (yafl_fiber_t *)t.data;
+static inline void *align_stack_pointer(void *ptr) {
+ uintptr_t addr = (uintptr_t)ptr;
+ return (void *)(addr & ~((uintptr_t)YAFL_STACK_ALIGNMENT - 1));
+}
- /* Save resumer's context (who called resume on us) */
- fiber->resumer_context = t.prev_context;
+
+/**
+ * @brief Enter a fiber through the low-level context trampoline.
+ *
+ * Calls the user entry function, updates fiber state, caches the final
+ * result, and switches back to the resumer.
+ *
+ * @param arg Argument supplied by the first resume into the fiber.
+ */
+static void fiber_entry_trampoline(void *arg) {
+ yafl_fiber_t *fiber = tls_current_fiber;
+ if(fiber == NULL) { abort(); }
/* Update status and TLS */
fiber->status = YAFL_FIBER_STATUS_RUNNING;
tls_current_fiber = fiber;
/* Call user entry with argument from first resume */
- void *result = fiber->user_entry(fiber->pending_arg);
+ void *result = fiber->user_entry(arg);
/* Mark complete and cache result */
fiber->status = YAFL_FIBER_STATUS_COMPLETE;
@@ -138,56 +177,56 @@ static void fiber_entry_trampoline(yafl_transfer_t t) {
tls_current_fiber = NULL;
/* Return to resumer with final result */
- jump_fcontext(fiber->resumer_context, result);
+ yafl_switch(&fiber->context, fiber->resumer_context, result);
/* Should never reach here */
+ abort();
}
-/* ========================================================================
- * Fiber Creation
- * ======================================================================== */
-extern yafl_fiber_t *yafl_fiber_create(yafl_fiber_fn fiber_fn, size_t stack_size,
- yafl_stack_flags_t flags) {
+/**
+ * @brief Create a fiber and allocate its backing stack.
+ *
+ * @param fiber_fn User entry function for the new fiber.
+ * @param stack_size Requested stack size in bytes, or 0 for the default.
+ * @param flags Stack allocation and feature flags.
+ * @return Newly created fiber, or NULL on failure.
+ */
+extern yafl_fiber_t *yafl_fiber_create(yafl_fiber_fn fiber_fn, size_t stack_size, yafl_stack_flags_t flags) {
/* Validate fiber function is not NULL */
- if (fiber_fn == NULL) {
- return NULL;
- }
+ if(fiber_fn == NULL) { return NULL; }
/* Validate exactly one allocation type is set */
int alloc_flags = flags & (YAFL_STACK_FLAGS_MALLOC | YAFL_STACK_FLAGS_VMEM);
- if (alloc_flags != YAFL_STACK_FLAGS_MALLOC && alloc_flags != YAFL_STACK_FLAGS_VMEM) {
- return NULL;
- }
+ if(alloc_flags != YAFL_STACK_FLAGS_MALLOC && alloc_flags != YAFL_STACK_FLAGS_VMEM) { return NULL; }
bool use_vmem = (flags & YAFL_STACK_FLAGS_VMEM) != 0;
bool use_watermark = (flags & YAFL_STACK_FLAGS_WATERMARK) != 0;
/* Allocate fiber structure */
yafl_fiber_t *fiber = malloc(sizeof(yafl_fiber_t));
- if (fiber == NULL) {
- return NULL;
- }
+ if(fiber == NULL) { return NULL; }
/* Initialize fiber structure */
- fiber->magic = FCONTEXT_FIBER_MAGIC;
- fiber->alloc_type = use_vmem ? FCONTEXT_ALLOC_VMEM : FCONTEXT_ALLOC_MALLOC;
+ fiber->magic = YAFL_FIBER_MAGIC;
+ fiber->alloc_type = use_vmem ? YAFL_ALLOC_VMEM : YAFL_ALLOC_MALLOC;
fiber->status = YAFL_FIBER_STATUS_SUSPENDED;
fiber->user_entry = fiber_fn;
fiber->cached_result = NULL;
- fiber->pending_arg = NULL;
fiber->watermark_filled = use_watermark;
fiber->context = NULL;
fiber->resumer_context = NULL;
+ fiber->stack_region = NULL;
+ fiber->stack_total_size = 0;
+ fiber->stack_top = NULL;
+ fiber->stack_size = 0;
/* Use default stack size if not specified */
- if (stack_size == 0) {
- stack_size = FCONTEXT_DEFAULT_STACK_SIZE;
- }
+ if(stack_size == 0) { stack_size = YAFL_DEFAULT_STACK_SIZE; }
/* Allocate stack based on allocation type */
- if (use_vmem) {
- size_t page_size = get_page_size();
+ if(use_vmem) {
+ size_t page_size = yafl_get_page_size();
size_t stack_with_overhead = stack_size + 256;
size_t aligned_stack_size = ((stack_with_overhead + page_size - 1) / page_size) * page_size;
size_t guard_size = page_size;
@@ -196,228 +235,178 @@ extern yafl_fiber_t *yafl_fiber_create(yafl_fiber_fn fiber_fn, size_t stack_size
void *region = NULL;
#ifdef _WIN32
region = VirtualAlloc(NULL, total_size, MEM_RESERVE, PAGE_NOACCESS);
- if (region == NULL) {
- free(fiber);
- return NULL;
- }
+ if(region == NULL) { goto create_fail; }
+ fiber->stack_region = region;
+ fiber->stack_total_size = total_size;
void *stack_base = (char *)region + guard_size;
- if (!VirtualAlloc(stack_base, aligned_stack_size, MEM_COMMIT, PAGE_READWRITE)) {
- VirtualFree(region, 0, MEM_RELEASE);
- free(fiber);
- return NULL;
- }
+ if(!VirtualAlloc(stack_base, aligned_stack_size, MEM_COMMIT, PAGE_READWRITE)) { goto create_fail; }
#else
region = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (region == MAP_FAILED) {
- free(fiber);
- return NULL;
- }
- if (mprotect(region, guard_size, PROT_NONE) == -1) {
- munmap(region, total_size);
- free(fiber);
- return NULL;
- }
- if (mprotect((char *)region + guard_size + aligned_stack_size, guard_size, PROT_NONE) == -1) {
- munmap(region, total_size);
- free(fiber);
- return NULL;
- }
+ if(region == MAP_FAILED) { goto create_fail; }
+ fiber->stack_region = region;
+ fiber->stack_total_size = total_size;
+ if(mprotect(region, guard_size, PROT_NONE) == -1) { goto create_fail; }
+ if(mprotect((char *)region + guard_size + aligned_stack_size, guard_size, PROT_NONE) == -1) { goto create_fail; }
void *stack_base = (char *)region + guard_size;
#endif
void *stack_region_end = (char *)stack_base + aligned_stack_size;
void *stack_top = (char *)stack_region_end - 256;
stack_top = align_stack_pointer(stack_top);
- size_t actual_stack_size = (char *)stack_top - (char *)stack_base;
+ size_t actual_stack_size = (uintptr_t)(intptr_t)((char *)stack_top - (char *)stack_base);
- fiber->stack_region = region;
- fiber->stack_total_size = total_size;
fiber->stack_top = stack_top;
fiber->stack_size = actual_stack_size;
} else {
/* malloc allocation */
size_t allocated_size = stack_size + 256;
void *block = malloc(allocated_size);
- if (block == NULL) {
- free(fiber);
- return NULL;
- }
+ if(block == NULL) { goto create_fail; }
+ fiber->stack_region = block;
+ fiber->stack_total_size = allocated_size;
void *block_end = (char *)block + allocated_size;
void *stack_top = (char *)block_end - 256;
stack_top = align_stack_pointer(stack_top);
- size_t actual_stack_size = (char *)stack_top - (char *)block;
+ size_t actual_stack_size = (uintptr_t)(intptr_t)((char *)stack_top - (char *)block);
- fiber->stack_region = block;
- fiber->stack_total_size = allocated_size;
fiber->stack_top = stack_top;
fiber->stack_size = actual_stack_size;
}
/* Initialize the low-level context with trampoline as entry */
- fiber->context = make_fcontext(fiber->stack_top, fiber->stack_size, fiber_entry_trampoline);
- if (fiber->context == NULL) {
- if (use_vmem) {
-#ifdef _WIN32
- VirtualFree(fiber->stack_region, 0, MEM_RELEASE);
-#else
- munmap(fiber->stack_region, fiber->stack_total_size);
-#endif
- } else {
- free(fiber->stack_region);
- }
- free(fiber);
- return NULL;
- }
+ if(!initialize_fiber_context(fiber)) { goto create_fail; }
/* Apply watermark if requested */
- if (use_watermark) {
- memset((char *)fiber->stack_top - fiber->stack_size, FCONTEXT_STACK_WATERMARK, fiber->stack_size);
- /* Reinitialize context after watermark (overwrites filled area) */
- fiber->context = make_fcontext(fiber->stack_top, fiber->stack_size, fiber_entry_trampoline);
- if (fiber->context == NULL) {
- if (use_vmem) {
-#ifdef _WIN32
- VirtualFree(fiber->stack_region, 0, MEM_RELEASE);
-#else
- munmap(fiber->stack_region, fiber->stack_total_size);
-#endif
- } else {
- free(fiber->stack_region);
- }
- free(fiber);
- return NULL;
- }
+ if(use_watermark) {
+ if(!reinitialize_fiber_context_with_watermark(fiber)) { goto create_fail; }
}
return fiber;
-}
-/* ========================================================================
- * Fiber Control Flow
- * ======================================================================== */
+create_fail:
+ free_fiber_stack(fiber);
+ free(fiber);
+ return NULL;
+}
+/**
+ * @brief Resume a suspended fiber.
+ *
+ * @param fiber Fiber to resume.
+ * @param arg Argument delivered to the fiber.
+ * @return Value yielded or returned by the fiber, or NULL on error.
+ */
extern void *yafl_fiber_resume(yafl_fiber_t *fiber, void *arg) {
/* Validation */
- if (fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC) {
- return NULL;
- }
+ if(fiber == NULL || fiber->magic != YAFL_FIBER_MAGIC) { return NULL; }
/* If complete, return cached result (idempotent) */
- if (fiber->status == YAFL_FIBER_STATUS_COMPLETE) {
- return fiber->cached_result;
- }
+ if(fiber->status == YAFL_FIBER_STATUS_COMPLETE) { return fiber->cached_result; }
/* Cannot resume running fiber */
- if (fiber->status == YAFL_FIBER_STATUS_RUNNING) {
- return NULL;
- }
-
- /* Store argument for delivery */
- fiber->pending_arg = arg;
+ if(fiber->status == YAFL_FIBER_STATUS_RUNNING) { return NULL; }
/* Update status and TLS */
fiber->status = YAFL_FIBER_STATUS_RUNNING;
tls_current_fiber = fiber;
- /* Pass fiber pointer to trampoline on first resume */
- void *transfer_data = (void *)fiber;
-
/* Perform context switch */
- yafl_transfer_t t = jump_fcontext(fiber->context, transfer_data);
+ void *result = yafl_switch(&fiber->resumer_context, fiber->context, arg);
- /* Back in resumer - update fiber's context for next resume */
- fiber->context = t.prev_context;
+ /* Back in resumer */
tls_current_fiber = NULL;
- return t.data;
+ return result;
}
+/**
+ * @brief Suspend the current fiber and return control to its resumer.
+ *
+ * @param result Value yielded back to the resumer.
+ * @return Argument supplied by the next resume call, or NULL on error.
+ */
extern void *yafl_fiber_suspend(void *result) {
yafl_fiber_t *current = tls_current_fiber;
/* Must be in a fiber */
- if (current == NULL) {
- return NULL;
- }
+ if(current == NULL) { return NULL; }
/* Update status */
current->status = YAFL_FIBER_STATUS_SUSPENDED;
/* Switch back to resumer */
- yafl_transfer_t t = jump_fcontext(current->resumer_context, result);
+ void *arg = yafl_switch(¤t->context, current->resumer_context, result);
/* When resumed - restore state */
current->status = YAFL_FIBER_STATUS_RUNNING;
- current->resumer_context = t.prev_context;
tls_current_fiber = current;
/* Return argument passed to resume */
- return current->pending_arg;
+ return arg;
}
-/* ========================================================================
- * Fiber Status and Monitoring
- * ======================================================================== */
-
+/**
+ * @brief Query the status of a fiber.
+ *
+ * @param fiber Fiber to inspect.
+ * @return Current fiber status, or YAFL_FIBER_STATUS_ERR on invalid input.
+ */
extern yafl_fiber_status_t yafl_fiber_status(yafl_fiber_t *fiber) {
- if (fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC) {
- return YAFL_FIBER_STATUS_ERR;
- }
+ if(fiber == NULL || fiber->magic != YAFL_FIBER_MAGIC) { return YAFL_FIBER_STATUS_ERR; }
return fiber->status;
}
+/**
+ * @brief Measure the maximum observed stack usage for a watermarked fiber.
+ *
+ * @param fiber Fiber to inspect.
+ * @return Number of bytes used, or 0 if watermarking is unavailable.
+ */
extern size_t yafl_fiber_stack_high_watermark(yafl_fiber_t *fiber) {
- if (fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC || !fiber->watermark_filled) {
- return 0;
- }
+ if(fiber == NULL || fiber->magic != YAFL_FIBER_MAGIC || !fiber->watermark_filled) { return 0; }
/* Scan from stack base for watermark bytes */
unsigned char *stack_base = (unsigned char *)fiber->stack_top - fiber->stack_size;
size_t unused = 0;
- while (unused < fiber->stack_size && stack_base[unused] == FCONTEXT_STACK_WATERMARK) {
- unused++;
- }
+ while(unused < fiber->stack_size && stack_base[unused] == YAFL_STACK_WATERMARK) { unused++; }
return fiber->stack_size - unused;
}
-/* ========================================================================
- * Cleanup
- * ======================================================================== */
-
+/**
+ * @brief Destroy a fiber and release any owned resources.
+ *
+ * @param fiber Fiber to destroy.
+ */
extern void yafl_fiber_destroy(yafl_fiber_t *fiber) {
- if (fiber == NULL || fiber->magic != FCONTEXT_FIBER_MAGIC) {
- return;
- }
+ if(fiber == NULL || fiber->magic != YAFL_FIBER_MAGIC) { return; }
/* Cannot destroy running fiber */
- if (fiber->status == YAFL_FIBER_STATUS_RUNNING) {
- return;
- }
+ if(fiber->status == YAFL_FIBER_STATUS_RUNNING) { return; }
- /* Free stack based on allocation type */
- if (fiber->alloc_type == FCONTEXT_ALLOC_MALLOC) {
- free(fiber->stack_region);
- } else if (fiber->alloc_type == FCONTEXT_ALLOC_VMEM) {
-#ifdef _WIN32
- VirtualFree(fiber->stack_region, 0, MEM_RELEASE);
-#else
- munmap(fiber->stack_region, fiber->stack_total_size);
-#endif
- }
+ free_fiber_stack(fiber);
/* Invalidate and free */
fiber->magic = 0;
free(fiber);
}
-/* ========================================================================
- * Utilities
- * ======================================================================== */
-
+/**
+ * @brief Return the host page size.
+ *
+ * @return System page size in bytes.
+ */
extern size_t yafl_get_page_size(void) {
- return get_page_size();
+#ifdef _WIN32
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return (size_t)si.dwPageSize;
+#else
+ long page_size = sysconf(_SC_PAGE_SIZE);
+ if(page_size <= 0) { return 4096; }
+ return (size_t)page_size;
+#endif
}
diff --git a/test_struct_size b/test_struct_size
deleted file mode 100755
index b739de0..0000000
Binary files a/test_struct_size and /dev/null differ
diff --git a/test_struct_size.c b/test_struct_size.c
deleted file mode 100644
index af8c1c0..0000000
--- a/test_struct_size.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "include/yafl.h"
-#include
-
-int main() {
- printf("sizeof(yafl_stack_t) = %zu\n", sizeof(yafl_stack_t));
- printf("sizeof(uint32_t) = %zu\n", sizeof(uint32_t));
- printf("sizeof(yafl_alloc_type_t) = %zu\n", sizeof(yafl_alloc_type_t));
- printf("sizeof(size_t) = %zu\n", sizeof(size_t));
- printf("sizeof(bool) = %zu\n", sizeof(bool));
- printf("sizeof(void*) = %zu\n", sizeof(void *));
- printf("sizeof(yafl_t) = %zu\n", sizeof(yafl_t));
- return 0;
-}
diff --git a/tests/test_yafl_api.c b/tests/test_yafl_api.c
deleted file mode 100644
index dc8ac94..0000000
--- a/tests/test_yafl_api.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/**
- * test_yafl_api.c
- * Comprehensive API test
- *
- * Tests all API functions, error conditions, and edge cases.
- *
- * Copyright Kyle Hayes (2026)
- * Distributed under the Boost Software License, Version 1.0.
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "yafl.h"
-
-static int call_count = 0;
-
-void *simple_fiber(void *data) {
- call_count++;
- fprintf(stderr, "[fiber] called with data: %p\n", data);
- fflush(stderr);
- return (void *)0xABCD;
-}
-
-void *null_data_fiber(void *data) {
- fprintf(stderr, "[fiber] received NULL data: %p\n", data);
- fflush(stderr);
- assert(data == NULL);
- return NULL;
-}
-
-void *yielding_fiber(void *data) {
- fprintf(stderr, "[fiber] first call, data: %p\n", data);
- fflush(stderr);
- assert(data == (void *)0x1);
-
- void *result = yafl_fiber_yield((void *)0x2);
- fprintf(stderr, "[fiber] resumed with: %p\n", result);
- fflush(stderr);
- assert(result == (void *)0x3);
-
- return (void *)0x4;
-}
-
-void *multi_yield_fiber(void *data) {
- (void)data;
- fprintf(stderr, "[multi_yield] starting\n");
- fflush(stderr);
-
- /* Multiple consecutive yields */
- for(int i = 0; i < 5; i++) {
- fprintf(stderr, "[multi_yield] yield %d\n", i);
- fflush(stderr);
- yafl_fiber_yield((void *)(uintptr_t)(0x100 + i));
- }
-
- fprintf(stderr, "[multi_yield] finishing\n");
- fflush(stderr);
- return (void *)0x999;
-}
-
-int main(void) {
- fprintf(stderr, "=== yafl Comprehensive API Test ===\n");
- fflush(stderr);
-
- /* Test: yafl_get_page_size() */
- fprintf(stderr, "\n[test] yafl_get_page_size()\n");
- fflush(stderr);
- size_t page_size = yafl_get_page_size();
- fprintf(stderr, "[test] page size: %zu bytes\n", page_size);
- fflush(stderr);
- assert(page_size > 0);
- assert(page_size >= 4096);
-
- /* Test: Explicit thread conversion */
- fprintf(stderr, "\n[test] explicit thread conversion\n");
- fflush(stderr);
- assert(!yafl_fiber_is_thread_converted());
- yafl_fiber_t *thread_fiber = yafl_fiber_convert_thread();
- assert(thread_fiber != NULL);
- assert(yafl_fiber_is_thread_converted());
- assert(yafl_fiber_current() == thread_fiber);
- fprintf(stderr, "[test] thread converted: %p\n", (void *)thread_fiber);
- fflush(stderr);
-
- /* Test: Idempotent thread conversion */
- fprintf(stderr, "\n[test] idempotent thread conversion\n");
- fflush(stderr);
- yafl_fiber_t *thread_fiber2 = yafl_fiber_convert_thread();
- assert(thread_fiber2 == thread_fiber);
- fprintf(stderr, "[test] same fiber returned: %p\n", (void *)thread_fiber2);
- fflush(stderr);
-
- /* Test: Default stack size (0) */
- fprintf(stderr, "\n[test] default stack size\n");
- fflush(stderr);
- yafl_fiber_t *fiber_default = yafl_fiber_create_vmem(0, simple_fiber);
- assert(fiber_default != NULL);
- size_t default_size = yafl_fiber_get_stack_size(fiber_default);
- fprintf(stderr, "[test] default stack size: %zu bytes\n", default_size);
- fflush(stderr);
- assert(default_size > 0);
-
- /* Test: Fiber state transitions */
- fprintf(stderr, "\n[test] fiber state transitions\n");
- fflush(stderr);
- assert(yafl_fiber_get_state(fiber_default) == FCONTEXT_FIBER_CREATED);
- fprintf(stderr, "[test] state: CREATED\n");
- fflush(stderr);
-
- void *result = yafl_fiber_switch(fiber_default, (void *)0x99);
- assert(yafl_fiber_get_state(fiber_default) == FCONTEXT_FIBER_FINISHED);
- fprintf(stderr, "[test] state: FINISHED\n");
- fflush(stderr);
- assert(result == (void *)0xABCD);
- assert(call_count == 1);
-
- /* Test: Idempotent switch to finished fiber */
- fprintf(stderr, "\n[test] idempotent switch to finished fiber\n");
- fflush(stderr);
- result = yafl_fiber_switch(fiber_default, (void *)0x88);
- assert(result == (void *)0xABCD); /* Cached result */
- assert(call_count == 1); /* Not called again */
- fprintf(stderr, "[test] returned cached result, fiber not re-entered\n");
- fflush(stderr);
-
- /* Test: Destroy returns cached result */
- fprintf(stderr, "\n[test] destroy returns result\n");
- fflush(stderr);
- void *destroy_result = yafl_fiber_destroy(fiber_default);
- assert(destroy_result == (void *)0xABCD);
- fprintf(stderr, "[test] destroy returned: %p\n", destroy_result);
- fflush(stderr);
-
- /* Test: NULL data handling */
- fprintf(stderr, "\n[test] NULL as valid data\n");
- fflush(stderr);
- yafl_fiber_t *fiber_null = yafl_fiber_create_malloc(16 * 1024, null_data_fiber);
- assert(fiber_null != NULL);
- result = yafl_fiber_switch(fiber_null, NULL);
- assert(result == NULL); /* NULL is valid return value */
- fprintf(stderr, "[test] NULL data passed and returned correctly\n");
- fflush(stderr);
- yafl_fiber_destroy(fiber_null);
-
- /* Test: yafl_fiber_get_caller() and yafl_fiber_current() */
- fprintf(stderr, "\n[test] get_caller() and current()\n");
- fflush(stderr);
- assert(yafl_fiber_current() == thread_fiber);
- assert(yafl_fiber_get_caller() == NULL); /* Thread fiber has no caller */
- fprintf(stderr, "[test] current: %p, caller: NULL\n", (void *)yafl_fiber_current());
- fflush(stderr);
-
- /* Test: Yield and state changes */
- fprintf(stderr, "\n[test] yield and state changes\n");
- fflush(stderr);
- yafl_fiber_t *fiber_yield = yafl_fiber_create_vmem(16 * 1024, yielding_fiber);
- assert(fiber_yield != NULL);
- assert(yafl_fiber_get_state(fiber_yield) == FCONTEXT_FIBER_CREATED);
-
- result = yafl_fiber_switch(fiber_yield, (void *)0x1);
- assert(result == (void *)0x2);
- assert(yafl_fiber_get_state(fiber_yield) == FCONTEXT_FIBER_SUSPENDED);
- fprintf(stderr, "[test] fiber yielded, state: SUSPENDED\n");
- fflush(stderr);
-
- result = yafl_fiber_switch(fiber_yield, (void *)0x3);
- assert(result == (void *)0x4);
- assert(yafl_fiber_get_state(fiber_yield) == FCONTEXT_FIBER_FINISHED);
- fprintf(stderr, "[test] fiber finished, state: FINISHED\n");
- fflush(stderr);
- yafl_fiber_destroy(fiber_yield);
-
- /* Test: Error conditions - NULL fiber */
- fprintf(stderr, "\n[test] error: switch to NULL fiber\n");
- fflush(stderr);
- result = yafl_fiber_switch(NULL, NULL);
- assert(result == NULL);
- fprintf(stderr, "[test] NULL fiber handled correctly\n");
- fflush(stderr);
-
- /* Test: Error conditions - get_state on NULL */
- fprintf(stderr, "\n[test] error: get_state on NULL\n");
- fflush(stderr);
- yafl_fiber_state_t state = yafl_fiber_get_state(NULL);
- assert(state == FCONTEXT_FIBER_CREATED); /* Safe default */
- fprintf(stderr, "[test] NULL fiber state handled correctly\n");
- fflush(stderr);
-
- /* Test: Error conditions - destroy NULL */
- fprintf(stderr, "\n[test] error: destroy NULL\n");
- fflush(stderr);
- destroy_result = yafl_fiber_destroy(NULL);
- assert(destroy_result == NULL);
- fprintf(stderr, "[test] destroy NULL handled correctly\n");
- fflush(stderr);
-
- /* Test: Watermark error conditions */
- fprintf(stderr, "\n[test] watermark error conditions\n");
- fflush(stderr);
- yafl_fiber_t *fiber_wm = yafl_fiber_create_vmem(16 * 1024, simple_fiber);
- assert(fiber_wm != NULL);
-
- /* Get usage without fill */
- size_t usage = yafl_fiber_get_stack_usage(fiber_wm);
- assert(usage == SIZE_MAX); /* Error return */
- fprintf(stderr, "[test] usage without fill: SIZE_MAX\n");
- fflush(stderr);
-
- /* Fill watermark */
- bool filled = yafl_fiber_fill_watermark(fiber_wm);
- assert(filled);
-
- /* Try to fill again (should fail, already filled) */
- filled = yafl_fiber_fill_watermark(fiber_wm);
- assert(!filled);
- fprintf(stderr, "[test] watermark cannot be re-filled\n");
- fflush(stderr);
-
- yafl_fiber_switch(fiber_wm, NULL);
- usage = yafl_fiber_get_stack_usage(fiber_wm);
- assert(usage != SIZE_MAX && usage > 0);
- fprintf(stderr, "[test] usage after fill: %zu bytes\n", usage);
- fflush(stderr);
- yafl_fiber_destroy(fiber_wm);
-
- /* Test: Create fiber with NULL entry */
- fprintf(stderr, "\n[test] error: create fiber with NULL entry\n");
- fflush(stderr);
- yafl_fiber_t *fiber_null_entry = yafl_fiber_create_vmem(16 * 1024, NULL);
- assert(fiber_null_entry == NULL);
- fiber_null_entry = yafl_fiber_create_malloc(16 * 1024, NULL);
- assert(fiber_null_entry == NULL);
- fprintf(stderr, "[test] NULL entry rejected correctly\n");
- fflush(stderr);
-
- /* Test: Thread fiber operations */
- fprintf(stderr, "\n[test] thread fiber operations\n");
- fflush(stderr);
-
- /* Get stack size of thread fiber (should be 0) */
- size_t thread_stack_size = yafl_fiber_get_stack_size(thread_fiber);
- assert(thread_stack_size == 0);
- fprintf(stderr, "[test] thread fiber stack size: 0\n");
- fflush(stderr);
-
- /* Try to destroy thread fiber (should fail) */
- destroy_result = yafl_fiber_destroy(thread_fiber);
- assert(destroy_result == NULL);
- assert(yafl_fiber_is_thread_converted()); /* Still converted */
- fprintf(stderr, "[test] cannot destroy thread fiber via yafl_fiber_destroy()\n");
- fflush(stderr);
-
- /* Try to fill watermark on thread fiber (should fail) */
- filled = yafl_fiber_fill_watermark(thread_fiber);
- assert(!filled);
- fprintf(stderr, "[test] cannot fill watermark on thread fiber\n");
- fflush(stderr);
-
- /* Test: Default stack size for malloc */
- fprintf(stderr, "\n[test] malloc default stack size\n");
- fflush(stderr);
- yafl_fiber_t *fiber_malloc_default = yafl_fiber_create_malloc(0, simple_fiber);
- assert(fiber_malloc_default != NULL);
- size_t malloc_default_size = yafl_fiber_get_stack_size(fiber_malloc_default);
- fprintf(stderr, "[test] malloc default stack size: %zu bytes\n", malloc_default_size);
- fflush(stderr);
- assert(malloc_default_size > 0);
- yafl_fiber_switch(fiber_malloc_default, NULL);
- yafl_fiber_destroy(fiber_malloc_default);
-
- /* Test: Both allocation types */
- fprintf(stderr, "\n[test] both allocation types\n");
- fflush(stderr);
- yafl_fiber_t *fiber_vmem = yafl_fiber_create_vmem(16 * 1024, simple_fiber);
- yafl_fiber_t *fiber_malloc = yafl_fiber_create_malloc(16 * 1024, simple_fiber);
- assert(fiber_vmem != NULL);
- assert(fiber_malloc != NULL);
- yafl_fiber_switch(fiber_vmem, NULL);
- yafl_fiber_switch(fiber_malloc, NULL);
- yafl_fiber_destroy(fiber_vmem);
- yafl_fiber_destroy(fiber_malloc);
- fprintf(stderr, "[test] both vmem and malloc work\n");
- fflush(stderr);
-
- /* Test: Small stack size */
- fprintf(stderr, "\n[test] small stack size (2KB)\n");
- fflush(stderr);
- yafl_fiber_t *fiber_small = yafl_fiber_create_malloc(2 * 1024, simple_fiber);
- if(fiber_small != NULL) {
- yafl_fiber_switch(fiber_small, NULL);
- yafl_fiber_destroy(fiber_small);
- fprintf(stderr, "[test] small stack works\n");
- fflush(stderr);
- } else {
- fprintf(stderr, "[test] small stack allocation failed (acceptable)\n");
- fflush(stderr);
- }
-
- /* Test: Multiple consecutive yields */
- fprintf(stderr, "\n[test] multiple consecutive yields\n");
- fflush(stderr);
- yafl_fiber_t *fiber_multi = yafl_fiber_create_vmem(16 * 1024, multi_yield_fiber);
- assert(fiber_multi != NULL);
-
- for(int i = 0; i < 5; i++) {
- result = yafl_fiber_switch(fiber_multi, NULL);
- assert(result == (void *)(uintptr_t)(0x100 + i));
- fprintf(stderr, "[test] received yield %d: %p\n", i, result);
- fflush(stderr);
- }
-
- result = yafl_fiber_switch(fiber_multi, NULL);
- assert(result == (void *)0x999);
- fprintf(stderr, "[test] fiber finished after 5 yields\n");
- fflush(stderr);
- yafl_fiber_destroy(fiber_multi);
-
- /* Test: Watermark on SUSPENDED fiber */
- fprintf(stderr, "\n[test] watermark on suspended fiber\n");
- fflush(stderr);
- yafl_fiber_t *fiber_wm_susp = yafl_fiber_create_vmem(16 * 1024, multi_yield_fiber);
- assert(fiber_wm_susp != NULL);
- yafl_fiber_fill_watermark(fiber_wm_susp);
-
- /* Run once and suspend */
- yafl_fiber_switch(fiber_wm_susp, NULL);
- assert(yafl_fiber_get_state(fiber_wm_susp) == FCONTEXT_FIBER_SUSPENDED);
-
- /* Get stack usage while suspended */
- usage = yafl_fiber_get_stack_usage(fiber_wm_susp);
- assert(usage != SIZE_MAX && usage > 0);
- fprintf(stderr, "[test] stack usage while SUSPENDED: %zu bytes\n", usage);
- fflush(stderr);
-
- /* Finish the fiber */
- while(yafl_fiber_get_state(fiber_wm_susp) != FCONTEXT_FIBER_FINISHED) {
- yafl_fiber_switch(fiber_wm_susp, NULL);
- }
- yafl_fiber_destroy(fiber_wm_susp);
-
- /* Cleanup */
- yafl_fiber_destroy_thread_fiber();
-
- /* Test: Yield from non-fiber context (must be last, after thread fiber destroyed) */
- fprintf(stderr, "\n[test] error: yield from non-fiber context\n");
- fflush(stderr);
- result = yafl_fiber_yield((void *)0xBAD);
- assert(result == NULL);
- fprintf(stderr, "[test] yield from non-fiber context returned NULL\n");
- fflush(stderr);
-
- fprintf(stderr, "\nPASS: All API functions and error conditions tested\n");
- fflush(stderr);
- return 0;
-}
diff --git a/tests/test_yafl_guard.c b/tests/test_yafl_guard.c
index 6475d43..744ee24 100644
--- a/tests/test_yafl_guard.c
+++ b/tests/test_yafl_guard.c
@@ -181,8 +181,8 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "[main] child killed by signal %d\n", sig);
fflush(stderr);
- /* Expect SIGSEGV (11) or SIGBUS (7) for guard page fault */
- if (sig == SIGSEGV || sig == SIGBUS) {
+ /* Expect SIGSEGV (11) or SIGBUS (7) SIGILL (4) for guard page fault */
+ if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL) {
fprintf(stderr, "[main] guard page successfully detected stack overflow\n");
fflush(stderr);
} else {
diff --git a/tests/test_yafl_symmetric.c b/tests/test_yafl_symmetric.c
deleted file mode 100644
index 85ea7bb..0000000
--- a/tests/test_yafl_symmetric.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/**
- * test_yafl_symmetric.c
- * Symmetric coroutine switching test
- *
- * Verifies that two fibers can switch back and forth to each other
- * with interleaved execution. Tests that context switches occur at least
- * twice with proper call ordering.
- *
- * Copyright Kyle Hayes (2026)
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- */
-
-#include "yafl.h"
-#include
-#include
-#include
-#include
-
-/* Track execution order to verify interleaving */
-#define MAX_EVENTS 16
-static size_t event_count = 0;
-static uint32_t events[MAX_EVENTS];
-
-/* Event identifiers */
-#define EVENT_MAIN_START 1
-#define EVENT_MAIN_TO_A 2
-#define EVENT_A_ENTER 3
-#define EVENT_A_TO_B 4
-#define EVENT_B_ENTER 5
-#define EVENT_B_TO_A 6
-#define EVENT_A_RESUME 7
-#define EVENT_A_TO_B_AGAIN 8
-#define EVENT_B_RESUME 9
-#define EVENT_B_TO_A_AGAIN 10
-#define EVENT_A_DONE 11
-#define EVENT_MAIN_END 12
-
-/* Fiber handle for symmetric switching */
-static yafl_fiber_t *fiber_b = NULL;
-
-static void record_event(uint32_t event) {
- if(event_count < MAX_EVENTS) { events[event_count++] = event; }
- fprintf(stderr, " [event] #%zu: %u\n", event_count, event);
- fflush(stderr);
-}
-
-/**
- * Fiber B - called by fiber A
- */
-void *fiber_b_entry(void *initial_data) {
- fprintf(stderr, "[fiber_b] entered with data: %p\n", initial_data);
- fflush(stderr);
- record_event(EVENT_B_ENTER);
-
- /* Yield back to caller (fiber A) */
- fprintf(stderr, "[fiber_b] yielding back to A\n");
- fflush(stderr);
- record_event(EVENT_B_TO_A);
- void *resumed_data = yafl_fiber_yield((void *)(uintptr_t)0xB0B0B0B0);
-
- fprintf(stderr, "[fiber_b] resumed from A with data: %p\n", resumed_data);
- fflush(stderr);
- assert(resumed_data == (void *)(uintptr_t)0xA1A1A1A1);
- record_event(EVENT_B_RESUME);
-
- /* Yield again */
- fprintf(stderr, "[fiber_b] yielding back to A again\n");
- fflush(stderr);
- record_event(EVENT_B_TO_A_AGAIN);
- yafl_fiber_yield((void *)(uintptr_t)0xB1B1B1B1);
-
- fprintf(stderr, "[fiber_b] finishing\n");
- fflush(stderr);
- return (void *)(uintptr_t)0xBBBBBBBB;
-}
-
-/**
- * Fiber A - calls fiber B, then gets called back
- */
-void *fiber_a_entry(void *initial_data) {
- fprintf(stderr, "[fiber_a] entered with data: %p\n", initial_data);
- fflush(stderr);
- record_event(EVENT_A_ENTER);
-
- assert(fiber_b != NULL);
- fprintf(stderr, "[fiber_a] have fiber_b: %p\n", (void *)fiber_b);
- fflush(stderr);
-
- /* First switch: call fiber B */
- fprintf(stderr, "[fiber_a] calling fiber B\n");
- fflush(stderr);
- record_event(EVENT_A_TO_B);
- void *result = yafl_fiber_switch(fiber_b, (void *)(uintptr_t)0xDEADBEEF);
-
- fprintf(stderr, "[fiber_a] B returned with: %p\n", result);
- fflush(stderr);
- assert(result == (void *)(uintptr_t)0xB0B0B0B0);
- record_event(EVENT_A_RESUME);
-
- /* Second switch: call fiber B again */
- fprintf(stderr, "[fiber_a] calling fiber B again\n");
- fflush(stderr);
- record_event(EVENT_A_TO_B_AGAIN);
- result = yafl_fiber_switch(fiber_b, (void *)(uintptr_t)0xA1A1A1A1);
-
- fprintf(stderr, "[fiber_a] B returned again with: %p\n", result);
- fflush(stderr);
- assert(result == (void *)(uintptr_t)0xB1B1B1B1);
- record_event(EVENT_A_DONE);
-
- fprintf(stderr, "[fiber_a] finishing\n");
- fflush(stderr);
- return (void *)(uintptr_t)0xAAAAAAAA;
-}
-
-int main(void) {
- fprintf(stderr, "=== yafl Symmetric Fiber Test ===\n");
- fflush(stderr);
- record_event(EVENT_MAIN_START);
-
- /* Create fibers */
- fprintf(stderr, "[main] creating fiber A\n");
- fflush(stderr);
- yafl_fiber_t *fiber_a = yafl_fiber_create_vmem(24 * 1024, fiber_a_entry);
- assert(fiber_a != NULL);
-
- fprintf(stderr, "[main] creating fiber B\n");
- fflush(stderr);
- fiber_b = yafl_fiber_create_vmem(24 * 1024, fiber_b_entry);
- assert(fiber_b != NULL);
-
- fprintf(stderr, "[main] entering fiber A\n");
- fflush(stderr);
- record_event(EVENT_MAIN_TO_A);
- void *result = yafl_fiber_switch(fiber_a, (void *)(uintptr_t)0xCAFEBABE);
-
- fprintf(stderr, "[main] fiber A finished with result: %p\n", result);
- fflush(stderr);
- assert(result == (void *)(uintptr_t)0xAAAAAAAA);
-
- fprintf(stderr, "[main] cleaning up\n");
- fflush(stderr);
- yafl_fiber_destroy(fiber_a);
- yafl_fiber_destroy(fiber_b);
- yafl_fiber_destroy_thread_fiber();
- record_event(EVENT_MAIN_END);
-
- /* Verify interleaving */
- fprintf(stderr, "\n[main] verifying execution order\n");
- fflush(stderr);
- fprintf(stderr, "[main] total events recorded: %zu\n", event_count);
- fflush(stderr);
-
- assert(event_count >= 10);
- fprintf(stderr, "[main] event count check passed\n");
- fflush(stderr);
-
- /* Verify the sequence contains the required interleaving pattern */
- bool found_a_to_b = false;
- bool found_b_to_a = false;
- bool found_a_to_b_again = false;
- bool found_b_to_a_again = false;
-
- for(size_t i = 0; i < event_count; i++) {
- fprintf(stderr, "[main] event[%zu] = %u\n", i, events[i]);
- fflush(stderr);
-
- if(events[i] == EVENT_A_TO_B) {
- found_a_to_b = true;
- fprintf(stderr, "[main] found A->B switch\n");
- fflush(stderr);
- }
- if(events[i] == EVENT_B_TO_A && found_a_to_b) {
- found_b_to_a = true;
- fprintf(stderr, "[main] found B->A switch\n");
- fflush(stderr);
- }
- if(events[i] == EVENT_A_TO_B_AGAIN && found_b_to_a) {
- found_a_to_b_again = true;
- fprintf(stderr, "[main] found A->B again switch\n");
- fflush(stderr);
- }
- if(events[i] == EVENT_B_TO_A_AGAIN && found_a_to_b_again) {
- found_b_to_a_again = true;
- fprintf(stderr, "[main] found B->A again switch\n");
- fflush(stderr);
- }
- }
-
- assert(found_a_to_b);
- fprintf(stderr, "[main] assertion passed: A switched to B\n");
- fflush(stderr);
-
- assert(found_b_to_a);
- fprintf(stderr, "[main] assertion passed: B switched to A\n");
- fflush(stderr);
-
- assert(found_a_to_b_again);
- fprintf(stderr, "[main] assertion passed: A switched to B again\n");
- fflush(stderr);
-
- assert(found_b_to_a_again);
- fprintf(stderr, "[main] assertion passed: B switched to A again\n");
- fflush(stderr);
-
- fprintf(stderr, "\nPASS: Symmetric fiber switching works correctly\n");
- fflush(stderr);
- return 0;
-}
diff --git a/tests/test_yafl_watermark.c b/tests/test_yafl_watermark.c
new file mode 100644
index 0000000..286da27
--- /dev/null
+++ b/tests/test_yafl_watermark.c
@@ -0,0 +1,131 @@
+/*
+ * test_yafl_watermark.c - Dedicated stack watermark tests
+ *
+ * Verifies watermark tracking for both allocation modes and confirms that
+ * watermark queries work while a fiber is suspended and after it completes.
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "../include/yafl.h"
+
+#define TEST_STACK_TOUCH_COMPLETE 0x34
+#define TEST_STACK_TOUCH_SUSPEND_BEFORE 0xC9
+#define TEST_STACK_TOUCH_SUSPEND_AFTER 0x9C
+
+static const char *alloc_name(yafl_stack_flags_t alloc_flag) { return alloc_flag == YAFL_STACK_FLAGS_VMEM ? "mmap" : "malloc"; }
+
+/* Force observable stack writes so YAFL's own watermark logic has real usage to measure. */
+static void touch_volatile_stack_buffer(volatile unsigned char *buffer, size_t size, unsigned char value) {
+ for(size_t index = 0; index < size; index++) { buffer[index] = value; }
+}
+
+static void *complete_after_stack_use(void *arg) {
+ volatile unsigned char stack_buffer[1536];
+
+ touch_volatile_stack_buffer(stack_buffer, sizeof(stack_buffer), TEST_STACK_TOUCH_COMPLETE);
+ return arg;
+}
+
+static void *suspend_after_stack_use(void *arg) {
+ volatile unsigned char stack_buffer[768];
+
+ touch_volatile_stack_buffer(stack_buffer, sizeof(stack_buffer), TEST_STACK_TOUCH_SUSPEND_BEFORE);
+ arg = yafl_fiber_suspend(arg);
+
+ touch_volatile_stack_buffer(stack_buffer, sizeof(stack_buffer), TEST_STACK_TOUCH_SUSPEND_AFTER);
+ return arg;
+}
+
+static void test_watermark_complete(yafl_stack_flags_t alloc_flag, uintptr_t value) {
+ printf("test_watermark_complete_%s: ", alloc_name(alloc_flag));
+ fflush(stdout);
+
+ yafl_fiber_t *fiber = yafl_fiber_create(complete_after_stack_use, 16 * 1024, alloc_flag | YAFL_STACK_FLAGS_WATERMARK);
+ assert(fiber != NULL);
+
+ void *result = yafl_fiber_resume(fiber, (void *)value);
+ assert(result == (void *)value);
+ assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
+
+ size_t usage = yafl_fiber_stack_high_watermark(fiber);
+ assert(usage > 0);
+ assert(usage < 16 * 1024);
+
+ yafl_fiber_destroy(fiber);
+
+ printf("PASS\n");
+}
+
+static void test_watermark_while_suspended(yafl_stack_flags_t alloc_flag, uintptr_t first_value, uintptr_t second_value) {
+ printf("test_watermark_while_suspended_%s: ", alloc_name(alloc_flag));
+ fflush(stdout);
+
+ yafl_fiber_t *fiber = yafl_fiber_create(suspend_after_stack_use, 16 * 1024, alloc_flag | YAFL_STACK_FLAGS_WATERMARK);
+ assert(fiber != NULL);
+
+ void *result = yafl_fiber_resume(fiber, (void *)first_value);
+ assert(result == (void *)first_value);
+ assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_SUSPENDED);
+
+ size_t suspended_usage = yafl_fiber_stack_high_watermark(fiber);
+ assert(suspended_usage > 0);
+ assert(suspended_usage < 16 * 1024);
+
+ result = yafl_fiber_resume(fiber, (void *)second_value);
+ assert(result == (void *)second_value);
+ assert(yafl_fiber_status(fiber) == YAFL_FIBER_STATUS_COMPLETE);
+
+ size_t complete_usage = yafl_fiber_stack_high_watermark(fiber);
+ assert(complete_usage >= suspended_usage);
+ assert(complete_usage < 16 * 1024);
+
+ yafl_fiber_destroy(fiber);
+
+ printf("PASS\n");
+}
+
+static void test_watermark_without_flag(yafl_stack_flags_t alloc_flag, uintptr_t value) {
+ printf("test_watermark_without_flag_%s: ", alloc_name(alloc_flag));
+ fflush(stdout);
+
+ yafl_fiber_t *fiber = yafl_fiber_create(complete_after_stack_use, 16 * 1024, alloc_flag);
+ assert(fiber != NULL);
+ assert(yafl_fiber_stack_high_watermark(fiber) == 0);
+
+ void *result = yafl_fiber_resume(fiber, (void *)value);
+ assert(result == (void *)value);
+ assert(yafl_fiber_stack_high_watermark(fiber) == 0);
+
+ yafl_fiber_destroy(fiber);
+
+ printf("PASS\n");
+}
+
+static void test_watermark_null_fiber(void) {
+ printf("test_watermark_null_fiber: ");
+ fflush(stdout);
+
+ assert(yafl_fiber_stack_high_watermark(NULL) == 0);
+
+ printf("PASS\n");
+}
+
+int main(void) {
+ printf("Running YAFL watermark tests...\n");
+
+ test_watermark_complete(YAFL_STACK_FLAGS_MALLOC, 0x11);
+ test_watermark_complete(YAFL_STACK_FLAGS_VMEM, 0x22);
+ test_watermark_while_suspended(YAFL_STACK_FLAGS_MALLOC, 0x33, 0x44);
+ test_watermark_while_suspended(YAFL_STACK_FLAGS_VMEM, 0x55, 0x66);
+ test_watermark_without_flag(YAFL_STACK_FLAGS_MALLOC, 0x77);
+ test_watermark_without_flag(YAFL_STACK_FLAGS_VMEM, 0x88);
+ test_watermark_null_fiber();
+
+ printf("\nAll watermark tests passed!\n");
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/test_yafl_watermark_mmap.c b/tests/test_yafl_watermark_mmap.c
deleted file mode 100644
index 733a495..0000000
--- a/tests/test_yafl_watermark_mmap.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * test_yafl_watermark.c
- * Watermark test with both vmem and malloc stacks
- *
- * Verifies watermark functionality for stack usage tracking.
- *
- * Copyright Kyle Hayes (2026)
- * Distributed under the Boost Software License, Version 1.0.
- */
-
-#include
-#include
-#include
-
-#include "yafl.h"
-
-void *watermark_fiber(void *data) {
- (void)data;
- fprintf(stderr, "[fiber] running\n");
- fflush(stderr);
-
- /* Use some stack space */
- volatile char buf[1024];
- buf[0] = 1;
- buf[1023] = 2;
-
- return (void *)0xCC;
-}
-
-static void test_watermark(const char *name, yafl_fiber_t *fiber) {
- fprintf(stderr, "\n[test] %s watermark\n", name);
- fflush(stderr);
-
- /* Fill watermark before first run */
- bool filled = yafl_fiber_fill_watermark(fiber);
- assert(filled);
- fprintf(stderr, "[test] watermark filled\n");
- fflush(stderr);
-
- /* Run the fiber */
- void *result = yafl_fiber_switch(fiber, NULL);
- assert(result == (void *)0xCC);
- fprintf(stderr, "[test] fiber completed\n");
- fflush(stderr);
-
- /* Check stack usage */
- size_t used = yafl_fiber_get_stack_usage(fiber);
- size_t total = yafl_fiber_get_stack_size(fiber);
-
- fprintf(stderr, "[test] stack used: %zu / %zu bytes (%.1f%%)\n",
- used, total, (used * 100.0) / total);
- fflush(stderr);
-
- assert(used > 0);
- assert(used < total);
- assert(used >= 1024); /* At least our buffer size */
-}
-
-int main(void) {
- fprintf(stderr, "=== yafl Watermark Test ===\n");
- fflush(stderr);
-
- /* Test with vmem allocation */
- yafl_fiber_t *fiber_vmem = yafl_fiber_create_vmem(24 * 1024, watermark_fiber);
- assert(fiber_vmem != NULL);
- test_watermark("vmem", fiber_vmem);
- yafl_fiber_destroy(fiber_vmem);
-
- /* Test with malloc allocation */
- yafl_fiber_t *fiber_malloc = yafl_fiber_create_malloc(24 * 1024, watermark_fiber);
- assert(fiber_malloc != NULL);
- test_watermark("malloc", fiber_malloc);
- yafl_fiber_destroy(fiber_malloc);
-
- yafl_fiber_destroy_thread_fiber();
-
- fprintf(stderr, "\nPASS: Watermark test passed for both allocation types\n");
- fflush(stderr);
- return 0;
-}
diff --git a/toolchains/aarch64-apple-darwin.cmake b/toolchains/aarch64-apple-darwin.cmake
index 520d885..749e900 100644
--- a/toolchains/aarch64-apple-darwin.cmake
+++ b/toolchains/aarch64-apple-darwin.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/arm64/make_arm64_aapcs_macho_gas.S
- src/asm/arm64/jump_arm64_aapcs_macho_gas.S
+ src/asm/arm64/make_context_arm64_aapcs_macho_gas.S
+ src/asm/arm64/switch_arm64_aapcs_macho_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/aarch64-apple-ios.cmake b/toolchains/aarch64-apple-ios.cmake
index b59ccb3..3cd9961 100644
--- a/toolchains/aarch64-apple-ios.cmake
+++ b/toolchains/aarch64-apple-ios.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/arm64/make_arm64_aapcs_macho_gas.S
- src/asm/arm64/jump_arm64_aapcs_macho_gas.S
+ src/asm/arm64/make_context_arm64_aapcs_macho_gas.S
+ src/asm/arm64/switch_arm64_aapcs_macho_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
diff --git a/toolchains/aarch64-pc-linux-gnu.cmake b/toolchains/aarch64-pc-linux-gnu.cmake
index 406c260..67a7896 100644
--- a/toolchains/aarch64-pc-linux-gnu.cmake
+++ b/toolchains/aarch64-pc-linux-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/arm64/make_arm64_aapcs_elf_gas.S
- src/asm/arm64/jump_arm64_aapcs_elf_gas.S
+ src/asm/arm64/make_context_arm64_aapcs_elf_gas.S
+ src/asm/arm64/switch_arm64_aapcs_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/aarch64-pc-windows-gnu.cmake b/toolchains/aarch64-pc-windows-gnu.cmake
index 46d6d71..8e8ad06 100644
--- a/toolchains/aarch64-pc-windows-gnu.cmake
+++ b/toolchains/aarch64-pc-windows-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/arm64/make_arm64_aapcs_pe_armclang.S
- src/asm/arm64/jump_arm64_aapcs_pe_armclang.S
+ src/asm/arm64/make_context_arm64_aapcs_pe_armclang.S
+ src/asm/arm64/switch_arm64_aapcs_pe_armclang.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/aarch64-pc-windows-msvc.cmake b/toolchains/aarch64-pc-windows-msvc.cmake
index b9b30f8..cec9528 100644
--- a/toolchains/aarch64-pc-windows-msvc.cmake
+++ b/toolchains/aarch64-pc-windows-msvc.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/arm64/make_arm64_aapcs_pe_armasm.asm
- src/asm/arm64/jump_arm64_aapcs_pe_armasm.asm
+ src/asm/arm64/make_context_arm64_aapcs_pe_armasm.asm
+ src/asm/arm64/switch_arm64_aapcs_pe_armasm.asm
)
find_program(ARMASM64
diff --git a/toolchains/arm-unknown-linux-gnueabihf.cmake b/toolchains/arm-unknown-linux-gnueabihf.cmake
index 54346b4..d6f0c5b 100644
--- a/toolchains/arm-unknown-linux-gnueabihf.cmake
+++ b/toolchains/arm-unknown-linux-gnueabihf.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/arm/make_arm_aapcs_elf_gas.S
- src/asm/arm/jump_arm_aapcs_elf_gas.S
+ src/asm/arm/make_context_arm_aapcs_elf_gas.S
+ src/asm/arm/switch_arm_aapcs_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/arm-unknown-linux-musleabihf.cmake b/toolchains/arm-unknown-linux-musleabihf.cmake
index 5815768..6cad185 100644
--- a/toolchains/arm-unknown-linux-musleabihf.cmake
+++ b/toolchains/arm-unknown-linux-musleabihf.cmake
@@ -6,8 +6,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/arm/make_arm_aapcs_elf_gas.S
- src/asm/arm/jump_arm_aapcs_elf_gas.S
+ src/asm/arm/make_context_arm_aapcs_elf_gas.S
+ src/asm/arm/switch_arm_aapcs_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2 -static)
diff --git a/toolchains/i386-unknown-linux-gnu.cmake b/toolchains/i386-unknown-linux-gnu.cmake
index a16ff7c..0471df0 100644
--- a/toolchains/i386-unknown-linux-gnu.cmake
+++ b/toolchains/i386-unknown-linux-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/i386/make_i386_sysv_elf_gas.S
- src/asm/i386/jump_i386_sysv_elf_gas.S
+ src/asm/i386/make_context_i386_sysv_elf_gas.S
+ src/asm/i386/switch_i386_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2 -m32)
\ No newline at end of file
diff --git a/toolchains/mips64el-unknown-linux-gnuabi64.cmake b/toolchains/mips64el-unknown-linux-gnuabi64.cmake
index 8c3b425..26af8af 100644
--- a/toolchains/mips64el-unknown-linux-gnuabi64.cmake
+++ b/toolchains/mips64el-unknown-linux-gnuabi64.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/mips64/make_mips64_n64_elf_gas.S
- src/asm/mips64/jump_mips64_n64_elf_gas.S
+ src/asm/mips64/make_context_mips64_n64_elf_gas.S
+ src/asm/mips64/switch_mips64_n64_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/mipsel-unknown-linux-gnu.cmake b/toolchains/mipsel-unknown-linux-gnu.cmake
index c8f5b47..9d212ce 100644
--- a/toolchains/mipsel-unknown-linux-gnu.cmake
+++ b/toolchains/mipsel-unknown-linux-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/mips/make_mips32_o32_elf_gas.S
- src/asm/mips/jump_mips32_o32_elf_gas.S
+ src/asm/mips/make_context_mips32_o32_elf_gas.S
+ src/asm/mips/switch_mips32_o32_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/powerpc-unknown-linux-gnu.cmake b/toolchains/powerpc-unknown-linux-gnu.cmake
index 86c609d..6ab6632 100644
--- a/toolchains/powerpc-unknown-linux-gnu.cmake
+++ b/toolchains/powerpc-unknown-linux-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/ppc32/make_ppc32_sysv_elf_gas.S
- src/asm/ppc32/jump_ppc32_sysv_elf_gas.S
+ src/asm/ppc32/make_context_ppc32_sysv_elf_gas.S
+ src/asm/ppc32/switch_ppc32_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/powerpc64le-unknown-linux-gnu.cmake b/toolchains/powerpc64le-unknown-linux-gnu.cmake
index 44f4325..855b1b4 100644
--- a/toolchains/powerpc64le-unknown-linux-gnu.cmake
+++ b/toolchains/powerpc64le-unknown-linux-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/ppc64/make_ppc64_sysv_elf_gas.S
- src/asm/ppc64/jump_ppc64_sysv_elf_gas.S
+ src/asm/ppc64/make_context_ppc64_sysv_elf_gas.S
+ src/asm/ppc64/switch_ppc64_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/powerpc64le-unknown-linux-musl.cmake b/toolchains/powerpc64le-unknown-linux-musl.cmake
index 846f96d..2eff142 100644
--- a/toolchains/powerpc64le-unknown-linux-musl.cmake
+++ b/toolchains/powerpc64le-unknown-linux-musl.cmake
@@ -6,8 +6,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/ppc64/make_ppc64_sysv_elf_gas.S
- src/asm/ppc64/jump_ppc64_sysv_elf_gas.S
+ src/asm/ppc64/make_context_ppc64_sysv_elf_gas.S
+ src/asm/ppc64/switch_ppc64_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2 -static)
diff --git a/toolchains/riscv64-unknown-linux-gnu.cmake b/toolchains/riscv64-unknown-linux-gnu.cmake
index c15f972..1d2da4d 100644
--- a/toolchains/riscv64-unknown-linux-gnu.cmake
+++ b/toolchains/riscv64-unknown-linux-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/riscv64/make_riscv64_sysv_elf_gas.S
- src/asm/riscv64/jump_riscv64_sysv_elf_gas.S
+ src/asm/riscv64/make_context_riscv64_sysv_elf_gas.S
+ src/asm/riscv64/switch_riscv64_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/riscv64-unknown-linux-musl.cmake b/toolchains/riscv64-unknown-linux-musl.cmake
index 0f368f5..e7c5bad 100644
--- a/toolchains/riscv64-unknown-linux-musl.cmake
+++ b/toolchains/riscv64-unknown-linux-musl.cmake
@@ -6,8 +6,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/riscv64/make_riscv64_sysv_elf_gas.S
- src/asm/riscv64/jump_riscv64_sysv_elf_gas.S
+ src/asm/riscv64/make_context_riscv64_sysv_elf_gas.S
+ src/asm/riscv64/switch_riscv64_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2 -static)
diff --git a/toolchains/s390x-ibm-linux-gnu.cmake b/toolchains/s390x-ibm-linux-gnu.cmake
index a232033..19f748b 100644
--- a/toolchains/s390x-ibm-linux-gnu.cmake
+++ b/toolchains/s390x-ibm-linux-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/s390x/make_s390x_sysv_elf_gas.S
- src/asm/s390x/jump_s390x_sysv_elf_gas.S
+ src/asm/s390x/make_context_s390x_sysv_elf_gas.S
+ src/asm/s390x/switch_s390x_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/s390x-ibm-linux-musl.cmake b/toolchains/s390x-ibm-linux-musl.cmake
index e15d4cc..2d3a8f4 100644
--- a/toolchains/s390x-ibm-linux-musl.cmake
+++ b/toolchains/s390x-ibm-linux-musl.cmake
@@ -6,8 +6,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/s390x/make_s390x_sysv_elf_gas.S
- src/asm/s390x/jump_s390x_sysv_elf_gas.S
+ src/asm/s390x/make_context_s390x_sysv_elf_gas.S
+ src/asm/s390x/switch_s390x_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2 -static)
diff --git a/toolchains/sparc64-unknown-linux-gnu.cmake b/toolchains/sparc64-unknown-linux-gnu.cmake
index e7f0478..e03f47c 100644
--- a/toolchains/sparc64-unknown-linux-gnu.cmake
+++ b/toolchains/sparc64-unknown-linux-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/sparc64/make_sparc64_sysv_elf_gas.S
- src/asm/sparc64/jump_sparc64_sysv_elf_gas.S
+ src/asm/sparc64/make_context_sparc64_sysv_elf_gas.S
+ src/asm/sparc64/switch_sparc64_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/x86_64-apple-darwin.cmake b/toolchains/x86_64-apple-darwin.cmake
index 1efa89e..f68681f 100644
--- a/toolchains/x86_64-apple-darwin.cmake
+++ b/toolchains/x86_64-apple-darwin.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/x86_64/make_x86_64_sysv_macho_gas.S
- src/asm/x86_64/jump_x86_64_sysv_macho_gas.S
+ src/asm/x86_64/make_context_x86_64_sysv_macho_gas.S
+ src/asm/x86_64/switch_x86_64_sysv_macho_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/x86_64-pc-linux-gnu.cmake b/toolchains/x86_64-pc-linux-gnu.cmake
index 610bc6f..00bc0ff 100644
--- a/toolchains/x86_64-pc-linux-gnu.cmake
+++ b/toolchains/x86_64-pc-linux-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/x86_64/make_x86_64_sysv_elf_gas.S
- src/asm/x86_64/jump_x86_64_sysv_elf_gas.S
+ src/asm/x86_64/make_context_x86_64_sysv_elf_gas.S
+ src/asm/x86_64/switch_x86_64_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/x86_64-pc-windows-gnu.cmake b/toolchains/x86_64-pc-windows-gnu.cmake
index eaa86b9..f2b8e24 100644
--- a/toolchains/x86_64-pc-windows-gnu.cmake
+++ b/toolchains/x86_64-pc-windows-gnu.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/x86_64/make_x86_64_ms_pe_gas.S
- src/asm/x86_64/jump_x86_64_ms_pe_gas.S
+ src/asm/x86_64/make_context_x86_64_ms_pe_gas.S
+ src/asm/x86_64/switch_x86_64_ms_pe_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file
diff --git a/toolchains/x86_64-pc-windows-msvc.cmake b/toolchains/x86_64-pc-windows-msvc.cmake
index 364b8b1..7af7a1d 100644
--- a/toolchains/x86_64-pc-windows-msvc.cmake
+++ b/toolchains/x86_64-pc-windows-msvc.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/x86_64/make_x86_64_ms_pe_masm.asm
- src/asm/x86_64/jump_x86_64_ms_pe_masm.asm
+ src/asm/x86_64/make_context_x86_64_ms_pe_masm.asm
+ src/asm/x86_64/switch_x86_64_ms_pe_masm.asm
)
set(CMAKE_ASM_MASM_COMPILER ml64.exe CACHE FILEPATH "x64 MASM assembler" FORCE)
diff --git a/toolchains/x86_64-unknown-linux-android.cmake b/toolchains/x86_64-unknown-linux-android.cmake
index d661864..1da83bc 100644
--- a/toolchains/x86_64-unknown-linux-android.cmake
+++ b/toolchains/x86_64-unknown-linux-android.cmake
@@ -4,8 +4,8 @@
# See LICENSE file for details
set(ASM_FILES
- src/asm/x86_64/make_x86_64_sysv_elf_gas.S
- src/asm/x86_64/jump_x86_64_sysv_elf_gas.S
+ src/asm/x86_64/make_context_x86_64_sysv_elf_gas.S
+ src/asm/x86_64/switch_x86_64_sysv_elf_gas.S
)
enable_language(ASM)
add_compile_options(-Wall -Wextra -Werror -g -O2)
\ No newline at end of file