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