summaryrefslogtreecommitdiffstats
path: root/lib/pthread_safe.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pthread_safe.c')
-rw-r--r--lib/pthread_safe.c246
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 *