1 |
|
|
/* |
2 |
|
|
Teem: Tools to process and visualize scientific data and images . |
3 |
|
|
Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago |
4 |
|
|
Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann |
5 |
|
|
Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah |
6 |
|
|
|
7 |
|
|
This library is free software; you can redistribute it and/or |
8 |
|
|
modify it under the terms of the GNU Lesser General Public License |
9 |
|
|
(LGPL) as published by the Free Software Foundation; either |
10 |
|
|
version 2.1 of the License, or (at your option) any later version. |
11 |
|
|
The terms of redistributing and/or modifying this software also |
12 |
|
|
include exceptions to the LGPL that facilitate static linking. |
13 |
|
|
|
14 |
|
|
This library is distributed in the hope that it will be useful, |
15 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 |
|
|
Lesser General Public License for more details. |
18 |
|
|
|
19 |
|
|
You should have received a copy of the GNU Lesser General Public License |
20 |
|
|
along with this library; if not, write to Free Software Foundation, Inc., |
21 |
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
#include "air.h" |
25 |
|
|
#include <teemDio.h> |
26 |
|
|
|
27 |
|
|
#if TEEM_DIO == 0 |
28 |
|
|
#else |
29 |
|
|
/* HEY: these may be SGI-specific */ |
30 |
|
|
#include <sys/types.h> |
31 |
|
|
#include <unistd.h> |
32 |
|
|
#include <fcntl.h> |
33 |
|
|
#endif |
34 |
|
|
|
35 |
|
|
#if TEEM_DIO == 0 |
36 |
|
|
const int airMyDio = 0; |
37 |
|
|
#else |
38 |
|
|
const int airMyDio = 1; |
39 |
|
|
#endif |
40 |
|
|
|
41 |
|
|
int airDisableDio = AIR_FALSE; |
42 |
|
|
|
43 |
|
|
static const char |
44 |
|
|
_airNoDioErr[AIR_NODIO_MAX+2][AIR_STRLEN_SMALL] = { |
45 |
|
|
"(invalid noDio value)", |
46 |
|
|
"CAN TOO do direct I/O!", |
47 |
|
|
"direct I/O apparently not available on this architecture", |
48 |
|
|
"direct I/O apparently not suitable for given file format", |
49 |
|
|
"won't do direct I/O on std{in|out|err}", |
50 |
|
|
"got -1 as file descriptor", |
51 |
|
|
"fcntl(F_DIOINFO) to learn direct I/O specifics failed", |
52 |
|
|
"requested transfer size is too small", |
53 |
|
|
"requested transfer size not a multiple of d_miniosz", |
54 |
|
|
"data memory address not multiple of d_mem", |
55 |
|
|
"current file position not multiple of d_miniosz", |
56 |
|
|
"fcntl(F_SETFL, FDIRECT) to turn on direct I/O failed", |
57 |
|
|
"memalign() test (on a small chuck of memory) failed", |
58 |
|
|
"direct I/O (in air library) has been disabled with airDisableDio" |
59 |
|
|
}; |
60 |
|
|
|
61 |
|
|
const char * |
62 |
|
|
airNoDioErr(int noDio) { |
63 |
|
|
|
64 |
|
|
if (AIR_IN_CL(0, noDio, AIR_NODIO_MAX)) { |
65 |
|
|
return _airNoDioErr[noDio+1]; |
66 |
|
|
} |
67 |
|
|
else { |
68 |
|
|
return _airNoDioErr[0]; |
69 |
|
|
} |
70 |
|
|
} |
71 |
|
|
|
72 |
|
|
/* |
73 |
|
|
******** airDioTest |
74 |
|
|
** |
75 |
|
|
** does everything necessary to assess whether direct IO can be used |
76 |
|
|
** to read a data segment of a given size, from a given file |
77 |
|
|
** descriptor, into a given pointer. The given pointer ptr can be |
78 |
|
|
** NULL, and/or the size can be 0, in order to test the other aspects |
79 |
|
|
** of direct IO. The return value of this is from the airNoDio_* enum. |
80 |
|
|
** Note that airNoDio_okay means, "actually, direct IO *does* seem to |
81 |
|
|
** be possible here". |
82 |
|
|
*/ |
83 |
|
|
#if TEEM_DIO == 0 |
84 |
|
|
int |
85 |
|
|
airDioTest(int fd, const void *ptr, size_t size) { |
86 |
|
|
AIR_UNUSED(fd); |
87 |
|
|
AIR_UNUSED(ptr); |
88 |
|
|
AIR_UNUSED(size); |
89 |
|
|
|
90 |
|
|
/* Teem makefiles think no direct IO is possible on this architecture */ |
91 |
|
116 |
return airNoDio_arch; |
92 |
|
|
} |
93 |
|
|
#else |
94 |
|
|
int |
95 |
|
|
airDioTest(int fd, const void *ptr, size_t size) { |
96 |
|
|
struct dioattr dioinfo; |
97 |
|
|
void *tmp; |
98 |
|
|
int flags; |
99 |
|
|
|
100 |
|
|
if (airDisableDio) { |
101 |
|
|
/* user turned direct I/O off */ |
102 |
|
|
return airNoDio_disable; |
103 |
|
|
} |
104 |
|
|
if (0 == fd || 1 == fd || 2 == fd) { |
105 |
|
|
/* This was added because I was noticing a problem with piping |
106 |
|
|
between unrrdu programs- sometimes the fread() of the receiving |
107 |
|
|
data through a unix pipe ("|") failed to read all the data. If |
108 |
|
|
the body of this function was bypassed (with "return |
109 |
|
|
airNoDio_disable;", for instance), then the problem went away. |
110 |
|
|
The problematic call seemed to be the fflush() below (Tue Feb 1 |
111 |
|
|
06:47:33 EST 2005: which has since been removed with the change |
112 |
|
|
of this function's argument from a FILE * to an integral file |
113 |
|
|
descriptor). I don't think direct I/O is possible on stdin, |
114 |
|
|
stdout, or stdout, since the fcntl() call below fails on stdin |
115 |
|
|
and stdout. However, something about making that fcntl() call |
116 |
|
|
changes something which means that about half the time, the |
117 |
|
|
read() on a piped stdin fails (on an irix6.n32 O2, at |
118 |
|
|
least). So, seems to be safest to just explicitly say that |
119 |
|
|
direct I/O is unavailable, based solely on the file descriptor |
120 |
|
|
number (0, 1, 2). */ |
121 |
|
|
return airNoDio_std; |
122 |
|
|
} |
123 |
|
|
if (-1 == fd) { |
124 |
|
|
/* caller probably couldn't get the underlying file descriptor */ |
125 |
|
|
return airNoDio_fd; |
126 |
|
|
} |
127 |
|
|
if (0 != fcntl(fd, F_DIOINFO, &dioinfo)) { |
128 |
|
|
/* couldn't learn direct I/O specifics */ |
129 |
|
|
return airNoDio_dioinfo; |
130 |
|
|
} |
131 |
|
|
|
132 |
|
|
if (size) { |
133 |
|
|
/* |
134 |
|
|
** direct I/O requirements: |
135 |
|
|
** 1) xfer size between d_miniosz and d_maxiosz |
136 |
|
|
** 2) xfer size a multiple of d_miniosz |
137 |
|
|
** 3) memory buffer on d_mem-byte boundary |
138 |
|
|
** 4) file position on d_miniosz-byte boundary |
139 |
|
|
** |
140 |
|
|
** As long as xfer size is >= d_miniosz and meets req. #2, then |
141 |
|
|
** we can break the xfer into d_maxiosz-size pieces of need be. |
142 |
|
|
** We can test #3 here if we're given non-NULL ptr |
143 |
|
|
** We can always test #4 |
144 |
|
|
*/ |
145 |
|
|
if (size < dioinfo.d_miniosz) { |
146 |
|
|
/* fails req. #1 above */ |
147 |
|
|
return airNoDio_small; |
148 |
|
|
} |
149 |
|
|
/* we don't actually check for being too large, since we can always |
150 |
|
|
do IO on d_maxiosz-sized pieces */ |
151 |
|
|
if (size % dioinfo.d_miniosz) { |
152 |
|
|
/* fails req. #2 above */ |
153 |
|
|
return airNoDio_size; |
154 |
|
|
} |
155 |
|
|
} |
156 |
|
|
if (ptr) { |
157 |
|
|
if ((unsigned long)(ptr) % dioinfo.d_mem) { |
158 |
|
|
/* fails req. #3 above */ |
159 |
|
|
return airNoDio_ptr; |
160 |
|
|
} |
161 |
|
|
} else { |
162 |
|
|
tmp = memalign(dioinfo.d_mem, dioinfo.d_miniosz); |
163 |
|
|
if (!tmp) { |
164 |
|
|
/* couldn't even alloc (via memalign) the minimum size */ |
165 |
|
|
return airNoDio_test; |
166 |
|
|
} |
167 |
|
|
free(tmp); |
168 |
|
|
} |
169 |
|
|
if (lseek(fd, 0, SEEK_CUR) % dioinfo.d_miniosz) { |
170 |
|
|
/* fails req. #4 above */ |
171 |
|
|
return airNoDio_fpos; |
172 |
|
|
} |
173 |
|
|
flags = fcntl(fd, F_GETFL); |
174 |
|
|
if (-1 == fcntl(fd, F_SETFL, flags | FDIRECT)) { |
175 |
|
|
/* couln't turn on direct I/O */ |
176 |
|
|
return airNoDio_setfl; |
177 |
|
|
} |
178 |
|
|
/* put things back the way they were */ |
179 |
|
|
fcntl(fd, F_SETFL, flags); |
180 |
|
|
|
181 |
|
|
/* as far as we know, direct I/O seems workable */ |
182 |
|
|
return airNoDio_okay; |
183 |
|
|
} |
184 |
|
|
#endif |
185 |
|
|
|
186 |
|
|
/* |
187 |
|
|
******** airDioInfo |
188 |
|
|
** |
189 |
|
|
** does the fcntl stuff to learn the direct IO parameters: |
190 |
|
|
** align: required alignment of memory (pointer must be multiple of this) |
191 |
|
|
** min: minimum size of dio transfer |
192 |
|
|
** max: maximum size of dio transfer |
193 |
|
|
** |
194 |
|
|
** NOTE: this does not try to do any error checking, because it assumes |
195 |
|
|
** that you've already called airDioTest without incident. |
196 |
|
|
*/ |
197 |
|
|
#if TEEM_DIO == 0 |
198 |
|
|
void |
199 |
|
|
airDioInfo(int *align, int *min, int *max, int fd) { |
200 |
|
|
AIR_UNUSED(align); |
201 |
|
|
AIR_UNUSED(min); |
202 |
|
|
AIR_UNUSED(max); |
203 |
|
|
AIR_UNUSED(fd); |
204 |
|
|
return; |
205 |
|
|
} |
206 |
|
|
#else |
207 |
|
|
void |
208 |
|
|
airDioInfo(int *align, int *min, int *max, int fd) { |
209 |
|
|
struct dioattr dioinfo; |
210 |
|
|
|
211 |
|
|
if (align && min && max && !fcntl(fd, F_DIOINFO, &dioinfo)) { |
212 |
|
|
*align = dioinfo.d_mem; |
213 |
|
|
*min = dioinfo.d_miniosz; |
214 |
|
|
*max = dioinfo.d_maxiosz; |
215 |
|
|
} |
216 |
|
|
return; |
217 |
|
|
} |
218 |
|
|
#endif |
219 |
|
|
|
220 |
|
|
/* |
221 |
|
|
******** airDioMalloc |
222 |
|
|
** |
223 |
|
|
** does direct IO compatible memory allocation. |
224 |
|
|
** |
225 |
|
|
** NOTE: like airDioInfo, this assumes that you've called airDioTest |
226 |
|
|
** without incident |
227 |
|
|
*/ |
228 |
|
|
#if TEEM_DIO == 0 |
229 |
|
|
void * |
230 |
|
|
airDioMalloc(size_t size, int fd) { |
231 |
|
|
AIR_UNUSED(size); |
232 |
|
|
AIR_UNUSED(fd); |
233 |
|
|
|
234 |
|
|
return NULL; |
235 |
|
|
} |
236 |
|
|
#else |
237 |
|
|
void * |
238 |
|
|
airDioMalloc(size_t size, int fd) { |
239 |
|
|
int align, min, max; |
240 |
|
|
|
241 |
|
|
airDioInfo(&align, &min, &max, fd); |
242 |
|
|
return memalign(align, size); |
243 |
|
|
} |
244 |
|
|
#endif |
245 |
|
|
|
246 |
|
|
/* |
247 |
|
|
******** airDioRead |
248 |
|
|
** |
249 |
|
|
** like read(), but for direct IO. The idea is that you call this on as |
250 |
|
|
** big a chunk of memory as possible. |
251 |
|
|
** |
252 |
|
|
** NOTE: like airDioInfo, this assumes that you've called airDioTest |
253 |
|
|
** without incident |
254 |
|
|
*/ |
255 |
|
|
#if TEEM_DIO == 0 |
256 |
|
|
size_t |
257 |
|
|
airDioRead(int fd, void *_ptr, size_t size) { |
258 |
|
|
AIR_UNUSED(fd); |
259 |
|
|
AIR_UNUSED(_ptr); |
260 |
|
|
AIR_UNUSED(size); |
261 |
|
|
|
262 |
|
|
return 0; |
263 |
|
|
} |
264 |
|
|
#else |
265 |
|
|
size_t |
266 |
|
|
airDioRead(int fd, void *_ptr, size_t size) { |
267 |
|
|
size_t red, totalred; |
268 |
|
|
int align, min, max, flags; |
269 |
|
|
size_t remain, part; |
270 |
|
|
char *ptr; |
271 |
|
|
|
272 |
|
|
if (!( _ptr && airNoDio_okay == airDioTest(fd, _ptr, size) )) { |
273 |
|
|
return 0; |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
flags = fcntl(fd, F_GETFL); |
277 |
|
|
fcntl(fd, F_SETFL, flags | FDIRECT); |
278 |
|
|
airDioInfo(&align, &min, &max, fd); |
279 |
|
|
remain = size; |
280 |
|
|
totalred = 0; |
281 |
|
|
ptr = (char*)_ptr; |
282 |
|
|
do { |
283 |
|
|
part = AIR_MIN(remain, max); |
284 |
|
|
red = read(fd, ptr, part); |
285 |
|
|
totalred += red; |
286 |
|
|
if (red != part) { |
287 |
|
|
break; |
288 |
|
|
} |
289 |
|
|
ptr += red; |
290 |
|
|
remain -= red; |
291 |
|
|
} while (remain); |
292 |
|
|
fcntl(fd, F_SETFL, flags); |
293 |
|
|
|
294 |
|
|
return totalred; |
295 |
|
|
} |
296 |
|
|
#endif |
297 |
|
|
|
298 |
|
|
/* |
299 |
|
|
******** airDioWrite |
300 |
|
|
** |
301 |
|
|
** like write(), but for direct IO. The idea is that you call this on as |
302 |
|
|
** big a chunk of memory as possible. |
303 |
|
|
** |
304 |
|
|
** NOTE: like airDioInfo, this assumes that you've called airDioTest |
305 |
|
|
** without incident |
306 |
|
|
*/ |
307 |
|
|
#if TEEM_DIO == 0 |
308 |
|
|
size_t |
309 |
|
|
airDioWrite(int fd, const void *_ptr, size_t size) { |
310 |
|
|
AIR_UNUSED(fd); |
311 |
|
|
AIR_UNUSED(_ptr); |
312 |
|
|
AIR_UNUSED(size); |
313 |
|
|
|
314 |
|
|
return 0; |
315 |
|
|
} |
316 |
|
|
#else |
317 |
|
|
size_t |
318 |
|
|
airDioWrite(int fd, const void *_ptr, size_t size) { |
319 |
|
|
size_t rit, totalrit; |
320 |
|
|
int align, min, max, flags; |
321 |
|
|
size_t remain, part; |
322 |
|
|
char *ptr; |
323 |
|
|
|
324 |
|
|
if (!( _ptr && (airNoDio_okay == airDioTest(fd, _ptr, size)) )) { |
325 |
|
|
return 0; |
326 |
|
|
} |
327 |
|
|
|
328 |
|
|
flags = fcntl(fd, F_GETFL); |
329 |
|
|
fcntl(fd, F_SETFL, flags | FDIRECT); |
330 |
|
|
airDioInfo(&align, &min, &max, fd); |
331 |
|
|
remain = size; |
332 |
|
|
totalrit = 0; |
333 |
|
|
ptr = (char*)_ptr; |
334 |
|
|
do { |
335 |
|
|
part = AIR_MIN(remain, max); |
336 |
|
|
rit = write(fd, ptr, part); |
337 |
|
|
totalrit += rit; |
338 |
|
|
if (rit != part) { |
339 |
|
|
break; |
340 |
|
|
} |
341 |
|
|
ptr += rit; |
342 |
|
|
remain -= rit; |
343 |
|
|
} while (remain); |
344 |
|
|
fcntl(fd, F_SETFL, flags); |
345 |
|
|
|
346 |
|
|
return totalrit; |
347 |
|
|
} |
348 |
|
|
#endif |