Lely core libraries  2.3.4
pipe.c
Go to the documentation of this file.
1 
24 #include "io.h"
25 
26 #if !LELY_NO_STDIO
27 
28 #include <lely/io/pipe.h>
29 
30 #include "default.h"
31 
32 #if _WIN32 || _POSIX_C_SOURCE >= 200112L
33 
34 #if _WIN32
35 #include <lely/libc/stdio.h>
36 
37 #ifdef __MINGW32__
38 // Ignore complaints that "I64" is not a valid ISO C length modifier.
39 #pragma GCC diagnostic ignored "-Wformat"
40 #pragma GCC diagnostic ignored "-Wformat-extra-args"
41 #endif
42 
43 static int pipe(HANDLE fildes[2]);
44 #endif
45 
46 static const struct io_handle_vtab pipe_vtab = { .type = IO_TYPE_PIPE,
47  .size = sizeof(struct io_handle),
48  .fini = &default_fini,
49  .flags = &default_flags,
50  .read = &default_read,
51  .write = &default_write };
52 
53 int
54 io_open_pipe(io_handle_t handle_vector[2])
55 {
56  assert(handle_vector);
57  handle_vector[0] = handle_vector[1] = IO_HANDLE_ERROR;
58 
59  int errc = 0;
60 
61 #if _WIN32
62  HANDLE fd[2];
63 #else
64  int fd[2];
65 #endif
66 #if (defined(__CYGWIN__) || defined(__linux__)) && defined(_GNU_SOURCE)
67  if (pipe2(fd, O_CLOEXEC) == -1) {
68 #else
69  if (pipe(fd) == -1) {
70 #endif
71  errc = get_errc();
72  goto error_pipe;
73  }
74 
75 #if _POSIX_C_SOURCE >= 200112L && !defined(__CYGINW__) && !defined(__linux__)
76  if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) == -1) {
77  errc = get_errc();
78  goto error_fcntl;
79  }
80  if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) == -1) {
81  errc = get_errc();
82  goto error_fcntl;
83  }
84 #endif
85 
86  handle_vector[0] = io_handle_alloc(&pipe_vtab);
87  if (!handle_vector[0]) {
88  errc = get_errc();
89  goto error_alloc_handle_vector_0;
90  }
91  handle_vector[0]->fd = fd[0];
92 
93  handle_vector[1] = io_handle_alloc(&pipe_vtab);
94  if (!handle_vector[1]) {
95  errc = get_errc();
96  goto error_alloc_handle_vector_1;
97  }
98  handle_vector[1]->fd = fd[1];
99 
100  io_handle_acquire(handle_vector[0]);
101  io_handle_acquire(handle_vector[1]);
102 
103  return 0;
104 
105 error_alloc_handle_vector_1:
106  handle_vector[1] = IO_HANDLE_ERROR;
107  io_handle_free(handle_vector[0]);
108 error_alloc_handle_vector_0:
109  handle_vector[0] = IO_HANDLE_ERROR;
110 #if _POSIX_C_SOURCE >= 200112L && !defined(__CYGINW__) && !defined(__linux__)
111 error_fcntl:
112 #endif
113 #if _WIN32
114  CloseHandle(fd[1]);
115  CloseHandle(fd[0]);
116 #else
117  close(fd[1]);
118  close(fd[0]);
119 #endif
120 error_pipe:
121  set_errc(errc);
122  return -1;
123 }
124 
125 #if _WIN32
126 static int
127 pipe(HANDLE fildes[2])
128 {
129  assert(fildes);
130  fildes[0] = fildes[1] = INVALID_HANDLE_VALUE;
131 
132  DWORD dwErrCode = 0;
133 
134  CHAR Name[MAX_PATH] = { 0 };
135  static LONGLONG cnt;
136  snprintf(Name, sizeof(Name) - 1,
137  "\\\\.\\pipe\\lely-io-pipe-%04lx-%08I64x",
138  GetCurrentProcessId(), InterlockedIncrement64(&cnt));
139 
140  fildes[0] = CreateNamedPipeA(Name,
141  PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
142  PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1, 1, 0, NULL);
143  if (fildes[0] == INVALID_HANDLE_VALUE) {
144  dwErrCode = GetLastError();
145  goto error_CreateNamedPipeA;
146  }
147 
148  fildes[1] = CreateFileA(Name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
149  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
150  if (fildes[1] == INVALID_HANDLE_VALUE) {
151  dwErrCode = GetLastError();
152  goto error_CreateFileA;
153  }
154 
155  return 0;
156 
157 error_CreateFileA:
158  CloseHandle(fildes[0]);
159  fildes[0] = INVALID_HANDLE_VALUE;
160 error_CreateNamedPipeA:
161  SetLastError(dwErrCode);
162  return -1;
163 }
164 #endif
165 
166 #endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
167 
168 #endif // !LELY_NO_STDIO
This is the internal header file of the default implementation of the I/O device handle methods.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:932
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
void io_handle_free(struct io_handle *handle)
Frees an I/O device handle.
Definition: handle.c:120
struct io_handle * io_handle_alloc(const struct io_handle_vtab *vtab)
Allocates a new I/O device handle from a virtual table.
Definition: handle.c:81
@ IO_TYPE_PIPE
A pipe.
Definition: io.h:51
io_handle_t io_handle_acquire(io_handle_t handle)
Increments the reference count of an I/O device handle.
Definition: handle.c:36
#define IO_HANDLE_ERROR
The value of an invalid I/O device handle.
Definition: io.h:34
int io_open_pipe(io_handle_t handle_vector[2])
Opens a pipe.
Definition: pipe.c:54
This header file is part of the I/O library; it contains the pipe declarations.
This is the internal header file of the Windows-specific I/O declarations.
This header file is part of the C11 and POSIX compatibility library; it includes <stdio....
The virtual table of an I/O device handle.
Definition: handle.h:66
int type
The type of the device (one of IO_TYPE_CAN, IO_TYPE_FILE, IO_TYPE_PIPE, IO_TYPE_SERIAL or IO_TYPE_SOC...
Definition: handle.h:71
An I/O device handle.
Definition: handle.h:33
int fd
The native file descriptor.
Definition: handle.h:48