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 : /* 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 : /*
37 : * Define a reasonable maximum that is safe to use on the stack in arrays of
38 : * struct iovec and other small types. The operating system could limit us to
39 : * a number as low as 16, but most systems have 1024.
40 : */
41 : #define PG_IOV_MAX Min(IOV_MAX, 128)
42 :
43 : /*
44 : * Like preadv(), but with a prefix to remind us of a side-effect: on Windows
45 : * this changes the current file position.
46 : */
47 : static inline ssize_t
48 3021446 : pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
49 : {
50 : #if HAVE_DECL_PREADV
51 : /*
52 : * Avoid a small amount of argument copying overhead in the kernel if
53 : * there is only one iovec.
54 : */
55 3021446 : if (iovcnt == 1)
56 3018244 : return pread(fd, iov[0].iov_base, iov[0].iov_len, offset);
57 : else
58 3202 : return preadv(fd, iov, iovcnt, offset);
59 : #else
60 : ssize_t sum = 0;
61 : ssize_t part;
62 :
63 : for (int i = 0; i < iovcnt; ++i)
64 : {
65 : part = pg_pread(fd, iov[i].iov_base, iov[i].iov_len, offset);
66 : if (part < 0)
67 : {
68 : if (i == 0)
69 : return -1;
70 : else
71 : return sum;
72 : }
73 : sum += part;
74 : offset += part;
75 : if ((size_t) part < iov[i].iov_len)
76 : return sum;
77 : }
78 : return sum;
79 : #endif
80 : }
81 :
82 : /*
83 : * Like pwritev(), but with a prefix to remind us of a side-effect: on Windows
84 : * this changes the current file position.
85 : */
86 : static inline ssize_t
87 1812088 : pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
88 : {
89 : #if HAVE_DECL_PWRITEV
90 : /*
91 : * Avoid a small amount of argument copying overhead in the kernel if
92 : * there is only one iovec.
93 : */
94 1812088 : if (iovcnt == 1)
95 1762214 : return pwrite(fd, iov[0].iov_base, iov[0].iov_len, offset);
96 : else
97 49874 : return pwritev(fd, iov, iovcnt, offset);
98 : #else
99 : ssize_t sum = 0;
100 : ssize_t part;
101 :
102 : for (int i = 0; i < iovcnt; ++i)
103 : {
104 : part = pg_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset);
105 : if (part < 0)
106 : {
107 : if (i == 0)
108 : return -1;
109 : else
110 : return sum;
111 : }
112 : sum += part;
113 : offset += part;
114 : if ((size_t) part < iov[i].iov_len)
115 : return sum;
116 : }
117 : return sum;
118 : #endif
119 : }
120 :
121 : #endif /* PG_IOVEC_H */
|