[PATCH v2 2/6] Add functions to ease using Lua iterators from C
Alexander Turenko
alexander.turenko at tarantool.org
Fri Mar 1 07:04:17 MSK 2019
Made several minor updates. I'll squash them into the original commit,
but show here separatelly to ease reading.
WBR, Alexander Turenko.
On Mon, Jan 28, 2019 at 09:17:16PM +0300, Alexander Turenko wrote:
> Updated a bit:
>
> diff --git a/src/lua/utils.c b/src/lua/utils.c
> index 173d59a59..c8cfa70b3 100644
> --- a/src/lua/utils.c
> +++ b/src/lua/utils.c
> @@ -981,6 +981,11 @@ struct luaL_iterator *
> luaL_iterator_new(lua_State *L, int idx)
> {
> struct luaL_iterator *it = malloc(sizeof(struct luaL_iterator));
> + if (it == NULL) {
> + diag_set(OutOfMemory, sizeof(struct luaL_iterator),
> + "malloc", "luaL_iterator");
> + return NULL;
> + }
>
> if (idx == 0) {
> /* gen, param, state are on top of a Lua stack. */
commit c7cf235b5ba68e911a1fd47e950fe205e963f9e7
Author: Alexander Turenko <alexander.turenko at tarantool.org>
Date: Thu Feb 21 14:06:39 2019 +0300
FIXUP: luaL_iterator: use global Lua state for unreferencing
diff --git a/src/lua/utils.c b/src/lua/utils.c
index 002c5e4b9..2e5096626 100644
--- a/src/lua/utils.c
+++ b/src/lua/utils.c
@@ -1052,11 +1052,11 @@ luaL_iterator_next(lua_State *L, struct luaL_iterator *it)
return nresults;
}
-void luaL_iterator_delete(lua_State *L, struct luaL_iterator *it)
+void luaL_iterator_delete(struct luaL_iterator *it)
{
- luaL_unref(L, LUA_REGISTRYINDEX, it->gen);
- luaL_unref(L, LUA_REGISTRYINDEX, it->param);
- luaL_unref(L, LUA_REGISTRYINDEX, it->state);
+ luaL_unref(tarantool_L, LUA_REGISTRYINDEX, it->gen);
+ luaL_unref(tarantool_L, LUA_REGISTRYINDEX, it->param);
+ luaL_unref(tarantool_L, LUA_REGISTRYINDEX, it->state);
free(it);
}
diff --git a/src/lua/utils.h b/src/lua/utils.h
index 772b5d877..c66a8a4b9 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -562,7 +562,7 @@ luaL_iterator_next(lua_State *L, struct luaL_iterator *it);
/**
* Free all resources held by the iterator.
*/
-void luaL_iterator_delete(lua_State *L, struct luaL_iterator *it);
+void luaL_iterator_delete(struct luaL_iterator *it);
/* }}} */
diff --git a/test/unit/luaL_iterator.c b/test/unit/luaL_iterator.c
index 5a254f27d..038d34c5c 100644
--- a/test/unit/luaL_iterator.c
+++ b/test/unit/luaL_iterator.c
@@ -98,6 +98,13 @@ main()
struct lua_State *L = luaL_newstate();
luaL_openlibs(L);
+ tarantool_L = L;
+
+ /*
+ * Check that everything works fine in a thread (a fiber)
+ * other then the main one.
+ */
+ L = lua_newthread(L);
/*
* Expose luafun.
@@ -148,7 +155,7 @@ main()
is(lua_gettop(L) - top, 0, "%s: stack size", description);
/* Free the luaL_iterator structure. */
- luaL_iterator_delete(L, it);
+ luaL_iterator_delete(it);
/* Check stack size. */
is(lua_gettop(L) - top, 0, "%s: stack size", description);
commit 1318e30c89efbb58de46fb5ed167cd61e3ff661a
Author: Alexander Turenko <alexander.turenko at tarantool.org>
Date: Mon Feb 25 01:05:01 2019 +0300
FIXUP: luaL_iterator: tweak a comment
diff --git a/src/lua/utils.h b/src/lua/utils.h
index c66a8a4b9..c4a16704f 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -543,7 +543,7 @@ struct luaL_iterator;
* Create a Lua iterator from a gen, param, state triplet.
*
* If idx == 0, then three top stack values are used as the
- * triplet.
+ * triplet. Note: they are not popped.
*
* Otherwise idx is index on Lua stack points to a
* {gen, param, state} table.
commit f95e07b340f4b698c2d6aa0ff6db437cc388ab85
Author: Alexander Turenko <alexander.turenko at tarantool.org>
Date: Mon Feb 25 09:50:34 2019 +0300
FIXUP: luaL_iterator: use pcall
diff --git a/src/lua/utils.c b/src/lua/utils.c
index 2e5096626..94f8c65d6 100644
--- a/src/lua/utils.c
+++ b/src/lua/utils.c
@@ -1029,7 +1029,15 @@ luaL_iterator_next(lua_State *L, struct luaL_iterator *it)
lua_rawgeti(L, LUA_REGISTRYINDEX, it->gen);
lua_rawgeti(L, LUA_REGISTRYINDEX, it->param);
lua_rawgeti(L, LUA_REGISTRYINDEX, it->state);
- lua_call(L, 2, LUA_MULTRET);
+ if (luaT_call(L, 2, LUA_MULTRET) != 0) {
+ /*
+ * Pop garbage from the call (a gen function
+ * likely will not leave the stack even when raise
+ * an error), pop a returned error.
+ */
+ lua_settop(L, frame_start);
+ return -1;
+ }
int nresults = lua_gettop(L) - frame_start;
/*
diff --git a/src/lua/utils.h b/src/lua/utils.h
index c4a16704f..4a87dac45 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -553,8 +553,11 @@ luaL_iterator_new(lua_State *L, int idx);
/**
* Move iterator to the next value. Push values returned by
- * gen(param, state) and return its count. Zero means no more
- * results available.
+ * gen(param, state).
+ *
+ * Return count of pushed values. Zero means no more results
+ * available. In case of a Lua error in a gen function return -1
+ * and set a diag.
*/
int
luaL_iterator_next(lua_State *L, struct luaL_iterator *it);
diff --git a/test/unit/luaL_iterator.c b/test/unit/luaL_iterator.c
index 038d34c5c..8d25a0062 100644
--- a/test/unit/luaL_iterator.c
+++ b/test/unit/luaL_iterator.c
@@ -2,7 +2,12 @@
#include <lauxlib.h> /* luaL_*() */
#include <lualib.h> /* luaL_openlibs() */
#include "unit.h" /* plan, header, footer, is */
+#include "memory.h" /* memory_init() */
+#include "fiber.h" /* fiber_init() */
+#include "diag.h" /* struct error, diag_*() */
+#include "exception.h" /* type_LuajitError */
#include "lua/utils.h" /* luaL_iterator_*() */
+#include "lua/error.h" /* tarantool_lua_error_init() */
extern char fun_lua[];
@@ -31,6 +36,8 @@ main()
int idx;
/* How much values are in the iterator. */
int iterations;
+ /* Expected error (if any). */
+ const char *exp_err;
} cases[] = {
{
.description = "pairs, zero idx",
@@ -39,6 +46,7 @@ main()
.first_value = 42,
.idx = 0,
.iterations = 1,
+ .exp_err = NULL,
},
{
.description = "ipairs, zero idx",
@@ -47,6 +55,7 @@ main()
.first_value = 42,
.idx = 0,
.iterations = 3,
+ .exp_err = NULL,
},
{
.description = "luafun iterator, zero idx",
@@ -55,6 +64,7 @@ main()
.first_value = 42,
.idx = 0,
.iterations = 3,
+ .exp_err = NULL,
},
{
.description = "pairs, from table",
@@ -63,6 +73,7 @@ main()
.first_value = 42,
.idx = -1,
.iterations = 1,
+ .exp_err = NULL,
},
{
.description = "ipairs, from table",
@@ -71,6 +82,7 @@ main()
.first_value = 42,
.idx = -1,
.iterations = 3,
+ .exp_err = NULL,
},
{
.description = "luafun iterator, from table",
@@ -79,19 +91,34 @@ main()
.first_value = 42,
.idx = -1,
.iterations = 3,
+ .exp_err = NULL,
+ },
+ {
+ .description = "lua error",
+ .init = "return error, 'I am the error', 0",
+ .init_retvals = 3,
+ .first_value = 0,
+ .idx = 0,
+ .iterations = 0,
+ .exp_err = "I am the error",
},
};
int cases_cnt = (int) (sizeof(cases) / sizeof(cases[0]));
/*
- * * Check stack size after creating luaL_iterator (triple
- * times).
* * 4 checks per iteration.
- * * Check that values ends.
+ * * 3 checks of a stack size.
+ * * 1 check that values ends (for success cases).
+ * * 1 check for an iterator error (for error cases).
+ * * 1 check for an error type (for error cases).
+ * * 1 check for an error message (for error cases).
*/
int planned = 0;
- for (int i = 0; i < cases_cnt; ++i)
+ for (int i = 0; i < cases_cnt; ++i) {
planned += cases[i].iterations * 4 + 4;
+ if (cases[i].exp_err != NULL)
+ planned += 2;
+ }
plan(planned);
header();
@@ -100,6 +127,10 @@ main()
luaL_openlibs(L);
tarantool_L = L;
+ memory_init();
+ fiber_init(fiber_c_invoke);
+ tarantool_lua_error_init(L);
+
/*
* Check that everything works fine in a thread (a fiber)
* other then the main one.
@@ -147,9 +178,20 @@ main()
description, j);
}
- /* Check the iterator ends when expected. */
- int rc = luaL_iterator_next(L, it);
- is(rc, 0, "%s: iterator ends", description);
+ if (cases[i].exp_err == NULL) {
+ /* Check the iterator ends when expected. */
+ int rc = luaL_iterator_next(L, it);
+ is(rc, 0, "%s: iterator ends", description);
+ } else {
+ /* Check expected error. */
+ int rc = luaL_iterator_next(L, it);
+ is(rc, -1, "%s: iterator error", description);
+ struct error *e = diag_last_error(diag_get());
+ is(e->type, &type_LuajitError, "%s: check error type",
+ description);
+ ok(!strcmp(e->errmsg, cases[i].exp_err),
+ "%s: check error message", description);
+ }
/* Check stack size. */
is(lua_gettop(L) - top, 0, "%s: stack size", description);
diff --git a/test/unit/luaL_iterator.result b/test/unit/luaL_iterator.result
index f4eda5695..2472eedcf 100644
--- a/test/unit/luaL_iterator.result
+++ b/test/unit/luaL_iterator.result
@@ -1,4 +1,4 @@
-1..80
+1..86
*** main ***
ok 1 - pairs, zero idx: stack size
ok 2 - pairs, zero idx: iter 0: gen() retval count
@@ -80,4 +80,10 @@ ok 77 - luafun iterator, from table: iter: 2: stack size
ok 78 - luafun iterator, from table: iterator ends
ok 79 - luafun iterator, from table: stack size
ok 80 - luafun iterator, from table: stack size
+ok 81 - lua error: stack size
+ok 82 - lua error: iterator error
+ok 83 - lua error: check error type
+ok 84 - lua error: check error message
+ok 85 - lua error: stack size
+ok 86 - lua error: stack size
*** main: done ***
commit 6edef55a8f689f595a760a9c06180de7da37976e
Author: Alexander Turenko <alexander.turenko at tarantool.org>
Date: Fri Mar 1 02:27:25 2019 +0300
FIXUP: luaL_iterator: after rebase fix
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 263856a7a..663ed2ec2 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -139,9 +139,9 @@ target_link_libraries(histogram.test stat unit)
add_executable(ratelimit.test ratelimit.c)
target_link_libraries(ratelimit.test unit)
add_executable(luaL_iterator.test luaL_iterator.c)
-target_link_libraries(luaL_iterator.test unit server core misc
+target_link_libraries(luaL_iterator.test unit server coll core misc
${CURL_LIBRARIES} ${LIBYAML_LIBRARIES} ${READLINE_LIBRARIES}
- ${ICU_LIBRARIES} ${LUAJIT_LIBRARIES})
+ ${ICU_LIBRARIES} ${LUAJIT_LIBRARIES} dl)
add_executable(say.test say.c)
target_link_libraries(say.test core unit)
More information about the Tarantool-patches
mailing list