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