1 /*****************************************************************************
2 * RRDtool 1.2.99907080300 Copyright by Tobi Oetiker, 1997-2007
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$
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 DWORD 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 struct rrd_context *rrd_get_context(
48 void)
49 {
50 struct rrd_context *ctx;
52 context_init_context();
54 ctx = TlsGetValue(context_key);
55 if (!ctx) {
56 ctx = rrd_new_context();
57 TlsSetValue(context_key, ctx);
58 }
59 return ctx;
60 }
62 #undef strerror
63 const char *rrd_strerror(
64 int err)
65 {
66 struct rrd_context *ctx;
68 context_init_context();
70 ctx = rrd_get_context();
72 EnterCriticalSection(&CriticalSection);
73 strncpy(ctx->lib_errstr, strerror(err), ctx->errlen);
74 ctx->lib_errstr[ctx->errlen] = '\0';
75 LeaveCriticalSection(&CriticalSection);
77 return ctx->lib_errstr;
78 }
80 /*
81 * there much be a re-entrant version of these somewhere in win32 land
82 */
83 struct tm *localtime_r(
84 const time_t *timep,
85 struct tm *result)
86 {
87 struct tm *local;
89 context_init_context();
91 EnterCriticalSection(&CriticalSection);
92 local = localtime(timep);
93 memcpy(result, local, sizeof(struct tm));
94 LeaveCriticalSection(&CriticalSection);
95 return result;
96 }
98 char *ctime_r(
99 const time_t *timep,
100 char *result)
101 {
102 char *local;
104 context_init_context();
106 EnterCriticalSection(&CriticalSection);
107 local = ctime(timep);
108 strcpy(result, local);
109 LeaveCriticalSection(&CriticalSection);
110 return result;
111 }
113 struct tm *gmtime_r(
114 const time_t *timep,
115 struct tm *result)
116 {
117 struct tm *local;
119 context_init_context();
121 EnterCriticalSection(&CriticalSection);
122 local = gmtime(timep);
123 memcpy(result, local, sizeof(struct tm));
124 LeaveCriticalSection(&CriticalSection);
125 return result;
126 }
128 /* implementation from Apache's APR library */
129 char *strtok_r(
130 char *str,
131 const char *sep,
132 char **last)
133 {
134 char *token;
136 context_init_context();
139 if (!str) /* subsequent call */
140 str = *last; /* start where we left off */
142 /* skip characters in sep (will terminate at '\0') */
143 while (*str && strchr(sep, *str))
144 ++str;
146 if (!*str) /* no more tokens */
147 return NULL;
149 token = str;
151 /* skip valid token characters to terminate token and
152 * prepare for the next call (will terminate at '\0)
153 */
154 *last = token + 1;
155 while (**last && !strchr(sep, **last))
156 ++ * last;
158 if (**last) {
159 **last = '\0';
160 ++*last;
161 }
163 return token;
164 }