(eglot--track-changes-signal): Improve last fix (bug#70541)
[emacs.git] / lib / pipe2.c
blob7b476df345718e9a3f2658eadd42266d72d0b676
1 /* Create a pipe, with specific opening flags.
2 Copyright (C) 2009-2024 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 #include <config.h>
19 /* Specification. */
20 #include <unistd.h>
22 #include <errno.h>
23 #include <fcntl.h>
25 #include "binary-io.h"
27 #if GNULIB_defined_O_NONBLOCK
28 # include "nonblocking.h"
29 #endif
31 #if defined _WIN32 && ! defined __CYGWIN__
32 /* Native Windows API. */
34 # include <io.h>
36 #endif
38 int
39 pipe2 (int fd[2], int flags)
41 /* Mingw _pipe() corrupts fd on failure; also, if we succeed at
42 creating the pipe but later fail at changing fcntl, we want
43 to leave fd unchanged: http://austingroupbugs.net/view.php?id=467 */
44 int tmp[2];
45 tmp[0] = fd[0];
46 tmp[1] = fd[1];
48 #if HAVE_PIPE2
49 # undef pipe2
50 /* Try the system call first, if it exists. (We may be running with a glibc
51 that has the function but with an older kernel that lacks it.) */
53 /* Cache the information whether the system call really exists. */
54 static int have_pipe2_really; /* 0 = unknown, 1 = yes, -1 = no */
55 if (have_pipe2_really >= 0)
57 int result = pipe2 (fd, flags);
58 if (!(result < 0 && errno == ENOSYS))
60 have_pipe2_really = 1;
61 return result;
63 have_pipe2_really = -1;
66 #endif
68 /* Check the supported flags. */
69 if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0)
71 errno = EINVAL;
72 return -1;
75 #if defined _WIN32 && ! defined __CYGWIN__
76 /* Native Windows API. */
78 if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0)
80 fd[0] = tmp[0];
81 fd[1] = tmp[1];
82 return -1;
85 /* O_NONBLOCK handling.
86 On native Windows platforms, O_NONBLOCK is defined by gnulib. Use the
87 functions defined by the gnulib module 'nonblocking'. */
88 # if GNULIB_defined_O_NONBLOCK
89 if (flags & O_NONBLOCK)
91 if (set_nonblocking_flag (fd[0], true) != 0
92 || set_nonblocking_flag (fd[1], true) != 0)
93 goto fail;
95 # else
97 static_assert (O_NONBLOCK == 0);
99 # endif
101 return 0;
103 #else
104 /* Unix API. */
106 if (pipe (fd) < 0)
107 return -1;
109 /* POSIX <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html>
110 says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on
111 both fd[0] and fd[1]. */
113 /* O_NONBLOCK handling.
114 On Unix platforms, O_NONBLOCK is defined by the system. Use fcntl(). */
115 if (flags & O_NONBLOCK)
117 int fcntl_flags;
119 if ((fcntl_flags = fcntl (fd[1], F_GETFL, 0)) < 0
120 || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1
121 || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0
122 || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1)
123 goto fail;
126 if (flags & O_CLOEXEC)
128 int fcntl_flags;
130 if ((fcntl_flags = fcntl (fd[1], F_GETFD, 0)) < 0
131 || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1
132 || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0
133 || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
134 goto fail;
137 # if O_BINARY
138 if (flags & O_BINARY)
140 set_binary_mode (fd[1], O_BINARY);
141 set_binary_mode (fd[0], O_BINARY);
143 else if (flags & O_TEXT)
145 set_binary_mode (fd[1], O_TEXT);
146 set_binary_mode (fd[0], O_TEXT);
148 # endif
150 return 0;
152 #endif
154 #if GNULIB_defined_O_NONBLOCK || !(defined _WIN32 && ! defined __CYGWIN__)
155 fail:
157 int saved_errno = errno;
158 close (fd[0]);
159 close (fd[1]);
160 fd[0] = tmp[0];
161 fd[1] = tmp[1];
162 errno = saved_errno;
163 return -1;
165 #endif