From efe97b7b74874087caf1ade3514884ae72b3ba12 Mon Sep 17 00:00:00 2001 From: Roman Tsisyk <roman@tsisyk.com> Date: Wed, 22 Apr 2015 18:36:59 +0300 Subject: [PATCH] Define public module API for Tarantool Lua/C modules This patch adds `src/module.h` header file with definition of all public API functions suitable to use in Lua/C modules for Tarantool. This header is automatically generated from src/*.h by CMake (`make generate_module_api`) by extracting code blocks between /** \cond public */ /* \endcond public */ Doxygen-style comments. Definitions of functions in module.h are frozen and must not be changed by future commits/releases. A new test case `app/module_api` is added to check compilation, linkage and loading of Lua modules and functionality of provided API functions. Other changes: * Convert mysql and pg to use module.h and prepare to convert to .c * Fix includes in say.h, coeio.h * Rename luaL_pushnumber64 to luaL_pushuint64 and luaL_pushinumber64 to luaL_pushint64 * Add LUA_API macros to public luaL_* functions (actually adds extern "C") --- .gitignore | 1 + cmake/utils.cmake | 20 ++++++ extra/apigen | 3 + extra/rpm/tarantool.rpm.spec.in | 1 + src/CMakeLists.txt | 5 ++ src/box/lua/info.cc | 5 +- src/box/lua/slab.cc | 20 +++--- src/box/vclock.c | 2 +- src/coeio.cc | 16 +++-- src/coeio.h | 22 +++---- src/evio.cc | 2 + src/fio.c | 1 + src/fiob.c | 1 + src/lib/small/region.h | 1 + src/lua/init.cc | 2 +- src/lua/msgpack.cc | 4 +- src/lua/pickle.cc | 4 +- src/lua/utils.cc | 4 +- src/lua/utils.h | 22 +++++-- src/module/mysql/CMakeLists.txt | 1 + src/module/mysql/mysql.cc | 23 +++---- src/module/pg/CMakeLists.txt | 1 + src/module/pg/pg.cc | 26 ++++---- src/module_footer.h | 5 ++ src/module_header.h | 20 ++++++ src/say.h | 13 ++-- src/sio.cc | 1 + test/CMakeLists.txt | 2 +- test/app/CMakeLists.txt | 4 ++ test/app/module_api.c | 103 ++++++++++++++++++++++++++++++ test/app/module_api.result | 11 ++++ test/app/module_api.test.lua | 20 ++++++ third_party/lua-cjson/lua_cjson.c | 4 +- third_party/lua-yaml/lyaml.cc | 4 +- 34 files changed, 291 insertions(+), 83 deletions(-) create mode 100755 extra/apigen create mode 100644 src/module_footer.h create mode 100644 src/module_header.h create mode 100644 test/app/CMakeLists.txt create mode 100644 test/app/module_api.c create mode 100644 test/app/module_api.result create mode 100755 test/app/module_api.test.lua diff --git a/.gitignore b/.gitignore index 290c2d0411..85843c056c 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ src/box/bootstrap.h src/lua/*.lua.c src/box/lua/*.lua.c src/tarantool +src/module.h tarantool-*.tar.gz test/lib/*.pyc test/lib/*/*.pyc diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 95aad2eda8..197d83b1e9 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -79,3 +79,23 @@ function(bin_source varname srcfile dstfile) DEPENDS ${srcfile} bin2c) endfunction() + +# A helper function to extract public API +function(apigen) + set (dstfile "${CMAKE_BINARY_DIR}/src/module.h") + set (tmpfile "${dstfile}.new") + + add_custom_command(OUTPUT ${dstfile} + COMMAND cat ${CMAKE_SOURCE_DIR}/src/module_header.h > ${tmpfile} + COMMAND cat ${ARGN} | ${CMAKE_SOURCE_DIR}/extra/apigen >> ${tmpfile} + COMMAND cat ${CMAKE_SOURCE_DIR}/src/module_footer.h >> ${tmpfile} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${tmpfile} ${dstfile} + COMMAND ${CMAKE_COMMAND} -E remove ${tmpfile} + DEPENDS ${srcfiles} + ${CMAKE_SOURCE_DIR}/src/module_header.h + ${CMAKE_SOURCE_DIR}/src/module_footer.h + ) + + add_custom_target(generate_module_api ALL DEPENDS ${dstfile}) + install(FILES ${dstfile} DESTINATION ${MODULE_INCLUDEDIR}) +endfunction() diff --git a/extra/apigen b/extra/apigen new file mode 100755 index 0000000000..7352e94b31 --- /dev/null +++ b/extra/apigen @@ -0,0 +1,3 @@ +#!/bin/sh + +sed -n '/^\/\*\* \\cond public \*\/$/,/^\/\*\* \\endcond public \*\/$/P' diff --git a/extra/rpm/tarantool.rpm.spec.in b/extra/rpm/tarantool.rpm.spec.in index 96cbdb18e3..19794386ae 100644 --- a/extra/rpm/tarantool.rpm.spec.in +++ b/extra/rpm/tarantool.rpm.spec.in @@ -300,6 +300,7 @@ chkconfig --del tarantool "%{_includedir}/tarantool/lua.hpp" "%{_includedir}/tarantool/luajit.h" "%{_includedir}/tarantool/lualib.h" +"%{_includedir}/tarantool/module.h" %files common %defattr(-,root,root,-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 58d9173143..8b526bba7b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -143,8 +143,13 @@ endif() set (common_libraries ${common_libraries} ${LIBUUID_LIBRARIES}) set (common_libraries ${common_libraries} PARENT_SCOPE) +set(api_headers say.h coeio.h lua/utils.h) + add_subdirectory(lib) add_subdirectory(box) + +apigen(${api_headers}) + # Save CMAKE_XXX_FLAGS from this directory for config.h (used in --version) set(TARANTOOL_C_FLAGS ${CMAKE_C_FLAGS} PARENT_SCOPE) set(TARANTOOL_CXX_FLAGS ${CMAKE_CXX_FLAGS} PARENT_SCOPE) diff --git a/src/box/lua/info.cc b/src/box/lua/info.cc index 74f7a3b617..3c5eae1873 100644 --- a/src/box/lua/info.cc +++ b/src/box/lua/info.cc @@ -85,8 +85,7 @@ lbox_info_server(struct lua_State *L) lua_pushlstring(L, tt_uuid_str(&recovery->server_uuid), UUID_STR_LEN); lua_settable(L, -3); lua_pushliteral(L, "lsn"); - luaL_pushinumber64(L, vclock_get(&recovery->vclock, - recovery->server_id)); + luaL_pushint64(L, vclock_get(&recovery->vclock, recovery->server_id)); lua_settable(L, -3); lua_pushliteral(L, "ro"); lua_pushboolean(L, box_is_ro()); @@ -103,7 +102,7 @@ lbox_info_vclock(struct lua_State *L) luaL_setmaphint(L, -1); vclock_foreach(&recovery->vclock, it) { lua_pushinteger(L, it.id); - luaL_pushnumber64(L, it.lsn); + luaL_pushuint64(L, it.lsn); lua_settable(L, -3); } diff --git a/src/box/lua/slab.cc b/src/box/lua/slab.cc index e0c00a0e5c..131cd23443 100644 --- a/src/box/lua/slab.cc +++ b/src/box/lua/slab.cc @@ -66,27 +66,27 @@ small_stats_lua_cb(const struct mempool_stats *stats, void *cb_ctx) luaL_setmaphint(L, -1); lua_pushstring(L, "mem_used"); - luaL_pushnumber64(L, stats->totals.used); + luaL_pushuint64(L, stats->totals.used); lua_settable(L, -3); lua_pushstring(L, "slab_size"); - luaL_pushnumber64(L, stats->slabsize); + luaL_pushuint64(L, stats->slabsize); lua_settable(L, -3); lua_pushstring(L, "mem_free"); - luaL_pushnumber64(L, stats->totals.total - stats->totals.used); + luaL_pushuint64(L, stats->totals.total - stats->totals.used); lua_settable(L, -3); lua_pushstring(L, "item_size"); - luaL_pushnumber64(L, stats->objsize); + luaL_pushuint64(L, stats->objsize); lua_settable(L, -3); lua_pushstring(L, "slab_count"); - luaL_pushnumber64(L, stats->slabcount); + luaL_pushuint64(L, stats->slabcount); lua_settable(L, -3); lua_pushstring(L, "item_count"); - luaL_pushnumber64(L, stats->objcount); + luaL_pushuint64(L, stats->objcount); lua_settable(L, -3); lua_settable(L, -3); @@ -107,11 +107,11 @@ lbox_slab_info(struct lua_State *L) lua_settable(L, -3); lua_pushstring(L, "arena_used"); - luaL_pushnumber64(L, totals.used); + luaL_pushuint64(L, totals.used); lua_settable(L, -3); lua_pushstring(L, "arena_size"); - luaL_pushnumber64(L, totals.total); + luaL_pushuint64(L, totals.total); lua_settable(L, -3); char value[32]; @@ -140,11 +140,11 @@ lbox_runtime_info(struct lua_State *L) lua_newtable(L); lua_pushstring(L, "used"); - luaL_pushnumber64(L, runtime.used); + luaL_pushuint64(L, runtime.used); lua_settable(L, -3); lua_pushstring(L, "maxalloc"); - luaL_pushnumber64(L, quota_get(runtime.quota)); + luaL_pushuint64(L, quota_get(runtime.quota)); lua_settable(L, -3); return 1; diff --git a/src/box/vclock.c b/src/box/vclock.c index a01a21dbd4..6168ef1e0c 100644 --- a/src/box/vclock.c +++ b/src/box/vclock.c @@ -50,7 +50,7 @@ vclock_follow(struct vclock *vclock, uint32_t server_id, int64_t lsn) return prev_lsn; } -static inline __attribute__ ((format(FORMAT_PRINTF, 4, 0))) int +static inline __attribute__ ((format(printf, 4, 0))) int rsnprintf(char **buf, char **pos, char **end, const char *fmt, ...) { int rc = 0; diff --git a/src/coeio.cc b/src/coeio.cc index 3cc8b10ee0..e2cbc2f12c 100644 --- a/src/coeio.cc +++ b/src/coeio.cc @@ -27,12 +27,18 @@ * SUCH DAMAGE. */ #include "coeio.h" -#include "fiber.h" -#include "exception.h" -#include <errno.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <errno.h> +#include <unistd.h> +#include <netdb.h> +#include <sys/socket.h> + +#include "fiber.h" +#include "exception.h" +#include "third_party/tarantool_ev.h" /* * Asynchronous IO Tasks (libeio wrapper). @@ -146,7 +152,7 @@ coio_on_finish(eio_req *req) ssize_t coio_task(struct coio_task *task, coio_task_cb func, - coio_task_timeout_cb on_timeout, ev_tstamp timeout) + coio_task_timeout_cb on_timeout, double timeout) { /* from eio.c: REQ() definition */ memset(&task->base, 0, sizeof(task->base)); @@ -296,7 +302,7 @@ getaddrinfo_free_cb(struct coio_task *ptr) int coio_getaddrinfo(const char *host, const char *port, const struct addrinfo *hints, struct addrinfo **res, - ev_tstamp timeout) + double timeout) { int rc = EAI_SYSTEM; int save_errno = 0; diff --git a/src/coeio.h b/src/coeio.h index d76b272a6f..09576d70ea 100644 --- a/src/coeio.h +++ b/src/coeio.h @@ -30,21 +30,11 @@ */ #include "trivia/config.h" -#include "trivia/util.h" -#include <stdbool.h> -#include <stdint.h> +#include <sys/types.h> /* ssize_t */ #include <stdarg.h> -#include <unistd.h> -#include <coro.h> -#include "third_party/tarantool_ev.h" -#include "third_party/tarantool_eio.h" - -#include <sys/types.h> -#include <sys/socket.h> -#include <netdb.h> -#define ERESOLVE -1 +#include "third_party/tarantool_eio.h" #if defined(__cplusplus) extern "C" { @@ -89,15 +79,19 @@ struct coio_task { ssize_t coio_task(struct coio_task *task, coio_task_cb func, - coio_task_timeout_cb on_timeout, ev_tstamp timeout); + coio_task_timeout_cb on_timeout, double timeout); +/** \cond public */ ssize_t coio_call(ssize_t (*func)(va_list ap), ...); +struct addrinfo; + int coio_getaddrinfo(const char *host, const char *port, const struct addrinfo *hints, struct addrinfo **res, - ev_tstamp timeout); + double timeout); +/** \endcond public */ #if defined(__cplusplus) } diff --git a/src/evio.cc b/src/evio.cc index 211d473329..53884a803b 100644 --- a/src/evio.cc +++ b/src/evio.cc @@ -36,6 +36,8 @@ #include <netinet/tcp.h> #include <arpa/inet.h> +#include <trivia/util.h> + #define BIND_RETRY_DELAY 0.1 static void diff --git a/src/fio.c b/src/fio.c index 2edae2f054..2a184161f3 100644 --- a/src/fio.c +++ b/src/fio.c @@ -39,6 +39,7 @@ #include <lib/bit/bit.h> #include <say.h> +#include <trivia/util.h> const char * fio_filename(int fd) diff --git a/src/fiob.c b/src/fiob.c index b7840bf440..afbd7f0e13 100644 --- a/src/fiob.c +++ b/src/fiob.c @@ -17,6 +17,7 @@ #include <assert.h> #include <unistd.h> #include <trivia/config.h> +#include <trivia/util.h> /* Use special implemention if we have O_DIRECT and FOPENCOOKIE or FUNOPEN */ #if defined(O_DIRECT) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE)) diff --git a/src/lib/small/region.h b/src/lib/small/region.h index 11adb988b7..f53bead861 100644 --- a/src/lib/small/region.h +++ b/src/lib/small/region.h @@ -32,6 +32,7 @@ #include <inttypes.h> #include <assert.h> #include <stdio.h> +#include <string.h> #include "salad/rlist.h" #include "slab_cache.h" diff --git a/src/lua/init.cc b/src/lua/init.cc index 96e998484b..e06b99970f 100644 --- a/src/lua/init.cc +++ b/src/lua/init.cc @@ -128,7 +128,7 @@ lbox_tonumber64(struct lua_State *L) errno = 0; unsigned long long result = strtoull(arg, &arge, 10); if (errno == 0 && arge != arg) { - luaL_pushnumber64(L, result); + luaL_pushuint64(L, result); return 1; } break; diff --git a/src/lua/msgpack.cc b/src/lua/msgpack.cc index c1b842dde6..8cff635fad 100644 --- a/src/lua/msgpack.cc +++ b/src/lua/msgpack.cc @@ -291,10 +291,10 @@ luamp_decode(struct lua_State *L, struct luaL_serializer *cfg, double d; switch (mp_typeof(**data)) { case MP_UINT: - luaL_pushnumber64(L, mp_decode_uint(data)); + luaL_pushuint64(L, mp_decode_uint(data)); break; case MP_INT: - luaL_pushinumber64(L, mp_decode_int(data)); + luaL_pushint64(L, mp_decode_int(data)); break; case MP_FLOAT: d = mp_decode_float(data); diff --git a/src/lua/pickle.cc b/src/lua/pickle.cc index 5b7d5e0af4..9666a2e343 100644 --- a/src/lua/pickle.cc +++ b/src/lua/pickle.cc @@ -209,12 +209,12 @@ lbox_unpack(struct lua_State *L) break; case 'l': CHECK_SIZE(s + 7); - luaL_pushnumber64(L, *(uint64_t*) s); + luaL_pushuint64(L, *(uint64_t*) s); s += 8; break; case 'q': CHECK_SIZE(s + 7); - luaL_pushnumber64(L, bswap_u64(*(uint64_t*) s)); + luaL_pushuint64(L, bswap_u64(*(uint64_t*) s)); s += 8; break; case 'd': diff --git a/src/lua/utils.cc b/src/lua/utils.cc index ffd0908c50..0f3b8be923 100644 --- a/src/lua/utils.cc +++ b/src/lua/utils.cc @@ -641,7 +641,7 @@ luaL_register_module(struct lua_State *L, const char *modname, } int -luaL_pushnumber64(struct lua_State *L, uint64_t val) +luaL_pushuint64(struct lua_State *L, uint64_t val) { if (val < (1ULL << 52)) { /* push lua_Number (double) */ @@ -655,7 +655,7 @@ luaL_pushnumber64(struct lua_State *L, uint64_t val) } int -luaL_pushinumber64(struct lua_State *L, int64_t val) +luaL_pushint64(struct lua_State *L, int64_t val) { if (val > (-1LL << 52) && val < (1LL << 52)) { /* push lua_Number (double) */ diff --git a/src/lua/utils.h b/src/lua/utils.h index 05119a885c..61194a5b42 100644 --- a/src/lua/utils.h +++ b/src/lua/utils.h @@ -52,6 +52,8 @@ extern "C" { struct lua_State; +/** \cond public */ + /** * @brief Allocate a new block of memory with the given size, push onto the * stack a new cdata of type ctypeid with the block address, and return @@ -63,7 +65,7 @@ struct lua_State; * @sa luaL_checkcdata * @return memory associated with this cdata */ -void * +LUA_API void * luaL_pushcdata(struct lua_State *L, uint32_t ctypeid, uint32_t size); /** @@ -74,7 +76,7 @@ luaL_pushcdata(struct lua_State *L, uint32_t ctypeid, uint32_t size); * @sa luaL_pushcdata * @return memory associated with this cdata */ -void * +LUA_API void * luaL_checkcdata(struct lua_State *L, int idx, uint32_t *ctypeid); /** @@ -85,7 +87,7 @@ luaL_checkcdata(struct lua_State *L, int idx, uint32_t *ctypeid); * @param idx object * @return 1 */ -int +LUA_API int luaL_setcdatagc(struct lua_State *L, int idx); /** @@ -96,9 +98,11 @@ luaL_setcdatagc(struct lua_State *L, int idx); * @sa luaL_checkcdata * @return CTypeID */ -uint32_t +LUA_API uint32_t luaL_ctypeid(struct lua_State *L, const char *ctypename); +/** \endcond public */ + static inline lua_Integer luaL_arrlen(struct lua_State *L, int idx) { @@ -352,6 +356,8 @@ void luaL_register_module(struct lua_State *L, const char *modname, const struct luaL_Reg *methods); +/** \cond public */ + /** * push uint64_t to Lua stack * @@ -359,12 +365,16 @@ luaL_register_module(struct lua_State *L, const char *modname, * @param val is a value to push * */ -int luaL_pushnumber64(struct lua_State *L, uint64_t val); +LUA_API int +luaL_pushuint64(struct lua_State *L, uint64_t val); /** * @copydoc luaL_pushnumber64 */ -int luaL_pushinumber64(struct lua_State *L, int64_t val); +LUA_API int +luaL_pushint64(struct lua_State *L, int64_t val); + +/** \endcond public */ /** * Push Lua Table with __serialize = 'map' hint onto the stack. diff --git a/src/module/mysql/CMakeLists.txt b/src/module/mysql/CMakeLists.txt index 3f5aa81354..28a155f733 100644 --- a/src/module/mysql/CMakeLists.txt +++ b/src/module/mysql/CMakeLists.txt @@ -5,6 +5,7 @@ if (MYSQL_FOUND) add_library(mysql SHARED mysql.cc) target_link_libraries(mysql ${MYSQL_LIBRARIES} -rdynamic) set_target_properties(mysql PROPERTIES PREFIX "") + add_dependencies(mysql generate_module_api) install(TARGETS mysql LIBRARY DESTINATION ${MODULE_LIBDIR}/box/net) else() message(STATUS "MySQL client not found, box.net.sql(mysql) disabled") diff --git a/src/module/mysql/mysql.cc b/src/module/mysql/mysql.cc index 3bc120684a..2aa4845625 100644 --- a/src/module/mysql/mysql.cc +++ b/src/module/mysql/mysql.cc @@ -27,6 +27,8 @@ * SUCH DAMAGE. */ +#include "module.h" + #include <stddef.h> extern "C" { @@ -39,14 +41,8 @@ extern "C" { #include <stdlib.h> #include <errno.h> #include <string.h> -#include <coeio.h> -#include "third_party/tarantool_ev.h" -#include <lua/init.h> -#include <lua/utils.h> -#include <say.h> #include <mysql.h> -#include <scoped_guard.h> /** * gets MYSQL connector from lua stack (or object) @@ -164,8 +160,8 @@ fetch_result(va_list ap) /** * push results to lua stack */ -int -lua_push_mysql_result(struct lua_State *L, MYSQL *mysql, +static int +lua_mysql_pushresult(struct lua_State *L, MYSQL *mysql, MYSQL_RES *result, int resno) { int tidx; @@ -187,6 +183,7 @@ lua_push_mysql_result(struct lua_State *L, MYSQL *mysql, lua_pushnumber(L, v); return 2; } + mysql_free_result(result); luaL_error(L, "%s", mysql_error(mysql)); } @@ -225,7 +222,7 @@ lua_push_mysql_result(struct lua_State *L, MYSQL *mysql, case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_TIMESTAMP: { long long v = atoll(row[i]); - luaL_pushnumber64(L, v); + luaL_pushuint64(L, v); break; } @@ -249,11 +246,10 @@ lua_push_mysql_result(struct lua_State *L, MYSQL *mysql, v += mysql_affected_rows(mysql); lua_pop(L, 1); lua_pushnumber(L, v); + mysql_free_result(result); return 2; } - - /** * mysql:execute() method */ @@ -335,10 +331,7 @@ lua_mysql_execute(struct lua_State *L) if (res == -1) luaL_error(L, "%s", strerror(errno)); - auto scope_guard = make_scoped_guard([&]{ - mysql_free_result(result); - }); - lua_push_mysql_result(L, mysql, result, resno++); + lua_mysql_pushresult(L, mysql, result, resno++); } while(mysql_more_results(mysql)); diff --git a/src/module/pg/CMakeLists.txt b/src/module/pg/CMakeLists.txt index 828aba9b8e..24aca28de8 100644 --- a/src/module/pg/CMakeLists.txt +++ b/src/module/pg/CMakeLists.txt @@ -6,6 +6,7 @@ if (PostgreSQL_FOUND) add_library(pg SHARED pg.cc) target_link_libraries(pg ${PostgreSQL_LIBRARIES} -rdynamic) set_target_properties(pg PROPERTIES PREFIX "") + add_dependencies(pg generate_module_api) install(TARGETS pg LIBRARY DESTINATION ${MODULE_LIBDIR}/box/net) else() message(STATUS "PostgreSQL client not found, box.net.sql(pg) disabled") diff --git a/src/module/pg/pg.cc b/src/module/pg/pg.cc index b58ecb1761..a0c6a3ba69 100644 --- a/src/module/pg/pg.cc +++ b/src/module/pg/pg.cc @@ -27,6 +27,8 @@ * SUCH DAMAGE. */ +#include "module.h" + extern "C" { #include <libpq-fe.h> #undef PACKAGE_VERSION @@ -52,12 +54,7 @@ extern "C" { #include <stdlib.h> #include <errno.h> #include <string.h> -#include <coeio.h> -#include "third_party/tarantool_ev.h" -#include <lua/init.h> -#include <say.h> -#include <scoped_guard.h> static PGconn * lua_check_pgconn(struct lua_State *L, int index) @@ -103,7 +100,7 @@ pg_exec(va_list ap) /** push query result into lua stack */ static int -lua_push_pgres(struct lua_State *L, PGresult *r) +lua_pg_pushresult(struct lua_State *L, PGresult *r) { if (!r) luaL_error(L, "PG internal error: zero rults"); @@ -120,21 +117,28 @@ lua_push_pgres(struct lua_State *L, PGresult *r) lua_pushnumber(L, v); } lua_pushstring(L, PQcmdStatus(r)); + PQclear(r); return 3; case PGRES_TUPLES_OK: break; case PGRES_BAD_RESPONSE: + PQclear(r); luaL_error(L, "Broken postgresql response"); + return 0; case PGRES_FATAL_ERROR: case PGRES_NONFATAL_ERROR: case PGRES_EMPTY_QUERY: - luaL_error(L, "%s", PQresultErrorMessage(r)); + lua_pushstring(L, PQresultErrorMessage(r)); + PQclear(r); + luaL_error(L, "%s", lua_tostring(L, -1)); + return 0; default: - luaL_error(L, "box.net.sql.pg: internal error"); + luaL_error(L, "pg: unsupported result type"); + return 0; } lua_newtable(L); @@ -192,6 +196,7 @@ lua_push_pgres(struct lua_State *L, PGresult *r) lua_pushnumber(L, v); } lua_pushstring(L, PQcmdStatus(r)); + PQclear(r); return 3; } @@ -290,11 +295,8 @@ lua_pg_execute(struct lua_State *L) strerror(errno)); } - auto scope_guard = make_scoped_guard([&]{ - PQclear(res); - }); lua_settop(L, 0); - return lua_push_pgres(L, res); + return lua_pg_pushresult(L, res); } /** diff --git a/src/module_footer.h b/src/module_footer.h new file mode 100644 index 0000000000..c5920a9f45 --- /dev/null +++ b/src/module_footer.h @@ -0,0 +1,5 @@ +#if defined(__cplusplus) +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + +#endif /* TARANTOOL_MODULE_H_INCLUDED */ diff --git a/src/module_header.h b/src/module_header.h new file mode 100644 index 0000000000..4859be717b --- /dev/null +++ b/src/module_header.h @@ -0,0 +1,20 @@ +#ifndef TARANTOOL_MODULE_H_INCLUDED +#define TARANTOOL_MODULE_H_INCLUDED + +#include <stddef.h> +#include <stdarg.h> /* va_list */ +#include <errno.h> +#include <string.h> /* strerror(3) */ +#include <stdint.h> +#include <sys/types.h> /* ssize_t */ + +#include <lua.h> + +/** + * \file + * Tarantool Module API + */ + +#if defined(__cplusplus) +extern "C" { +#endif /* defined(__cplusplus) */ diff --git a/src/say.h b/src/say.h index b8132ef0f5..6a01587323 100644 --- a/src/say.h +++ b/src/say.h @@ -32,12 +32,12 @@ #include <stdarg.h> #include <errno.h> -#include "trivia/util.h" /* for FORMAT_PRINTF */ - #if defined(__cplusplus) extern "C" { #endif /* defined(__cplusplus) */ +/** \cond public */ + enum say_level { S_FATAL, /* do not this value use directly */ S_SYSERROR, @@ -48,6 +48,8 @@ enum say_level { S_DEBUG }; +/** \endcond public */ + extern int log_fd; extern pid_t logger_pid; @@ -66,12 +68,13 @@ void say_logger_init(const char *logger, int log_level, int nonblock, void vsay(int level, const char *filename, int line, const char *error, const char *format, va_list ap) - __attribute__ ((format(FORMAT_PRINTF, 5, 0))); + __attribute__ ((format(printf, 5, 0))); +/** \cond public */ typedef void (*sayfunc_t)(int level, const char *filename, int line, const char *error, const char *format, ...); -extern sayfunc_t _say __attribute__ ((format(FORMAT_PRINTF, 5, 6))); +extern sayfunc_t _say __attribute__ ((format(printf, 5, 6))); #define say(level, ...) ({ _say(level, __FILE__, __LINE__, __VA_ARGS__); }) @@ -84,7 +87,7 @@ extern sayfunc_t _say __attribute__ ((format(FORMAT_PRINTF, 5, 6))); #define say_warn(...) say(S_WARN, NULL, __VA_ARGS__) #define say_info(...) say(S_INFO, NULL, __VA_ARGS__) #define say_debug(...) say(S_DEBUG, NULL, __VA_ARGS__) - +/** \endcond public */ #if defined(__cplusplus) } /* extern "C" */ diff --git a/src/sio.cc b/src/sio.cc index 08eda96cda..8c981f041c 100644 --- a/src/sio.cc +++ b/src/sio.cc @@ -44,6 +44,7 @@ #endif /* #ifdef TARGET_OS_LINUX */ #include "say.h" +#include "trivia/util.h" SocketError::SocketError(const char *file, unsigned line, int fd, const char *format, ...) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 547d6a50ee..466cceaf2d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,7 +13,7 @@ add_custom_target(test add_custom_target(test-force COMMAND ${PROJECT_SOURCE_DIR}/test/test-run.py --builddir=${PROJECT_BINARY_DIR} --force --vardir=${PROJECT_BINARY_DIR}/test/var) - +add_subdirectory(app) add_subdirectory(unit) # Disable connector_c for 1.6 #add_subdirectory(connector_c) diff --git a/test/app/CMakeLists.txt b/test/app/CMakeLists.txt new file mode 100644 index 0000000000..1245fe14c4 --- /dev/null +++ b/test/app/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(module_api SHARED module_api.c) +target_link_libraries(module_api -rdynamic) +set_target_properties(module_api PROPERTIES PREFIX "") +add_dependencies(module_api generate_module_api) diff --git a/test/app/module_api.c b/test/app/module_api.c new file mode 100644 index 0000000000..36d52807fc --- /dev/null +++ b/test/app/module_api.c @@ -0,0 +1,103 @@ +#include "module.h" + +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> + +#include <lua.h> +#include <lauxlib.h> + +static int +test_say(lua_State *L) +{ + say_debug("test debug"); + say_info("test info"); + say_warn("test warn"); + say_crit("test crit"); + say_error("test error"); + errno = 0; + say_syserror("test sysserror"); + lua_pushboolean(L, 1); + return 1; +} + +static ssize_t +coio_call_func(va_list ap) +{ + return va_arg(ap, int); +} + +static int +test_coio_call(lua_State *L) +{ + ssize_t rc = coio_call(coio_call_func, 48); + lua_pushboolean(L, rc == 48); + return 1; +} + +static int +test_coio_getaddrinfo(lua_State *L) +{ + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG|AI_PASSIVE; + hints.ai_protocol = 0; + struct addrinfo *ai = NULL; + if (coio_getaddrinfo("localhost", "80", &hints, &ai, 0.1) == 0) + freeaddrinfo(ai); + lua_pushboolean(L, 1); + return 1; +} + +static int +test_pushcheck_cdata(lua_State *L) +{ + uint32_t uint64_ctypeid = luaL_ctypeid(L, "uint64_t"); + *(uint64_t *) luaL_pushcdata(L, uint64_ctypeid, sizeof(uint64_t)) = 48; + uint32_t test_ctypeid = 0; + luaL_checkcdata(L, -1, &test_ctypeid); + lua_pushboolean(L, test_ctypeid != 0 && uint64_ctypeid == test_ctypeid); + return 1; +} + +static int +test_pushuint64(lua_State *L) +{ + uint32_t ctypeid = 0; + uint64_t num = 18446744073709551615ULL; + luaL_pushuint64(L, num); + uint64_t r = *(uint64_t *) luaL_checkcdata(L, -1, &ctypeid); + lua_pushboolean(L, r == num && ctypeid == luaL_ctypeid(L, "uint64_t")); + return 1; +} + +static int +test_pushint64(lua_State *L) +{ + uint32_t ctypeid = 0; + int64_t num = 9223372036854775807LL; + luaL_pushint64(L, num); + int64_t r = *(int64_t *) luaL_checkcdata(L, -1, &ctypeid); + lua_pushboolean(L, r == num && ctypeid == luaL_ctypeid(L, "int64_t")); + return 1; +} + +LUA_API int +luaopen_module_api(lua_State *L) +{ + static const struct luaL_reg lib[] = { + {"test_say", test_say }, + {"test_coio_call", test_coio_call }, + {"test_coio_getaddrinfo", test_coio_getaddrinfo }, + {"test_pushcheck_cdata", test_pushcheck_cdata }, + {"test_pushuint64", test_pushuint64 }, + {"test_pushint64", test_pushint64 }, + + {NULL, NULL} + }; + luaL_register(L, "module_api", lib); + return 1; +} diff --git a/test/app/module_api.result b/test/app/module_api.result new file mode 100644 index 0000000000..38640458a6 --- /dev/null +++ b/test/app/module_api.result @@ -0,0 +1,11 @@ +TAP version 13 +# module_api +1..7 +ok - module is loaded +ok - test_coio_call is ok +ok - test_pushint64 is ok +ok - test_say is ok +ok - test_pushuint64 is ok +ok - test_pushcheck_cdata is ok +ok - test_coio_getaddrinfo is ok +# module_api: end diff --git a/test/app/module_api.test.lua b/test/app/module_api.test.lua new file mode 100755 index 0000000000..b8e50193b6 --- /dev/null +++ b/test/app/module_api.test.lua @@ -0,0 +1,20 @@ +#!/usr/bin/env tarantool + +box.cfg{logger = "tarantool.log"} + +local work_dir = require('fio').dirname(arg[0]) +package.cpath = work_dir..'/?.so;' + +local test = require('tap').test("module_api", function(test) + test:plan(7) + local status, module = pcall(require, 'module_api') + test:ok(status, "module is loaded") + if not status then + return + end + + for name, fun in pairs(module) do + test:ok(fun, name .. " is ok") + end +end) +os.exit(0) diff --git a/third_party/lua-cjson/lua_cjson.c b/third_party/lua-cjson/lua_cjson.c index 88599082cf..1b18473b8d 100644 --- a/third_party/lua-cjson/lua_cjson.c +++ b/third_party/lua-cjson/lua_cjson.c @@ -946,10 +946,10 @@ static void json_process_value(lua_State *l, json_parse_t *json, lua_pushlstring(l, token->value.string, token->string_len); break;; case T_UINT: - luaL_pushnumber64(l, token->value.ival); + luaL_pushuint64(l, token->value.ival); break;; case T_INT: - luaL_pushinumber64(l, token->value.ival); + luaL_pushint64(l, token->value.ival); break;; case T_NUMBER: luaL_checkfinite(l, json->cfg, token->value.number); diff --git a/third_party/lua-yaml/lyaml.cc b/third_party/lua-yaml/lyaml.cc index e3b4596407..0818cb4faa 100644 --- a/third_party/lua-yaml/lyaml.cc +++ b/third_party/lua-yaml/lyaml.cc @@ -224,12 +224,12 @@ static void load_scalar(struct lua_yaml_loader *loader) { char *endptr = NULL; long long ival = strtoll(str, &endptr, 10); if (endptr == str + length && ival != LLONG_MAX) { - luaL_pushinumber64(loader->L, ival); + luaL_pushint64(loader->L, ival); return; } unsigned long long uval = strtoull(str, &endptr, 10); if (endptr == str + length) { - luaL_pushnumber64(loader->L, uval); + luaL_pushuint64(loader->L, uval); return; } double dval = fpconv_strtod(str, &endptr); -- GitLab