Copilot commented on code in PR #3599:
URL: https://github.com/apache/brpc/pull/3599#discussion_r4254363231


##########
test/endpoint_unittest.cpp:
##########
@@ -500,119 +508,207 @@ TEST(EndPointTest, endpoint_concurrency) {
     }
 }
 
-const char* g_hostname1 = "github.com";
-const char* g_hostname2 = "baidu.com";
 TEST(EndPointTest, tcp_connect) {
-    butil::EndPoint ep1;
-    butil::EndPoint ep2;
-    ASSERT_EQ(0, butil::hostname2endpoint(g_hostname1, 80, &ep1));
-    ASSERT_EQ(0, butil::hostname2endpoint(g_hostname2, 80, &ep2));
+    butil::EndPoint ep;
+    ASSERT_EQ(0, butil::str2endpoint("127.0.0.1:0", &ep));
+    butil::fd_guard listener(butil::tcp_listen(ep));
+    ASSERT_LE(0, listener) << "errno=" << errno;
+    ASSERT_EQ(0, butil::get_local_side(listener, &ep));
+    // The local TCP handshake completes without a concurrent accept thread.
     {
-        butil::fd_guard sockfd(butil::tcp_connect(ep1, nullptr));
+        butil::fd_guard sockfd(butil::tcp_connect(ep, nullptr));
         ASSERT_LE(0, sockfd) << "errno=" << errno;
     }
     {
-        butil::fd_guard sockfd(butil::tcp_connect(ep1, nullptr, 1000));
+        butil::fd_guard sockfd(butil::tcp_connect(ep, nullptr, 1000));
         ASSERT_LE(0, sockfd) << "errno=" << errno;
     }
-    {
-        butil::fd_guard sockfd(butil::tcp_connect(ep2, nullptr, 1));
-        ASSERT_EQ(-1, sockfd) << "errno=" << errno;
-        ASSERT_EQ(ETIMEDOUT, errno);
-    }
 
-    {
-        struct sockaddr_storage serv_addr{};
-        socklen_t serv_addr_size = 0;
-        ASSERT_EQ(0, endpoint2sockaddr(ep1, &serv_addr, &serv_addr_size));
-        butil::fd_guard sockfd(socket(serv_addr.ss_family, SOCK_STREAM, 0));
-        ASSERT_LE(0, sockfd);
-        bool is_blocking = butil::is_blocking(sockfd);
-        ASSERT_EQ(0, butil::pthread_timed_connect(
-            sockfd, (struct sockaddr*) &serv_addr, serv_addr_size, nullptr));
-        ASSERT_EQ(is_blocking, butil::is_blocking(sockfd));
+    sockaddr_storage serv_addr{};
+    socklen_t serv_addr_size = 0;
+    ASSERT_EQ(0, endpoint2sockaddr(ep, &serv_addr, &serv_addr_size));
+    for (bool timed : {false, true}) {
+        for (bool blocking : {false, true}) {
+            butil::fd_guard sockfd(socket(serv_addr.ss_family, SOCK_STREAM, 
0));
+            ASSERT_LE(0, sockfd);
+            if (!blocking) {
+                ASSERT_EQ(0, butil::make_non_blocking(sockfd));
+            }
+            timespec deadline = butil::seconds_from_now(1);
+            ASSERT_EQ(0, butil::pthread_timed_connect(
+                sockfd, reinterpret_cast<sockaddr*>(&serv_addr), 
serv_addr_size,
+                timed ? &deadline : nullptr)) << "errno=" << errno;
+            ASSERT_EQ(blocking, butil::is_blocking(sockfd));
+            ASSERT_EQ(0, butil::is_connected(sockfd));
+        }
     }
+}
 
+#if defined(OS_LINUX)
+TEST(EndPointTest, tcp_connect_timeout_with_full_accept_queue) {
+    butil::EndPoint ep;
+    ASSERT_EQ(0, butil::str2endpoint("127.0.0.1:0", &ep));
+    butil::fd_guard listener(butil::tcp_listen(ep));
+    ASSERT_LE(0, listener) << "errno=" << errno;
+    // Linux allows one queued connection with backlog=0. Keep it unaccepted
+    // so subsequent handshakes must wait instead of relying on Internet 
latency.
+    ASSERT_EQ(0, listen(listener, 0));
+    ASSERT_EQ(0, butil::get_local_side(listener, &ep));
+    butil::fd_guard queued(butil::tcp_connect(ep, nullptr, 1000));
+    ASSERT_LE(0, queued) << "errno=" << errno;
     {
-        struct sockaddr_storage serv_addr{};
-        socklen_t serv_addr_size = 0;
-        ASSERT_EQ(0, endpoint2sockaddr(ep2, &serv_addr, &serv_addr_size));
+        butil::fd_guard sockfd(butil::tcp_connect(ep, nullptr, 300));
+        const int error = errno;
+        ASSERT_EQ(-1, sockfd);
+        // tcp_abort_on_overflow may reject the connection rather than time 
out.
+        ASSERT_TRUE(error == ETIMEDOUT || error == ECONNREFUSED)
+            << "errno=" << error;
+    }
+    sockaddr_storage serv_addr{};
+    socklen_t serv_addr_size = 0;
+    ASSERT_EQ(0, endpoint2sockaddr(ep, &serv_addr, &serv_addr_size));
+    for (bool blocking : {false, true}) {
         butil::fd_guard sockfd(socket(serv_addr.ss_family, SOCK_STREAM, 0));
         ASSERT_LE(0, sockfd);
-        bool is_blocking = butil::is_blocking(sockfd);
-        // In most cases, 1 millisecond will result in a connection timeout.
-        timespec abstime = butil::milliseconds_from_now(1);
+        if (!blocking) {
+            ASSERT_EQ(0, butil::make_non_blocking(sockfd));
+        }
+        timespec abstime = butil::milliseconds_from_now(300);
         const int rc = butil::pthread_timed_connect(
-            sockfd, (struct sockaddr*) &serv_addr,
+            sockfd, reinterpret_cast<sockaddr*>(&serv_addr),
             serv_addr_size, &abstime);
+        const int error = errno;
         ASSERT_EQ(-1, rc);
-        ASSERT_EQ(ETIMEDOUT, errno);
-        ASSERT_EQ(is_blocking, butil::is_blocking(sockfd));
+        ASSERT_TRUE(error == ETIMEDOUT || error == ECONNREFUSED)
+            << "errno=" << error;
+        ASSERT_EQ(blocking, butil::is_blocking(sockfd));
     }
 }
+#endif
 
-bool g_connect_startd = false;
-
-void TestConnectInterruptImpl(bool timed) {
-    butil::EndPoint ep;
-    ASSERT_EQ(0, butil::hostname2endpoint(g_hostname1, 80, &ep));
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+int WaitForPipe(int fd, const timespec* abstime) {
+#if defined(OS_LINUX)
+    return butil::pthread_fd_wait(fd, EPOLLIN, abstime);
+#else
+    return butil::pthread_fd_wait(
+        fd, static_cast<unsigned>(EVFILT_READ), abstime);
+#endif
+}
 
-    struct sockaddr_storage serv_addr{};
-    socklen_t serv_addr_size = 0;
-    ASSERT_EQ(0, endpoint2sockaddr(ep, &serv_addr, &serv_addr_size));
-    butil::fd_guard sockfd(socket(serv_addr.ss_family, SOCK_STREAM, 0));
-    ASSERT_LE(0, sockfd);
-
-    int rc;
-    if (timed) {
-        int64_t start_ms = butil::cpuwide_time_ms();
-        butil::tcp_connect(ep, nullptr);
-        int64_t connect_ms = butil::cpuwide_time_ms() - start_ms;
-        LOG(INFO) << "Connect to " << ep << ", cost " << connect_ms << "ms";
-
-        timespec abstime = butil::milliseconds_from_now(connect_ms * 10);
-        rc = butil::pthread_timed_connect(
-            sockfd, (struct sockaddr*) &serv_addr,
-            serv_addr_size, &abstime);
-    } else {
-        rc = butil::pthread_timed_connect(
-            sockfd, (struct sockaddr*) &serv_addr,
-            serv_addr_size, nullptr);
-    }
-    ASSERT_EQ(0, rc) << "errno=" << errno;
-    ASSERT_EQ(0, butil::is_connected(sockfd));
+TEST(EndPointTest, fd_wait_timeout) {
+    int fds[2];
+    ASSERT_EQ(0, pipe(fds));
+    butil::fd_guard reader(fds[0]);
+    butil::fd_guard writer(fds[1]);
+    timespec deadline = butil::milliseconds_from_now(300);
+    ASSERT_EQ(-1, WaitForPipe(reader, &deadline));
+    ASSERT_EQ(ETIMEDOUT, errno);
 }
 
-void* ConnectThread(void* arg) {
-    bool timed = *(bool*)arg;
-    TestConnectInterruptImpl(timed);
-    return nullptr;
+#if defined(OS_MACOSX)
+TEST(EndPointTest, fd_wait_kqueue_events) {
+    int fds[2];
+    ASSERT_EQ(0, pipe(fds));
+    butil::fd_guard reader(fds[0]);
+    butil::fd_guard writer(fds[1]);
+    timespec deadline = butil::seconds_from_now(5);
+    ASSERT_EQ(0, butil::pthread_fd_wait(
+        writer, static_cast<unsigned>(EVFILT_WRITE), &deadline));
+
+    const char byte = 'x';
+    ASSERT_EQ(1, write(writer, &byte, sizeof(byte)));
+    ASSERT_EQ(0, butil::pthread_fd_wait(
+        reader, static_cast<unsigned>(EVFILT_READ), &deadline));
+
+    ASSERT_EQ(-1, butil::pthread_fd_wait(reader, 0u, &deadline));
+    EXPECT_EQ(EINVAL, errno);
 }
+#endif
+
+volatile sig_atomic_t g_sigurg_received = 0;
 
-void do_nothing_handler(int) {}
+void RecordSigurg(int) {
+    g_sigurg_received = 1;
+}
 
-void register_sigurg() {
-    signal(SIGURG, do_nothing_handler);
+struct FDWaitInterruptArgs {
+    int fd;
+    bool timed;
+    std::atomic<bool> started{false};
+    std::atomic<bool> finished{false};
+    int signal_mask_error = 0;
+    int result = -1;
+    int error = 0;
+};
+
+void* FDWaitThread(void* arg) {
+    FDWaitInterruptArgs* args = static_cast<FDWaitInterruptArgs*>(arg);
+    sigset_t signals;
+    sigemptyset(&signals);
+    sigaddset(&signals, SIGURG);
+    args->signal_mask_error = pthread_sigmask(SIG_UNBLOCK, &signals, nullptr);
+    timespec deadline = butil::seconds_from_now(5);
+    args->started.store(true, std::memory_order_release);

Review Comment:
   `started` is set before the worker calls `WaitForPipe`, not when `poll()` is 
blocked. If the worker is descheduled after this store, the main thread can 
send all ten signals before the wait begins; the later pipe write makes the 
test pass even if `pthread_fd_wait_impl` no longer retries `EINTR`. Make the 
test observe an interruption of an active wait (for example, through a test 
hook or an observed `EINTR` retry) before writing to the pipe, so it actually 
covers the behavior it claims to test.



##########
test/run_tests.sh:
##########
@@ -46,6 +46,23 @@ if [ $test_num -eq 0 ]; then
 fi
 
 print_bt () {
+    case "${2-}" in
+        ''|*[!0-9]*) return ;;
+    esac
+    # Assertion failures exit normally. A passing death test may have left a
+    # core in this binary, so only consider statuses that can represent a 
signal.
+    if [ "$2" -le 128 ] || [ "$2" -gt 255 ]; then

Review Comment:
   The shell reports the same status (`143`) for a program that calls 
`exit(143)` and one killed by `SIGTERM`; `kill -l` cannot tell them apart. Thus 
a normal exit with a code in this range still triggers a backtrace from a core 
left by a passing death test in the same binary, contrary to the intended 
signal-only behavior. Capture whether the test process was actually signaled 
(for example, with a small `waitpid`-based runner), or verify that the selected 
core belongs to that failed process before printing it.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to