I have a question about gRPC Core(C Base).
I have been implementing servers with gRPC(C++) async API in CentOS7. I have been analyzing the gRPC internal code(tag: v1.35.0) for my curiosity. I have recently read a document about poller engine. This document explains as follows.
- epollex (default but requires kernel version >= 4.5),
- epoll1 (If epollex is not available and glibc version >= 2.9)
- poll (If kernel does not have epoll support)
However, as far as I have confirmed, this is not true.
I built gRPC in linux kernel version 3.10, then I thought this gRPC poller engine have to be built based on epoll1, but this gRPC poller engine was built into epollex.
I checked gRPC code in detail to find the reason. In the code, the kernel version has not been checked by the macro condition. (only check GRPC_LINUX_EPOLL_CREATE1, then, it is true in my system because the macro variable is satisfied with glibc version above 2.8)
Also, I checked g_factories and GPR_GLOBAL_CONFIG_DEFINE_STRING.
static event_engine_factory g_factories[] = {
{ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
{ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
{"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux},
{"poll", grpc_init_poll_posix}, {"none", init_non_polling},
{ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
{ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
};
static bool is(const char* want, const char* have) {
return 0 == strcmp(want, "all") || 0 == strcmp(want, have);
}
static void try_engine(const char* engine) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(g_factories); i++) {
if (g_factories[i].factory != nullptr && is(engine, g_factories[i].name)) {
if ((g_event_engine = g_factories[i].factory(
0 == strcmp(engine, g_factories[i].name)))) {
g_poll_strategy_name = g_factories[i].name;
gpr_log(GPR_DEBUG, "Using polling engine: %s", g_factories[i].name);
return;
}
}
}
}
GPR_GLOBAL_CONFIG_DEFINE_STRING(
grpc_poll_strategy, "all",
"Declares which polling engines to try when starting gRPC. "
"This is a comma-separated list of engines, which are tried in priority "
"order first -> last.")
epollex is used in my system on the above conditions
epollex uses EPOLLEXCLUSIVE which can avoid thundering herd problems.
When a wakeup event occurs and multiple epoll file descriptors are attached to the same target file using EPOLLEXCLUSIVE, one or more of the epoll file descriptors will receive an event with epoll_wait(2).
https://man7.org/linux/man-pages/man2/epoll_ctl.2.html
EPOLLEXCLUSIVE is supported by the 4.5 or higher kernel version. Therefore, epollex cannot avoid the above problem in my system. Then, I think it could be inefficient to run into epollex that has a mechanism.
Thus, I would like to ask two questions.
- Is this the intended behavior?
epollex (default but requires kernel version >= 4.5),
- Then, Is this wrong information?