Skip to content

Commit b4e197d

Browse files
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 392934e commit b4e197d

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 = 0.1;
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));
1168+
fail_unless(!conn.futureIsReady(*f));
1169+
pthread_t tid = pthread_self();
1170+
*signal_thread = std::thread([tid] {
1171+
sleep(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
@@ -1324,6 +1367,41 @@ test_wait(Connector<BUFFER, NetProvider> &client)
13241367
fail_unless(result.header.sync == static_cast<int>(f1));
13251368
fail_unless(result.header.code == 0);
13261369

1370+
#ifdef __linux__
1371+
TEST_CASE("wait methods internal wait failure (gh-121)");
1372+
struct sigaction act;
1373+
act.sa_handler = sigusr_handler;
1374+
act.sa_flags = 0;
1375+
sigemptyset(&act.sa_mask);
1376+
sigaction(SIGUSR1, &act, nullptr);
1377+
std::thread signal_thread;
1378+
1379+
setup_internal_wait_failure_test_case(conn, &f, &signal_thread);
1380+
fail_unless(client.wait(conn, f) != 0);
1381+
conn.reset();
1382+
fail_unless(client.wait(conn, f) == 0);
1383+
teardown_internal_wait_failure_test_case(conn, f, signal_thread);
1384+
1385+
setup_internal_wait_failure_test_case(conn, &f, &signal_thread);
1386+
fail_unless(client.waitAll(conn, {f}) != 0);
1387+
conn.reset();
1388+
fail_unless(client.waitAll(conn, {f}) == 0);
1389+
teardown_internal_wait_failure_test_case(conn, f, signal_thread);
1390+
1391+
setup_internal_wait_failure_test_case(conn, &f, &signal_thread);
1392+
fail_unless(client.waitCount(conn, 1) != 0);
1393+
conn.reset();
1394+
fail_unless(client.waitCount(conn, 1) == 0);
1395+
teardown_internal_wait_failure_test_case(conn, f, signal_thread);
1396+
1397+
setup_internal_wait_failure_test_case(conn, &f, &signal_thread);
1398+
fail_unless(!client.waitAny().has_value());
1399+
fail_unless(client.waitAny().has_value());
1400+
teardown_internal_wait_failure_test_case(conn, f, signal_thread);
1401+
1402+
sigaction(SIGUSR1, nullptr, nullptr);
1403+
#endif /* __linux__ */
1404+
13271405
client.close(conn);
13281406
}
13291407

0 commit comments

Comments
 (0)