1 /*****************************************************************************
2  * RRDtool 1.2.30  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 1735 2009-01-19 14:29:11Z oetiker $
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  */
context_destroy_context(void)31 static void context_destroy_context(void)
32 {
33 	DeleteCriticalSection(&CriticalSection);
34     TlsFree(context_key);
35 	context_key_once=0;
36 }
context_init_context(void)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 }
rrd_get_context(void)45 struct rrd_context *rrd_get_context(void) {
46     struct rrd_context *ctx;
47 
48 	context_init_context();
49 
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
rrd_strerror(int err)58 const char *rrd_strerror(int err) {
59     struct rrd_context *ctx;
60 	context_init_context();
61 
62 	ctx = rrd_get_context();
63 
64     EnterCriticalSection(&CriticalSection);
65     strncpy(ctx->lib_errstr, strerror(err), ctx->errlen);
66     ctx->lib_errstr[ctx->errlen] = '\0';
67     LeaveCriticalSection(&CriticalSection);
68 
69     return ctx->lib_errstr;
70 }
71 /*
72  * there much be a re-entrant version of these somewhere in win32 land
73  */
localtime_r(const time_t * timep,struct tm * result)74 struct tm* localtime_r(const time_t *timep, struct tm* result)
75 {
76 	struct tm *local;
77 	context_init_context();
78 
79 	EnterCriticalSection(&CriticalSection);
80 	local = localtime(timep);
81 	memcpy(result,local,sizeof(struct tm));
82 	LeaveCriticalSection(&CriticalSection);
83 	return result;
84 }
ctime_r(const time_t * timep,char * result)85 char* ctime_r(const time_t *timep, char* result)
86 {
87 	char *local;
88 	context_init_context();
89 
90 	EnterCriticalSection(&CriticalSection);
91 	local = ctime(timep);
92 	strcpy(result,local);
93 	LeaveCriticalSection(&CriticalSection);
94 	return result;
95 }
96 
gmtime_r(const time_t * timep,struct tm * result)97 struct tm* gmtime_r(const time_t *timep, struct tm* result)
98 {
99 	struct tm *local;
100 	context_init_context();
101 
102 	EnterCriticalSection(&CriticalSection);
103 	local = gmtime(timep);
104 	memcpy(result,local,sizeof(struct tm));
105 	LeaveCriticalSection(&CriticalSection);
106 	return result;
107 }
108 
109 /* implementation from Apache's APR library */
strtok_r(char * str,const char * sep,char ** last)110 char *strtok_r(char *str, const char *sep, char **last)
111 {
112     char *token;
113 	context_init_context();
114 
115 
116     if (!str)           /* subsequent call */
117         str = *last;    /* start where we left off */
118 
119     /* skip characters in sep (will terminate at '\0') */
120     while (*str && strchr(sep, *str))
121         ++str;
122 
123     if (!*str)          /* no more tokens */
124         return NULL;
125 
126     token = str;
127 
128     /* skip valid token characters to terminate token and
129      * prepare for the next call (will terminate at '\0)
130      */
131     *last = token + 1;
132     while (**last && !strchr(sep, **last))
133         ++*last;
134 
135     if (**last) {
136         **last = '\0';
137         ++*last;
138     }
139 
140     return token;
141 }
142 
143