xref: /aosp_15_r20/bionic/tests/pty_test.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker  *
4*8d67ca89SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*8d67ca89SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*8d67ca89SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*8d67ca89SAndroid Build Coastguard Worker  *
8*8d67ca89SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*8d67ca89SAndroid Build Coastguard Worker  *
10*8d67ca89SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*8d67ca89SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*8d67ca89SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8d67ca89SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*8d67ca89SAndroid Build Coastguard Worker  * limitations under the License.
15*8d67ca89SAndroid Build Coastguard Worker  */
16*8d67ca89SAndroid Build Coastguard Worker 
17*8d67ca89SAndroid Build Coastguard Worker #include <pty.h>
18*8d67ca89SAndroid Build Coastguard Worker 
19*8d67ca89SAndroid Build Coastguard Worker #include <gtest/gtest.h>
20*8d67ca89SAndroid Build Coastguard Worker 
21*8d67ca89SAndroid Build Coastguard Worker #include <pthread.h>
22*8d67ca89SAndroid Build Coastguard Worker #include <sys/ioctl.h>
23*8d67ca89SAndroid Build Coastguard Worker 
24*8d67ca89SAndroid Build Coastguard Worker #include <atomic>
25*8d67ca89SAndroid Build Coastguard Worker 
26*8d67ca89SAndroid Build Coastguard Worker #include <android-base/file.h>
27*8d67ca89SAndroid Build Coastguard Worker 
28*8d67ca89SAndroid Build Coastguard Worker #include "utils.h"
29*8d67ca89SAndroid Build Coastguard Worker 
TEST(pty,openpty)30*8d67ca89SAndroid Build Coastguard Worker TEST(pty, openpty) {
31*8d67ca89SAndroid Build Coastguard Worker   int pty, tty;
32*8d67ca89SAndroid Build Coastguard Worker   char name[32];
33*8d67ca89SAndroid Build Coastguard Worker   struct winsize w = { 123, 456, 9999, 999 };
34*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, openpty(&pty, &tty, name, nullptr, &w));
35*8d67ca89SAndroid Build Coastguard Worker   ASSERT_NE(-1, pty);
36*8d67ca89SAndroid Build Coastguard Worker   ASSERT_NE(-1, tty);
37*8d67ca89SAndroid Build Coastguard Worker   ASSERT_NE(pty, tty);
38*8d67ca89SAndroid Build Coastguard Worker 
39*8d67ca89SAndroid Build Coastguard Worker   char tty_name[32];
40*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, ttyname_r(tty, tty_name, sizeof(tty_name)));
41*8d67ca89SAndroid Build Coastguard Worker   ASSERT_STREQ(tty_name, name);
42*8d67ca89SAndroid Build Coastguard Worker 
43*8d67ca89SAndroid Build Coastguard Worker   struct winsize w_actual;
44*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, ioctl(tty, TIOCGWINSZ, &w_actual));
45*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(w_actual.ws_row, w.ws_row);
46*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(w_actual.ws_col, w.ws_col);
47*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(w_actual.ws_xpixel, w.ws_xpixel);
48*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(w_actual.ws_ypixel, w.ws_ypixel);
49*8d67ca89SAndroid Build Coastguard Worker 
50*8d67ca89SAndroid Build Coastguard Worker   close(pty);
51*8d67ca89SAndroid Build Coastguard Worker   close(tty);
52*8d67ca89SAndroid Build Coastguard Worker }
53*8d67ca89SAndroid Build Coastguard Worker 
TEST(pty,forkpty)54*8d67ca89SAndroid Build Coastguard Worker TEST(pty, forkpty) {
55*8d67ca89SAndroid Build Coastguard Worker   pid_t sid = getsid(0);
56*8d67ca89SAndroid Build Coastguard Worker 
57*8d67ca89SAndroid Build Coastguard Worker   int pty;
58*8d67ca89SAndroid Build Coastguard Worker   pid_t pid = forkpty(&pty, nullptr, nullptr, nullptr);
59*8d67ca89SAndroid Build Coastguard Worker   ASSERT_NE(-1, pid);
60*8d67ca89SAndroid Build Coastguard Worker 
61*8d67ca89SAndroid Build Coastguard Worker   if (pid == 0) {
62*8d67ca89SAndroid Build Coastguard Worker     // We're the child.
63*8d67ca89SAndroid Build Coastguard Worker     ASSERT_NE(sid, getsid(0));
64*8d67ca89SAndroid Build Coastguard Worker     _exit(0);
65*8d67ca89SAndroid Build Coastguard Worker   }
66*8d67ca89SAndroid Build Coastguard Worker 
67*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(sid, getsid(0));
68*8d67ca89SAndroid Build Coastguard Worker 
69*8d67ca89SAndroid Build Coastguard Worker   AssertChildExited(pid, 0);
70*8d67ca89SAndroid Build Coastguard Worker 
71*8d67ca89SAndroid Build Coastguard Worker   close(pty);
72*8d67ca89SAndroid Build Coastguard Worker }
73*8d67ca89SAndroid Build Coastguard Worker 
74*8d67ca89SAndroid Build Coastguard Worker struct PtyReader_28979140_Arg {
75*8d67ca89SAndroid Build Coastguard Worker   int main_cpu_id;
76*8d67ca89SAndroid Build Coastguard Worker   int fd;
77*8d67ca89SAndroid Build Coastguard Worker   uint32_t data_count;
78*8d67ca89SAndroid Build Coastguard Worker   bool finished;
79*8d67ca89SAndroid Build Coastguard Worker   std::atomic<bool> matched;
80*8d67ca89SAndroid Build Coastguard Worker };
81*8d67ca89SAndroid Build Coastguard Worker 
PtyReader_28979140(PtyReader_28979140_Arg * arg)82*8d67ca89SAndroid Build Coastguard Worker static void PtyReader_28979140(PtyReader_28979140_Arg* arg) {
83*8d67ca89SAndroid Build Coastguard Worker   arg->finished = false;
84*8d67ca89SAndroid Build Coastguard Worker   cpu_set_t cpus;
85*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, sched_getaffinity(0, sizeof(cpu_set_t), &cpus));
86*8d67ca89SAndroid Build Coastguard Worker   CPU_CLR(arg->main_cpu_id, &cpus);
87*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus));
88*8d67ca89SAndroid Build Coastguard Worker 
89*8d67ca89SAndroid Build Coastguard Worker   uint32_t counter = 0;
90*8d67ca89SAndroid Build Coastguard Worker   while (counter <= arg->data_count) {
91*8d67ca89SAndroid Build Coastguard Worker     char buf[4096];  // Use big buffer to read to hit the bug more easily.
92*8d67ca89SAndroid Build Coastguard Worker     size_t to_read = std::min(sizeof(buf), (arg->data_count + 1 - counter) * sizeof(uint32_t));
93*8d67ca89SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::ReadFully(arg->fd, buf, to_read));
94*8d67ca89SAndroid Build Coastguard Worker     size_t num_of_value = to_read / sizeof(uint32_t);
95*8d67ca89SAndroid Build Coastguard Worker     uint32_t* p = reinterpret_cast<uint32_t*>(buf);
96*8d67ca89SAndroid Build Coastguard Worker     while (num_of_value-- > 0) {
97*8d67ca89SAndroid Build Coastguard Worker       if (*p++ != counter++) {
98*8d67ca89SAndroid Build Coastguard Worker         arg->matched = false;
99*8d67ca89SAndroid Build Coastguard Worker       }
100*8d67ca89SAndroid Build Coastguard Worker     }
101*8d67ca89SAndroid Build Coastguard Worker   }
102*8d67ca89SAndroid Build Coastguard Worker   close(arg->fd);
103*8d67ca89SAndroid Build Coastguard Worker   arg->finished = true;
104*8d67ca89SAndroid Build Coastguard Worker }
105*8d67ca89SAndroid Build Coastguard Worker 
TEST(pty,bug_28979140)106*8d67ca89SAndroid Build Coastguard Worker TEST(pty, bug_28979140) {
107*8d67ca89SAndroid Build Coastguard Worker   // This test is to test a kernel bug, which uses a lock free ring-buffer to
108*8d67ca89SAndroid Build Coastguard Worker   // pass data through a raw pty, but missing necessary memory barriers.
109*8d67ca89SAndroid Build Coastguard Worker   cpu_set_t cpus;
110*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, sched_getaffinity(0, sizeof(cpu_set_t), &cpus));
111*8d67ca89SAndroid Build Coastguard Worker   if (CPU_COUNT(&cpus) < 2) {
112*8d67ca89SAndroid Build Coastguard Worker     GTEST_SKIP() << "This bug only happens on multiprocessors";
113*8d67ca89SAndroid Build Coastguard Worker   }
114*8d67ca89SAndroid Build Coastguard Worker   constexpr uint32_t TEST_DATA_COUNT = 2000000;
115*8d67ca89SAndroid Build Coastguard Worker 
116*8d67ca89SAndroid Build Coastguard Worker   // 1. Open raw pty.
117*8d67ca89SAndroid Build Coastguard Worker   int pty;
118*8d67ca89SAndroid Build Coastguard Worker   int tty;
119*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, openpty(&pty, &tty, nullptr, nullptr, nullptr));
120*8d67ca89SAndroid Build Coastguard Worker   termios tattr;
121*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, tcgetattr(tty, &tattr));
122*8d67ca89SAndroid Build Coastguard Worker   cfmakeraw(&tattr);
123*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, tcsetattr(tty, TCSADRAIN, &tattr));
124*8d67ca89SAndroid Build Coastguard Worker 
125*8d67ca89SAndroid Build Coastguard Worker   // 2. Make two threads running on different cpus:
126*8d67ca89SAndroid Build Coastguard Worker   // pty thread uses first available cpu, and tty thread uses other cpus.
127*8d67ca89SAndroid Build Coastguard Worker   PtyReader_28979140_Arg arg;
128*8d67ca89SAndroid Build Coastguard Worker   arg.main_cpu_id = -1;
129*8d67ca89SAndroid Build Coastguard Worker   for (int i = 0; i < CPU_SETSIZE; i++) {
130*8d67ca89SAndroid Build Coastguard Worker     if (CPU_ISSET(i, &cpus)) {
131*8d67ca89SAndroid Build Coastguard Worker       arg.main_cpu_id = i;
132*8d67ca89SAndroid Build Coastguard Worker       break;
133*8d67ca89SAndroid Build Coastguard Worker     }
134*8d67ca89SAndroid Build Coastguard Worker   }
135*8d67ca89SAndroid Build Coastguard Worker   ASSERT_GE(arg.main_cpu_id, 0);
136*8d67ca89SAndroid Build Coastguard Worker 
137*8d67ca89SAndroid Build Coastguard Worker   // 3. Create thread for tty reader.
138*8d67ca89SAndroid Build Coastguard Worker   pthread_t thread;
139*8d67ca89SAndroid Build Coastguard Worker   arg.fd = tty;
140*8d67ca89SAndroid Build Coastguard Worker   arg.data_count = TEST_DATA_COUNT;
141*8d67ca89SAndroid Build Coastguard Worker   arg.matched = true;
142*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, pthread_create(&thread, nullptr,
143*8d67ca89SAndroid Build Coastguard Worker                               reinterpret_cast<void*(*)(void*)>(PtyReader_28979140),
144*8d67ca89SAndroid Build Coastguard Worker                               &arg));
145*8d67ca89SAndroid Build Coastguard Worker 
146*8d67ca89SAndroid Build Coastguard Worker   CPU_ZERO(&cpus);
147*8d67ca89SAndroid Build Coastguard Worker   CPU_SET(arg.main_cpu_id, &cpus);
148*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus));
149*8d67ca89SAndroid Build Coastguard Worker 
150*8d67ca89SAndroid Build Coastguard Worker   // 4. Send data to tty reader.
151*8d67ca89SAndroid Build Coastguard Worker   // Send a bunch of data at a time, so it is easier to catch the bug that some data isn't seen
152*8d67ca89SAndroid Build Coastguard Worker   // by the reader thread on another cpu.
153*8d67ca89SAndroid Build Coastguard Worker   uint32_t counter_buf[100];
154*8d67ca89SAndroid Build Coastguard Worker   uint32_t counter = 0;
155*8d67ca89SAndroid Build Coastguard Worker   while (counter <= TEST_DATA_COUNT) {
156*8d67ca89SAndroid Build Coastguard Worker     for (size_t i = 0; i < sizeof(counter_buf) / sizeof(counter_buf[0]); ++i) {
157*8d67ca89SAndroid Build Coastguard Worker       counter_buf[i] = counter++;
158*8d67ca89SAndroid Build Coastguard Worker     }
159*8d67ca89SAndroid Build Coastguard Worker     ASSERT_TRUE(android::base::WriteFully(pty, &counter_buf, sizeof(counter_buf)));
160*8d67ca89SAndroid Build Coastguard Worker     ASSERT_TRUE(arg.matched) << "failed at count = " << counter;
161*8d67ca89SAndroid Build Coastguard Worker   }
162*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, pthread_join(thread, nullptr));
163*8d67ca89SAndroid Build Coastguard Worker   ASSERT_TRUE(arg.finished);
164*8d67ca89SAndroid Build Coastguard Worker   ASSERT_TRUE(arg.matched);
165*8d67ca89SAndroid Build Coastguard Worker   close(pty);
166*8d67ca89SAndroid Build Coastguard Worker }
167