1 /*
2 * $Id: yrdwr.c,v 1.1 2005-09-18 22:04:16 dhmunro Exp $
3 * Implement YRead and YWrite functions, plus general gather/scatter
4 * routines with StructDef format Converter.
5 */
6 /* Copyright (c) 2005, The Regents of the University of California.
7 * All rights reserved.
8 * This file is part of yorick (http://yorick.sourceforge.net).
9 * Read the accompanying LICENSE file for details.
10 */
11
12 #include "bcast.h"
13 #include "pstdlib.h"
14
15 /* Things to note:
16 (1) If base->file!=0, then base->model!=0 (since the in-memory
17 version of the StructDef can't refer to any particular file).
18 (2) The Convert operator will be 0 for non-pointer,
19 native-format disk files, since no conversion operation
20 is required.
21 */
22
23 extern void ReadGather(void *dst, void *srcM, long srcD, StructDef *base,
24 long number, const Strider *strider);
25 extern void WriteScatter(void *src, void *dstM, long dstD, StructDef *base,
26 long number, const Strider *strider);
27
28 static void *WriteRecurse(void *src, StructDef *base, long number);
29 extern void SetSequentialWrite(IOStream *file, long last);
30
31 static void ClearTmp(Array **tmpArray);
32 static StructDef *NeedsConversion(StructDef *base);
33
34 /*--------------------------------------------------------------------------*/
35
36 /* YRead and YWrite assume that the buffer passed to them is to hold
37 the data in its FINAL format, that is, as base->model->...->model. */
38
YRead(void * dst,long src,StructDef * base,long number,const Strider * strider)39 void YRead(void *dst, long src, StructDef *base, long number,
40 const Strider *strider)
41 {
42 if (base->file && base->addressType==2 && strider)
43 YError("cannot use a strider reading sequential object from file");
44 ReadGather(dst, (void *)0, src, base, number, strider);
45 }
46
YWrite(void * src,long dst,StructDef * base,long number,const Strider * strider)47 void YWrite(void *src, long dst, StructDef *base, long number,
48 const Strider *strider)
49 {
50 if (base->file && base->addressType==2) {
51 if (strider)
52 YError("cannot use a strider writing sequential object to file");
53 SetSequentialWrite(base->file, dst+base->size*number);
54 }
55 WriteScatter(src, (void *)0, dst, base, number, strider);
56 }
57
SetSequentialWrite(IOStream * file,long last)58 void SetSequentialWrite(IOStream *file, long last)
59 {
60 if (last<file->nextAddress)
61 YError("sequential object must be written at end of binary file");
62 /* Converter for sequential object may need to know address at
63 end of object being written, since the corresponding write
64 occurs AFTER the Converter is called. */
65 file->seqAddress= last;
66 }
67
68 /*--------------------------------------------------------------------------*/
69
70 static Array *tmp1Array= 0, *tmp2Array= 0;
71
ClearTmpArray(void)72 void ClearTmpArray(void)
73 {
74 ClearTmp(&tmp1Array);
75 ClearTmp(&tmp2Array);
76 }
77
NewTmpArray(StructDef * base,Dimension * dims)78 Array *NewTmpArray(StructDef *base, Dimension *dims)
79 {
80 Array *array= NewArray(base, dims);
81 if (tmp1Array) {
82 if (tmp2Array) { /* both tmp1 and tmp2 exist -- deallocate tmp1 */
83 Array *tmp= tmp2Array;
84 ClearTmp(&tmp1Array);
85 tmp2Array= array;
86 tmp1Array= tmp;
87 } else { /* only tmp1 exists, leave it alone */
88 tmp2Array= array;
89 }
90 } else { /* neither tmp1 nor tmp2 exist, use tmp1 */
91 tmp1Array= array;
92 }
93 return array;
94 }
95
ClearTmp(Array ** tmpArray)96 static void ClearTmp(Array **tmpArray)
97 {
98 Array *array= *tmpArray;
99 *tmpArray= 0;
100 Unref(array);
101 }
102
NeedsConversion(StructDef * base)103 static StructDef *NeedsConversion(StructDef *base)
104 {
105 while (base) {
106 if (base->Convert) return base;
107 base= base->model;
108 }
109 return 0;
110 }
111
112 /*--------------------------------------------------------------------------*/
113
114 /* In a read/gather operation, base describes the data type of the
115 source (which is either in memory or on disk). The destination is
116 assumed to have been allocated prior to this call, and to have the
117 data type base->model->...->model.
118 If base->file, then srcM==0 will cause a subsequent call to
119 ReadPointees, while if srcM!=0, the call will not be made
120 (this is intended to prevent recursion). */
ReadGather(void * dst,void * srcM,long srcD,StructDef * base,long number,const Strider * strider)121 void ReadGather(void *dst, void *srcM, long srcD, StructDef *base,
122 long number, const Strider *strider)
123 {
124 StructDef *preModel= NeedsConversion(base);
125 void *dstM;
126 int doPointees= (srcM==0);
127
128 if (preModel) {
129 Array *array;
130 Dimension *dims;
131 ClearTmpArray();
132 dims= NewDimension(number, 1L, (Dimension *)0);
133 array= NewTmpArray(preModel, dims);
134 dims->references--;
135 dstM= array->value.c;
136 } else {
137 dstM= dst;
138 }
139
140 if (base->file) CastRead(dstM, srcD, base, number, strider);
141 else Gather(dstM, srcM, base, number, strider);
142
143 if (preModel) {
144 StructDef *model= preModel->model;
145 Converter *Convert= preModel->Convert;
146 Converter *NextConvert= 0;
147
148 while (model) {
149 while (model->model && !model->Convert) model= model->model;
150
151 srcM= dstM;
152 if ((NextConvert= model->Convert)) {
153 /* There are two temporary arrays; NewTmpArray automatically
154 frees the array it allocated two calls before. Both
155 arrays are deallocated by ClearTmpArray, which is also called
156 from YError. */
157 Dimension *dims= NewDimension(number, 1L, (Dimension *)0);
158 Array *array= NewTmpArray(model, dims);
159 dims->references--;
160 dstM= array->value.c;
161 } else {
162 /* last pass always takes this branch */
163 dstM= dst;
164 }
165
166 Convert(preModel, srcM, dstM, number, 0);
167 preModel= model;
168 model= model->model;
169 Convert= NextConvert;
170 }
171
172 ClearTmpArray();
173 }
174
175 if (doPointees && base->file) ReadPointees(base->file);
176 }
177
178 /* In a write/scatter operation, base describes the data type of the
179 destination (which is either in memory or on disk). The source is
180 assumed to have been allocated prior to this call, and to have the
181 data type base->model->...->model.
182 If base->file, then dstM==0 will cause a subsequent call to
183 WritePointees, while if dstM!=0, the call will not be made
184 (this is intended to prevent recursion). */
WriteScatter(void * src,void * dstM,long dstD,StructDef * base,long number,const Strider * strider)185 void WriteScatter(void *src, void *dstM, long dstD, StructDef *base,
186 long number, const Strider *strider)
187 {
188 StructDef *preModel= NeedsConversion(base);
189 void *sbuffer;
190
191 if (preModel) {
192 ClearTmpArray();
193 /* Note that SetSequentialWrite has set seqAddress properly BEFORE
194 the call to WriteScatter -- DO NOT do anything like this:
195 if (base->file && base->addressType==2) base->file->seqAddress= dstD;
196 */
197 sbuffer= WriteRecurse(src, preModel, number);
198
199 } else {
200 sbuffer= src;
201 }
202
203 if (base->file) {
204 IOStream *file= base->file;
205 long nextAddress= file->nextAddress;
206 CastWrite(sbuffer, dstD, base, number, strider);
207 if (!dstM) {
208 WritePointees(file);
209 if (nextAddress<file->nextAddress) FlushFile(file, 0);
210 }
211 } else {
212 Scatter(sbuffer, dstM, base, number, strider);
213 }
214
215 if (preModel) ClearTmpArray();
216 }
217
WriteRecurse(void * src,StructDef * base,long number)218 static void *WriteRecurse(void *src, StructDef *base, long number)
219 {
220 StructDef *model= base->model;
221 Converter *Convert= base->Convert; /* guaranteed non-zero */
222 Array *darray;
223 void *dst;
224 Dimension *dims;
225
226 while (model->model && !model->Convert) model= model->model;
227
228 if (model->Convert) src= WriteRecurse(src, model, number);
229
230 /* There are two temporary arrays; NewTmpArray automatically
231 frees the array it allocated two calls before. Both
232 arrays are deallocated by ClearTmpArray, which is also called
233 from YError. */
234 dims= NewDimension(number, 1L, (Dimension *)0);
235 darray= NewTmpArray(base, dims);
236 dims->references--;
237 dst= darray->value.c;
238
239 Convert(base, dst, src, number, 1);
240 return dst;
241 }
242
243 /*--------------------------------------------------------------------------*/
244
ReadPointees(IOStream * file)245 void ReadPointees(IOStream *file)
246 {
247 long nValid= file->pointeeList.nValid;
248 long n= file->pointeeList.table.nItems - nValid;
249 MDinfo *mdInfo= &file->pointeeList.mdInfo[nValid];
250 Array *array;
251 int noRecursion= 1;
252
253 if (file->pointeeList.writing!=0) return;
254
255 /* mark that read is in progress */
256 file->pointeeList.writing= 2;
257
258 /* The Convert routine has already read the header, storing
259 the addresses of the header, the data, and the memory address
260 of a newly created Array into pointeeList.mdInfo. */
261
262 while (n>0) {
263 if (mdInfo->m) {
264 array= Pointee(mdInfo->m);
265 ReadGather(array->value.c, &noRecursion, mdInfo->data,
266 mdInfo->base, array->type.number, (Strider *)0);
267 }
268
269 /* note that pointeeList.table.nItems may have increased
270 during the reading of this pointee */
271 file->pointeeList.nValid= (++nValid);
272 mdInfo= &file->pointeeList.mdInfo[nValid];
273 n= file->pointeeList.table.nItems - nValid;
274 }
275
276 /* successful completion of read */
277 file->pointeeList.writing= 0;
278 }
279
WritePointees(IOStream * file)280 void WritePointees(IOStream *file)
281 {
282 long nValid= file->pointeeList.nValid;
283 long n= file->pointeeList.table.nItems - nValid;
284 MDinfo *mdInfo= &file->pointeeList.mdInfo[nValid];
285 Array *array;
286 int noRecursion= 1;
287
288 if (file->pointeeList.writing!=1) return;
289
290 /* mark that write is in progress */
291 file->pointeeList.writing= 3;
292
293 /* The Convert routine has already written the header, storing
294 the addresses of the header, the data, and the memory data
295 into pointeeList.mdInfo. */
296
297 while (n>0) {
298 if (mdInfo->m) {
299 array= Pointee(mdInfo->m);
300 WriteScatter(array->value.c, &noRecursion, mdInfo->data,
301 mdInfo->base, array->type.number, (Strider *)0);
302 }
303
304 /* note that pointeeList.table.nItems may have increased
305 during the writing of this pointee */
306 file->pointeeList.nValid= (++nValid);
307 mdInfo= &file->pointeeList.mdInfo[nValid];
308 n= file->pointeeList.table.nItems - nValid;
309 }
310
311 /* successful completion of write */
312 file->pointeeList.writing= 1;
313 }
314
ClearPointees(IOStream * file,int writing)315 void ClearPointees(IOStream *file, int writing)
316 {
317 long i, nItems= file->pointeeList.table.nItems;
318 MDinfo *mdInfo;
319 Array *array;
320
321 if (nItems && !(file->pointeeList.writing&2)) {
322 /* Note that this is skipped if failed at previous attempt to
323 call WritePointees or ReadPointees. */
324 if (file->pointeeList.writing) WritePointees(file);
325 else ReadPointees(file);
326 /* tracking down pointers may have changed nItems, mdInfo */
327 nItems= file->pointeeList.table.nItems;
328 }
329
330 mdInfo= file->pointeeList.mdInfo;
331 HashXClear(&file->pointeeList.table);
332 file->pointeeList.nValid= 0;
333 file->pointeeList.mdInfo= 0;
334 file->pointeeList.writing= writing;
335
336 for (i=0 ; i<nItems ; i++) {
337 array= Pointee(mdInfo[i].m);
338 Unref(array);
339 }
340 p_free(mdInfo);
341 }
342
343 /*--------------------------------------------------------------------------*/
344