Coverage Report

Created: 2023-09-15 06:20

/src/testdir/build/lua-master/source/lcorolib.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
** $Id: lcorolib.c $
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
0
static lua_State *getco (lua_State *L) {
22
0
  lua_State *co = lua_tothread(L, 1);
23
0
  luaL_argexpected(L, co, 1, "thread");
24
0
  return co;
25
0
}
26
27
28
/*
29
** Resumes a coroutine. Returns the number of results for non-error
30
** cases or -1 for errors.
31
*/
32
0
static int auxresume (lua_State *L, lua_State *co, int narg) {
33
0
  int status, nres;
34
0
  if (l_unlikely(!lua_checkstack(co, narg))) {
35
0
    lua_pushliteral(L, "too many arguments to resume");
36
0
    return -1;  /* error flag */
37
0
  }
38
0
  lua_xmove(L, co, narg);
39
0
  status = lua_resume(co, L, narg, &nres);
40
0
  if (l_likely(status == LUA_OK || status == LUA_YIELD)) {
41
0
    if (l_unlikely(!lua_checkstack(L, nres + 1))) {
42
0
      lua_pop(co, nres);  /* remove results anyway */
43
0
      lua_pushliteral(L, "too many results to resume");
44
0
      return -1;  /* error flag */
45
0
    }
46
0
    lua_xmove(co, L, nres);  /* move yielded values */
47
0
    return nres;
48
0
  }
49
0
  else {
50
0
    lua_xmove(co, L, 1);  /* move error message */
51
0
    return -1;  /* error flag */
52
0
  }
53
0
}
54
55
56
0
static int luaB_coresume (lua_State *L) {
57
0
  lua_State *co = getco(L);
58
0
  int r;
59
0
  r = auxresume(L, co, lua_gettop(L) - 1);
60
0
  if (l_unlikely(r < 0)) {
61
0
    lua_pushboolean(L, 0);
62
0
    lua_insert(L, -2);
63
0
    return 2;  /* return false + error message */
64
0
  }
65
0
  else {
66
0
    lua_pushboolean(L, 1);
67
0
    lua_insert(L, -(r + 1));
68
0
    return r + 1;  /* return true + 'resume' returns */
69
0
  }
70
0
}
71
72
73
0
static int luaB_auxwrap (lua_State *L) {
74
0
  lua_State *co = lua_tothread(L, lua_upvalueindex(1));
75
0
  int r = auxresume(L, co, lua_gettop(L));
76
0
  if (l_unlikely(r < 0)) {  /* error? */
77
0
    int stat = lua_status(co);
78
0
    if (stat != LUA_OK && stat != LUA_YIELD) {  /* error in the coroutine? */
79
0
      stat = lua_closethread(co, L);  /* close its tbc variables */
80
0
      lua_assert(stat != LUA_OK);
81
0
      lua_xmove(co, L, 1);  /* move error message to the caller */
82
0
    }
83
0
    if (stat != LUA_ERRMEM &&  /* not a memory error and ... */
84
0
        lua_type(L, -1) == LUA_TSTRING) {  /* ... error object is a string? */
85
0
      luaL_where(L, 1);  /* add extra info, if available */
86
0
      lua_insert(L, -2);
87
0
      lua_concat(L, 2);
88
0
    }
89
0
    return lua_error(L);  /* propagate error */
90
0
  }
91
0
  return r;
92
0
}
93
94
95
0
static int luaB_cocreate (lua_State *L) {
96
0
  lua_State *NL;
97
0
  luaL_checktype(L, 1, LUA_TFUNCTION);
98
0
  NL = lua_newthread(L);
99
0
  lua_pushvalue(L, 1);  /* move function to top */
100
0
  lua_xmove(L, NL, 1);  /* move function from L to NL */
101
0
  return 1;
102
0
}
103
104
105
0
static int luaB_cowrap (lua_State *L) {
106
0
  luaB_cocreate(L);
107
0
  lua_pushcclosure(L, luaB_auxwrap, 1);
108
0
  return 1;
109
0
}
110
111
112
0
static int luaB_yield (lua_State *L) {
113
0
  return lua_yield(L, lua_gettop(L));
114
0
}
115
116
117
0
#define COS_RUN   0
118
0
#define COS_DEAD  1
119
0
#define COS_YIELD 2
120
0
#define COS_NORM  3
121
122
123
static const char *const statname[] =
124
  {"running", "dead", "suspended", "normal"};
125
126
127
0
static int auxstatus (lua_State *L, lua_State *co) {
128
0
  if (L == co) return COS_RUN;
129
0
  else {
130
0
    switch (lua_status(co)) {
131
0
      case LUA_YIELD:
132
0
        return COS_YIELD;
133
0
      case LUA_OK: {
134
0
        lua_Debug ar;
135
0
        if (lua_getstack(co, 0, &ar))  /* does it have frames? */
136
0
          return COS_NORM;  /* it is running */
137
0
        else if (lua_gettop(co) == 0)
138
0
            return COS_DEAD;
139
0
        else
140
0
          return COS_YIELD;  /* initial state */
141
0
      }
142
0
      default:  /* some error occurred */
143
0
        return COS_DEAD;
144
0
    }
145
0
  }
146
0
}
147
148
149
0
static int luaB_costatus (lua_State *L) {
150
0
  lua_State *co = getco(L);
151
0
  lua_pushstring(L, statname[auxstatus(L, co)]);
152
0
  return 1;
153
0
}
154
155
156
0
static int luaB_yieldable (lua_State *L) {
157
0
  lua_State *co = lua_isnone(L, 1) ? L : getco(L);
158
0
  lua_pushboolean(L, lua_isyieldable(co));
159
0
  return 1;
160
0
}
161
162
163
0
static int luaB_corunning (lua_State *L) {
164
0
  int ismain = lua_pushthread(L);
165
0
  lua_pushboolean(L, ismain);
166
0
  return 2;
167
0
}
168
169
170
0
static int luaB_close (lua_State *L) {
171
0
  lua_State *co = getco(L);
172
0
  int status = auxstatus(L, co);
173
0
  switch (status) {
174
0
    case COS_DEAD: case COS_YIELD: {
175
0
      status = lua_closethread(co, L);
176
0
      if (status == LUA_OK) {
177
0
        lua_pushboolean(L, 1);
178
0
        return 1;
179
0
      }
180
0
      else {
181
0
        lua_pushboolean(L, 0);
182
0
        lua_xmove(co, L, 1);  /* move error message */
183
0
        return 2;
184
0
      }
185
0
    }
186
0
    default:  /* normal or running coroutine */
187
0
      return luaL_error(L, "cannot close a %s coroutine", statname[status]);
188
0
  }
189
0
}
190
191
192
static const luaL_Reg co_funcs[] = {
193
  {"create", luaB_cocreate},
194
  {"resume", luaB_coresume},
195
  {"running", luaB_corunning},
196
  {"status", luaB_costatus},
197
  {"wrap", luaB_cowrap},
198
  {"yield", luaB_yield},
199
  {"isyieldable", luaB_yieldable},
200
  {"close", luaB_close},
201
  {NULL, NULL}
202
};
203
204
205
206
3.20k
LUAMOD_API int luaopen_coroutine (lua_State *L) {
207
3.20k
  luaL_newlib(L, co_funcs);
208
3.20k
  return 1;
209
3.20k
}
210