Skip to content

Commit 8e009e8

Browse files
CuriousGeorgiydrewdzzz
authored andcommitted
client: check wait return code in waitAny
Currently, we do not check the return code of `wait` in `waitAny`. If there is an error, we must log it and return a `nullopt`. Closes #121
1 parent 3bc68db commit 8e009e8

File tree

2 files changed

+82
-1
lines changed

2 files changed

+82
-1
lines changed

src/Client/Connector.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,10 @@ Connector<BUFFER, NetProvider>::waitAny(int timeout)
345345
Timer timer{timeout};
346346
timer.start();
347347
while (m_ReadyToDecode.empty()) {
348-
m_NetProvider.wait(timer.timeLeft());
348+
if (m_NetProvider.wait(timer.timeLeft()) != 0) {
349+
LOG_ERROR("Failed to poll connections: ", strerror(errno));
350+
return std::nullopt;
351+
}
349352
if (timer.isExpired())
350353
break;
351354
}

test/ClientTest.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#include "../src/Client/LibevNetProvider.hpp"
3636
#include "../src/Client/Connector.hpp"
3737

38+
#include <thread>
39+
3840
const char *localhost = "127.0.0.1";
3941
int port = 3301;
4042
int dummy_server_port = 3302;
@@ -1144,6 +1146,47 @@ response_decoding(Connector<BUFFER, NetProvider> &client)
11441146
client.close(conn);
11451147
}
11461148

1149+
#ifdef __linux__
1150+
/** Sleep time for internal wait failure test. */
1151+
static constexpr double INTERNAL_WAIT_FAILURE_SLEEP_TIME = 1e5;
1152+
1153+
/** No-op signal handler for internal wait failure test. */
1154+
void
1155+
sigusr_handler(int signo)
1156+
{
1157+
fail_unless(signo != SIGINT);
1158+
}
1159+
1160+
/**
1161+
* Helper for setting up an internal wait failure test case. Creates a request and spawns a thread that will send
1162+
* a signal to the request processing thread to interrupt its wait method.
1163+
*/
1164+
void
1165+
setup_internal_wait_failure_test_case(Connection<Buf_t, NetProvider> &conn, rid_t *f, std::thread *signal_thread)
1166+
{
1167+
*f = conn.call("remote_sleep", std::forward_as_tuple(INTERNAL_WAIT_FAILURE_SLEEP_TIME / 1e6));
1168+
fail_unless(!conn.futureIsReady(*f));
1169+
pthread_t tid = pthread_self();
1170+
*signal_thread = std::thread([tid] {
1171+
usleep(INTERNAL_WAIT_FAILURE_SLEEP_TIME / 2);
1172+
pthread_kill(tid, SIGUSR1);
1173+
});
1174+
}
1175+
1176+
/**
1177+
* Helper for tearing down an internal wait failure test case. Gets the response for the future and joins the
1178+
* signalling thread.
1179+
*/
1180+
void
1181+
teardown_internal_wait_failure_test_case(Connection<Buf_t, NetProvider> &conn, rid_t f, std::thread &signal_thread)
1182+
{
1183+
fail_unless(conn.futureIsReady(f));
1184+
std::optional<Response<Buf_t>> response = conn.getResponse(f);
1185+
fail_unless(response.has_value());
1186+
signal_thread.join();
1187+
}
1188+
#endif /* __linux__ */
1189+
11471190
/** Checks all available `wait` methods of connector. */
11481191
template <class BUFFER, class NetProvider>
11491192
void
@@ -1346,6 +1389,41 @@ test_wait(Connector<BUFFER, NetProvider> &client)
13461389
conn.getResponse(f);
13471390
#endif
13481391

1392+
#ifdef __linux__
1393+
TEST_CASE("wait methods internal wait failure (gh-121)");
1394+
struct sigaction act;
1395+
act.sa_handler = sigusr_handler;
1396+
act.sa_flags = 0;
1397+
sigemptyset(&act.sa_mask);
1398+
sigaction(SIGUSR1, &act, nullptr);
1399+
std::thread signal_thread;
1400+
1401+
setup_internal_wait_failure_test_case(conn, &f, &signal_thread);
1402+
fail_unless(client.wait(conn, f) != 0);
1403+
conn.reset();
1404+
fail_unless(client.wait(conn, f) == 0);
1405+
teardown_internal_wait_failure_test_case(conn, f, signal_thread);
1406+
1407+
setup_internal_wait_failure_test_case(conn, &f, &signal_thread);
1408+
fail_unless(client.waitAll(conn, {f}) != 0);
1409+
conn.reset();
1410+
fail_unless(client.waitAll(conn, {f}) == 0);
1411+
teardown_internal_wait_failure_test_case(conn, f, signal_thread);
1412+
1413+
setup_internal_wait_failure_test_case(conn, &f, &signal_thread);
1414+
fail_unless(client.waitCount(conn, 1) != 0);
1415+
conn.reset();
1416+
fail_unless(client.waitCount(conn, 1) == 0);
1417+
teardown_internal_wait_failure_test_case(conn, f, signal_thread);
1418+
1419+
setup_internal_wait_failure_test_case(conn, &f, &signal_thread);
1420+
fail_unless(!client.waitAny().has_value());
1421+
fail_unless(client.waitAny().has_value());
1422+
teardown_internal_wait_failure_test_case(conn, f, signal_thread);
1423+
1424+
sigaction(SIGUSR1, nullptr, nullptr);
1425+
#endif /* __linux__ */
1426+
13491427
client.close(conn);
13501428
}
13511429

0 commit comments

Comments
 (0)