diff options
Diffstat (limited to 'lib/pthread_safe.c')
-rw-r--r-- | lib/pthread_safe.c | 246 |
1 files changed, 169 insertions, 77 deletions
diff --git a/lib/pthread_safe.c b/lib/pthread_safe.c index c4ab9679..336f686e 100644 --- a/lib/pthread_safe.c +++ b/lib/pthread_safe.c @@ -25,6 +25,12 @@ * safe_ function is called on the same thread */ +/* Need "NO_USE_GNU" to turn off __USE_GNU in "misc.h" in order to get the + * POSIX version of strerror_r() :-( + */ +#define NO_USE_GNU + +#include "misc.h" #include "pthread_safe.h" #include "qpthreads.h" #include "memory.h" @@ -41,14 +47,25 @@ #include "qfstring.h" #include "errno_names.h" -/* prototypes */ -static void destructor(void* data); -static char * thread_buff(void); - +/*============================================================================== + * Initialisation, close down and local variables. + * + * Note that the "thread_safe" mutex is recursive, so one thread safe function + * can call another, if required. + */ static pthread_key_t tsd_key; static const int buff_size = 1024; -/* Module initialization, before any threads have been created */ +static qpt_mutex thread_safe = NULL ; + +static const char ellipsis[] = "..." ; + +static void destructor(void* data); +static char * thread_buff(void); + +/*------------------------------------------------------------------------------ + * Module initialization, before any threads have been created + */ void safe_init_r(void) { @@ -58,50 +75,36 @@ safe_init_r(void) status = pthread_key_create(&tsd_key, destructor); if (status != 0) zabort("Can't create thread specific data key"); - } + + qassert(thread_safe == NULL) ; + + thread_safe = qpt_mutex_init_new(NULL, qpt_mutex_recursive) ; + } ; } -/* Clean up */ +/*------------------------------------------------------------------------------ + * Clean up + */ void safe_finish(void) { if (qpthreads_enabled) - pthread_key_delete(tsd_key); -} + { + pthread_key_delete(tsd_key) ; -/* called when thread terminates, clean up */ + thread_safe = qpt_mutex_destroy(thread_safe, free_it) ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * called when thread terminates, clean up + */ static void destructor(void* data) { XFREE(MTYPE_TSD, data); } -/* Thread safe version of strerror. Never returns NULL. - * Contents of result remains intact until another call of - * a safe_ function. - */ -const char * -safe_strerror(int errnum) -{ - static const char * unknown = "Unknown error"; - if (qpthreads_enabled) - { - char * buff = thread_buff(); - int ret = strerror_r(errnum, buff, buff_size); - - return (ret >= 0) - ? buff - : unknown; - } - else - { - const char *s = strerror(errnum); - return (s != NULL) - ? s - : unknown; - } -} - /*============================================================================== * Alternative error number handling. * @@ -134,7 +137,7 @@ safe_strerror(int errnum) * to show this has happened. */ -static void errtox(strerror_t* st, int err, int len, int want) ; +static void errtox(strerror_t* st, int err, uint len, uint want) ; /*------------------------------------------------------------------------------ * Construct string to describe the given error of the form: @@ -144,7 +147,7 @@ static void errtox(strerror_t* st, int err, int len, int want) ; * Thread safe extension to strerror. Never returns NULL. */ extern strerror_t -errtoa(int err, int len) +errtoa(int err, uint len) { strerror_t st ; @@ -159,7 +162,7 @@ errtoa(int err, int len) * Thread-safe. Never returns NULL. */ extern strerror_t -errtoname(int err, int len) +errtoname(int err, uint len) { strerror_t st ; @@ -174,7 +177,7 @@ errtoname(int err, int len) * Thread safe replacement for strerror. Never returns NULL. */ extern strerror_t -errtostr(int err, int len) +errtostr(int err, uint len) { strerror_t st ; @@ -189,21 +192,23 @@ errtostr(int err, int len) * want == 1 -- return just name * want == 2 -- return just the strerror() * want == 3 -- return both, with the strerror() in single quotes. + * + * NB: this is not async-signal-safe ! */ static void -errtox(strerror_t* st, int err, int len, int want) +errtox(strerror_t* st, int err, uint len, uint want) { qf_str_t qfs ; const char* q ; - int ql ; + uint ql ; /* Prepare. */ int errno_saved = errno ; - if ((len <= 0) || (len >= (int)sizeof(st->str))) - len = sizeof(st->str) - 1 ; - qfs_init(&qfs, st->str, len + 1) ; + if ((len <= 0) || (len >= sizeof(st->str))) + len = sizeof(st->str) ; + qfs_init(qfs, st->str, len) ; q = "" ; ql = 0 ; @@ -214,15 +219,15 @@ errtox(strerror_t* st, int err, int len, int want) const char* name = errno_name_lookup(err) ; if (name != NULL) - qfs_append(&qfs, name) ; + qfs_append(qfs, name) ; else - qfs_printf(&qfs, "ERRNO=%d", err) ; + qfs_printf(qfs, "ERRNO=%d", err) ; } ; /* name and string ? */ if (want == 3) { - qfs_append(&qfs, " ") ; + qfs_append(qfs, " ") ; q = "'" ; ql = 2 ; } ; @@ -285,24 +290,30 @@ errtox(strerror_t* st, int err, int len, int want) else { qf_str_t qfs_b ; - qfs_init(&qfs_b, buf, sizeof(buf)) ; - qfs_printf(&qfs_b, "strerror%s(%d) returned error %d", + qfs_init(qfs_b, buf, sizeof(buf)) ; + qfs_printf(qfs_b, "strerror%s(%d) returned error %d", qpthreads_enabled ? "_r" : "", err, ret) ; errm = buf ; } ; } ; } ; - /* Add strerror to the result... looking out for overflow. */ - len = strlen(errm) ; + /* Add strerror to the result... with quotes as rquired */ + if (ql != 0) + qfs_append(qfs, q) ; - if ((len + ql) <= qfs_left(&qfs)) /* accounting for "quotes" */ - qfs_printf(&qfs, "%s%s%s", q, errm, q) ; - else - qfs_printf(&qfs, "%s%.*s...%s", q, qfs_left(&qfs) - ql - 3, errm, q) ; - /* -ve precision is ignored ! */ + qfs_append(qfs, errm) ; + + if (ql != 0) + qfs_append(qfs, q) ; } ; + /* '\0' terminate -- if has overflowed, replace last few characters + * by "..." -- noting that sizeof("...") includes the '\0'. + */ + if (qfs_term(qfs) != 0) + qfs_term_string(qfs, ellipsis, sizeof(ellipsis)) ; + /* Put back errno */ errno = errno_saved ; } ; @@ -340,7 +351,7 @@ errtox(strerror_t* st, int err, int len, int want) * error. */ -static void eaitox(strerror_t* st, int eai, int err, int len, int want) ; +static void eaitox(strerror_t* st, int eai, int err, uint len, uint want) ; /*------------------------------------------------------------------------------ * Construct string to describe the given EAI_XXX error of the form: @@ -351,7 +362,7 @@ static void eaitox(strerror_t* st, int eai, int err, int len, int want) ; * Thread safe. Never returns NULL. */ extern strerror_t -eaitoa(int eai, int err, int len) +eaitoa(int eai, int err, uint len) { strerror_t st ; @@ -368,7 +379,7 @@ eaitoa(int eai, int err, int len) * Thread-safe. Never returns NULL. */ extern strerror_t -eaitoname(int eai, int err, int len) +eaitoname(int eai, int err, uint len) { strerror_t st ; @@ -385,7 +396,7 @@ eaitoname(int eai, int err, int len) * Thread-safe. Never returns NULL. */ extern strerror_t -eaitostr(int eai, int err, int len) +eaitostr(int eai, int err, uint len) { strerror_t st ; @@ -404,12 +415,12 @@ eaitostr(int eai, int err, int len) * err != 0 => if EAI_SYSTEM, return result for errno == err instead. */ static void -eaitox(strerror_t* st, int eai, int err, int len, int want) +eaitox(strerror_t* st, int eai, int err, uint len, uint want) { qf_str_t qfs ; const char* q ; - int ql ; + uint ql ; /* Look out for mapping EAI_SYSTEM */ if ((eai == EAI_SYSTEM) && (err != 0)) @@ -420,7 +431,7 @@ eaitox(strerror_t* st, int eai, int err, int len, int want) if ((len <= 0) || (len >= (int)sizeof(st->str))) len = sizeof(st->str) - 1 ; - qfs_init(&qfs, st->str, len + 1) ; + qfs_init(qfs, st->str, len + 1) ; q = "" ; ql = 0 ; @@ -431,15 +442,15 @@ eaitox(strerror_t* st, int eai, int err, int len, int want) const char* name = eaino_name_lookup(eai) ; if (name != NULL) - qfs_append(&qfs, name) ; + qfs_append(qfs, name) ; else - qfs_printf(&qfs, "EAI=%d", eai) ; + qfs_printf(qfs, "EAI=%d", eai) ; } ; /* name and string ? */ if (want == 3) { - qfs_append(&qfs, " ") ; + qfs_append(qfs, " ") ; q = "'" ; ql = 2 ; } ; @@ -454,23 +465,103 @@ eaitox(strerror_t* st, int eai, int err, int len, int want) else eaim = gai_strerror(eai) ; - /* Add strerror to the result... looking out for overflow. */ - len = strlen(eaim) ; + /* Add strerror to the result... with quotes as rquired */ + if (ql != 0) + qfs_append(qfs, q) ; - if ((len + ql) <= qfs_left(&qfs)) /* accounting for "quotes" */ - qfs_printf(&qfs, "%s%s%s", q, eaim, q) ; - else - qfs_printf(&qfs, "%s%.*s...%s", q, qfs_left(&qfs) - ql - 3, eaim, q) ; - /* -ve precision is ignored ! */ + qfs_append(qfs, eaim) ; + + if (ql != 0) + qfs_append(qfs, q) ; + + /* '\0' terminate -- if has overflowed, replace last few characters + * by "..." -- noting that sizeof("...") includes the '\0'. + */ + if (qfs_term(qfs) != 0) + qfs_term_string(qfs, ellipsis, sizeof(ellipsis)) ; } ; /* Put back errno */ errno = errno_saved ; } ; -/*============================================================================*/ +/*============================================================================== + * Miscellaneous thread-safe functions + */ + +/*------------------------------------------------------------------------------ + * getenv_r -- fetch environment variable into the given buffer. + * + * If buffer is not long enough, fetches as much as can and '\0' terminates. + * + * Returns: -1 => not found -- buffer set empty + * >= 0 == length of environment variable + * + * NB: this is NOT signal safe. If need value of environment variable in + * a signal action -- make OTHER arrangements !! + */ +extern int +getenv_r(const char* name, char* buf, int buf_len) +{ + char* val ; + int len ; + int cl ; + + qpt_mutex_lock(thread_safe) ; + + val = getenv(name) ; + if (val == NULL) + { + len = -1 ; + cl = 0 ; + } + else + { + len = strlen(val) ; + cl = (len < buf_len) ? len : buf_len - 1 ; + } ; + + if (buf_len > 0) + { + if (cl > 0) + memcpy(buf, val, cl) ; + buf[cl] = '\0' ; + } ; + + qpt_mutex_unlock(thread_safe) ; + + return len ; +} ; + +/*------------------------------------------------------------------------------ + * Thread safe version of strerror. Never returns NULL. + * Contents of result remains intact until another call of + * a safe_ function. + */ +const char * +safe_strerror(int errnum) +{ + static const char * unknown = "Unknown error"; + if (qpthreads_enabled) + { + char * buff = thread_buff(); + int ret = strerror_r(errnum, buff, buff_size); + + return (ret >= 0) + ? buff + : unknown; + } + else + { + const char *s = strerror(errnum); + return (s != NULL) + ? s + : unknown; + } +} -/* Thread safe version of inet_ntoa. Never returns NULL. +/*------------------------------------------------------------------------------ + * Thread safe version of inet_ntoa. Never returns NULL. * Contents of result remains intact until another call of * a safe_ function. */ @@ -489,7 +580,8 @@ safe_inet_ntoa (struct in_addr in) : unknown; } -/* Return the thread's buffer, create it if necessary. +/*------------------------------------------------------------------------------ + * Return the thread's buffer, create it if necessary. * (pthread Thread Specific Data) */ static char * |