win32 portability patch and win32/rrdlib.vcproj file for the source
[rrdtool.git] / src / rrd_thread_safe_nt.c
1 /*****************************************************************************
2  * RRDtool 1.3.2  Copyright by Tobi Oetiker, 1997-2008
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  *************************************************************************** */
12
13 #include <windows.h>
14 #include <string.h>
15 /* #include <error.h> */
16 #include "rrd.h"
17 #include "rrd_tool.h"
18
19 /* Key for the thread-specific rrd_context */
20 static DWORD context_key;
21 static CRITICAL_SECTION CriticalSection;
22
23
24 /* Once-only initialisation of the key */
25 static DWORD context_key_once = 0;
26
27
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((LONG*)(&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;
51
52     context_init_context();
53
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 }
61
62
63 /* this was added by the win32 porters Christof.Wegmann@exitgames.com */
64
65 rrd_context_t *rrd_force_new_context(
66     void)
67 {
68     rrd_context_t *ctx;
69
70     context_init_context();
71
72     ctx = rrd_new_context();
73     TlsSetValue(context_key, ctx);
74
75     return ctx;
76 }
77
78
79 #undef strerror
80 const char *rrd_strerror(
81     int err)
82 {
83     rrd_context_t *ctx;
84
85     context_init_context();
86
87     ctx = rrd_get_context();
88
89     EnterCriticalSection(&CriticalSection);
90     strncpy(ctx->lib_errstr, strerror(err), sizeof(ctx->lib_errstr));
91     ctx->lib_errstr[sizeof(ctx->lib_errstr) - 1] = '\0';
92     LeaveCriticalSection(&CriticalSection);
93
94     return ctx->lib_errstr;
95 }
96
97 /*
98  * there much be a re-entrant version of these somewhere in win32 land
99  */
100 struct tm *localtime_r(
101     const time_t *timep,
102     struct tm *result)
103 {
104     struct tm *local;
105
106     context_init_context();
107
108     EnterCriticalSection(&CriticalSection);
109     local = localtime(timep);
110     memcpy(result, local, sizeof(struct tm));
111     LeaveCriticalSection(&CriticalSection);
112     return result;
113 }
114
115 char     *ctime_r(
116     const time_t *timep,
117     char *result)
118 {
119     char     *local;
120
121     context_init_context();
122
123     EnterCriticalSection(&CriticalSection);
124     local = ctime(timep);
125     strcpy(result, local);
126     LeaveCriticalSection(&CriticalSection);
127     return result;
128 }
129
130 struct tm *gmtime_r(
131     const time_t *timep,
132     struct tm *result)
133 {
134     struct tm *local;
135
136     context_init_context();
137
138     EnterCriticalSection(&CriticalSection);
139     local = gmtime(timep);
140     memcpy(result, local, sizeof(struct tm));
141     LeaveCriticalSection(&CriticalSection);
142     return result;
143 }
144
145 /* implementation from Apache's APR library */
146 char     *strtok_r(
147     char *str,
148     const char *sep,
149     char **last)
150 {
151     char     *token;
152
153     context_init_context();
154
155
156     if (!str)           /* subsequent call */
157         str = *last;    /* start where we left off */
158
159     /* skip characters in sep (will terminate at '\0') */
160     while (*str && strchr(sep, *str))
161         ++str;
162
163     if (!*str)          /* no more tokens */
164         return NULL;
165
166     token = str;
167
168     /* skip valid token characters to terminate token and
169      * prepare for the next call (will terminate at '\0) 
170      */
171     *last = token + 1;
172     while (**last && !strchr(sep, **last))
173         ++ * last;
174
175     if (**last) {
176         **last = '\0';
177         ++*last;
178     }
179
180     return token;
181 }