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-2025, 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> /* IWYU pragma: export */
20 : #include <unistd.h>
21 :
22 : #else
23 :
24 : /* Define our own POSIX-compatible iovec struct. */
25 : struct iovec
26 : {
27 : void *iov_base;
28 : size_t iov_len;
29 : };
30 :
31 : #endif
32 :
33 : /*
34 : * If <limits.h> didn't define IOV_MAX, define our own. X/Open requires at
35 : * least 16. (GNU Hurd apparently feel that they're not bound by X/Open,
36 : * because they don't define this symbol at all.)
37 : */
38 : #ifndef IOV_MAX
39 : #define IOV_MAX 16
40 : #endif
41 :
42 : /*
43 : * Define a reasonable maximum that is safe to use on the stack in arrays of
44 : * struct iovec and other small types. The operating system could limit us to
45 : * a number as low as 16, but most systems have 1024.
46 : */
47 : #define PG_IOV_MAX Min(IOV_MAX, 128)
48 :
49 : /*
50 : * Like preadv(), but with a prefix to remind us of a side-effect: on Windows
51 : * this changes the current file position.
52 : */
53 : static inline ssize_t
54 3029060 : pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
55 : {
56 : #if HAVE_DECL_PREADV
57 : /*
58 : * Avoid a small amount of argument copying overhead in the kernel if
59 : * there is only one iovec.
60 : */
61 3029060 : if (iovcnt == 1)
62 3027176 : return pread(fd, iov[0].iov_base, iov[0].iov_len, offset);
63 : else
64 1884 : return preadv(fd, iov, iovcnt, offset);
65 : #else
66 : ssize_t sum = 0;
67 : ssize_t part;
68 :
69 : for (int i = 0; i < iovcnt; ++i)
70 : {
71 : part = pg_pread(fd, iov[i].iov_base, iov[i].iov_len, offset);
72 : if (part < 0)
73 : {
74 : if (i == 0)
75 : return -1;
76 : else
77 : return sum;
78 : }
79 : sum += part;
80 : offset += part;
81 : if ((size_t) part < iov[i].iov_len)
82 : return sum;
83 : }
84 : return sum;
85 : #endif
86 : }
87 :
88 : /*
89 : * Like pwritev(), but with a prefix to remind us of a side-effect: on Windows
90 : * this changes the current file position.
91 : */
92 : static inline ssize_t
93 1965136 : pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
94 : {
95 : #if HAVE_DECL_PWRITEV
96 : /*
97 : * Avoid a small amount of argument copying overhead in the kernel if
98 : * there is only one iovec.
99 : */
100 1965136 : if (iovcnt == 1)
101 1913724 : return pwrite(fd, iov[0].iov_base, iov[0].iov_len, offset);
102 : else
103 51412 : return pwritev(fd, iov, iovcnt, offset);
104 : #else
105 : ssize_t sum = 0;
106 : ssize_t part;
107 :
108 : for (int i = 0; i < iovcnt; ++i)
109 : {
110 : part = pg_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset);
111 : if (part < 0)
112 : {
113 : if (i == 0)
114 : return -1;
115 : else
116 : return sum;
117 : }
118 : sum += part;
119 : offset += part;
120 : if ((size_t) part < iov[i].iov_len)
121 : return sum;
122 : }
123 : return sum;
124 : #endif
125 : }
126 :
127 : #endif /* PG_IOVEC_H */
|