Ruby  3.1.4p223 (2023-03-30 revision HEAD)
Context.h
1 #ifndef COROUTINE_UCONTEXT_CONTEXT_H
2 #define COROUTINE_UCONTEXT_CONTEXT_H 1
3 
4 /*
5  * This file is part of the "Coroutine" project and released under the MIT License.
6  *
7  * Created by Samuel Williams on 24/6/2019.
8  * Copyright, 2019, by Samuel Williams.
9 */
10 
11 #pragma once
12 
13 #include <assert.h>
14 #include <stddef.h>
15 #include <ucontext.h>
16 
17 #define COROUTINE __attribute__((noreturn)) void
18 
19 #ifdef HAVE_STDINT_H
20 #include <stdint.h>
21 #if INTPTR_MAX <= INT32_MAX
22 #define COROUTINE_LIMITED_ADDRESS_SPACE
23 #endif
24 #endif
25 
26 struct coroutine_context
27 {
28  ucontext_t state;
29  struct coroutine_context * from;
30  void *argument;
31 };
32 
33 typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
34 
35 COROUTINE coroutine_trampoline(void * _start, void * _context);
36 
37 static inline void coroutine_initialize_main(struct coroutine_context * context) {
38  context->from = NULL;
39  getcontext(&context->state);
40 }
41 
42 static inline void coroutine_initialize(
43  struct coroutine_context *context,
44  coroutine_start start,
45  void *stack,
46  size_t size
47 ) {
48  assert(start && stack && size >= 1024);
49 
50  coroutine_initialize_main(context);
51 
52  context->state.uc_stack.ss_size = size;
53  // Despite what it's called, this is not actually a stack pointer. It points to the address of the stack allocation (the lowest address).
54  context->state.uc_stack.ss_sp = (char*)stack;
55  context->state.uc_stack.ss_flags = 0;
56  context->state.uc_link = NULL;
57 
58  makecontext(&context->state, (void(*)(void))coroutine_trampoline, 2, (void*)start, (void*)context);
59 }
60 
61 static inline struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target)
62 {
63  struct coroutine_context * previous = target->from;
64 
65  target->from = current;
66  swapcontext(&current->state, &target->state);
67  target->from = previous;
68 
69  return target;
70 }
71 
72 static inline void coroutine_destroy(struct coroutine_context * context)
73 {
74  context->state.uc_stack.ss_sp = NULL;
75  context->state.uc_stack.ss_size = 0;
76  context->from = NULL;
77 }
78 
79 #endif /* COROUTINE_UCONTEXT_CONTEXT_H */