Age Owner Branch data TLA 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
647 tmunro@postgresql.or 54 :CBC 1540573 : 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 [ + + ]: 1540573 : if (iovcnt == 1)
62 : 1539981 : return pread(fd, iov[0].iov_base, iov[0].iov_len, offset);
63 : : else
64 : 592 : 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 : 969461 : 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 [ + + ]: 969461 : if (iovcnt == 1)
101 : 946179 : return pwrite(fd, iov[0].iov_base, iov[0].iov_len, offset);
102 : : else
103 : 23282 : 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 */
|