1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #ifndef _XOPEN_SOURCE
6 #define _XOPEN_SOURCE 600 /* PTHREAD_MUTEX_RECURSIVE */
7 #endif
8
9 #include <limits.h>
10 #include <stdio.h>
11
12 #include "cdi.h"
13 #include "dmemory.h"
14 #include "namespace.h"
15 #include "resource_handle.h"
16 #include "serialize.h"
17 #include "error.h"
18 #include "cdf_int.h"
19 #include "file.h"
20 #include "cdi_int.h"
21 #include "stream_cdf.h"
22
23 static unsigned nNamespaces = 1;
24 static int activeNamespace = 0;
25
26 #ifdef HAVE_LIBNETCDF
27 #define CDI_NETCDF_SWITCHES \
28 { .func = (void (*)()) nc__create }, \
29 { .func = (void (*)()) cdf_def_var_serial }, \
30 { .func = (void (*)()) cdfDefTimestep }, \
31 { .func = (void (*)()) cdfDefCoordinateVars }
32
33 #else
34 #define CDI_NETCDF_SWITCHES
35 #endif
36
37 #define defaultSwitches { \
38 { .func = (void (*)()) cdiAbortC_serial }, \
39 { .func = (void (*)()) cdiWarning }, \
40 { .func = (void (*)()) serializeGetSizeInCore }, \
41 { .func = (void (*)()) serializePackInCore }, \
42 { .func = (void (*)()) serializeUnpackInCore }, \
43 { .func = (void (*)()) fileOpen_serial }, \
44 { .func = (void (*)()) fileWrite }, \
45 { .func = (void (*)()) fileClose_serial }, \
46 { .func = (void (*)()) cdiStreamOpenDefaultDelegate }, \
47 { .func = (void (*)()) cdiStreamDefVlist_ }, \
48 { .func = (void (*)()) cdiStreamSetupVlist_ }, \
49 { .func = (void (*)()) cdiStreamWriteVar_ }, \
50 { .func = (void (*)()) cdiStreamWriteVarChunk_ }, \
51 { .func = (void (*)()) 0 }, \
52 { .func = (void (*)()) 0 }, \
53 { .func = (void (*)()) cdiStreamCloseDefaultDelegate }, \
54 { .func = (void (*)()) cdiStreamDefTimestep_ }, \
55 { .func = (void (*)()) cdiStreamSync_ }, \
56 CDI_NETCDF_SWITCHES \
57 }
58
59 #if defined (SX) || defined (__cplusplus)
60 static const union namespaceSwitchValue
61 defaultSwitches_[NUM_NAMESPACE_SWITCH] = defaultSwitches;
62 #endif
63
64 enum namespaceStatus {
65 NAMESPACE_STATUS_INUSE,
66 NAMESPACE_STATUS_UNUSED,
67 };
68
69 static struct Namespace
70 {
71 enum namespaceStatus resStage;
72 union namespaceSwitchValue switches[NUM_NAMESPACE_SWITCH];
73 } initialNamespace = {
74 .resStage = NAMESPACE_STATUS_INUSE,
75 .switches = defaultSwitches
76 };
77
78 static struct Namespace *namespaces = &initialNamespace;
79
80 static unsigned namespacesSize = 1;
81
82 #if defined (HAVE_LIBPTHREAD)
83 # include <pthread.h>
84
85 static pthread_once_t namespaceOnce = PTHREAD_ONCE_INIT;
86 static pthread_mutex_t namespaceMutex;
87
88 static void
namespaceInitialize(void)89 namespaceInitialize(void)
90 {
91 #if defined(PTHREAD_MUTEXATTR)
92 pthread_mutexattr_t ma;
93 pthread_mutexattr_init(&ma);
94 pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
95 pthread_mutex_init(&namespaceMutex, &ma);
96 pthread_mutexattr_destroy(&ma);
97 #endif
98 }
99
100 # define NAMESPACE_LOCK() pthread_mutex_lock(&namespaceMutex)
101 # define NAMESPACE_UNLOCK() pthread_mutex_unlock(&namespaceMutex)
102 # define NAMESPACE_INIT() pthread_once(&namespaceOnce, \
103 namespaceInitialize)
104
105
106 #else
107
108 # define NAMESPACE_INIT() do { } while (0)
109 # define NAMESPACE_LOCK()
110 # define NAMESPACE_UNLOCK()
111
112 #endif
113
114
115 enum {
116 intbits = sizeof(int) * CHAR_BIT,
117 nspbits = 4,
118 idxbits = intbits - nspbits,
119 nspmask = (int)((( (unsigned)1 << nspbits ) - 1) << idxbits),
120 idxmask = ( 1 << idxbits ) - 1,
121 };
122
123 enum {
124 NUM_NAMESPACES = 1 << nspbits,
125 NUM_IDX = 1 << idxbits,
126 };
127
128
namespaceIdxEncode(namespaceTuple_t tin)129 int namespaceIdxEncode ( namespaceTuple_t tin )
130 {
131 xassert ( tin.nsp < NUM_NAMESPACES && tin.idx < NUM_IDX);
132 return ( tin.nsp << idxbits ) + tin.idx;
133 }
134
namespaceIdxEncode2(int nsp,int idx)135 int namespaceIdxEncode2 ( int nsp, int idx )
136 {
137 xassert(nsp < NUM_NAMESPACES && idx < NUM_IDX);
138 return ( nsp << idxbits ) + idx;
139 }
140
141
namespaceResHDecode(int resH)142 namespaceTuple_t namespaceResHDecode ( int resH )
143 {
144 namespaceTuple_t tin;
145
146 tin.idx = resH & idxmask;
147 tin.nsp = (int)(((unsigned)( resH & nspmask )) >> idxbits);
148
149 return tin;
150 }
151
152 int
namespaceNew()153 namespaceNew()
154 {
155 int newNamespaceID = -1;
156 NAMESPACE_INIT();
157 NAMESPACE_LOCK();
158 if (namespacesSize > nNamespaces)
159 {
160 /* namespace is already available and only needs reinitialization */
161 for (unsigned i = 0; i < namespacesSize; ++i)
162 if (namespaces[i].resStage == NAMESPACE_STATUS_UNUSED)
163 {
164 newNamespaceID = (int)i;
165 break;
166 }
167 }
168 else if (namespacesSize == 1)
169 {
170 /* make room for additional namespace */
171 struct Namespace *newNameSpaces
172 = (struct Namespace *) Malloc(((size_t)namespacesSize + 1) * sizeof (namespaces[0]));
173 memcpy(newNameSpaces, namespaces, sizeof (namespaces[0]));
174 namespaces = newNameSpaces;
175 ++namespacesSize;
176 newNamespaceID = 1;
177 }
178 else if (namespacesSize < NUM_NAMESPACES)
179 {
180 /* make room for additional namespace */
181 newNamespaceID = (int)namespacesSize;
182 namespaces
183 = (struct Namespace *) Realloc(namespaces, ((size_t)namespacesSize + 1) * sizeof (namespaces[0]));
184 ++namespacesSize;
185 }
186 else /* implicit: namespacesSize >= NUM_NAMESPACES */
187 {
188 NAMESPACE_UNLOCK();
189 return -1;
190 }
191 xassert(newNamespaceID >= 0 && newNamespaceID < NUM_NAMESPACES);
192 ++nNamespaces;
193 namespaces[newNamespaceID].resStage = NAMESPACE_STATUS_INUSE;
194 #if defined (SX) || defined (__cplusplus)
195 memcpy(namespaces[newNamespaceID].switches,
196 defaultSwitches_,
197 sizeof (namespaces[newNamespaceID].switches));
198 #else
199 memcpy(namespaces[newNamespaceID].switches,
200 (union namespaceSwitchValue[NUM_NAMESPACE_SWITCH])defaultSwitches,
201 sizeof (namespaces[newNamespaceID].switches));
202 #endif
203 reshListCreate(newNamespaceID);
204 NAMESPACE_UNLOCK();
205 return newNamespaceID;
206 }
207
208 void
namespaceDelete(int namespaceID)209 namespaceDelete(int namespaceID)
210 {
211 NAMESPACE_INIT();
212 NAMESPACE_LOCK();
213 xassert(namespaceID >= 0 && (unsigned)namespaceID < namespacesSize
214 && nNamespaces);
215 reshListDestruct(namespaceID);
216 namespaces[namespaceID].resStage = NAMESPACE_STATUS_UNUSED;
217 --nNamespaces;
218 NAMESPACE_UNLOCK();
219 }
220
namespaceGetNumber()221 int namespaceGetNumber ()
222 {
223 return (int)nNamespaces;
224 }
225
226
namespaceSetActive(int nId)227 void namespaceSetActive ( int nId )
228 {
229 xassert((unsigned)nId < namespacesSize
230 && namespaces[nId].resStage != NAMESPACE_STATUS_UNUSED);
231 activeNamespace = nId;
232 }
233
234
namespaceGetActive()235 int namespaceGetActive ()
236 {
237 return activeNamespace;
238 }
239
namespaceAdaptKey(int originResH,int originNamespace)240 int namespaceAdaptKey ( int originResH, int originNamespace )
241 {
242 namespaceTuple_t tin;
243 int nsp;
244
245 if ( originResH == CDI_UNDEFID ) return CDI_UNDEFID;
246
247 tin.idx = originResH & idxmask;
248 tin.nsp = (int)(((unsigned)( originResH & nspmask )) >> idxbits);
249
250 xassert ( tin.nsp == originNamespace );
251
252 nsp = namespaceGetActive ();
253
254 return namespaceIdxEncode2 ( nsp, tin.idx );
255 }
256
257
namespaceAdaptKey2(int originResH)258 int namespaceAdaptKey2 ( int originResH )
259 {
260 namespaceTuple_t tin;
261 int nsp;
262
263 if ( originResH == CDI_UNDEFID ) return CDI_UNDEFID;
264
265 tin.idx = originResH & idxmask;
266 tin.nsp = (int)(((unsigned)( originResH & nspmask )) >> idxbits);
267
268 nsp = namespaceGetActive ();
269
270 return namespaceIdxEncode2 ( nsp, tin.idx );
271 }
272
namespaceSwitchSet(enum namespaceSwitch sw,union namespaceSwitchValue value)273 void namespaceSwitchSet(enum namespaceSwitch sw, union namespaceSwitchValue value)
274 {
275 xassert(sw > NSSWITCH_NO_SUCH_SWITCH && sw < NUM_NAMESPACE_SWITCH);
276 int nsp = namespaceGetActive();
277 namespaces[nsp].switches[sw] = value;
278 }
279
namespaceSwitchGet(enum namespaceSwitch sw)280 union namespaceSwitchValue namespaceSwitchGet(enum namespaceSwitch sw)
281 {
282 xassert(sw > NSSWITCH_NO_SUCH_SWITCH && sw < NUM_NAMESPACE_SWITCH);
283 int nsp = namespaceGetActive();
284 return namespaces[nsp].switches[sw];
285 }
286
cdiReset(void)287 void cdiReset(void)
288 {
289 NAMESPACE_INIT();
290 NAMESPACE_LOCK();
291 for (unsigned namespaceID = 0; namespaceID < namespacesSize; ++namespaceID)
292 if (namespaces[namespaceID].resStage != NAMESPACE_STATUS_UNUSED)
293 namespaceDelete((int)namespaceID);
294 if (namespaces != &initialNamespace)
295 {
296 Free(namespaces);
297 namespaces = &initialNamespace;
298 namespaces[0].resStage = NAMESPACE_STATUS_UNUSED;
299 }
300 namespacesSize = 1;
301 nNamespaces = 0;
302 NAMESPACE_UNLOCK();
303 }
304
305 /*
306 * Local Variables:
307 * c-file-style: "Java"
308 * c-basic-offset: 2
309 * indent-tabs-mode: nil
310 * show-trailing-whitespace: t
311 * require-trailing-newline: t
312 * End:
313 */
314