mirror of https://github.com/grpc/grpc.git
parent
4b1aa50e37
commit
be18cedf90
26 changed files with 14 additions and 2870 deletions
File diff suppressed because it is too large
Load Diff
@ -1,35 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H |
||||
#define GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/ev_posix.h" |
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
const grpc_event_engine_vtable* grpc_init_epollsig_linux(bool explicit_request); |
||||
|
||||
#ifdef GRPC_LINUX_EPOLL_CREATE1 |
||||
void* grpc_fd_get_polling_island(grpc_fd* fd); |
||||
void* grpc_pollset_get_polling_island(grpc_pollset* ps); |
||||
bool grpc_are_polling_islands_equal(void* p, void* q); |
||||
#endif /* defined(GRPC_LINUX_EPOLL_CREATE1) */ |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H */ |
@ -1,321 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
/* This test only relevant on linux systems where epoll() is available */ |
||||
#ifdef GRPC_LINUX_EPOLL_CREATE1 |
||||
#include "src/core/lib/iomgr/ev_epollsig_linux.h" |
||||
#include "src/core/lib/iomgr/ev_posix.h" |
||||
|
||||
#include <errno.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/gpr/useful.h" |
||||
#include "src/core/lib/gprpp/thd.h" |
||||
#include "src/core/lib/iomgr/iomgr.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
typedef struct test_pollset { |
||||
grpc_pollset* pollset; |
||||
gpr_mu* mu; |
||||
} test_pollset; |
||||
|
||||
typedef struct test_fd { |
||||
int inner_fd; |
||||
grpc_fd* fd; |
||||
} test_fd; |
||||
|
||||
/* num_fds should be an even number */ |
||||
static void test_fd_init(test_fd* tfds, int* fds, int num_fds) { |
||||
int i; |
||||
int r; |
||||
|
||||
/* Create some dummy file descriptors. Currently using pipe file descriptors
|
||||
* for this test but we could use any other type of file descriptors. Also, |
||||
* since pipe() used in this test creates two fds in each call, num_fds should |
||||
* be an even number */ |
||||
GPR_ASSERT((num_fds % 2) == 0); |
||||
for (i = 0; i < num_fds; i = i + 2) { |
||||
r = pipe(fds + i); |
||||
if (r != 0) { |
||||
gpr_log(GPR_ERROR, "Error in creating pipe. %d (%s)", errno, |
||||
strerror(errno)); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
for (i = 0; i < num_fds; i++) { |
||||
tfds[i].inner_fd = fds[i]; |
||||
tfds[i].fd = grpc_fd_create(fds[i], "test_fd", false); |
||||
} |
||||
} |
||||
|
||||
static void test_fd_cleanup(test_fd* tfds, int num_fds) { |
||||
int release_fd; |
||||
int i; |
||||
|
||||
for (i = 0; i < num_fds; i++) { |
||||
grpc_fd_shutdown(tfds[i].fd, |
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING("test_fd_cleanup")); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, "test_fd_cleanup"); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
GPR_ASSERT(release_fd == tfds[i].inner_fd); |
||||
close(tfds[i].inner_fd); |
||||
} |
||||
} |
||||
|
||||
static void test_pollset_init(test_pollset* pollsets, int num_pollsets) { |
||||
int i; |
||||
for (i = 0; i < num_pollsets; i++) { |
||||
pollsets[i].pollset = |
||||
static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size())); |
||||
grpc_pollset_init(pollsets[i].pollset, &pollsets[i].mu); |
||||
} |
||||
} |
||||
|
||||
static void destroy_pollset(void* p, grpc_error* error) { |
||||
grpc_pollset_destroy(static_cast<grpc_pollset*>(p)); |
||||
} |
||||
|
||||
static void test_pollset_cleanup(test_pollset* pollsets, int num_pollsets) { |
||||
grpc_closure destroyed; |
||||
int i; |
||||
|
||||
for (i = 0; i < num_pollsets; i++) { |
||||
GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, pollsets[i].pollset, |
||||
grpc_schedule_on_exec_ctx); |
||||
grpc_pollset_shutdown(pollsets[i].pollset, &destroyed); |
||||
|
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
gpr_free(pollsets[i].pollset); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Cases to test: |
||||
* case 1) Polling islands of both fd and pollset are NULL |
||||
* case 2) Polling island of fd is NULL but that of pollset is not-NULL |
||||
* case 3) Polling island of fd is not-NULL but that of pollset is NULL |
||||
* case 4) Polling islands of both fd and pollset are not-NULL and: |
||||
* case 4.1) Polling islands of fd and pollset are equal |
||||
* case 4.2) Polling islands of fd and pollset are NOT-equal (This results |
||||
* in a merge) |
||||
* */ |
||||
|
||||
#define NUM_FDS 8 |
||||
#define NUM_POLLSETS 4 |
||||
|
||||
static void test_add_fd_to_pollset() { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
test_fd tfds[NUM_FDS]; |
||||
int fds[NUM_FDS]; |
||||
test_pollset pollsets[NUM_POLLSETS]; |
||||
void* expected_pi = nullptr; |
||||
int i; |
||||
|
||||
test_fd_init(tfds, fds, NUM_FDS); |
||||
test_pollset_init(pollsets, NUM_POLLSETS); |
||||
|
||||
/*Step 1.
|
||||
* Create three polling islands (This will exercise test case 1 and 2) with |
||||
* the following configuration: |
||||
* polling island 0 = { fds:0,1,2, pollsets:0} |
||||
* polling island 1 = { fds:3,4, pollsets:1} |
||||
* polling island 2 = { fds:5,6,7 pollsets:2} |
||||
* |
||||
*Step 2. |
||||
* Add pollset 3 to polling island 0 (by adding fds 0 and 1 to pollset 3) |
||||
* (This will exercise test cases 3 and 4.1). The configuration becomes: |
||||
* polling island 0 = { fds:0,1,2, pollsets:0,3} <<< pollset 3 added here |
||||
* polling island 1 = { fds:3,4, pollsets:1} |
||||
* polling island 2 = { fds:5,6,7 pollsets:2} |
||||
* |
||||
*Step 3. |
||||
* Merge polling islands 0 and 1 by adding fd 0 to pollset 1 (This will |
||||
* exercise test case 4.2). The configuration becomes: |
||||
* polling island (merged) = {fds: 0,1,2,3,4, pollsets: 0,1,3} |
||||
* polling island 2 = {fds: 5,6,7 pollsets: 2} |
||||
* |
||||
*Step 4. |
||||
* Finally do one more merge by adding fd 3 to pollset 2. |
||||
* polling island (merged) = {fds: 0,1,2,3,4,5,6,7, pollsets: 0,1,2,3} |
||||
*/ |
||||
|
||||
/* == Step 1 == */ |
||||
for (i = 0; i <= 2; i++) { |
||||
grpc_pollset_add_fd(pollsets[0].pollset, tfds[i].fd); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
for (i = 3; i <= 4; i++) { |
||||
grpc_pollset_add_fd(pollsets[1].pollset, tfds[i].fd); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
for (i = 5; i <= 7; i++) { |
||||
grpc_pollset_add_fd(pollsets[2].pollset, tfds[i].fd); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
/* == Step 2 == */ |
||||
for (i = 0; i <= 1; i++) { |
||||
grpc_pollset_add_fd(pollsets[3].pollset, tfds[i].fd); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
/* == Step 3 == */ |
||||
grpc_pollset_add_fd(pollsets[1].pollset, tfds[0].fd); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
/* == Step 4 == */ |
||||
grpc_pollset_add_fd(pollsets[2].pollset, tfds[3].fd); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
/* All polling islands are merged at this point */ |
||||
|
||||
/* Compare Fd:0's polling island with that of all other Fds */ |
||||
expected_pi = grpc_fd_get_polling_island(tfds[0].fd); |
||||
for (i = 1; i < NUM_FDS; i++) { |
||||
GPR_ASSERT(grpc_are_polling_islands_equal( |
||||
expected_pi, grpc_fd_get_polling_island(tfds[i].fd))); |
||||
} |
||||
|
||||
/* Compare Fd:0's polling island with that of all other pollsets */ |
||||
for (i = 0; i < NUM_POLLSETS; i++) { |
||||
GPR_ASSERT(grpc_are_polling_islands_equal( |
||||
expected_pi, grpc_pollset_get_polling_island(pollsets[i].pollset))); |
||||
} |
||||
|
||||
test_fd_cleanup(tfds, NUM_FDS); |
||||
test_pollset_cleanup(pollsets, NUM_POLLSETS); |
||||
} |
||||
|
||||
#undef NUM_FDS |
||||
#undef NUM_POLLSETS |
||||
|
||||
typedef struct threading_shared { |
||||
gpr_mu* mu; |
||||
grpc_pollset* pollset; |
||||
grpc_wakeup_fd* wakeup_fd; |
||||
grpc_fd* wakeup_desc; |
||||
grpc_closure on_wakeup; |
||||
int wakeups; |
||||
} threading_shared; |
||||
|
||||
static __thread int thread_wakeups = 0; |
||||
|
||||
static void test_threading_loop(void* arg) { |
||||
threading_shared* shared = static_cast<threading_shared*>(arg); |
||||
while (thread_wakeups < 1000000) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_pollset_worker* worker; |
||||
gpr_mu_lock(shared->mu); |
||||
GPR_ASSERT(GRPC_LOG_IF_ERROR( |
||||
"pollset_work", |
||||
grpc_pollset_work(shared->pollset, &worker, GRPC_MILLIS_INF_FUTURE))); |
||||
gpr_mu_unlock(shared->mu); |
||||
} |
||||
} |
||||
|
||||
static void test_threading_wakeup(void* arg, grpc_error* error) { |
||||
threading_shared* shared = static_cast<threading_shared*>(arg); |
||||
++shared->wakeups; |
||||
++thread_wakeups; |
||||
if (error == GRPC_ERROR_NONE) { |
||||
GPR_ASSERT(GRPC_LOG_IF_ERROR( |
||||
"consume_wakeup", grpc_wakeup_fd_consume_wakeup(shared->wakeup_fd))); |
||||
grpc_fd_notify_on_read(shared->wakeup_desc, &shared->on_wakeup); |
||||
GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_next", |
||||
grpc_wakeup_fd_wakeup(shared->wakeup_fd))); |
||||
} |
||||
} |
||||
|
||||
static void test_threading(void) { |
||||
threading_shared shared; |
||||
shared.pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size())); |
||||
grpc_pollset_init(shared.pollset, &shared.mu); |
||||
|
||||
grpc_core::Thread thds[10]; |
||||
for (auto& th : thds) { |
||||
th = grpc_core::Thread("test_thread", test_threading_loop, &shared); |
||||
th.Start(); |
||||
} |
||||
grpc_wakeup_fd fd; |
||||
GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_fd_init", grpc_wakeup_fd_init(&fd))); |
||||
shared.wakeup_fd = &fd; |
||||
shared.wakeup_desc = grpc_fd_create(fd.read_fd, "wakeup", false); |
||||
shared.wakeups = 0; |
||||
{ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_pollset_add_fd(shared.pollset, shared.wakeup_desc); |
||||
grpc_fd_notify_on_read( |
||||
shared.wakeup_desc, |
||||
GRPC_CLOSURE_INIT(&shared.on_wakeup, test_threading_wakeup, &shared, |
||||
grpc_schedule_on_exec_ctx)); |
||||
} |
||||
GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_first", |
||||
grpc_wakeup_fd_wakeup(shared.wakeup_fd))); |
||||
for (auto& th : thds) { |
||||
th.Join(); |
||||
} |
||||
fd.read_fd = 0; |
||||
grpc_wakeup_fd_destroy(&fd); |
||||
{ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_fd_shutdown(shared.wakeup_desc, GRPC_ERROR_CANCELLED); |
||||
grpc_fd_orphan(shared.wakeup_desc, nullptr, nullptr, "done"); |
||||
grpc_pollset_shutdown(shared.pollset, |
||||
GRPC_CLOSURE_CREATE(destroy_pollset, shared.pollset, |
||||
grpc_schedule_on_exec_ctx)); |
||||
} |
||||
gpr_free(shared.pollset); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
const char* poll_strategy = nullptr; |
||||
grpc_test_init(argc, argv); |
||||
grpc_init(); |
||||
{ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
poll_strategy = grpc_get_poll_strategy_name(); |
||||
if (poll_strategy != nullptr && strcmp(poll_strategy, "epollsig") == 0) { |
||||
test_add_fd_to_pollset(); |
||||
test_threading(); |
||||
} else { |
||||
gpr_log(GPR_INFO, |
||||
"Skipping the test. The test is only relevant for 'epollsig' " |
||||
"strategy. and the current strategy is: '%s'", |
||||
poll_strategy); |
||||
} |
||||
} |
||||
|
||||
grpc_shutdown(); |
||||
return 0; |
||||
} |
||||
#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */ |
||||
int main(int argc, char** argv) { return 0; } |
||||
#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */ |
@ -1,447 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
/* This test only relevant on linux systems where epoll is available */ |
||||
#ifdef GRPC_LINUX_EPOLL_CREATE1 |
||||
|
||||
#include <errno.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/gpr/useful.h" |
||||
#include "src/core/lib/iomgr/ev_posix.h" |
||||
#include "src/core/lib/iomgr/iomgr.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
/*******************************************************************************
|
||||
* test_pollset_set |
||||
*/ |
||||
|
||||
typedef struct test_pollset_set { |
||||
grpc_pollset_set* pss; |
||||
} test_pollset_set; |
||||
|
||||
void init_test_pollset_sets(test_pollset_set* pollset_sets, const int num_pss) { |
||||
for (int i = 0; i < num_pss; i++) { |
||||
pollset_sets[i].pss = grpc_pollset_set_create(); |
||||
} |
||||
} |
||||
|
||||
void cleanup_test_pollset_sets(test_pollset_set* pollset_sets, |
||||
const int num_pss) { |
||||
for (int i = 0; i < num_pss; i++) { |
||||
grpc_pollset_set_destroy(pollset_sets[i].pss); |
||||
pollset_sets[i].pss = nullptr; |
||||
} |
||||
} |
||||
|
||||
/*******************************************************************************
|
||||
* test_pollset |
||||
*/ |
||||
|
||||
typedef struct test_pollset { |
||||
grpc_pollset* ps; |
||||
gpr_mu* mu; |
||||
} test_pollset; |
||||
|
||||
static void init_test_pollsets(test_pollset* pollsets, const int num_pollsets) { |
||||
for (int i = 0; i < num_pollsets; i++) { |
||||
pollsets[i].ps = |
||||
static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size())); |
||||
grpc_pollset_init(pollsets[i].ps, &pollsets[i].mu); |
||||
} |
||||
} |
||||
|
||||
static void destroy_pollset(void* p, grpc_error* error) { |
||||
grpc_pollset_destroy(static_cast<grpc_pollset*>(p)); |
||||
} |
||||
|
||||
static void cleanup_test_pollsets(test_pollset* pollsets, |
||||
const int num_pollsets) { |
||||
grpc_closure destroyed; |
||||
for (int i = 0; i < num_pollsets; i++) { |
||||
GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, pollsets[i].ps, |
||||
grpc_schedule_on_exec_ctx); |
||||
grpc_pollset_shutdown(pollsets[i].ps, &destroyed); |
||||
|
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
gpr_free(pollsets[i].ps); |
||||
pollsets[i].ps = nullptr; |
||||
} |
||||
} |
||||
|
||||
/*******************************************************************************
|
||||
* test_fd |
||||
*/ |
||||
|
||||
typedef struct test_fd { |
||||
grpc_fd* fd; |
||||
grpc_wakeup_fd wakeup_fd; |
||||
|
||||
bool is_on_readable_called; /* Is on_readable closure is called ? */ |
||||
grpc_closure on_readable; /* Closure to call when this fd is readable */ |
||||
} test_fd; |
||||
|
||||
void on_readable(void* tfd, grpc_error* error) { |
||||
(static_cast<test_fd*>(tfd))->is_on_readable_called = true; |
||||
} |
||||
|
||||
static void reset_test_fd(test_fd* tfd) { |
||||
tfd->is_on_readable_called = false; |
||||
|
||||
GRPC_CLOSURE_INIT(&tfd->on_readable, on_readable, tfd, |
||||
grpc_schedule_on_exec_ctx); |
||||
grpc_fd_notify_on_read(tfd->fd, &tfd->on_readable); |
||||
} |
||||
|
||||
static void init_test_fds(test_fd* tfds, const int num_fds) { |
||||
for (int i = 0; i < num_fds; i++) { |
||||
GPR_ASSERT(GRPC_ERROR_NONE == grpc_wakeup_fd_init(&tfds[i].wakeup_fd)); |
||||
tfds[i].fd = grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&tfds[i].wakeup_fd), |
||||
"test_fd", false); |
||||
reset_test_fd(&tfds[i]); |
||||
} |
||||
} |
||||
|
||||
static void cleanup_test_fds(test_fd* tfds, const int num_fds) { |
||||
int release_fd; |
||||
|
||||
for (int i = 0; i < num_fds; i++) { |
||||
grpc_fd_shutdown(tfds[i].fd, |
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING("fd cleanup")); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
/* grpc_fd_orphan frees the memory allocated for grpc_fd. Normally it also
|
||||
* calls close() on the underlying fd. In our case, we are using |
||||
* grpc_wakeup_fd and we would like to destroy it ourselves (by calling |
||||
* grpc_wakeup_fd_destroy). To prevent grpc_fd from calling close() on the |
||||
* underlying fd, call it with a non-NULL 'release_fd' parameter */ |
||||
grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, "test_fd_cleanup"); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
grpc_wakeup_fd_destroy(&tfds[i].wakeup_fd); |
||||
} |
||||
} |
||||
|
||||
static void make_test_fds_readable(test_fd* tfds, const int num_fds) { |
||||
for (int i = 0; i < num_fds; i++) { |
||||
GPR_ASSERT(GRPC_ERROR_NONE == grpc_wakeup_fd_wakeup(&tfds[i].wakeup_fd)); |
||||
} |
||||
} |
||||
|
||||
static void verify_readable_and_reset(test_fd* tfds, const int num_fds) { |
||||
for (int i = 0; i < num_fds; i++) { |
||||
/* Verify that the on_readable callback was called */ |
||||
GPR_ASSERT(tfds[i].is_on_readable_called); |
||||
|
||||
/* Reset the tfd[i] structure */ |
||||
GPR_ASSERT(GRPC_ERROR_NONE == |
||||
grpc_wakeup_fd_consume_wakeup(&tfds[i].wakeup_fd)); |
||||
reset_test_fd(&tfds[i]); |
||||
} |
||||
} |
||||
|
||||
/*******************************************************************************
|
||||
* Main tests |
||||
*/ |
||||
|
||||
/* Test some typical scenarios in pollset_set */ |
||||
static void pollset_set_test_basic() { |
||||
/* We construct the following structure for this test:
|
||||
* |
||||
* +---> FD0 (Added before PSS1, PS1 and PS2 are added to PSS0) |
||||
* | |
||||
* +---> FD5 (Added after PSS1, PS1 and PS2 are added to PSS0) |
||||
* | |
||||
* | |
||||
* | +---> FD1 (Added before PSS1 is added to PSS0) |
||||
* | | |
||||
* | +---> FD6 (Added after PSS1 is added to PSS0) |
||||
* | | |
||||
* +---> PSS1--+ +--> FD2 (Added before PS0 is added to PSS1) |
||||
* | | | |
||||
* | +---> PS0---+ |
||||
* | | |
||||
* PSS0---+ +--> FD7 (Added after PS0 is added to PSS1) |
||||
* | |
||||
* | |
||||
* | +---> FD3 (Added before PS1 is added to PSS0) |
||||
* | | |
||||
* +---> PS1---+ |
||||
* | | |
||||
* | +---> FD8 (Added after PS1 added to PSS0) |
||||
* | |
||||
* | |
||||
* | +---> FD4 (Added before PS2 is added to PSS0) |
||||
* | | |
||||
* +---> PS2---+ |
||||
* | |
||||
* +---> FD9 (Added after PS2 is added to PSS0) |
||||
*/ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_pollset_worker* worker; |
||||
grpc_millis deadline; |
||||
|
||||
test_fd tfds[10]; |
||||
test_pollset pollsets[3]; |
||||
test_pollset_set pollset_sets[2]; |
||||
const int num_fds = GPR_ARRAY_SIZE(tfds); |
||||
const int num_ps = GPR_ARRAY_SIZE(pollsets); |
||||
const int num_pss = GPR_ARRAY_SIZE(pollset_sets); |
||||
|
||||
init_test_fds(tfds, num_fds); |
||||
init_test_pollsets(pollsets, num_ps); |
||||
init_test_pollset_sets(pollset_sets, num_pss); |
||||
|
||||
/* Construct the pollset_set/pollset/fd tree (see diagram above) */ |
||||
|
||||
grpc_pollset_set_add_fd(pollset_sets[0].pss, tfds[0].fd); |
||||
grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[1].fd); |
||||
|
||||
grpc_pollset_add_fd(pollsets[0].ps, tfds[2].fd); |
||||
grpc_pollset_add_fd(pollsets[1].ps, tfds[3].fd); |
||||
grpc_pollset_add_fd(pollsets[2].ps, tfds[4].fd); |
||||
|
||||
grpc_pollset_set_add_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss); |
||||
|
||||
grpc_pollset_set_add_pollset(pollset_sets[1].pss, pollsets[0].ps); |
||||
grpc_pollset_set_add_pollset(pollset_sets[0].pss, pollsets[1].ps); |
||||
grpc_pollset_set_add_pollset(pollset_sets[0].pss, pollsets[2].ps); |
||||
|
||||
grpc_pollset_set_add_fd(pollset_sets[0].pss, tfds[5].fd); |
||||
grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[6].fd); |
||||
|
||||
grpc_pollset_add_fd(pollsets[0].ps, tfds[7].fd); |
||||
grpc_pollset_add_fd(pollsets[1].ps, tfds[8].fd); |
||||
grpc_pollset_add_fd(pollsets[2].ps, tfds[9].fd); |
||||
|
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
/* Test that if any FD in the above structure is readable, it is observable by
|
||||
* doing grpc_pollset_work on any pollset |
||||
* |
||||
* For every pollset, do the following: |
||||
* - (Ensure that all FDs are in reset state) |
||||
* - Make all FDs readable |
||||
* - Call grpc_pollset_work() on the pollset |
||||
* - Flush the exec_ctx |
||||
* - Verify that on_readable call back was called for all FDs (and |
||||
* reset the FDs) |
||||
* */ |
||||
for (int i = 0; i < num_ps; i++) { |
||||
make_test_fds_readable(tfds, num_fds); |
||||
|
||||
gpr_mu_lock(pollsets[i].mu); |
||||
deadline = grpc_timespec_to_millis_round_up( |
||||
grpc_timeout_milliseconds_to_deadline(2)); |
||||
GPR_ASSERT(GRPC_ERROR_NONE == |
||||
grpc_pollset_work(pollsets[i].ps, &worker, deadline)); |
||||
gpr_mu_unlock(pollsets[i].mu); |
||||
|
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
verify_readable_and_reset(tfds, num_fds); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
/* Test tear down */ |
||||
grpc_pollset_set_del_fd(pollset_sets[0].pss, tfds[0].fd); |
||||
grpc_pollset_set_del_fd(pollset_sets[0].pss, tfds[5].fd); |
||||
grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[1].fd); |
||||
grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[6].fd); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
grpc_pollset_set_del_pollset(pollset_sets[1].pss, pollsets[0].ps); |
||||
grpc_pollset_set_del_pollset(pollset_sets[0].pss, pollsets[1].ps); |
||||
grpc_pollset_set_del_pollset(pollset_sets[0].pss, pollsets[2].ps); |
||||
|
||||
grpc_pollset_set_del_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
cleanup_test_fds(tfds, num_fds); |
||||
cleanup_test_pollsets(pollsets, num_ps); |
||||
cleanup_test_pollset_sets(pollset_sets, num_pss); |
||||
} |
||||
|
||||
/* Same FD added multiple times to the pollset_set tree */ |
||||
void pollset_set_test_dup_fds() { |
||||
/* We construct the following structure for this test:
|
||||
* |
||||
* +---> FD0 |
||||
* | |
||||
* | |
||||
* PSS0---+ |
||||
* | +---> FD0 (also under PSS0) |
||||
* | | |
||||
* +---> PSS1--+ +--> FD1 (also under PSS1) |
||||
* | | |
||||
* +---> PS ---+ |
||||
* | | |
||||
* | +--> FD2 |
||||
* +---> FD1 |
||||
*/ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_pollset_worker* worker; |
||||
grpc_millis deadline; |
||||
|
||||
test_fd tfds[3]; |
||||
test_pollset pollset; |
||||
test_pollset_set pollset_sets[2]; |
||||
const int num_fds = GPR_ARRAY_SIZE(tfds); |
||||
const int num_ps = 1; |
||||
const int num_pss = GPR_ARRAY_SIZE(pollset_sets); |
||||
|
||||
init_test_fds(tfds, num_fds); |
||||
init_test_pollsets(&pollset, num_ps); |
||||
init_test_pollset_sets(pollset_sets, num_pss); |
||||
|
||||
/* Construct the structure */ |
||||
grpc_pollset_set_add_fd(pollset_sets[0].pss, tfds[0].fd); |
||||
grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[0].fd); |
||||
grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[1].fd); |
||||
|
||||
grpc_pollset_add_fd(pollset.ps, tfds[1].fd); |
||||
grpc_pollset_add_fd(pollset.ps, tfds[2].fd); |
||||
|
||||
grpc_pollset_set_add_pollset(pollset_sets[1].pss, pollset.ps); |
||||
grpc_pollset_set_add_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss); |
||||
|
||||
/* Test. Make all FDs readable and make sure that can be observed by doing a
|
||||
* grpc_pollset_work on the pollset 'PS' */ |
||||
make_test_fds_readable(tfds, num_fds); |
||||
|
||||
gpr_mu_lock(pollset.mu); |
||||
deadline = grpc_timespec_to_millis_round_up( |
||||
grpc_timeout_milliseconds_to_deadline(2)); |
||||
GPR_ASSERT(GRPC_ERROR_NONE == |
||||
grpc_pollset_work(pollset.ps, &worker, deadline)); |
||||
gpr_mu_unlock(pollset.mu); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
verify_readable_and_reset(tfds, num_fds); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
/* Tear down */ |
||||
grpc_pollset_set_del_fd(pollset_sets[0].pss, tfds[0].fd); |
||||
grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[0].fd); |
||||
grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[1].fd); |
||||
|
||||
grpc_pollset_set_del_pollset(pollset_sets[1].pss, pollset.ps); |
||||
grpc_pollset_set_del_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
cleanup_test_fds(tfds, num_fds); |
||||
cleanup_test_pollsets(&pollset, num_ps); |
||||
cleanup_test_pollset_sets(pollset_sets, num_pss); |
||||
} |
||||
|
||||
/* Pollset_set with an empty pollset */ |
||||
void pollset_set_test_empty_pollset() { |
||||
/* We construct the following structure for this test:
|
||||
* |
||||
* +---> PS0 (EMPTY) |
||||
* | |
||||
* +---> FD0 |
||||
* | |
||||
* PSS0---+ |
||||
* | +---> FD1 |
||||
* | | |
||||
* +---> PS1--+ |
||||
* | |
||||
* +---> FD2 |
||||
*/ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_pollset_worker* worker; |
||||
grpc_millis deadline; |
||||
|
||||
test_fd tfds[3]; |
||||
test_pollset pollsets[2]; |
||||
test_pollset_set pollset_set; |
||||
const int num_fds = GPR_ARRAY_SIZE(tfds); |
||||
const int num_ps = GPR_ARRAY_SIZE(pollsets); |
||||
const int num_pss = 1; |
||||
|
||||
init_test_fds(tfds, num_fds); |
||||
init_test_pollsets(pollsets, num_ps); |
||||
init_test_pollset_sets(&pollset_set, num_pss); |
||||
|
||||
/* Construct the structure */ |
||||
grpc_pollset_set_add_fd(pollset_set.pss, tfds[0].fd); |
||||
grpc_pollset_add_fd(pollsets[1].ps, tfds[1].fd); |
||||
grpc_pollset_add_fd(pollsets[1].ps, tfds[2].fd); |
||||
|
||||
grpc_pollset_set_add_pollset(pollset_set.pss, pollsets[0].ps); |
||||
grpc_pollset_set_add_pollset(pollset_set.pss, pollsets[1].ps); |
||||
|
||||
/* Test. Make all FDs readable and make sure that can be observed by doing
|
||||
* grpc_pollset_work on the empty pollset 'PS0' */ |
||||
make_test_fds_readable(tfds, num_fds); |
||||
|
||||
gpr_mu_lock(pollsets[0].mu); |
||||
deadline = grpc_timespec_to_millis_round_up( |
||||
grpc_timeout_milliseconds_to_deadline(2)); |
||||
GPR_ASSERT(GRPC_ERROR_NONE == |
||||
grpc_pollset_work(pollsets[0].ps, &worker, deadline)); |
||||
gpr_mu_unlock(pollsets[0].mu); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
verify_readable_and_reset(tfds, num_fds); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
/* Tear down */ |
||||
grpc_pollset_set_del_fd(pollset_set.pss, tfds[0].fd); |
||||
grpc_pollset_set_del_pollset(pollset_set.pss, pollsets[0].ps); |
||||
grpc_pollset_set_del_pollset(pollset_set.pss, pollsets[1].ps); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
cleanup_test_fds(tfds, num_fds); |
||||
cleanup_test_pollsets(pollsets, num_ps); |
||||
cleanup_test_pollset_sets(&pollset_set, num_pss); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
grpc_test_init(argc, argv); |
||||
grpc_init(); |
||||
{ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
const char* poll_strategy = grpc_get_poll_strategy_name(); |
||||
|
||||
if (poll_strategy != nullptr && |
||||
(strcmp(poll_strategy, "epollsig") == 0 || |
||||
strcmp(poll_strategy, "epoll-threadpool") == 0)) { |
||||
pollset_set_test_basic(); |
||||
pollset_set_test_dup_fds(); |
||||
pollset_set_test_empty_pollset(); |
||||
} else { |
||||
gpr_log(GPR_INFO, |
||||
"Skipping the test. The test is only relevant for 'epoll' " |
||||
"strategy. and the current strategy is: '%s'", |
||||
poll_strategy); |
||||
} |
||||
} |
||||
grpc_shutdown(); |
||||
return 0; |
||||
} |
||||
#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */ |
||||
int main(int argc, char** argv) { return 0; } |
||||
#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */ |
Loading…
Reference in new issue