diff options
-rw-r--r-- | dist/api_err.py | 43 | ||||
-rw-r--r-- | dist/s_string.ok | 1 | ||||
-rw-r--r-- | dist/s_symbols.list | 1 | ||||
-rw-r--r-- | examples/c/ex_all.c | 16 | ||||
-rw-r--r-- | src/conn/api_strerror.c | 56 | ||||
-rw-r--r-- | src/include/extern.h | 1 | ||||
-rw-r--r-- | src/include/wiredtiger.in | 19 | ||||
-rw-r--r-- | src/os_posix/os_errno.c | 27 | ||||
-rw-r--r-- | src/os_win/os_errno.c | 27 |
9 files changed, 155 insertions, 36 deletions
diff --git a/dist/api_err.py b/dist/api_err.py index cb2c8cc588e..d45e6988ed2 100644 --- a/dist/api_err.py +++ b/dist/api_err.py @@ -78,7 +78,7 @@ for line in open('../src/include/wiredtiger.in', 'r'): tfile.close() compare_srcfile(tmp_file, '../src/include/wiredtiger.in') -# Output the wiredtiger_strerror code. +# Output the wiredtiger_strerror and wiredtiger_sterror_r code. tmp_file = '__tmp' tfile = open(tmp_file, 'w') tfile.write('''/* DO NOT EDIT: automatically built by dist/api_err.py. */ @@ -87,37 +87,52 @@ tfile.write('''/* DO NOT EDIT: automatically built by dist/api_err.py. */ /* * wiredtiger_strerror -- - *\tReturn a string for any error value. + *\tReturn a string for any error value in a static buffer. */ const char * wiredtiger_strerror(int error) { -\tstatic char errbuf[64]; -\tchar *p; +\tstatic char buf[128]; -\tif (error == 0) -\t\treturn ("Successful return: 0"); +\tif (wiredtiger_strerror_r(error, buf, sizeof(buf)) != 0) +\t\t(void)snprintf(buf, sizeof(buf), "error return: %d", error); +\treturn (buf); +} + +/* + * wiredtiger_strerror_r -- + *\tReturn a string for any error value, thread-safe version. + */ +int +wiredtiger_strerror_r(int error, char *buf, size_t buflen) +{ +\tconst char *p; + +\t/* Require at least 2 bytes, printable character and trailing nul. */ +\tif (buflen < 2) +\t\treturn (ENOMEM); \tswitch (error) { +\tcase 0: +\t\tp = "Successful return: 0"; +\t\tbreak; ''') for err in errors: tfile.write('\tcase ' + err.name + ':\n') - tfile.write('\t\treturn ("' + err.name + ': ' + err.desc + '");\n') + tfile.write('\t\tp = "' + err.name + ': ' + err.desc + '";\n') + tfile.write('\t\tbreak;\n') tfile.write('''\ \tdefault: -\t\tif (error > 0 && (p = strerror(error)) != NULL) -\t\t\treturn (p); -\t\tbreak; +\t\treturn (__wt_strerror_r(error, buf, buflen)); \t} \t/* -\t * !!! -\t * Not thread-safe, but this is never supposed to happen. +\t * Return success if anything printed (we checked if the buffer had +\t * space for at least one character). \t */ -\t(void)snprintf(errbuf, sizeof(errbuf), "Unknown error: %d", error); -\treturn (errbuf); +\treturn (snprintf(buf, buflen, "%s", p) > 0 ? 0 : ENOMEM); } ''') tfile.close() diff --git a/dist/s_string.ok b/dist/s_string.ok index 94f3ea6b6a5..786a787c5f3 100644 --- a/dist/s_string.ok +++ b/dist/s_string.ok @@ -436,6 +436,7 @@ btmem btree btrees buf +buflen bufs bufsz builtin diff --git a/dist/s_symbols.list b/dist/s_symbols.list index d3803bc3afa..8f469e94433 100644 --- a/dist/s_symbols.list +++ b/dist/s_symbols.list @@ -8,6 +8,7 @@ wiredtiger_pack_start wiredtiger_pack_str wiredtiger_pack_uint wiredtiger_strerror +wiredtiger_strerror_r wiredtiger_struct_pack wiredtiger_struct_size wiredtiger_struct_unpack diff --git a/examples/c/ex_all.c b/examples/c/ex_all.c index 01966b5196f..bf5a588274b 100644 --- a/examples/c/ex_all.c +++ b/examples/c/ex_all.c @@ -342,6 +342,22 @@ cursor_ops(WT_SESSION *session) /*! [Display an error] */ } + { + /*! [Display an error thread safe] */ + const char *key = "non-existent key"; + cursor->set_key(cursor, key); + if ((ret = cursor->remove(cursor)) != 0) { + char buf[128]; + + if (wiredtiger_strerror_r(ret, buf, sizeof(buf)) != 0) + (void)snprintf( + buf, sizeof(buf), "error value: %d\n", ret); + fprintf(stderr, "cursor.remove: %s\n", buf); + return (ret); + } + /*! [Display an error thread safe] */ + } + /*! [Close the cursor] */ ret = cursor->close(cursor); /*! [Close the cursor] */ diff --git a/src/conn/api_strerror.c b/src/conn/api_strerror.c index caf536b24f7..5cabe55d3f6 100644 --- a/src/conn/api_strerror.c +++ b/src/conn/api_strerror.c @@ -4,40 +4,60 @@ /* * wiredtiger_strerror -- - * Return a string for any error value. + * Return a string for any error value in a static buffer. */ const char * wiredtiger_strerror(int error) { - static char errbuf[64]; - char *p; + static char buf[128]; - if (error == 0) - return ("Successful return: 0"); + if (wiredtiger_strerror_r(error, buf, sizeof(buf)) != 0) + (void)snprintf(buf, sizeof(buf), "error return: %d", error); + return (buf); +} + +/* + * wiredtiger_strerror_r -- + * Return a string for any error value, thread-safe version. + */ +int +wiredtiger_strerror_r(int error, char *buf, size_t buflen) +{ + const char *p; + + /* Require at least 2 bytes, printable character and trailing nul. */ + if (buflen < 2) + return (ENOMEM); switch (error) { + case 0: + p = "Successful return: 0"; + break; case WT_ROLLBACK: - return ("WT_ROLLBACK: conflict between concurrent operations"); + p = "WT_ROLLBACK: conflict between concurrent operations"; + break; case WT_DUPLICATE_KEY: - return ("WT_DUPLICATE_KEY: attempt to insert an existing key"); + p = "WT_DUPLICATE_KEY: attempt to insert an existing key"; + break; case WT_ERROR: - return ("WT_ERROR: non-specific WiredTiger error"); + p = "WT_ERROR: non-specific WiredTiger error"; + break; case WT_NOTFOUND: - return ("WT_NOTFOUND: item not found"); + p = "WT_NOTFOUND: item not found"; + break; case WT_PANIC: - return ("WT_PANIC: WiredTiger library panic"); + p = "WT_PANIC: WiredTiger library panic"; + break; case WT_RESTART: - return ("WT_RESTART: restart the operation (internal)"); - default: - if (error > 0 && (p = strerror(error)) != NULL) - return (p); + p = "WT_RESTART: restart the operation (internal)"; break; + default: + return (__wt_strerror_r(error, buf, buflen)); } /* - * !!! - * Not thread-safe, but this is never supposed to happen. + * Return success if anything printed (we checked if the buffer had + * space for at least one character). */ - (void)snprintf(errbuf, sizeof(errbuf), "Unknown error: %d", error); - return (errbuf); + return (snprintf(buf, buflen, "%s", p) > 0 ? 0 : ENOMEM); } diff --git a/src/include/extern.h b/src/include/extern.h index 056058f3828..b5c71aa7c15 100644 --- a/src/include/extern.h +++ b/src/include/extern.h @@ -431,6 +431,7 @@ extern int __wt_dlopen(WT_SESSION_IMPL *session, const char *path, WT_DLH **dlhp extern int __wt_dlsym(WT_SESSION_IMPL *session, WT_DLH *dlh, const char *name, int fail, void *sym_ret); extern int __wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh); extern int __wt_errno(void); +extern int __wt_strerror_r(int error, char *buf, size_t buflen); extern int __wt_exist(WT_SESSION_IMPL *session, const char *filename, int *existp); extern void __wt_fallocate_config(WT_SESSION_IMPL *session, WT_FH *fh); extern int __wt_fallocate( WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, wt_off_t len); diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in index 075514e02b4..20991278440 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -2019,15 +2019,26 @@ int wiredtiger_open(const char *home, WT_CONNECTION **connectionp); /*! - * Return information about an error as a string; wiredtiger_strerror is a - * superset of the ISO C99/POSIX 1003.1-2001 function strerror. + * Return information about a WiredTiger error as a string, not thread-safe. * * @snippet ex_all.c Display an error * - * @param err a return value from a WiredTiger, C library or POSIX function + * @param error a return value from a WiredTiger call * @returns a string representation of the error */ -const char *wiredtiger_strerror(int err); +const char *wiredtiger_strerror(int error); + +/*! + * Return information about a WiredTiger error as a string, thread-safe version. + * + * @snippet ex_all.c Display an error thread safe + * + * @param error a return value from a WiredTiger call + * @param buf a buffer of at least \c buflen bytes + * @param buflen the length of the buffer + * @returns zero for success, non-zero to indicate an error. + */ +int wiredtiger_strerror_r(int error, char *buf, size_t buflen); #if !defined(SWIG) /*! diff --git a/src/os_posix/os_errno.c b/src/os_posix/os_errno.c index 9290f7d651f..b0cb288ea74 100644 --- a/src/os_posix/os_errno.c +++ b/src/os_posix/os_errno.c @@ -20,3 +20,30 @@ __wt_errno(void) */ return (errno == 0 ? WT_ERROR : errno); } + +/* + * __wt_strerror_r -- + * POSIX implementation of strerror_r. + */ +int +__wt_strerror_r(int error, char *buf, size_t buflen) +{ + char *p; + + /* Require at least 2 bytes, printable character and trailing nul. */ + if (buflen < 2) + return (ENOMEM); + + /* + * POSIX errors are non-negative integers, copy the string into the + * user's buffer. Return success if anything printed (we checked if + * the buffer had space for at least one character). + */ + if (error > 0 && + (p = strerror(error)) != NULL && snprintf(buf, buflen, "%s", p) > 0) + return (0); + + /* Fallback to a generic message, then guess it's a memory problem. */ + return ( + snprintf(buf, buflen, "error return: %d", error) > 0 ? 0 : ENOMEM); +} diff --git a/src/os_win/os_errno.c b/src/os_win/os_errno.c index ce50106b0cc..856db1ae96d 100644 --- a/src/os_win/os_errno.c +++ b/src/os_win/os_errno.c @@ -25,3 +25,30 @@ __wt_errno(void) return (err == ERROR_SUCCESS ? WT_ERROR : err); } + +/* + * __wt_strerror_r -- + * Windows implementation of strerror_r. + */ +int +__wt_strerror_r(int error, char *buf, size_t buflen) +{ + char *p; + + /* Require at least 2 bytes, printable character and trailing nul. */ + if (buflen < 2) + return (ENOMEM); + + /* + * POSIX errors are non-negative integers, copy the string into the + * user's buffer. Return success if anything printed (we checked if + * the buffer had space for at least one character). + */ + if (error > 0 && + (p = strerror(error)) != NULL && snprintf(buf, buflen, "%s", p) > 0) + return (0); + + /* Fallback to a generic message, then guess it's a memory problem. */ + return ( + snprintf(buf, buflen, "error return: %d", error) > 0 ? 0 : ENOMEM); +} |