/* * Copyright (C) by Argonne National Laboratory * See COPYRIGHT in top-level directory */ #include "mpl.h" #if defined MPL_HAVE_SYS_UIO_H /* Some platforms, such as Mac OSX (at least as of 10.9.1) hang when * attempting to send more than 2GB data, even though the writev * function is supposed to be able to handle large data. This * function is a simple workaround for this case by attempting to send * lesser data, and having the upper layer retry later if needed. * This adds a small amount of bookkeeping overhead, but it should be * negligible compared to the system call overhead for small messages * and compared to the data transmission overhead for large * messages. */ ssize_t MPL_large_writev(int fd, const struct iovec *iov, int iovcnt) { ssize_t total_size, tmp; struct iovec dummy; int i; /* If the total data fits into INT_MAX, directly use writev */ total_size = 0; for (i = 0; i < iovcnt; i++) total_size += iov[i].iov_len; if (total_size <= INT_MAX) { do { tmp = writev(fd, iov, iovcnt); } while (tmp == -1 && errno == EINTR); return tmp; } /* Total data is larger than INT_MAX. Issue writev with fewer * elements, so as to not exceed INT_MAX. In this case, doing * multiple write calls, one for each iov segment is not a big * deal with respect to performance. */ total_size = 0; for (i = 0; i < iovcnt; i++) { if (iov[i].iov_len <= INT_MAX) { do { tmp = writev(fd, &iov[i], 1); } while (tmp == -1 && errno == EINTR); } else { dummy.iov_base = iov[i].iov_base; dummy.iov_len = INT_MAX; do { tmp = writev(fd, &dummy, 1); } while (tmp == -1 && errno == EINTR); } if (tmp < 0) return tmp; else if (tmp < iov[i].iov_len) { total_size += tmp; return total_size; } else total_size += tmp; } return total_size; } ssize_t MPL_large_readv(int fd, const struct iovec * iov, int iovcnt) { ssize_t total_size, tmp; struct iovec dummy; int i; /* If the total data fits into INT_MAX, directly use readv */ total_size = 0; for (i = 0; i < iovcnt; i++) total_size += iov[i].iov_len; if (total_size <= INT_MAX) { do { tmp = readv(fd, iov, iovcnt); } while (tmp == -1 && errno == EINTR); return tmp; } /* Total data is larger than INT_MAX. Issue readv with fewer * elements, so as to not exceed INT_MAX. In this case, doing * multiple read calls, one for each iov segment is not a big * deal with respect to performance. */ total_size = 0; for (i = 0; i < iovcnt; i++) { if (iov[i].iov_len <= INT_MAX) { do { tmp = readv(fd, &iov[i], 1); } while (tmp == -1 && errno == EINTR); } else { dummy.iov_base = iov[i].iov_base; dummy.iov_len = INT_MAX; do { tmp = readv(fd, &dummy, 1); } while (tmp == -1 && errno == EINTR); } if (tmp < 0) return tmp; else if (tmp < iov[i].iov_len) { total_size += tmp; return total_size; } else total_size += tmp; } return total_size; } #endif /* MPL_HAVE_SYS_UIO_H */