xref: /ext-fiber/src/fiber_asm.c (revision 1f333ab9)
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