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