Line data Source code
1 : /*
2 : ** $Id: lcorolib.c,v 1.10.1.1 2017/04/19 17:20:42 roberto Exp $
3 : ** Coroutine Library
4 : ** See Copyright Notice in lua.h
5 : */
6 :
7 : #define lcorolib_c
8 : #define LUA_LIB
9 :
10 : #include "lprefix.h"
11 :
12 :
13 : #include <stdlib.h>
14 :
15 : #include "lua.h"
16 :
17 : #include "lauxlib.h"
18 : #include "lualib.h"
19 :
20 :
21 5952 : static lua_State *getco (lua_State *L) {
22 5952 : lua_State *co = lua_tothread(L, 1);
23 5952 : luaL_argcheck(L, co, 1, "thread expected");
24 5950 : return co;
25 : }
26 :
27 :
28 5972 : static int auxresume (lua_State *L, lua_State *co, int narg) {
29 : int status;
30 5972 : if (!lua_checkstack(co, narg)) {
31 0 : lua_pushliteral(L, "too many arguments to resume");
32 0 : return -1; /* error flag */
33 : }
34 5972 : if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
35 2 : lua_pushliteral(L, "cannot resume dead coroutine");
36 2 : return -1; /* error flag */
37 : }
38 5970 : lua_xmove(L, co, narg);
39 5970 : status = lua_resume(co, L, narg);
40 5970 : if (status == LUA_OK || status == LUA_YIELD) {
41 5968 : int nres = lua_gettop(co);
42 5968 : if (!lua_checkstack(L, nres + 1)) {
43 0 : lua_pop(co, nres); /* remove results anyway */
44 0 : lua_pushliteral(L, "too many results to resume");
45 0 : return -1; /* error flag */
46 : }
47 5968 : lua_xmove(co, L, nres); /* move yielded values */
48 5968 : return nres;
49 : }
50 : else {
51 2 : lua_xmove(co, L, 1); /* move error message */
52 2 : return -1; /* error flag */
53 : }
54 : }
55 :
56 :
57 5948 : static int luaB_coresume (lua_State *L) {
58 5948 : lua_State *co = getco(L);
59 : int r;
60 5947 : r = auxresume(L, co, lua_gettop(L) - 1);
61 5947 : if (r < 0) {
62 3 : lua_pushboolean(L, 0);
63 3 : lua_insert(L, -2);
64 3 : return 2; /* return false + error message */
65 : }
66 : else {
67 5944 : lua_pushboolean(L, 1);
68 5944 : lua_insert(L, -(r + 1));
69 5944 : return r + 1; /* return true + 'resume' returns */
70 : }
71 : }
72 :
73 :
74 25 : static int luaB_auxwrap (lua_State *L) {
75 25 : lua_State *co = lua_tothread(L, lua_upvalueindex(1));
76 25 : int r = auxresume(L, co, lua_gettop(L));
77 25 : if (r < 0) {
78 1 : if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
79 1 : luaL_where(L, 1); /* add extra info */
80 1 : lua_insert(L, -2);
81 1 : lua_concat(L, 2);
82 : }
83 1 : return lua_error(L); /* propagate error */
84 : }
85 24 : return r;
86 : }
87 :
88 :
89 29 : static int luaB_cocreate (lua_State *L) {
90 : lua_State *NL;
91 29 : luaL_checktype(L, 1, LUA_TFUNCTION);
92 27 : NL = lua_newthread(L);
93 27 : lua_pushvalue(L, 1); /* move function to top */
94 27 : lua_xmove(L, NL, 1); /* move function from L to NL */
95 27 : return 1;
96 : }
97 :
98 :
99 8 : static int luaB_cowrap (lua_State *L) {
100 8 : luaB_cocreate(L);
101 7 : lua_pushcclosure(L, luaB_auxwrap, 1);
102 7 : return 1;
103 : }
104 :
105 :
106 5954 : static int luaB_yield (lua_State *L) {
107 5954 : return lua_yield(L, lua_gettop(L));
108 : }
109 :
110 :
111 4 : static int luaB_costatus (lua_State *L) {
112 4 : lua_State *co = getco(L);
113 3 : if (L == co) lua_pushliteral(L, "running");
114 : else {
115 3 : switch (lua_status(co)) {
116 1 : case LUA_YIELD:
117 1 : lua_pushliteral(L, "suspended");
118 1 : break;
119 2 : case LUA_OK: {
120 : lua_Debug ar;
121 2 : if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
122 0 : lua_pushliteral(L, "normal"); /* it is running */
123 2 : else if (lua_gettop(co) == 0)
124 1 : lua_pushliteral(L, "dead");
125 : else
126 1 : lua_pushliteral(L, "suspended"); /* initial state */
127 2 : break;
128 : }
129 0 : default: /* some error occurred */
130 0 : lua_pushliteral(L, "dead");
131 0 : break;
132 : }
133 : }
134 3 : return 1;
135 : }
136 :
137 :
138 1 : static int luaB_yieldable (lua_State *L) {
139 1 : lua_pushboolean(L, lua_isyieldable(L));
140 1 : return 1;
141 : }
142 :
143 :
144 1 : static int luaB_corunning (lua_State *L) {
145 1 : int ismain = lua_pushthread(L);
146 1 : lua_pushboolean(L, ismain);
147 1 : return 2;
148 : }
149 :
150 :
151 : static const luaL_Reg co_funcs[] = {
152 : {"create", luaB_cocreate},
153 : {"resume", luaB_coresume},
154 : {"running", luaB_corunning},
155 : {"status", luaB_costatus},
156 : {"wrap", luaB_cowrap},
157 : {"yield", luaB_yield},
158 : {"isyieldable", luaB_yieldable},
159 : {NULL, NULL}
160 : };
161 :
162 :
163 :
164 86 : LUAMOD_API int luaopen_coroutine (lua_State *L) {
165 86 : luaL_newlib(L, co_funcs);
166 86 : return 1;
167 : }
168 :
|