1 /*****************************************************************************
2 * RRDtool 1.4.3 Copyright by Tobi Oetiker, 1997-2010
3 * This file: Copyright 2003 Peter Stamfest <peter@stamfest.at>
4 * & Tobias Oetiker
5 * Distributed under the GPL
6 *****************************************************************************
7 * rrd_thread_safe.c Contains routines used when thread safety is required
8 *****************************************************************************
9 * $Id$
10 *************************************************************************** */
12 #include <pthread.h>
13 #include <string.h>
14 /* #include <error.h> */
15 #include "rrd.h"
16 #include "rrd_tool.h"
18 /* Key for the thread-specific rrd_context */
19 static pthread_key_t context_key;
21 /* Once-only initialisation of the key */
22 static pthread_once_t context_key_once = PTHREAD_ONCE_INIT;
24 /* Free the thread-specific rrd_context - we might actually use
25 rrd_free_context instead...
26 */
27 static void context_destroy_context(
28 void *ctx_)
29 {
30 rrd_context_t *ctx = ctx_;
32 if (ctx)
33 rrd_free_context(ctx);
34 }
36 /* Allocate the key */
37 static void context_get_key(
38 void)
39 {
40 pthread_key_create(&context_key, context_destroy_context);
41 }
43 rrd_context_t *rrd_get_context(
44 void)
45 {
46 rrd_context_t *ctx;
48 pthread_once(&context_key_once, context_get_key);
49 ctx = pthread_getspecific(context_key);
50 if (!ctx) {
51 ctx = rrd_new_context();
52 pthread_setspecific(context_key, ctx);
53 }
54 return ctx;
55 }
57 #ifdef HAVE_STRERROR_R
58 const char *rrd_strerror(
59 int err)
60 {
61 rrd_context_t *ctx = rrd_get_context();
62 char *ret = "unknown error";
64 *ctx->lib_errstr = '\0';
66 /* Even though POSIX/XSI requires "strerror_r" to return an "int", some
67 * systems (e.g. the GNU libc) return a "char *" _and_ ignore the second
68 * argument ... -tokkee */
69 #ifdef STRERROR_R_CHAR_P
70 ret = strerror_r(err, ctx->lib_errstr, sizeof(ctx->lib_errstr));
71 if ((! ret) || (*ret == '\0')) {
72 if (*ctx->lib_errstr != '\0')
73 ret = ctx->lib_errstr;
74 else {
75 /* according to the manpage this should not happen -
76 let's handle it somehow sanely anyway */
77 snprintf(ctx->lib_errstr, sizeof(ctx->lib_errstr),
78 "unknown error %i - strerror_r did not return anything",
79 err);
80 ctx->lib_errstr[sizeof(ctx->lib_errstr) - 1] = '\0';
81 ret = ctx->lib_errstr;
82 }
83 }
84 #else /* ! STRERROR_R_CHAR_P */
85 if (strerror_r(err, ctx->lib_errstr, sizeof(ctx->lib_errstr))) {
86 snprintf(ctx->lib_errstr, sizeof(ctx->lib_errstr),
87 "unknown error %i - strerror_r returned with errno = %i",
88 err, errno);
89 ctx->lib_errstr[sizeof(ctx->lib_errstr) - 1] = '\0';
90 }
91 ret = ctx->lib_errstr;
92 #endif
93 return ret;
94 }
95 #else
96 #undef strerror
97 const char *rrd_strerror(
98 int err)
99 {
100 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
101 rrd_context_t *ctx;
103 ctx = rrd_get_context();
104 pthread_mutex_lock(&mtx);
105 strncpy(ctx->lib_errstr, strerror(err), sizeof(ctx->lib_errstr));
106 ctx->lib_errstr[sizeof(ctx->lib_errstr) - 1] = '\0';
107 pthread_mutex_unlock(&mtx);
108 return ctx->lib_errstr;
109 }
110 #endif