diff --git a/src/box/box.cc b/src/box/box.cc index 6256663de517b39913079640ff0813b4aafbb93e..79721a2e633b066aba18c1b94304a6eb257bd6e3 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -878,7 +878,7 @@ box_load_cfg() box_init(); } catch (Exception *e) { e->log(); - panic("can't initialize storage: %s", e->errmsg()); + panic("can't initialize storage: %s", e->get_errmsg()); } } diff --git a/src/box/error.cc b/src/box/error.cc index 9b0f92068ef6e14a6aa880df5f2a56bff4e3a3ad..56b319c7edda91d5833c47339a12864f7e309c32 100644 --- a/src/box/error.cc +++ b/src/box/error.cc @@ -52,11 +52,10 @@ ClientError::ClientError(const char *file, unsigned line, m_errcode = errcode; va_list ap; va_start(ap, errcode); - vsnprintf(m_errmsg, sizeof(m_errmsg), - tnt_errcode_desc(m_errcode), ap); + error_vformat_msg(this, tnt_errcode_desc(m_errcode), ap); + va_end(ap); if (rmean_error) rmean_collect(rmean_error, RMEAN_ERROR, 1); - va_end(ap); } ClientError::ClientError(const char *file, unsigned line, const char *msg, @@ -64,8 +63,7 @@ ClientError::ClientError(const char *file, unsigned line, const char *msg, : Exception(&type_ClientError, file, line) { m_errcode = errcode; - strncpy(m_errmsg, msg, sizeof(m_errmsg) - 1); - m_errmsg[sizeof(m_errmsg) - 1] = 0; + error_format_msg(this, "%s", msg); if (rmean_error) rmean_collect(rmean_error, RMEAN_ERROR, 1); } @@ -73,7 +71,7 @@ ClientError::ClientError(const char *file, unsigned line, const char *msg, void ClientError::log() const { - _say(S_ERROR, m_file, m_line, m_errmsg, "%s", tnt_errcode_str(m_errcode)); + _say(S_ERROR, file, line, errmsg, "%s", tnt_errcode_str(m_errcode)); } @@ -95,9 +93,8 @@ ErrorInjection::ErrorInjection(const char *file, unsigned line, const char *msg) } const char * -box_error_type(const box_error_t *error) +box_error_type(const box_error_t *e) { - Exception *e = (Exception *) error; return e->type->name; } @@ -111,14 +108,13 @@ box_error_code(const box_error_t *error) const char * box_error_message(const box_error_t *error) { - Exception *e = (Exception *) error; - return e->errmsg(); + return error->errmsg; } const box_error_t * box_error_last(void) { - return (box_error_t *) diag_last_error(&fiber()->diag); + return diag_last_error(&fiber()->diag); } void diff --git a/src/box/error.h b/src/box/error.h index 40dccfeee8580f8e9ec37a14253fd39ced8b0229..d7dc50d2974b6c94dc2aa3184c983ec14e9e9c45 100644 --- a/src/box/error.h +++ b/src/box/error.h @@ -96,11 +96,11 @@ class ErrorInjection: public LoggedError { /** \cond public */ -struct diag_msg; +struct error; /** * Error - contains information about error. */ -typedef struct diag_msg box_error_t; +typedef struct error box_error_t; /** * Return the error type, e.g. "ClientError", "SocketError", etc. diff --git a/src/box/iproto_port.cc b/src/box/iproto_port.cc index bdacd141cbedd686f33d0288c7fb6c0948b3bab7..2f07732855d9adc1d53172c96f6f6751ff5989b5 100644 --- a/src/box/iproto_port.cc +++ b/src/box/iproto_port.cc @@ -84,7 +84,7 @@ iproto_reply_ok(struct obuf *out, uint64_t sync) void iproto_reply_error(struct obuf *out, const Exception *e, uint64_t sync) { - uint32_t msg_len = strlen(e->errmsg()); + uint32_t msg_len = strlen(e->get_errmsg()); uint32_t errcode = ClientError::get_errcode(e); struct iproto_header_bin header = iproto_header_bin; @@ -99,7 +99,7 @@ iproto_reply_error(struct obuf *out, const Exception *e, uint64_t sync) obuf_dup(out, &header, sizeof(header)); obuf_dup(out, &body, sizeof(body)); - obuf_dup(out, e->errmsg(), msg_len); + obuf_dup(out, e->get_errmsg(), msg_len); } static inline struct iproto_port * diff --git a/src/box/lua/info.cc b/src/box/lua/info.cc index c75189808690aa9b751f1a6096356eba3106fe82..36708b883f3a23210763d3ff0cce87af6cae073a 100644 --- a/src/box/lua/info.cc +++ b/src/box/lua/info.cc @@ -80,11 +80,10 @@ lbox_info_replication(struct lua_State *L) lua_pushnumber(L, ev_now(loop()) - applier->last_row_time); lua_settable(L, -3); - Exception *e = (Exception *) - diag_last_error(&applier->reader->diag); + struct error *e = diag_last_error(&applier->reader->diag); if (e != NULL) { lua_pushstring(L, "message"); - lua_pushstring(L, e->errmsg()); + lua_pushstring(L, e->errmsg); lua_settable(L, -3); } } diff --git a/src/box/memtx_engine.cc b/src/box/memtx_engine.cc index f4d5bc5a44a15d3598cc9cebe62741ff007a0823..7ebe7955679efa37849a1693a3bc52d3b192611d 100644 --- a/src/box/memtx_engine.cc +++ b/src/box/memtx_engine.cc @@ -1122,7 +1122,7 @@ MemtxEngine::waitCheckpoint() result = -1; SystemError *se = type_cast(SystemError, e); if (se) - errno = se->errnum(); + errno = se->get_errno(); } m_checkpoint->waiting_for_snap_thread = false; diff --git a/src/box/xlog.cc b/src/box/xlog.cc index 6ee2d73ea0e64864792b0ea4caa40d1d4777304d..cb6cf5e0c4dc528ada3a365529697743f6e37d46 100644 --- a/src/box/xlog.cc +++ b/src/box/xlog.cc @@ -63,7 +63,7 @@ XlogError::XlogError(const char *file, unsigned line, { va_list ap; va_start(ap, format); - vsnprintf(m_errmsg, sizeof(m_errmsg), format, ap); + error_vformat_msg(this, format, ap); va_end(ap); } @@ -73,7 +73,7 @@ XlogError::XlogError(const struct type *type, const char *file, unsigned line, { va_list ap; va_start(ap, format); - vsnprintf(m_errmsg, sizeof(m_errmsg), format, ap); + error_vformat_msg(this, format, ap); va_end(ap); } @@ -87,7 +87,7 @@ XlogGapError::XlogGapError(const char *file, unsigned line, { char *s_from = vclock_to_string(from); char *s_to = vclock_to_string(to); - snprintf(m_errmsg, sizeof(m_errmsg), + snprintf(errmsg, sizeof(errmsg), "Missing .xlog file between LSN %lld %s and %lld %s", (long long) vclock_sum(from), s_from ? s_from : "", (long long) vclock_sum(to), s_to ? s_to : ""); diff --git a/src/diag.c b/src/diag.c index c72f736d8d68033af3521d344e13a24a19bbe510..9477087a163000c86c4bd2f35a8d54a8cf015285 100644 --- a/src/diag.c +++ b/src/diag.c @@ -32,13 +32,23 @@ #include "fiber.h" void -diag_msg_create(struct diag_msg *msg, - void (*destroy)(struct diag_msg *), - const struct type *type) +error_create(struct error *e, + void (*destroy)(struct error *), + const struct type *type, + const char *file, + unsigned line) { - msg->destroy = destroy; - msg->type = type; - msg->refs = 0; + e->destroy = destroy; + e->type = type; + e->refs = 0; + if (file != NULL) { + snprintf(e->file, sizeof(e->file), "%s", file); + e->line = line; + } else { + e->file[0] = '\0'; + e->line = 0; + } + e->errmsg[0] = '\0'; } struct diag * @@ -47,3 +57,18 @@ diag_get() return &fiber()->diag; } +void +error_format_msg(struct error *e, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + error_vformat_msg(e, format, ap); + va_end(ap); +} + +void +error_vformat_msg(struct error *e, const char *format, va_list ap) +{ + vsnprintf(e->errmsg, sizeof(e->errmsg), format, ap); +} + diff --git a/src/diag.h b/src/diag.h index 7427aa1bd459d66981e4218733fe33b35288fc04..39bcdf15916984fb2c0d87043d32d96505503382 100644 --- a/src/diag.h +++ b/src/diag.h @@ -51,47 +51,61 @@ struct type; * code. This is why there is a common infrastructure for errors. * * Any error or warning or note is represented by an instance of - * struct diag_msg. + * struct error. * - * struct diag_msg has the most common members, but more + * struct error has the most common members, but more * importantly it has a type descriptor, which makes it possible * to work with C++ exceptions and extra members via reflection, * in pure C. * * (destroy) is there to gracefully delete C++ exceptions from C. */ -struct diag_msg { - void (*destroy)(struct diag_msg *msg); +struct error { + void (*destroy)(struct error *e); const struct type *type; int refs; + /** Line number. */ + unsigned line; + /* Source file name. */ + char file[DIAG_FILENAME_MAX]; + /* Error description. */ + char errmsg[DIAG_ERRMSG_MAX]; }; static inline void -diag_msg_ref(struct diag_msg *msg) +error_ref(struct error *e) { - msg->refs++; + e->refs++; } static inline void -diag_msg_unref(struct diag_msg *msg) +error_unref(struct error *e) { - assert(msg->refs > 0); - --msg->refs; - if (msg->refs == 0) - msg->destroy(msg); + assert(e->refs > 0); + --e->refs; + if (e->refs == 0) + e->destroy(e); } void -diag_msg_create(struct diag_msg *msg, - void (*destroy)(struct diag_msg *msg), - const struct type *type); +error_create(struct error *e, + void (*destroy)(struct error *e), + const struct type *type, + const char *file, + unsigned line); + +void +error_format_msg(struct error *e, const char *format, ...); + +void +error_vformat_msg(struct error *e, const char *format, va_list ap); /** * Diagnostics Area - a container for errors */ struct diag { /* \cond private */ - struct diag_msg *last; + struct error *last; /* \endcond private */ }; @@ -123,7 +137,7 @@ diag_clear(struct diag *diag) { if (diag->last == NULL) return; - diag_msg_unref(diag->last); + error_unref(diag->last); diag->last = NULL; } @@ -133,10 +147,10 @@ diag_clear(struct diag *diag) * \param e error to add */ static inline void -diag_add_error(struct diag *diag, struct diag_msg *e) +diag_add_error(struct diag *diag, struct error *e) { assert(e != NULL); - diag_msg_ref(e); + error_ref(e); diag_clear(diag); diag->last = e; } @@ -172,7 +186,7 @@ diag_destroy(struct diag *diag) * \return last error * \param diag diagnostics area */ -static inline struct diag_msg * +static inline struct error * diag_last_error(struct diag *diag) { return diag->last; diff --git a/src/evio.cc b/src/evio.cc index c12dc8f3113111461df4acc12f099ea3b9079028..337a4c72d4e3b1312601dbe149548d19cf8aa54c 100644 --- a/src/evio.cc +++ b/src/evio.cc @@ -262,7 +262,7 @@ evio_service_bind_and_listen(struct evio_service *service) say_error("%s: failed to bind on %s: %s", evio_service_name(service), sio_strfaddr(ai->ai_addr, ai->ai_addrlen), - e->errmsg()); + e->get_errmsg()); /* ignore */ } } diff --git a/src/exception.cc b/src/exception.cc index e31504f0b666bb792566cecfa8477cef3f9ed74e..9659942886c2a76fabe964b850b24bdf493e11d2 100644 --- a/src/exception.cc +++ b/src/exception.cc @@ -40,9 +40,9 @@ static OutOfMemory out_of_memory(__FILE__, __LINE__, sizeof(OutOfMemory), "malloc", "exception"); static const struct method exception_methods[] = { - make_method(&type_Exception, "message", &Exception::errmsg), - make_method(&type_Exception, "file", &Exception::file), - make_method(&type_Exception, "line", &Exception::line), + make_method(&type_Exception, "message", &Exception::get_errmsg), + make_method(&type_Exception, "file", &Exception::get_file), + make_method(&type_Exception, "line", &Exception::get_line), make_method(&type_Exception, "log", &Exception::log), METHODS_SENTINEL }; @@ -73,7 +73,7 @@ Exception::~Exception() } extern "C" void -exception_destroy(struct diag_msg *msg) +exception_destroy(struct error *msg) { delete (Exception *) msg; } @@ -81,15 +81,8 @@ exception_destroy(struct diag_msg *msg) Exception::Exception(const struct type *type_arg, const char *file, unsigned line) { - diag_msg_create(this, exception_destroy, type_arg); - if (file != NULL) { - snprintf(m_file, sizeof(m_file), "%s", file); - m_line = line; - } else { - m_file[0] = '\0'; - m_line = 0; - } - m_errmsg[0] = '\0'; + error_create(this, exception_destroy, type_arg, + file, line); if (this == &out_of_memory) { /* A special workaround for out_of_memory static init */ out_of_memory.refs = 1; @@ -100,11 +93,11 @@ Exception::Exception(const struct type *type_arg, const char *file, void Exception::log() const { - _say(S_ERROR, m_file, m_line, m_errmsg, "%s", type->name); + _say(S_ERROR, file, line, errmsg, "%s", type->name); } static const struct method systemerror_methods[] = { - make_method(&type_SystemError, "errnum", &SystemError::errnum), + make_method(&type_SystemError, "errno", &SystemError::get_errno), METHODS_SENTINEL }; @@ -126,30 +119,15 @@ SystemError::SystemError(const char *file, unsigned line, { va_list ap; va_start(ap, format); - init(format, ap); - va_end(ap); -} - -void -SystemError::init(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - init(format, ap); + error_vformat_msg(this, format, ap); va_end(ap); } -void -SystemError::init(const char *format, va_list ap) -{ - vsnprintf(m_errmsg, sizeof(m_errmsg), format, ap); -} - void SystemError::log() const { - _say(S_SYSERROR, m_file, m_line, strerror(m_errno), "SystemError %s", - m_errmsg); + _say(S_SYSERROR, file, line, strerror(m_errno), "SystemError %s", + errmsg); } const struct type type_OutOfMemory = @@ -161,9 +139,8 @@ OutOfMemory::OutOfMemory(const char *file, unsigned line, : SystemError(&type_OutOfMemory, file, line) { m_errno = ENOMEM; - snprintf(m_errmsg, sizeof(m_errmsg), - "Failed to allocate %u bytes in %s for %s", - (unsigned) amount, allocator, object); + error_format_msg(this, "Failed to allocate %u bytes in %s for %s", + (unsigned) amount, allocator, object); } const struct type type_TimedOut = diff --git a/src/exception.h b/src/exception.h index 045f9eec88106492827e1c1f4141dd290a524ec3..9ba9219965a592703b3997a6e5fa640de13e07b5 100644 --- a/src/exception.h +++ b/src/exception.h @@ -39,26 +39,16 @@ extern const struct type type_Exception; -class Exception: public diag_msg { +class Exception: public error { public: void *operator new(size_t size); void operator delete(void*); - virtual void raise() = 0; - - const char * - errmsg() const - { - return m_errmsg; - } - - const char *file() const { - return m_file; - } - int line() const { - return m_line; - } + const char *get_file() const { return file; } + int get_line() const { return line; } + const char *get_errmsg() const { return errmsg; } + virtual void raise() = 0; virtual void log() const; virtual ~Exception(); @@ -66,27 +56,14 @@ class Exception: public diag_msg { Exception& operator=(const Exception&) = delete; protected: Exception(const struct type *type, const char *file, unsigned line); - - /* line number */ - unsigned m_line; - /* file name */ - char m_file[DIAG_FILENAME_MAX]; - - /* error description */ - char m_errmsg[DIAG_ERRMSG_MAX]; }; extern const struct type type_SystemError; class SystemError: public Exception { public: - virtual void raise() { throw this; } - int - errnum() const - { - return m_errno; - } + int get_errno() const { return m_errno; } virtual void log() const; @@ -94,13 +71,6 @@ class SystemError: public Exception { const char *format, ...); protected: SystemError(const struct type *type, const char *file, unsigned line); - - void - init(const char *format, ...); - - void - init(const char *format, va_list ap); - protected: /* system errno */ int m_errno; diff --git a/src/ffisyms.cc b/src/ffisyms.cc index 5ec554840ad7bf4b5a7d58747290450b56eca55c..df42c79ab67ccbfc1b17d37ee469c4569b74e375 100644 --- a/src/ffisyms.cc +++ b/src/ffisyms.cc @@ -59,7 +59,6 @@ void *ffi_symbols[] = { (void *) box_iterator_next, (void *) boxffi_tuple_update, (void *) password_prepare, - (void *) tarantool_error_message, (void *) load_cfg, (void *) box_set_listen, (void *) box_set_replication_source, diff --git a/src/fiber.cc b/src/fiber.cc index af5e3a6fe78152aa8e9cad64405ff83549c1a3df..d1f0f361c0831c178a827a7f6f40913bcd51fff3 100644 --- a/src/fiber.cc +++ b/src/fiber.cc @@ -215,7 +215,7 @@ fiber_join(struct fiber *fiber) /* Move exception to the caller */ diag_move(&fiber->diag, &fiber()->diag); - Exception *e = (Exception *) diag_last_error(&fiber()->diag); + struct error *e = diag_last_error(&fiber()->diag); /** Don't bother with propagation of FiberCancelException */ if (e != NULL && type_cast(FiberCancelException, e) != NULL) diag_clear(&fiber()->diag); diff --git a/src/lua/init.cc b/src/lua/init.cc index ab25b2ef100244e3ead82002ddb4eb772d955f93..7c15718f9a3c8fadbc460d352354b85f38d91fc0 100644 --- a/src/lua/init.cc +++ b/src/lua/init.cc @@ -446,15 +446,6 @@ tarantool_lua_slab_cache() return &cord()->slabc; } -extern "C" const char * -tarantool_error_message(void) -{ - /* called only from error handler */ - Exception *e = (Exception *) diag_last_error(&fiber()->diag); - assert(e != NULL); - return e->errmsg(); -} - /** * Execute start-up script. */ @@ -498,7 +489,7 @@ run_script(va_list ap) lua_pushstring(L, argv[i]); lbox_call(L, lua_gettop(L) - 1, 0); } catch (Exception *e) { - panic("%s", e->errmsg()); + panic("%s", e->get_errmsg()); } /* clear the stack from return values. */ diff --git a/src/lua/init.lua b/src/lua/init.lua index 3568ae036ea1ed57b5dff80c6317ac0d364cc76e..ddfe26b34210779e5d3a472e77d3c669bbf52092 100644 --- a/src/lua/init.lua +++ b/src/lua/init.lua @@ -4,8 +4,13 @@ local ffi = require('ffi') ffi.cdef[[ -char * -tarantool_error_message(void); +struct error; + +typedef struct error box_error_t; +const box_error_t * +box_error_last(void); +const char * +box_error_message(const box_error_t *); double tarantool_uptime(void); typedef int32_t pid_t; @@ -16,7 +21,7 @@ local pcall_lua = pcall local function pcall_wrap(status, ...) if status == false and ... == 'C++ exception' then - return false, ffi.string(ffi.C.tarantool_error_message()) + return false, ffi.string(ffi.C.box_error_message(ffi.C.box_error_last())) end return status, ... end diff --git a/src/lua/utils.cc b/src/lua/utils.cc index 8c23809dc7e4184b17ac440e30a04569d289d809..a334467e2ed9bc49f93d1e7c5a12a9a3a6366aae 100644 --- a/src/lua/utils.cc +++ b/src/lua/utils.cc @@ -831,5 +831,5 @@ LuajitError::LuajitError(const char *file, unsigned line, : Exception(&type_LuajitError, file, line) { const char *msg = lua_tostring(L, -1); - snprintf(m_errmsg, sizeof(m_errmsg), "%s", msg ? msg : ""); + snprintf(errmsg, sizeof(errmsg), "%s", msg ? msg : ""); } diff --git a/src/sio.cc b/src/sio.cc index 51e9ac10d134adb1f5c5e0e72aeed73493db1ad5..4ded0c61c5ece438fcf8e3fd9371343961ddef2c 100644 --- a/src/sio.cc +++ b/src/sio.cc @@ -61,9 +61,9 @@ SocketError::SocketError(const char *file, unsigned line, int fd, va_list ap; va_start(ap, format); vsnprintf(buf, sizeof(buf), format, ap); - const char *socketname = sio_socketname(fd); - init("%s, called on %s", buf, socketname); va_end(ap); + const char *socketname = sio_socketname(fd); + error_format_msg(this, "%s, called on %s", buf, socketname); errno = save_errno; }