1 /*****************************************************************************
2 * RRDtool 1.2.9 Copyright by Tobi Oetiker, 1997-2005
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(void)
32 {
33 DeleteCriticalSection(&CriticalSection);
34 TlsFree(context_key);
35 context_key_once=0;
36 }
37 static void context_init_context(void)
38 {
39 if (!InterlockedExchange(&context_key_once, 1)) {
40 context_key = TlsAlloc();
41 InitializeCriticalSection(&CriticalSection);
42 atexit(context_destroy_context);
43 }
44 }
45 struct rrd_context *rrd_get_context(void) {
46 struct rrd_context *ctx;
48 context_init_context();
50 ctx = TlsGetValue(context_key);
51 if (!ctx) {
52 ctx = rrd_new_context();
53 TlsSetValue(context_key, ctx);
54 }
55 return ctx;
56 }
57 #undef strerror
58 const char *rrd_strerror(int err) {
59 struct rrd_context *ctx;
60 context_init_context();
62 ctx = rrd_get_context();
64 EnterCriticalSection(&CriticalSection);
65 strncpy(ctx->lib_errstr, strerror(err), ctx->errlen);
66 LeaveCriticalSection(&CriticalSection);
68 return ctx->lib_errstr;
69 }
70 /*
71 * there much be a re-entrant version of these somewhere in win32 land
72 */
73 struct tm* localtime_r(const time_t *timep, struct tm* result)
74 {
75 struct tm *local;
76 context_init_context();
78 EnterCriticalSection(&CriticalSection);
79 local = localtime(timep);
80 memcpy(result,local,sizeof(struct tm));
81 LeaveCriticalSection(&CriticalSection);
82 return result;
83 }
84 char* ctime_r(const time_t *timep, char* result)
85 {
86 char *local;
87 context_init_context();
89 EnterCriticalSection(&CriticalSection);
90 local = ctime(timep);
91 strcpy(result,local);
92 LeaveCriticalSection(&CriticalSection);
93 return result;
94 }
96 struct tm* gmtime_r(const time_t *timep, struct tm* result)
97 {
98 struct tm *local;
99 context_init_context();
101 EnterCriticalSection(&CriticalSection);
102 local = gmtime(timep);
103 memcpy(result,local,sizeof(struct tm));
104 LeaveCriticalSection(&CriticalSection);
105 return result;
106 }
108 /* implementation from Apache's APR library */
109 char *strtok_r(char *str, const char *sep, char **last)
110 {
111 char *token;
112 context_init_context();
115 if (!str) /* subsequent call */
116 str = *last; /* start where we left off */
118 /* skip characters in sep (will terminate at '\0') */
119 while (*str && strchr(sep, *str))
120 ++str;
122 if (!*str) /* no more tokens */
123 return NULL;
125 token = str;
127 /* skip valid token characters to terminate token and
128 * prepare for the next call (will terminate at '\0)
129 */
130 *last = token + 1;
131 while (**last && !strchr(sep, **last))
132 ++*last;
134 if (**last) {
135 **last = '\0';
136 ++*last;
137 }
139 return token;
140 }