2
** Copyright (C) 2004-2007 Mike Pall. All rights reserved.
4
** Permission is hereby granted, free of charge, to any person obtaining
5
** a copy of this software and associated documentation files (the
6
** "Software"), to deal in the Software without restriction, including
7
** without limitation the rights to use, copy, modify, merge, publish,
8
** distribute, sublicense, and/or sell copies of the Software, and to
9
** permit persons to whom the Software is furnished to do so, subject to
10
** the following conditions:
12
** The above copyright notice and this permission notice shall be
13
** included in all copies or substantial portions of the Software.
15
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
26
/* Coco -- True C coroutines for Lua. http://luajit.org/coco.html */
42
** Define this if you want to run Coco with valgrind. You will get random
43
** errors about accessing memory from newly allocated C stacks if you don't.
44
** You need at least valgrind 3.0 for this to work.
46
** This macro evaluates to a no-op if not run with valgrind. I.e. you can
47
** use the same binary for regular runs, too (without a performance loss).
50
#include <valgrind/valgrind.h>
51
#define STACK_REG(coco, p, sz) (coco)->vgid = VALGRIND_STACK_REGISTER(p, p+sz);
52
#define STACK_DEREG(coco) VALGRIND_STACK_DEREGISTER((coco)->vgid);
53
#define STACK_VGID unsigned int vgid;
55
#define STACK_REG(coco, p, sz)
56
#define STACK_DEREG(id)
60
/* ------------------------------------------------------------------------ */
62
/* Use Windows Fibers. */
63
#if defined(COCO_USE_FIBERS)
65
#define _WIN32_WINNT 0x0400
68
#define COCO_MAIN_DECL CALLBACK
70
typedef LPFIBER_START_ROUTINE coco_MainFunc;
72
#define COCO_NEW(OL, NL, cstacksize, mainfunc) \
73
if ((L2COCO(NL)->fib = CreateFiber(cstacksize, mainfunc, NL)) == NULL) \
74
luaD_throw(OL, LUA_ERRMEM);
76
#define COCO_FREE(L) \
77
DeleteFiber(L2COCO(L)->fib); \
78
L2COCO(L)->fib = NULL;
80
/* See: http://blogs.msdn.com/oldnewthing/archive/2004/12/31/344799.aspx */
81
#define COCO_JUMPIN(coco) \
82
{ void *cur = GetCurrentFiber(); \
83
coco->back = (cur == NULL || cur == (void *)0x1e00) ? \
84
ConvertThreadToFiber(NULL) : cur; } \
85
SwitchToFiber(coco->fib);
87
#define COCO_JUMPOUT(coco) \
88
SwitchToFiber(coco->back);
90
/* CreateFiber() defaults to STACKSIZE from the Windows module .def file. */
91
#define COCO_DEFAULT_CSTACKSIZE 0
93
/* ------------------------------------------------------------------------ */
95
#else /* !COCO_USE_FIBERS */
97
#ifndef COCO_USE_UCONTEXT
99
/* Try inline asm first. */
100
#if __GNUC__ >= 3 && !defined(COCO_USE_SETJMP)
102
#if defined(__i386) || defined(__i386__)
105
typedef void *coco_ctx[4]; /* eip, esp, ebp, ebx */
106
static inline void coco_switch(coco_ctx from, coco_ctx to)
108
__asm__ __volatile__ (
109
"call 1f\n" "1:\tpopl %%eax\n\t" "addl $(2f-1b),%%eax\n\t"
110
"movl %%eax, (%0)\n\t" "movl %%esp, 4(%0)\n\t"
111
"movl %%ebp, 8(%0)\n\t" "movl %%ebx, 12(%0)\n\t"
112
"movl 12(%1), %%ebx\n\t" "movl 8(%1), %%ebp\n\t"
113
"movl 4(%1), %%esp\n\t" "jmp *(%1)\n" "2:\n"
114
: "+S" (from), "+D" (to) : : "eax", "ecx", "edx", "memory", "cc");
117
typedef void *coco_ctx[3]; /* eip, esp, ebp */
118
static inline void coco_switch(coco_ctx from, coco_ctx to)
120
__asm__ __volatile__ (
121
"movl $1f, (%0)\n\t" "movl %%esp, 4(%0)\n\t" "movl %%ebp, 8(%0)\n\t"
122
"movl 8(%1), %%ebp\n\t" "movl 4(%1), %%esp\n\t" "jmp *(%1)\n" "1:\n"
123
: "+S" (from), "+D" (to) : : "eax", "ebx", "ecx", "edx", "memory", "cc");
127
#define COCO_CTX coco_ctx
128
#define COCO_SWITCH(from, to) coco_switch(from, to);
129
#define COCO_MAKECTX(coco, buf, func, stack, a0) \
130
buf[0] = (void *)(func); \
131
buf[1] = (void *)(stack); \
132
buf[2] = (void *)0; \
133
stack[0] = 0xdeadc0c0; /* Dummy return address. */ \
134
coco->arg0 = (size_t)(a0);
135
#define COCO_STATE_HEAD size_t arg0;
137
#elif __mips && _MIPS_SIM == _MIPS_SIM_ABI32 && !defined(__mips_eabi)
139
/* No way to avoid the function prologue with inline assembler. So use this: */
140
static const unsigned int coco_switch[] = {
141
#ifdef __mips_soft_float
142
#define COCO_STACKSAVE -10
143
0x27bdffd8, /* addiu sp, sp, -(10*4) */
145
#define COCO_STACKSAVE -22
146
0x27bdffa8, /* addiu sp, sp, -(10*4+6*8) */
147
/* sdc1 {$f20-$f30}, offset(sp) */
148
0xf7be0050, 0xf7bc0048, 0xf7ba0040, 0xf7b80038, 0xf7b60030, 0xf7b40028,
150
/* sw {gp,s0-s8}, offset(sp) */
151
0xafbe0024, 0xafb70020, 0xafb6001c, 0xafb50018, 0xafb40014, 0xafb30010,
152
0xafb2000c, 0xafb10008, 0xafb00004, 0xafbc0000,
153
/* sw sp, 4(a0); sw ra, 0(a0); lw ra, 0(a1); lw sp, 4(a1); move t9, ra */
154
0xac9d0004, 0xac9f0000, 0x8cbf0000, 0x8cbd0004, 0x03e0c821,
155
/* lw caller-saved-reg, offset(sp) */
156
0x8fbe0024, 0x8fb70020, 0x8fb6001c, 0x8fb50018, 0x8fb40014, 0x8fb30010,
157
0x8fb2000c, 0x8fb10008, 0x8fb00004, 0x8fbc0000,
158
#ifdef __mips_soft_float
159
0x03e00008, 0x27bd0028 /* jr ra; addiu sp, sp, 10*4 */
161
/* ldc1 {$f20-$f30}, offset(sp) */
162
0xd7be0050, 0xd7bc0048, 0xd7ba0040, 0xd7b80038, 0xd7b60030, 0xd7b40028,
163
0x03e00008, 0x27bd0058 /* jr ra; addiu sp, sp, 10*4+6*8 */
167
typedef void *coco_ctx[2]; /* ra, sp */
168
#define COCO_CTX coco_ctx
169
#define COCO_SWITCH(from, to) \
170
((void (*)(coco_ctx, coco_ctx))coco_switch)(from, to);
171
#define COCO_MAKECTX(coco, buf, func, stack, a0) \
172
buf[0] = (void *)(func); \
173
buf[1] = (void *)&stack[COCO_STACKSAVE]; \
174
stack[4] = (size_t)(a0); /* Assumes o32 ABI. */
175
#define COCO_STACKADJUST 8
176
#define COCO_MAIN_PARAM int _a, int _b, int _c, int _d, lua_State *L
178
#endif /* arch check */
180
#endif /* !(__GNUC__ >= 3 && !defined(COCO_USE_SETJMP)) */
182
/* Try _setjmp/_longjmp with a patched jump buffer. */
186
/* Check for supported CPU+OS combinations. */
187
#if defined(__i386) || defined(__i386__)
189
#define COCO_STATE_HEAD size_t arg0;
190
#define COCO_SETJMP_X86(coco, stack, a0) \
191
stack[COCO_STACKADJUST-1] = 0xdeadc0c0; /* Dummy return address. */ \
192
coco->arg0 = (size_t)(a0);
194
#if __GLIBC__ == 2 && defined(JB_SP) /* x86-linux-glibc2 */
195
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
196
buf->__jmpbuf[JB_PC] = (int)(func); \
197
buf->__jmpbuf[JB_SP] = (int)(stack); \
198
buf->__jmpbuf[JB_BP] = 0; \
199
COCO_SETJMP_X86(coco, stack, a0)
200
#elif defined(__linux__) && defined(_I386_JMP_BUF_H) /* x86-linux-libc5 */
201
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
202
buf->__pc = (func); \
203
buf->__sp = (stack); \
205
COCO_SETJMP_X86(coco, stack, a0)
206
#elif defined(__FreeBSD__) /* x86-FreeBSD */
207
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
208
buf->_jb[0] = (long)(func); \
209
buf->_jb[2] = (long)(stack); \
210
buf->_jb[3] = 0; /* ebp */ \
211
COCO_SETJMP_X86(coco, stack, a0)
212
#define COCO_STACKADJUST 2
213
#elif defined(__NetBSD__) || defined(__OpenBSD__) /* x86-NetBSD, x86-OpenBSD */
214
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
215
buf[0] = (long)(func); \
216
buf[2] = (long)(stack); \
217
buf[3] = 0; /* ebp */ \
218
COCO_SETJMP_X86(coco, stack, a0)
219
#define COCO_STACKADJUST 2
220
#elif defined(__solaris__) && _JBLEN == 10 /* x86-solaris */
221
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
222
buf[5] = (int)(func); \
223
buf[4] = (int)(stack); \
225
COCO_SETJMP_X86(coco, stack, a0)
226
#elif defined(__MACH__) && defined(_BSD_I386_SETJMP_H_) /* x86-macosx */
227
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
228
buf[12] = (int)(func); \
229
buf[9] = (int)(stack); \
230
buf[8] = 0; /* ebp */ \
231
COCO_SETJMP_X86(coco, stack, a0)
234
#elif defined(__x86_64__) || defined(__x86_64)
236
#define COCO_STATE_HEAD size_t arg0;
238
#define COCO_MAIN_PARAM \
239
int _a, int _b, int _c, int _d, int _e, int _f, lua_State *L
241
#if __GLIBC__ == 2 && defined(JB_RSP) /* x64-linux-glibc2 */
242
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
243
buf->__jmpbuf[JB_PC] = (long)(func); \
244
buf->__jmpbuf[JB_RSP] = (long)(stack); \
245
buf->__jmpbuf[JB_RBP] = 0; \
246
stack[0] = 0xdeadc0c0; /* Dummy return address. */ \
247
coco->arg0 = (size_t)(a0);
248
#elif defined(__solaris__) && _JBLEN == 8 /* x64-solaris */
249
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
250
buf[7] = (long)(func); \
251
buf[6] = (long)(stack); \
253
stack[0] = 0xdeadc0c0; /* Dummy return address. */ \
254
coco->arg0 = (size_t)(a0);
257
#elif defined(PPC) || defined(__ppc__) || defined(__PPC__) || \
258
defined(__powerpc__) || defined(__POWERPC__) || defined(_ARCH_PPC)
260
#define COCO_STACKADJUST 16
261
#define COCO_MAIN_PARAM \
262
int _a, int _b, int _c, int _d, int _e, int _f, int _g, int _h, lua_State *L
264
#if defined(__MACH__) && defined(_BSD_PPC_SETJMP_H_) /* ppc32-macosx */
265
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
266
buf[21] = (int)(func); \
267
buf[0] = (int)(stack); \
268
stack[6+8] = (size_t)(a0);
271
#elif (defined(MIPS) || defined(MIPSEL) || defined(__mips)) && \
272
_MIPS_SIM == _MIPS_SIM_ABI32 && !defined(__mips_eabi)
274
/* Stack layout for o32 ABI. */
275
#define COCO_STACKADJUST 8
276
#define COCO_MAIN_PARAM int _a, int _b, int _c, int _d, lua_State *L
278
#if __GLIBC__ == 2 || defined(__UCLIBC__) /* mips32-linux-glibc2 */
279
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
280
buf->__jmpbuf->__pc = (func); /* = t9 in _longjmp. Reqd. for -mabicalls. */ \
281
buf->__jmpbuf->__sp = (stack); \
282
buf->__jmpbuf->__fp = (void *)0; \
283
stack[4] = (size_t)(a0);
286
#elif defined(__arm__) || defined(__ARM__)
288
#if __GLIBC__ == 2 || defined(__UCLIBC__) /* arm-linux-glibc2 */
289
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
290
buf->__jmpbuf[__JMP_BUF_SP+1] = (int)(func); /* pc */ \
291
buf->__jmpbuf[__JMP_BUF_SP] = (int)(stack); /* sp */ \
292
buf->__jmpbuf[__JMP_BUF_SP-1] = 0; /* fp */ \
293
stack[0] = (size_t)(a0);
294
#define COCO_STACKADJUST 2
295
#define COCO_MAIN_PARAM int _a, int _b, int _c, int _d, lua_State *L
298
#endif /* arch check */
301
#define COCO_CTX jmp_buf
302
#define COCO_MAKECTX(coco, buf, func, stack, a0) \
303
_setjmp(buf); COCO_PATCHCTX(coco, buf, func, stack, a0)
304
#define COCO_SWITCH(from, to) if (!_setjmp(from)) _longjmp(to, 1);
307
#endif /* !defined(COCO_MAKECTX) */
309
#endif /* !defined(COCO_USE_UCONTEXT) */
311
/* ------------------------------------------------------------------------ */
313
/* Use inline asm or _setjmp/_longjmp if available. */
316
#ifndef COCO_STACKADJUST
317
#define COCO_STACKADJUST 1
320
#define COCO_FILL(coco, NL, mainfunc) \
321
{ /* Include the return address to get proper stack alignment. */ \
322
size_t *stackptr = &((size_t *)coco)[-COCO_STACKADJUST]; \
323
COCO_MAKECTX(coco, coco->ctx, mainfunc, stackptr, NL) \
326
/* ------------------------------------------------------------------------ */
328
/* Else fallback to ucontext. Slower, because it saves/restores signals. */
329
#else /* !defined(COCO_MAKECTX) */
331
#include <ucontext.h>
333
#define COCO_CTX ucontext_t
335
/* Ugly workaround for makecontext() deficiencies on 64 bit CPUs. */
336
/* Note that WIN64 (which is LLP64) never comes here. See above. */
337
#if defined(__LP64__) || defined(_LP64) || INT_MAX != LONG_MAX
338
/* 64 bit CPU: split the pointer into two 32 bit ints. */
339
#define COCO_MAIN_PARAM unsigned int lo, unsigned int hi
340
#define COCO_MAIN_GETL \
341
lua_State *L = (lua_State *)((((unsigned long)hi)<<32)+(unsigned long)lo);
342
#define COCO_MAKECTX(coco, NL, mainfunc) \
343
makecontext(&coco->ctx, mainfunc, 2, \
344
(int)(ptrdiff_t)NL, (int)((ptrdiff_t)NL>>32));
346
/* 32 bit CPU: a pointer fits into an int. */
347
#define COCO_MAKECTX(coco, NL, mainfunc) \
348
makecontext(&coco->ctx, mainfunc, 1, (int)NL);
351
#define COCO_FILL(coco, NL, mainfunc) \
352
getcontext(&coco->ctx); \
353
coco->ctx.uc_link = NULL; /* We never exit from coco_main. */ \
354
coco->ctx.uc_stack.ss_sp = coco->allocptr; \
355
coco->ctx.uc_stack.ss_size = (char *)coco - (char *)(coco->allocptr); \
356
COCO_MAKECTX(coco, NL, mainfunc)
358
#define COCO_SWITCH(from, to) swapcontext(&(from), &(to));
360
#endif /* !defined(COCO_MAKECTX) */
363
/* Common code for inline asm/setjmp/ucontext to allocate/free the stack. */
366
#ifdef COCO_STATE_HEAD
369
COCO_CTX ctx; /* Own context. */
370
COCO_CTX back; /* Context to switch back to. */
371
void *allocptr; /* Pointer to allocated memory. */
372
int allocsize; /* Size of allocated memory. */
373
int nargs; /* Number of arguments to pass. */
374
STACK_VGID /* Optional valgrind stack id. See above. */
377
typedef void (*coco_MainFunc)(void);
379
/* Put the Coco state at the end and align it downwards. */
380
#define ALIGNED_END(p, s, t) \
381
((t *)(((char *)0) + ((((char *)(p)-(char *)0)+(s)-sizeof(t)) & -16)))
383
/* TODO: use mmap. */
384
#define COCO_NEW(OL, NL, cstacksize, mainfunc) \
386
void *ptr = luaM_malloc(OL, cstacksize); \
387
coco_State *coco = ALIGNED_END(ptr, cstacksize, coco_State); \
388
STACK_REG(coco, ptr, cstacksize) \
389
coco->allocptr = ptr; \
390
coco->allocsize = cstacksize; \
391
COCO_FILL(coco, NL, mainfunc) \
395
#define COCO_FREE(L) \
396
STACK_DEREG(L2COCO(L)) \
397
luaM_freemem(L, L2COCO(L)->allocptr, L2COCO(L)->allocsize); \
400
#define COCO_JUMPIN(coco) COCO_SWITCH(coco->back, coco->ctx)
401
#define COCO_JUMPOUT(coco) COCO_SWITCH(coco->ctx, coco->back)
403
#endif /* !COCO_USE_FIBERS */
405
/* ------------------------------------------------------------------------ */
407
#ifndef COCO_MIN_CSTACKSIZE
408
#define COCO_MIN_CSTACKSIZE (32768+4096)
411
/* Don't use multiples of 64K to avoid D-cache aliasing conflicts. */
412
#ifndef COCO_DEFAULT_CSTACKSIZE
413
#define COCO_DEFAULT_CSTACKSIZE (65536-4096)
416
static int defaultcstacksize = COCO_DEFAULT_CSTACKSIZE;
418
/* Start the Lua or C function. */
419
static void coco_start(lua_State *L, void *ud)
421
if (luaD_precall(L, (StkId)ud, LUA_MULTRET) == PCRLUA)
422
luaV_execute(L, L->ci - L->base_ci);
425
#ifndef COCO_MAIN_PARAM
426
#define COCO_MAIN_PARAM lua_State *L
429
#ifndef COCO_MAIN_DECL
430
#define COCO_MAIN_DECL
433
/* Toplevel function for the new coroutine stack. Never exits. */
434
static void COCO_MAIN_DECL coco_main(COCO_MAIN_PARAM)
436
#ifdef COCO_MAIN_GETL
439
coco_State *coco = L2COCO(L);
441
L->status = luaD_rawrunprotected(L, coco_start, L->top - (coco->nargs+1));
442
if (L->status != 0) luaD_seterrorobj(L, L->status, L->top);
447
/* Add a C stack to a coroutine. */
448
lua_State *lua_newcthread(lua_State *OL, int cstacksize)
450
lua_State *NL = lua_newthread(OL);
455
cstacksize = defaultcstacksize;
456
else if (cstacksize < COCO_MIN_CSTACKSIZE)
457
cstacksize = COCO_MIN_CSTACKSIZE;
460
COCO_NEW(OL, NL, cstacksize, ((coco_MainFunc)(coco_main)))
465
/* Free the C stack of a coroutine. Called from lstate.c. */
466
void luaCOCO_free(lua_State *L)
471
/* Resume a coroutine with a C stack. Called from ldo.c. */
472
int luaCOCO_resume(lua_State *L, int nargs)
474
coco_State *coco = L2COCO(L);
477
#ifndef COCO_DISABLE_EARLY_FREE
478
if (L->status != LUA_YIELD) {
485
/* Yield from a coroutine with a C stack. Called from ldo.c. */
486
int luaCOCO_yield(lua_State *L)
488
coco_State *coco = L2COCO(L);
489
L->status = LUA_YIELD;
493
StkId base = L->top - coco->nargs;
494
StkId rbase = L->base;
495
if (rbase < base) { /* Need to move args down? */
496
while (base < L->top)
497
setobjs2s(L, rbase++, base++);
501
L->base = L->ci->base; /* Restore invariant. */
505
/* Get/set the default C stack size. */
506
int luaCOCO_cstacksize(int cstacksize)
508
int oldsz = defaultcstacksize;
509
if (cstacksize >= 0) {
511
cstacksize = COCO_DEFAULT_CSTACKSIZE;
512
else if (cstacksize < COCO_MIN_CSTACKSIZE)
513
cstacksize = COCO_MIN_CSTACKSIZE;
514
defaultcstacksize = cstacksize;