1 // Copyright 2022 The gRPC Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <grpc/support/port_platform.h>
16
17 #include <utility>
18
19 #include "absl/strings/str_cat.h"
20 #include "src/core/lib/iomgr/port.h"
21 #include "src/core/util/crash.h" // IWYU pragma: keep
22
23 #ifdef GRPC_LINUX_EVENTFD
24
25 #include <errno.h>
26 #include <sys/eventfd.h>
27 #include <unistd.h>
28
29 #include "src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h"
30 #endif
31
32 #include "src/core/lib/event_engine/posix_engine/wakeup_fd_eventfd.h"
33 #include "src/core/util/strerror.h"
34
35 namespace grpc_event_engine {
36 namespace experimental {
37
38 #ifdef GRPC_LINUX_EVENTFD
39
Init()40 absl::Status EventFdWakeupFd::Init() {
41 int read_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
42 int write_fd = -1;
43 if (read_fd < 0) {
44 return absl::Status(absl::StatusCode::kInternal,
45 absl::StrCat("eventfd: ", grpc_core::StrError(errno)));
46 }
47 SetWakeupFds(read_fd, write_fd);
48 return absl::OkStatus();
49 }
50
ConsumeWakeup()51 absl::Status EventFdWakeupFd::ConsumeWakeup() {
52 eventfd_t value;
53 int err;
54 do {
55 err = eventfd_read(ReadFd(), &value);
56 } while (err < 0 && errno == EINTR);
57 if (err < 0 && errno != EAGAIN) {
58 return absl::Status(
59 absl::StatusCode::kInternal,
60 absl::StrCat("eventfd_read: ", grpc_core::StrError(errno)));
61 }
62 return absl::OkStatus();
63 }
64
Wakeup()65 absl::Status EventFdWakeupFd::Wakeup() {
66 int err;
67 do {
68 err = eventfd_write(ReadFd(), 1);
69 } while (err < 0 && errno == EINTR);
70 if (err < 0) {
71 return absl::Status(
72 absl::StatusCode::kInternal,
73 absl::StrCat("eventfd_write: ", grpc_core::StrError(errno)));
74 }
75 return absl::OkStatus();
76 }
77
~EventFdWakeupFd()78 EventFdWakeupFd::~EventFdWakeupFd() {
79 if (ReadFd() != 0) {
80 close(ReadFd());
81 }
82 }
83
IsSupported()84 bool EventFdWakeupFd::IsSupported() {
85 EventFdWakeupFd event_fd_wakeup_fd;
86 return event_fd_wakeup_fd.Init().ok();
87 }
88
89 absl::StatusOr<std::unique_ptr<WakeupFd>>
CreateEventFdWakeupFd()90 EventFdWakeupFd::CreateEventFdWakeupFd() {
91 static bool kIsEventFdWakeupFdSupported = EventFdWakeupFd::IsSupported();
92 if (kIsEventFdWakeupFdSupported) {
93 auto event_fd_wakeup_fd = std::make_unique<EventFdWakeupFd>();
94 auto status = event_fd_wakeup_fd->Init();
95 if (status.ok()) {
96 return std::unique_ptr<WakeupFd>(std::move(event_fd_wakeup_fd));
97 }
98 return status;
99 }
100 return absl::NotFoundError("Eventfd wakeup fd is not supported");
101 }
102
103 #else // GRPC_LINUX_EVENTFD
104
105 #include "src/core/util/crash.h"
106
107 absl::Status EventFdWakeupFd::Init() { grpc_core::Crash("unimplemented"); }
108
109 absl::Status EventFdWakeupFd::ConsumeWakeup() {
110 grpc_core::Crash("unimplemented");
111 }
112
113 absl::Status EventFdWakeupFd::Wakeup() { grpc_core::Crash("unimplemented"); }
114
115 bool EventFdWakeupFd::IsSupported() { return false; }
116
117 absl::StatusOr<std::unique_ptr<WakeupFd>>
118 EventFdWakeupFd::CreateEventFdWakeupFd() {
119 return absl::NotFoundError("Eventfd wakeup fd is not supported");
120 }
121
122 #endif // GRPC_LINUX_EVENTFD
123
124 } // namespace experimental
125 } // namespace grpc_event_engine
126