Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_iovec.h
4 : * Header for vectored I/O functions, to use in place of <sys/uio.h>.
5 : *
6 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : * src/include/port/pg_iovec.h
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 : #ifndef PG_IOVEC_H
14 : #define PG_IOVEC_H
15 :
16 : #ifndef WIN32
17 :
18 : #include <limits.h>
19 : #include <sys/uio.h>
20 : #include <unistd.h>
21 :
22 : #else
23 :
24 : /* POSIX requires at least 16 as a maximum iovcnt. */
25 : #define IOV_MAX 16
26 :
27 : /* Define our own POSIX-compatible iovec struct. */
28 : struct iovec
29 : {
30 : void *iov_base;
31 : size_t iov_len;
32 : };
33 :
34 : #endif
35 :
36 : /* Define a reasonable maximum that is safe to use on the stack. */
37 : #define PG_IOV_MAX Min(IOV_MAX, 32)
38 :
39 : /*
40 : * Like preadv(), but with a prefix to remind us of a side-effect: on Windows
41 : * this changes the current file position.
42 : */
43 : static inline ssize_t
44 2900776 : pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
45 : {
46 : #if HAVE_DECL_PREADV
47 : /*
48 : * Avoid a small amount of argument copying overhead in the kernel if
49 : * there is only one iovec.
50 : */
51 2900776 : if (iovcnt == 1)
52 2899474 : return pread(fd, iov[0].iov_base, iov[0].iov_len, offset);
53 : else
54 1302 : return preadv(fd, iov, iovcnt, offset);
55 : #else
56 : ssize_t sum = 0;
57 : ssize_t part;
58 :
59 : for (int i = 0; i < iovcnt; ++i)
60 : {
61 : part = pg_pread(fd, iov[i].iov_base, iov[i].iov_len, offset);
62 : if (part < 0)
63 : {
64 : if (i == 0)
65 : return -1;
66 : else
67 : return sum;
68 : }
69 : sum += part;
70 : offset += part;
71 : if ((size_t) part < iov[i].iov_len)
72 : return sum;
73 : }
74 : return sum;
75 : #endif
76 : }
77 :
78 : /*
79 : * Like pwritev(), but with a prefix to remind us of a side-effect: on Windows
80 : * this changes the current file position.
81 : */
82 : static inline ssize_t
83 1838074 : pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
84 : {
85 : #if HAVE_DECL_PWRITEV
86 : /*
87 : * Avoid a small amount of argument copying overhead in the kernel if
88 : * there is only one iovec.
89 : */
90 1838074 : if (iovcnt == 1)
91 1665844 : return pwrite(fd, iov[0].iov_base, iov[0].iov_len, offset);
92 : else
93 172230 : return pwritev(fd, iov, iovcnt, offset);
94 : #else
95 : ssize_t sum = 0;
96 : ssize_t part;
97 :
98 : for (int i = 0; i < iovcnt; ++i)
99 : {
100 : part = pg_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset);
101 : if (part < 0)
102 : {
103 : if (i == 0)
104 : return -1;
105 : else
106 : return sum;
107 : }
108 : sum += part;
109 : offset += part;
110 : if ((size_t) part < iov[i].iov_len)
111 : return sum;
112 : }
113 : return sum;
114 : #endif
115 : }
116 :
117 : #endif /* PG_IOVEC_H */
|