1 /*
2 Copyright 2011, 2012 Kristian Nielsen and Monty Program Ab
3
4 This file is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*
19 Implementation of async context spawning using Posix ucontext and
20 swapcontext().
21 */
22
23 #include "mysys_priv.h"
24 #include "m_string.h"
25 #include "my_context.h"
26
27 #ifdef HAVE_VALGRIND_MEMCHECK_H
28 #include <valgrind/valgrind.h>
29 #endif
30
31 #ifdef MY_CONTEXT_USE_UCONTEXT
32 #ifdef __APPLE__
33 #pragma GCC diagnostic push
34 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
35 #endif
36 /*
37 The makecontext() only allows to pass integers into the created context :-(
38 We want to pass pointers, so we do it this kinda hackish way.
39 Anyway, it should work everywhere, and at least it does not break strict
40 aliasing.
41 */
42 union pass_void_ptr_as_2_int {
43 int a[2];
44 void *p;
45 };
46
47
48 /*
49 We use old-style function definition here, as this is passed to
50 makecontext(). And the type of the makecontext() argument does not match
51 the actual type (as the actual type can differ from call to call).
52 */
53 static void
my_context_spawn_internal(i0,i1)54 my_context_spawn_internal(i0, i1)
55 int i0, i1;
56 {
57 int err;
58 struct my_context *c;
59 union pass_void_ptr_as_2_int u;
60
61 u.a[0]= i0;
62 u.a[1]= i1;
63 c= (struct my_context *)u.p;
64
65 (*c->user_func)(c->user_data);
66 c->active= 0;
67 err= setcontext(&c->base_context);
68 fprintf(stderr, "Aieie, setcontext() failed: %d (errno=%d)\n", err, errno);
69 }
70
71
72 int
my_context_continue(struct my_context * c)73 my_context_continue(struct my_context *c)
74 {
75 int err;
76
77 if (!c->active)
78 return 0;
79
80 DBUG_SWAP_CODE_STATE(&c->dbug_state);
81 err= swapcontext(&c->base_context, &c->spawned_context);
82 DBUG_SWAP_CODE_STATE(&c->dbug_state);
83 if (err)
84 {
85 fprintf(stderr, "Aieie, swapcontext() failed: %d (errno=%d)\n",
86 err, errno);
87 return -1;
88 }
89
90 return c->active;
91 }
92
93
94 int
my_context_spawn(struct my_context * c,void (* f)(void *),void * d)95 my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
96 {
97 int err;
98 union pass_void_ptr_as_2_int u;
99
100 err= getcontext(&c->spawned_context);
101 if (err)
102 return -1;
103 c->spawned_context.uc_stack.ss_sp= c->stack;
104 c->spawned_context.uc_stack.ss_size= c->stack_size;
105 c->spawned_context.uc_link= NULL;
106 c->user_func= f;
107 c->user_data= d;
108 c->active= 1;
109 u.p= c;
110 makecontext(&c->spawned_context, my_context_spawn_internal, 2,
111 u.a[0], u.a[1]);
112
113 return my_context_continue(c);
114 }
115
116
117 int
my_context_yield(struct my_context * c)118 my_context_yield(struct my_context *c)
119 {
120 int err;
121
122 if (!c->active)
123 return -1;
124
125 err= swapcontext(&c->spawned_context, &c->base_context);
126 if (err)
127 return -1;
128 return 0;
129 }
130
131 int
my_context_init(struct my_context * c,size_t stack_size)132 my_context_init(struct my_context *c, size_t stack_size)
133 {
134 #if SIZEOF_CHARP > SIZEOF_INT*2
135 #error Error: Unable to store pointer in 2 ints on this architecture
136 #endif
137 bzero(c, sizeof(*c));
138 if (!(c->stack= malloc(stack_size)))
139 return -1; /* Out of memory */
140 c->stack_size= stack_size;
141 #ifdef HAVE_VALGRIND_MEMCHECK_H
142 c->valgrind_stack_id=
143 VALGRIND_STACK_REGISTER(c->stack, ((unsigned char *)(c->stack))+stack_size);
144 #endif
145 return 0;
146 }
147
148 void
my_context_destroy(struct my_context * c)149 my_context_destroy(struct my_context *c)
150 {
151 if (c->stack)
152 {
153 #ifdef HAVE_VALGRIND_MEMCHECK_H
154 VALGRIND_STACK_DEREGISTER(c->valgrind_stack_id);
155 #endif
156 free(c->stack);
157 }
158 DBUG_FREE_CODE_STATE(&c->dbug_state);
159 }
160
161 #ifdef __APPLE__
162 #pragma GCC diagnostic pop
163 #endif
164 #endif /* MY_CONTEXT_USE_UCONTEXT */
165
166
167 #ifdef MY_CONTEXT_USE_X86_64_GCC_ASM
168 /*
169 GCC-amd64 implementation of my_context.
170
171 This is slightly optimized in the common case where we never yield
172 (eg. fetch next row and it is already fully received in buffer). In this
173 case we do not need to restore registers at return (though we still need to
174 save them as we cannot know if we will yield or not in advance).
175 */
176
177 #include <stdint.h>
178 #include <stdlib.h>
179
180 /*
181 Layout of saved registers etc.
182 Since this is accessed through gcc inline assembler, it is simpler to just
183 use numbers than to try to define nice constants or structs.
184
185 0 0 %rsp
186 1 8 %rbp
187 2 16 %rbx
188 3 24 %r12
189 4 32 %r13
190 5 40 %r14
191 6 48 %r15
192 7 56 %rip for done
193 8 64 %rip for yield/continue
194 */
195
196 int
my_context_spawn(struct my_context * c,void (* f)(void *),void * d)197 my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
198 {
199 int ret;
200
201 DBUG_SWAP_CODE_STATE(&c->dbug_state);
202
203 /*
204 There are 6 callee-save registers we need to save and restore when
205 suspending and continuing, plus stack pointer %rsp and instruction pointer
206 %rip.
207
208 However, if we never suspend, the user-supplied function will in any case
209 restore the 6 callee-save registers, so we can avoid restoring them in
210 this case.
211 */
212 __asm__ __volatile__
213 (
214 "movq %%rsp, (%[save])\n\t"
215 "movq %[stack], %%rsp\n\t"
216 #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __clang__) && \
217 !defined(__INTEL_COMPILER)
218 /*
219 This emits a DWARF DW_CFA_undefined directive to make the return address
220 undefined. This indicates that this is the top of the stack frame, and
221 helps tools that use DWARF stack unwinding to obtain stack traces.
222 (I use numeric constant to avoid a dependency on libdwarf includes).
223 */
224 ".cfi_escape 0x07, 16\n\t"
225 #endif
226 "movq %%rbp, 8(%[save])\n\t"
227 "movq %%rbx, 16(%[save])\n\t"
228 "movq %%r12, 24(%[save])\n\t"
229 "movq %%r13, 32(%[save])\n\t"
230 "movq %%r14, 40(%[save])\n\t"
231 "movq %%r15, 48(%[save])\n\t"
232 "leaq 1f(%%rip), %%rax\n\t"
233 "leaq 2f(%%rip), %%rcx\n\t"
234 "movq %%rax, 56(%[save])\n\t"
235 "movq %%rcx, 64(%[save])\n\t"
236 /*
237 Constraint below puts the argument to the user function into %rdi, as
238 needed for the calling convention.
239 */
240 "callq *%[f]\n\t"
241 "jmpq *56(%[save])\n"
242 /*
243 Come here when operation is done.
244 We do not need to restore callee-save registers, as the called function
245 will do this for us if needed.
246 */
247 "1:\n\t"
248 "movq (%[save]), %%rsp\n\t"
249 "xorl %[ret], %[ret]\n\t"
250 "jmp 3f\n"
251 /* Come here when operation was suspended. */
252 "2:\n\t"
253 "movl $1, %[ret]\n"
254 "3:\n"
255 : [ret] "=a" (ret),
256 [f] "+S" (f),
257 /* Need this in %rdi to follow calling convention. */
258 [d] "+D" (d)
259 : [stack] "a" (c->stack_top),
260 /* Need this in callee-save register to preserve in function call. */
261 [save] "b" (&c->save[0])
262 : "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc"
263 );
264
265 DBUG_SWAP_CODE_STATE(&c->dbug_state);
266
267 return ret;
268 }
269
270 int
my_context_continue(struct my_context * c)271 my_context_continue(struct my_context *c)
272 {
273 int ret;
274
275 DBUG_SWAP_CODE_STATE(&c->dbug_state);
276
277 __asm__ __volatile__
278 (
279 "movq (%[save]), %%rax\n\t"
280 "movq %%rsp, (%[save])\n\t"
281 "movq %%rax, %%rsp\n\t"
282 "movq 8(%[save]), %%rax\n\t"
283 "movq %%rbp, 8(%[save])\n\t"
284 "movq %%rax, %%rbp\n\t"
285 "movq 24(%[save]), %%rax\n\t"
286 "movq %%r12, 24(%[save])\n\t"
287 "movq %%rax, %%r12\n\t"
288 "movq 32(%[save]), %%rax\n\t"
289 "movq %%r13, 32(%[save])\n\t"
290 "movq %%rax, %%r13\n\t"
291 "movq 40(%[save]), %%rax\n\t"
292 "movq %%r14, 40(%[save])\n\t"
293 "movq %%rax, %%r14\n\t"
294 "movq 48(%[save]), %%rax\n\t"
295 "movq %%r15, 48(%[save])\n\t"
296 "movq %%rax, %%r15\n\t"
297
298 "leaq 1f(%%rip), %%rax\n\t"
299 "leaq 2f(%%rip), %%rcx\n\t"
300 "movq %%rax, 56(%[save])\n\t"
301 "movq 64(%[save]), %%rax\n\t"
302 "movq %%rcx, 64(%[save])\n\t"
303
304 "movq 16(%[save]), %%rcx\n\t"
305 "movq %%rbx, 16(%[save])\n\t"
306 "movq %%rcx, %%rbx\n\t"
307
308 "jmpq *%%rax\n"
309 /*
310 Come here when operation is done.
311 Be sure to use the same callee-save register for %[save] here and in
312 my_context_spawn(), so we preserve the value correctly at this point.
313 */
314 "1:\n\t"
315 "movq (%[save]), %%rsp\n\t"
316 "movq 8(%[save]), %%rbp\n\t"
317 /* %rbx is preserved from my_context_spawn() in this case. */
318 "movq 24(%[save]), %%r12\n\t"
319 "movq 32(%[save]), %%r13\n\t"
320 "movq 40(%[save]), %%r14\n\t"
321 "movq 48(%[save]), %%r15\n\t"
322 "xorl %[ret], %[ret]\n\t"
323 "jmp 3f\n"
324 /* Come here when operation is suspended. */
325 "2:\n\t"
326 "movl $1, %[ret]\n"
327 "3:\n"
328 : [ret] "=a" (ret)
329 : /* Need this in callee-save register to preserve in function call. */
330 [save] "b" (&c->save[0])
331 : "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "memory", "cc"
332 );
333
334 DBUG_SWAP_CODE_STATE(&c->dbug_state);
335
336 return ret;
337 }
338
339 int
my_context_yield(struct my_context * c)340 my_context_yield(struct my_context *c)
341 {
342 uint64_t *save= &c->save[0];
343 __asm__ __volatile__
344 (
345 "movq (%[save]), %%rax\n\t"
346 "movq %%rsp, (%[save])\n\t"
347 "movq %%rax, %%rsp\n\t"
348 "movq 8(%[save]), %%rax\n\t"
349 "movq %%rbp, 8(%[save])\n\t"
350 "movq %%rax, %%rbp\n\t"
351 "movq 16(%[save]), %%rax\n\t"
352 "movq %%rbx, 16(%[save])\n\t"
353 "movq %%rax, %%rbx\n\t"
354 "movq 24(%[save]), %%rax\n\t"
355 "movq %%r12, 24(%[save])\n\t"
356 "movq %%rax, %%r12\n\t"
357 "movq 32(%[save]), %%rax\n\t"
358 "movq %%r13, 32(%[save])\n\t"
359 "movq %%rax, %%r13\n\t"
360 "movq 40(%[save]), %%rax\n\t"
361 "movq %%r14, 40(%[save])\n\t"
362 "movq %%rax, %%r14\n\t"
363 "movq 48(%[save]), %%rax\n\t"
364 "movq %%r15, 48(%[save])\n\t"
365 "movq %%rax, %%r15\n\t"
366 "movq 64(%[save]), %%rax\n\t"
367 "leaq 1f(%%rip), %%rcx\n\t"
368 "movq %%rcx, 64(%[save])\n\t"
369
370 "jmpq *%%rax\n"
371
372 "1:\n"
373 : [save] "+D" (save)
374 :
375 : "rax", "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc"
376 );
377 return 0;
378 }
379
380 int
my_context_init(struct my_context * c,size_t stack_size)381 my_context_init(struct my_context *c, size_t stack_size)
382 {
383 bzero(c, sizeof(*c));
384
385 if (!(c->stack_bot= malloc(stack_size)))
386 return -1; /* Out of memory */
387 /*
388 The x86_64 ABI specifies 16-byte stack alignment.
389 Also put two zero words at the top of the stack.
390 */
391 c->stack_top= (void *)
392 (( ((intptr)c->stack_bot + stack_size) & ~(intptr)0xf) - 16);
393 bzero(c->stack_top, 16);
394
395 #ifdef HAVE_VALGRIND_MEMCHECK_H
396 c->valgrind_stack_id=
397 VALGRIND_STACK_REGISTER(c->stack_bot, c->stack_top);
398 #endif
399 return 0;
400 }
401
402 void
my_context_destroy(struct my_context * c)403 my_context_destroy(struct my_context *c)
404 {
405 if (c->stack_bot)
406 {
407 free(c->stack_bot);
408 #ifdef HAVE_VALGRIND_MEMCHECK_H
409 VALGRIND_STACK_DEREGISTER(c->valgrind_stack_id);
410 #endif
411 }
412 DBUG_FREE_CODE_STATE(&c->dbug_state);
413 }
414
415 #endif /* MY_CONTEXT_USE_X86_64_GCC_ASM */
416
417
418 #ifdef MY_CONTEXT_USE_I386_GCC_ASM
419 /*
420 GCC-i386 implementation of my_context.
421
422 This is slightly optimized in the common case where we never yield
423 (eg. fetch next row and it is already fully received in buffer). In this
424 case we do not need to restore registers at return (though we still need to
425 save them as we cannot know if we will yield or not in advance).
426 */
427
428 #include <stdint.h>
429 #include <stdlib.h>
430
431 /*
432 Layout of saved registers etc.
433 Since this is accessed through gcc inline assembler, it is simpler to just
434 use numbers than to try to define nice constants or structs.
435
436 0 0 %esp
437 1 4 %ebp
438 2 8 %ebx
439 3 12 %esi
440 4 16 %edi
441 5 20 %eip for done
442 6 24 %eip for yield/continue
443 */
444
445 int
my_context_spawn(struct my_context * c,void (* f)(void *),void * d)446 my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
447 {
448 int ret;
449
450 DBUG_SWAP_CODE_STATE(&c->dbug_state);
451
452 /*
453 There are 4 callee-save registers we need to save and restore when
454 suspending and continuing, plus stack pointer %esp and instruction pointer
455 %eip.
456
457 However, if we never suspend, the user-supplied function will in any case
458 restore the 4 callee-save registers, so we can avoid restoring them in
459 this case.
460 */
461 __asm__ __volatile__
462 (
463 "movl %%esp, (%[save])\n\t"
464 "movl %[stack], %%esp\n\t"
465 #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) && !defined(__INTEL_COMPILER)
466 /*
467 This emits a DWARF DW_CFA_undefined directive to make the return address
468 undefined. This indicates that this is the top of the stack frame, and
469 helps tools that use DWARF stack unwinding to obtain stack traces.
470 (I use numeric constant to avoid a dependency on libdwarf includes).
471 */
472 ".cfi_escape 0x07, 8\n\t"
473 #endif
474 /* Push the parameter on the stack. */
475 "pushl %[d]\n\t"
476 "movl %%ebp, 4(%[save])\n\t"
477 "movl %%ebx, 8(%[save])\n\t"
478 "movl %%esi, 12(%[save])\n\t"
479 "movl %%edi, 16(%[save])\n\t"
480 /* Get label addresses in -fPIC-compatible way (no pc-relative on 32bit) */
481 "call 1f\n"
482 "1:\n\t"
483 "popl %%eax\n\t"
484 "addl $(2f-1b), %%eax\n\t"
485 "movl %%eax, 20(%[save])\n\t"
486 "addl $(3f-2f), %%eax\n\t"
487 "movl %%eax, 24(%[save])\n\t"
488 "call *%[f]\n\t"
489 "jmp *20(%[save])\n"
490 /*
491 Come here when operation is done.
492 We do not need to restore callee-save registers, as the called function
493 will do this for us if needed.
494 */
495 "2:\n\t"
496 "movl (%[save]), %%esp\n\t"
497 "xorl %[ret], %[ret]\n\t"
498 "jmp 4f\n"
499 /* Come here when operation was suspended. */
500 "3:\n\t"
501 "movl $1, %[ret]\n"
502 "4:\n"
503 : [ret] "=a" (ret),
504 [f] "+c" (f),
505 [d] "+d" (d)
506 : [stack] "a" (c->stack_top),
507 /* Need this in callee-save register to preserve across function call. */
508 [save] "D" (&c->save[0])
509 : "memory", "cc"
510 );
511
512 DBUG_SWAP_CODE_STATE(&c->dbug_state);
513
514 return ret;
515 }
516
517 int
my_context_continue(struct my_context * c)518 my_context_continue(struct my_context *c)
519 {
520 int ret;
521
522 DBUG_SWAP_CODE_STATE(&c->dbug_state);
523
524 __asm__ __volatile__
525 (
526 "movl (%[save]), %%eax\n\t"
527 "movl %%esp, (%[save])\n\t"
528 "movl %%eax, %%esp\n\t"
529 "movl 4(%[save]), %%eax\n\t"
530 "movl %%ebp, 4(%[save])\n\t"
531 "movl %%eax, %%ebp\n\t"
532 "movl 8(%[save]), %%eax\n\t"
533 "movl %%ebx, 8(%[save])\n\t"
534 "movl %%eax, %%ebx\n\t"
535 "movl 12(%[save]), %%eax\n\t"
536 "movl %%esi, 12(%[save])\n\t"
537 "movl %%eax, %%esi\n\t"
538
539 "movl 24(%[save]), %%eax\n\t"
540 "call 1f\n"
541 "1:\n\t"
542 "popl %%ecx\n\t"
543 "addl $(2f-1b), %%ecx\n\t"
544 "movl %%ecx, 20(%[save])\n\t"
545 "addl $(3f-2f), %%ecx\n\t"
546 "movl %%ecx, 24(%[save])\n\t"
547
548 /* Must restore %edi last as it is also our %[save] register. */
549 "movl 16(%[save]), %%ecx\n\t"
550 "movl %%edi, 16(%[save])\n\t"
551 "movl %%ecx, %%edi\n\t"
552
553 "jmp *%%eax\n"
554 /*
555 Come here when operation is done.
556 Be sure to use the same callee-save register for %[save] here and in
557 my_context_spawn(), so we preserve the value correctly at this point.
558 */
559 "2:\n\t"
560 "movl (%[save]), %%esp\n\t"
561 "movl 4(%[save]), %%ebp\n\t"
562 "movl 8(%[save]), %%ebx\n\t"
563 "movl 12(%[save]), %%esi\n\t"
564 "movl 16(%[save]), %%edi\n\t"
565 "xorl %[ret], %[ret]\n\t"
566 "jmp 4f\n"
567 /* Come here when operation is suspended. */
568 "3:\n\t"
569 "movl $1, %[ret]\n"
570 "4:\n"
571 : [ret] "=a" (ret)
572 : /* Need this in callee-save register to preserve in function call. */
573 [save] "D" (&c->save[0])
574 : "ecx", "edx", "memory", "cc"
575 );
576
577 DBUG_SWAP_CODE_STATE(&c->dbug_state);
578
579 return ret;
580 }
581
582 int
my_context_yield(struct my_context * c)583 my_context_yield(struct my_context *c)
584 {
585 uint64_t *save= &c->save[0];
586 __asm__ __volatile__
587 (
588 "movl (%[save]), %%eax\n\t"
589 "movl %%esp, (%[save])\n\t"
590 "movl %%eax, %%esp\n\t"
591 "movl 4(%[save]), %%eax\n\t"
592 "movl %%ebp, 4(%[save])\n\t"
593 "movl %%eax, %%ebp\n\t"
594 "movl 8(%[save]), %%eax\n\t"
595 "movl %%ebx, 8(%[save])\n\t"
596 "movl %%eax, %%ebx\n\t"
597 "movl 12(%[save]), %%eax\n\t"
598 "movl %%esi, 12(%[save])\n\t"
599 "movl %%eax, %%esi\n\t"
600 "movl 16(%[save]), %%eax\n\t"
601 "movl %%edi, 16(%[save])\n\t"
602 "movl %%eax, %%edi\n\t"
603
604 "movl 24(%[save]), %%eax\n\t"
605 "call 1f\n"
606 "1:\n\t"
607 "popl %%ecx\n\t"
608 "addl $(2f-1b), %%ecx\n\t"
609 "movl %%ecx, 24(%[save])\n\t"
610
611 "jmp *%%eax\n"
612
613 "2:\n"
614 : [save] "+d" (save)
615 :
616 : "eax", "ecx", "memory", "cc"
617 );
618 return 0;
619 }
620
621 int
my_context_init(struct my_context * c,size_t stack_size)622 my_context_init(struct my_context *c, size_t stack_size)
623 {
624 bzero(c, sizeof(*c));
625 if (!(c->stack_bot= malloc(stack_size)))
626 return -1; /* Out of memory */
627 c->stack_top= (void *)
628 (( ((intptr)c->stack_bot + stack_size) & ~(intptr)0xf) - 16);
629 bzero(c->stack_top, 16);
630
631 #ifdef HAVE_VALGRIND_MEMCHECK_H
632 c->valgrind_stack_id=
633 VALGRIND_STACK_REGISTER(c->stack_bot, c->stack_top);
634 #endif
635 return 0;
636 }
637
638 void
my_context_destroy(struct my_context * c)639 my_context_destroy(struct my_context *c)
640 {
641 if (c->stack_bot)
642 {
643 free(c->stack_bot);
644 #ifdef HAVE_VALGRIND_MEMCHECK_H
645 VALGRIND_STACK_DEREGISTER(c->valgrind_stack_id);
646 #endif
647 }
648 DBUG_FREE_CODE_STATE(&c->dbug_state);
649 }
650
651 #endif /* MY_CONTEXT_USE_I386_GCC_ASM */
652
653
654 #ifdef MY_CONTEXT_USE_WIN32_FIBERS
655 int
my_context_yield(struct my_context * c)656 my_context_yield(struct my_context *c)
657 {
658 c->return_value= 1;
659 SwitchToFiber(c->app_fiber);
660 return 0;
661 }
662
663
664 static void WINAPI
my_context_trampoline(void * p)665 my_context_trampoline(void *p)
666 {
667 struct my_context *c= (struct my_context *)p;
668 /*
669 Reuse the Fiber by looping infinitely, each time we are scheduled we
670 spawn the appropriate function and switch back when it is done.
671
672 This way we avoid the overhead of CreateFiber() for every asynchroneous
673 operation.
674 */
675 for(;;)
676 {
677 (*(c->user_func))(c->user_arg);
678 c->return_value= 0;
679 SwitchToFiber(c->app_fiber);
680 }
681 }
682
683 int
my_context_init(struct my_context * c,size_t stack_size)684 my_context_init(struct my_context *c, size_t stack_size)
685 {
686 bzero(c, sizeof(*c));
687 c->lib_fiber= CreateFiber(stack_size, my_context_trampoline, c);
688 if (c->lib_fiber)
689 return 0;
690 return -1;
691 }
692
693 void
my_context_destroy(struct my_context * c)694 my_context_destroy(struct my_context *c)
695 {
696 DBUG_FREE_CODE_STATE(&c->dbug_state);
697 if (c->lib_fiber)
698 {
699 DeleteFiber(c->lib_fiber);
700 c->lib_fiber= NULL;
701 }
702 }
703
704 int
my_context_spawn(struct my_context * c,void (* f)(void *),void * d)705 my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
706 {
707 c->user_func= f;
708 c->user_arg= d;
709 return my_context_continue(c);
710 }
711
712 int
my_context_continue(struct my_context * c)713 my_context_continue(struct my_context *c)
714 {
715 /*
716 This seems to be a common trick to run ConvertThreadToFiber() only on the
717 first occurrence in a thread, in a way that works on multiple Windows
718 versions.
719 */
720 void *current_fiber= GetCurrentFiber();
721 if (current_fiber == NULL || current_fiber == (void *)0x1e00)
722 current_fiber= ConvertThreadToFiber(c);
723 c->app_fiber= current_fiber;
724 DBUG_SWAP_CODE_STATE(&c->dbug_state);
725 SwitchToFiber(c->lib_fiber);
726 DBUG_SWAP_CODE_STATE(&c->dbug_state);
727
728 return c->return_value;
729 }
730
731 #endif /* MY_CONTEXT_USE_WIN32_FIBERS */
732
733 #ifdef MY_CONTEXT_DISABLE
734 int
my_context_continue(struct my_context * c)735 my_context_continue(struct my_context *c __attribute__((unused)))
736 {
737 return -1;
738 }
739
740
741 int
my_context_spawn(struct my_context * c,void (* f)(void *),void * d)742 my_context_spawn(struct my_context *c __attribute__((unused)),
743 void (*f)(void *) __attribute__((unused)),
744 void *d __attribute__((unused)))
745 {
746 return -1;
747 }
748
749
750 int
my_context_yield(struct my_context * c)751 my_context_yield(struct my_context *c __attribute__((unused)))
752 {
753 return -1;
754 }
755
756 int
my_context_init(struct my_context * c,size_t stack_size)757 my_context_init(struct my_context *c __attribute__((unused)),
758 size_t stack_size __attribute__((unused)))
759 {
760 return -1; /* Out of memory */
761 }
762
763 void
my_context_destroy(struct my_context * c)764 my_context_destroy(struct my_context *c __attribute__((unused)))
765 {
766 }
767
768 #endif
769