1 /*****************************************************************************
2 * RRDtool 1.3.7 Copyright by Tobi Oetiker, 1997-2009
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 * for win32
9 *****************************************************************************
10 * $Id: rrd_thread_safe_nt.c 1781 2009-04-07 07:31:53Z oetiker $
11 *************************************************************************** */
13 #include <windows.h>
14 #include <string.h>
15 /* #include <error.h> */
16 #include "rrd.h"
17 #include "rrd_tool.h"
19 /* Key for the thread-specific rrd_context */
20 static DWORD context_key;
21 static CRITICAL_SECTION CriticalSection;
24 /* Once-only initialisation of the key */
25 static volatile LONG context_key_once = 0;
28 /* Free the thread-specific rrd_context - we might actually use
29 rrd_free_context instead...
30 */
31 static void context_destroy_context(
32 void)
33 {
34 DeleteCriticalSection(&CriticalSection);
35 TlsFree(context_key);
36 context_key_once = 0;
37 }
38 static void context_init_context(
39 void)
40 {
41 if (!InterlockedExchange(&context_key_once, 1)) {
42 context_key = TlsAlloc();
43 InitializeCriticalSection(&CriticalSection);
44 atexit(context_destroy_context);
45 }
46 }
47 rrd_context_t *rrd_get_context(
48 void)
49 {
50 rrd_context_t *ctx;
52 context_init_context();
54 ctx = (rrd_context_t*)(TlsGetValue(context_key));
55 if (!ctx) {
56 ctx = rrd_new_context();
57 TlsSetValue(context_key, ctx);
58 }
59 return ctx;
60 }
62 #ifdef WIN32
63 rrd_context_t *rrd_force_new_context(void)
64 {
65 rrd_context_t *ctx;
67 context_init_context();
69 ctx = rrd_new_context();
70 TlsSetValue(context_key, ctx);
72 return ctx;
73 }
74 #endif
76 #undef strerror
77 const char *rrd_strerror(
78 int err)
79 {
80 rrd_context_t *ctx;
82 context_init_context();
84 ctx = rrd_get_context();
86 EnterCriticalSection(&CriticalSection);
87 strncpy(ctx->lib_errstr, strerror(err), sizeof(ctx->lib_errstr));
88 ctx->lib_errstr[sizeof(ctx->lib_errstr) - 1] = '\0';
89 LeaveCriticalSection(&CriticalSection);
91 return ctx->lib_errstr;
92 }
94 /*
95 * there much be a re-entrant version of these somewhere in win32 land
96 */
97 struct tm *localtime_r(
98 const time_t *timep,
99 struct tm *result)
100 {
101 struct tm *local;
103 context_init_context();
105 EnterCriticalSection(&CriticalSection);
106 local = localtime(timep);
107 memcpy(result, local, sizeof(struct tm));
108 LeaveCriticalSection(&CriticalSection);
109 return result;
110 }
112 char *ctime_r(
113 const time_t *timep,
114 char *result)
115 {
116 char *local;
118 context_init_context();
120 EnterCriticalSection(&CriticalSection);
121 local = ctime(timep);
122 strcpy(result, local);
123 LeaveCriticalSection(&CriticalSection);
124 return result;
125 }
127 struct tm *gmtime_r(
128 const time_t *timep,
129 struct tm *result)
130 {
131 struct tm *local;
133 context_init_context();
135 EnterCriticalSection(&CriticalSection);
136 local = gmtime(timep);
137 memcpy(result, local, sizeof(struct tm));
138 LeaveCriticalSection(&CriticalSection);
139 return result;
140 }
142 /* implementation from Apache's APR library */
143 char *strtok_r(
144 char *str,
145 const char *sep,
146 char **last)
147 {
148 char *token;
150 context_init_context();
153 if (!str) /* subsequent call */
154 str = *last; /* start where we left off */
156 /* skip characters in sep (will terminate at '\0') */
157 while (*str && strchr(sep, *str))
158 ++str;
160 if (!*str) /* no more tokens */
161 return NULL;
163 token = str;
165 /* skip valid token characters to terminate token and
166 * prepare for the next call (will terminate at '\0)
167 */
168 *last = token + 1;
169 while (**last && !strchr(sep, **last))
170 ++ * last;
172 if (**last) {
173 **last = '\0';
174 ++*last;
175 }
177 return token;
178 }