1 /*
2 * Copyright (C) by Argonne National Laboratory
3 * See COPYRIGHT in top-level directory
4 */
5
6 #include "mpl.h"
7
8 #if defined MPL_HAVE_SYS_UIO_H
9 /* Some platforms, such as Mac OSX (at least as of 10.9.1) hang when
10 * attempting to send more than 2GB data, even though the writev
11 * function is supposed to be able to handle large data. This
12 * function is a simple workaround for this case by attempting to send
13 * lesser data, and having the upper layer retry later if needed.
14 * This adds a small amount of bookkeeping overhead, but it should be
15 * negligible compared to the system call overhead for small messages
16 * and compared to the data transmission overhead for large
17 * messages. */
MPL_large_writev(int fd,const struct iovec * iov,int iovcnt)18 ssize_t MPL_large_writev(int fd, const struct iovec *iov, int iovcnt)
19 {
20 ssize_t total_size, tmp;
21 struct iovec dummy;
22 int i;
23
24 /* If the total data fits into INT_MAX, directly use writev */
25 total_size = 0;
26 for (i = 0; i < iovcnt; i++)
27 total_size += iov[i].iov_len;
28
29 if (total_size <= INT_MAX) {
30 do {
31 tmp = writev(fd, iov, iovcnt);
32 } while (tmp == -1 && errno == EINTR);
33 return tmp;
34 }
35
36 /* Total data is larger than INT_MAX. Issue writev with fewer
37 * elements, so as to not exceed INT_MAX. In this case, doing
38 * multiple write calls, one for each iov segment is not a big
39 * deal with respect to performance. */
40
41 total_size = 0;
42 for (i = 0; i < iovcnt; i++) {
43 if (iov[i].iov_len <= INT_MAX) {
44 do {
45 tmp = writev(fd, &iov[i], 1);
46 } while (tmp == -1 && errno == EINTR);
47 } else {
48 dummy.iov_base = iov[i].iov_base;
49 dummy.iov_len = INT_MAX;
50 do {
51 tmp = writev(fd, &dummy, 1);
52 } while (tmp == -1 && errno == EINTR);
53 }
54
55 if (tmp < 0)
56 return tmp;
57 else if (tmp < iov[i].iov_len) {
58 total_size += tmp;
59 return total_size;
60 } else
61 total_size += tmp;
62 }
63
64 return total_size;
65 }
66
67
MPL_large_readv(int fd,const struct iovec * iov,int iovcnt)68 ssize_t MPL_large_readv(int fd, const struct iovec * iov, int iovcnt)
69 {
70 ssize_t total_size, tmp;
71 struct iovec dummy;
72 int i;
73
74 /* If the total data fits into INT_MAX, directly use readv */
75 total_size = 0;
76 for (i = 0; i < iovcnt; i++)
77 total_size += iov[i].iov_len;
78
79 if (total_size <= INT_MAX) {
80 do {
81 tmp = readv(fd, iov, iovcnt);
82 } while (tmp == -1 && errno == EINTR);
83 return tmp;
84 }
85
86 /* Total data is larger than INT_MAX. Issue readv with fewer
87 * elements, so as to not exceed INT_MAX. In this case, doing
88 * multiple read calls, one for each iov segment is not a big
89 * deal with respect to performance. */
90
91 total_size = 0;
92 for (i = 0; i < iovcnt; i++) {
93 if (iov[i].iov_len <= INT_MAX) {
94 do {
95 tmp = readv(fd, &iov[i], 1);
96 } while (tmp == -1 && errno == EINTR);
97 } else {
98 dummy.iov_base = iov[i].iov_base;
99 dummy.iov_len = INT_MAX;
100 do {
101 tmp = readv(fd, &dummy, 1);
102 } while (tmp == -1 && errno == EINTR);
103 }
104
105 if (tmp < 0)
106 return tmp;
107 else if (tmp < iov[i].iov_len) {
108 total_size += tmp;
109 return total_size;
110 } else
111 total_size += tmp;
112 }
113
114 return total_size;
115 }
116 #endif /* MPL_HAVE_SYS_UIO_H */
117