GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/air/dio.c Lines: 1 8 12.5 %
Date: 2017-05-26 Branches: 0 2 0.0 %

Line Branch Exec Source
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