1 /*
2 +--------------------------------------------------------------------+
3 | ext-fiber |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Authors: Aaron Piotrowski <aaron@trowski.com> |
10 | Martin Schröder <m.schroeder2007@gmail.com> |
11 +--------------------------------------------------------------------+
12 */
13
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17
18 #include "fiber.h"
19
20 typedef void *fcontext_t;
21
22 typedef struct _transfer_t {
23 fcontext_t context;
24 void *data;
25 } transfer_t;
26
27 extern fcontext_t make_fcontext(void *sp, size_t size, void (*fn)(transfer_t));
28 extern transfer_t jump_fcontext(fcontext_t to, void *vp);
29
zend_fiber_backend_info(void)30 const char *zend_fiber_backend_info(void)
31 {
32 return "assembler (boost.context v1.76.0)";
33 }
34
zend_fiber_trampoline(transfer_t transfer)35 static ZEND_NORETURN void zend_fiber_trampoline(transfer_t transfer)
36 {
37 zend_fiber_context *context = transfer.data;
38
39 context->caller = transfer.context;
40
41 context->function(context);
42
43 context->self = NULL;
44
45 zend_fiber_suspend_context(context);
46
47 abort();
48 }
49
zend_fiber_init_context(zend_fiber_context * context,zend_fiber_coroutine coroutine,size_t stack_size)50 PHP_FIBER_API zend_bool zend_fiber_init_context(zend_fiber_context *context, zend_fiber_coroutine coroutine, size_t stack_size)
51 {
52 if (UNEXPECTED(!zend_fiber_stack_allocate(&context->stack, stack_size))) {
53 return 0;
54 }
55
56 // Stack grows down, calculate the top of the stack. make_fcontext then shifts pointer to lower 16-byte boundary.
57 void *stack = (void *) ((uintptr_t) context->stack.pointer + context->stack.size);
58
59 context->self = make_fcontext(stack, context->stack.size, zend_fiber_trampoline);
60
61 if (UNEXPECTED(!context->self)) {
62 zend_fiber_stack_free(&context->stack);
63 return 0;
64 }
65
66 context->function = coroutine;
67 context->caller = NULL;
68
69 return 1;
70 }
71
zend_fiber_destroy_context(zend_fiber_context * context)72 PHP_FIBER_API void zend_fiber_destroy_context(zend_fiber_context *context)
73 {
74 zend_fiber_stack_free(&context->stack);
75 }
76
zend_fiber_switch_context(zend_fiber_context * to)77 PHP_FIBER_API void zend_fiber_switch_context(zend_fiber_context *to)
78 {
79 ZEND_ASSERT(to && to->self && to->stack.pointer && "Invalid fiber context");
80
81 transfer_t transfer = jump_fcontext(to->self, to);
82
83 to->self = transfer.context;
84 }
85
zend_fiber_suspend_context(zend_fiber_context * current)86 PHP_FIBER_API void zend_fiber_suspend_context(zend_fiber_context *current)
87 {
88 ZEND_ASSERT(current && current->caller && current->stack.pointer && "Invalid fiber context");
89
90 transfer_t transfer = jump_fcontext(current->caller, NULL);
91
92 current->caller = transfer.context;
93 }
94
95 /*
96 * vim: sw=4 ts=4
97 * vim600: fdm=marker
98 */
99