blob: 609f2dcc8ab842d9f4b3df64f176ab68f5862590 [file] [log] [blame]
Elliott Hughes65f0df72014-12-03 14:39:20 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Yabin Cuif35c6bc2016-06-09 16:36:28 -070017#include <pty.h>
18
Elliott Hughes65f0df72014-12-03 14:39:20 -080019#include <gtest/gtest.h>
20
Yabin Cuif35c6bc2016-06-09 16:36:28 -070021#include <pthread.h>
Elliott Hughes65f0df72014-12-03 14:39:20 -080022#include <sys/ioctl.h>
23
Yabin Cuif35c6bc2016-06-09 16:36:28 -070024#include <atomic>
25
26#include <android-base/file.h>
27
Elliott Hughes33697a02016-01-26 13:04:57 -080028#include "utils.h"
29
Elliott Hughes65f0df72014-12-03 14:39:20 -080030TEST(pty, openpty) {
31 int master, slave;
32 char name[32];
33 struct winsize w = { 123, 456, 9999, 999 };
34 ASSERT_EQ(0, openpty(&master, &slave, name, NULL, &w));
35 ASSERT_NE(-1, master);
36 ASSERT_NE(-1, slave);
37 ASSERT_NE(master, slave);
38
39 char tty_name[32];
40 ASSERT_EQ(0, ttyname_r(slave, tty_name, sizeof(tty_name)));
41 ASSERT_STREQ(tty_name, name);
42
43 struct winsize w_actual;
44 ASSERT_EQ(0, ioctl(slave, TIOCGWINSZ, &w_actual));
45 ASSERT_EQ(w_actual.ws_row, w.ws_row);
46 ASSERT_EQ(w_actual.ws_col, w.ws_col);
47 ASSERT_EQ(w_actual.ws_xpixel, w.ws_xpixel);
48 ASSERT_EQ(w_actual.ws_ypixel, w.ws_ypixel);
49
50 close(master);
51 close(slave);
52}
53
54TEST(pty, forkpty) {
55 pid_t sid = getsid(0);
56
57 int master;
58 pid_t pid = forkpty(&master, NULL, NULL, NULL);
59 ASSERT_NE(-1, pid);
60
61 if (pid == 0) {
62 // We're the child.
63 ASSERT_NE(sid, getsid(0));
64 _exit(0);
65 }
66
67 ASSERT_EQ(sid, getsid(0));
68
Elliott Hughes33697a02016-01-26 13:04:57 -080069 AssertChildExited(pid, 0);
Elliott Hughes65f0df72014-12-03 14:39:20 -080070
71 close(master);
72}
Yabin Cuif35c6bc2016-06-09 16:36:28 -070073
74struct PtyReader_28979140_Arg {
Alex Vakulenkoc14d7f02016-07-11 17:26:35 -070075 int main_cpu_id;
76 int slave_fd;
77 uint32_t data_count;
78 bool finished;
79 std::atomic<bool> matched;
Yabin Cuif35c6bc2016-06-09 16:36:28 -070080};
81
82static void PtyReader_28979140(PtyReader_28979140_Arg* arg) {
83 arg->finished = false;
84 cpu_set_t cpus;
85 ASSERT_EQ(0, sched_getaffinity(0, sizeof(cpu_set_t), &cpus));
Alex Vakulenkoc14d7f02016-07-11 17:26:35 -070086 CPU_CLR(arg->main_cpu_id, &cpus);
Yabin Cuif35c6bc2016-06-09 16:36:28 -070087 ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus));
88
89 uint32_t counter = 0;
90 while (counter <= arg->data_count) {
91 char buf[4096]; // Use big buffer to read to hit the bug more easily.
92 size_t to_read = std::min(sizeof(buf), (arg->data_count + 1 - counter) * sizeof(uint32_t));
93 ASSERT_TRUE(android::base::ReadFully(arg->slave_fd, buf, to_read));
94 size_t num_of_value = to_read / sizeof(uint32_t);
95 uint32_t* p = reinterpret_cast<uint32_t*>(buf);
96 while (num_of_value-- > 0) {
97 if (*p++ != counter++) {
98 arg->matched = false;
99 }
100 }
101 }
102 close(arg->slave_fd);
103 arg->finished = true;
104}
105
106TEST(pty, bug_28979140) {
107 // This test is to test a kernel bug, which uses a lock free ring-buffer to
108 // pass data through a raw pty, but missing necessary memory barriers.
Alex Vakulenkoc14d7f02016-07-11 17:26:35 -0700109 cpu_set_t cpus;
110 ASSERT_EQ(0, sched_getaffinity(0, sizeof(cpu_set_t), &cpus));
111 if (CPU_COUNT(&cpus) < 2) {
Yabin Cuif35c6bc2016-06-09 16:36:28 -0700112 GTEST_LOG_(INFO) << "This test tests bug happens only on multiprocessors.";
113 return;
114 }
Yabin Cui57a40062017-11-16 15:25:12 -0800115 constexpr uint32_t TEST_DATA_COUNT = 2000000;
Yabin Cuif35c6bc2016-06-09 16:36:28 -0700116
117 // 1. Open raw pty.
118 int master;
119 int slave;
120 ASSERT_EQ(0, openpty(&master, &slave, nullptr, nullptr, nullptr));
121 termios tattr;
122 ASSERT_EQ(0, tcgetattr(slave, &tattr));
123 cfmakeraw(&tattr);
124 ASSERT_EQ(0, tcsetattr(slave, TCSADRAIN, &tattr));
125
Alex Vakulenkoc14d7f02016-07-11 17:26:35 -0700126 // 2. Make master thread and slave thread running on different cpus:
127 // master thread uses first available cpu, and slave thread uses other cpus.
Yabin Cuif35c6bc2016-06-09 16:36:28 -0700128 PtyReader_28979140_Arg arg;
Alex Vakulenkoc14d7f02016-07-11 17:26:35 -0700129 arg.main_cpu_id = -1;
130 for (int i = 0; i < CPU_SETSIZE; i++) {
131 if (CPU_ISSET(i, &cpus)) {
132 arg.main_cpu_id = i;
133 break;
134 }
135 }
136 ASSERT_GE(arg.main_cpu_id, 0);
137
138 // 3. Create thread for slave reader.
139 pthread_t thread;
Yabin Cuif35c6bc2016-06-09 16:36:28 -0700140 arg.slave_fd = slave;
141 arg.data_count = TEST_DATA_COUNT;
142 arg.matched = true;
143 ASSERT_EQ(0, pthread_create(&thread, nullptr,
144 reinterpret_cast<void*(*)(void*)>(PtyReader_28979140),
145 &arg));
146
Yabin Cuif35c6bc2016-06-09 16:36:28 -0700147 CPU_ZERO(&cpus);
Alex Vakulenkoc14d7f02016-07-11 17:26:35 -0700148 CPU_SET(arg.main_cpu_id, &cpus);
Yabin Cuif35c6bc2016-06-09 16:36:28 -0700149 ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus));
150
151 // 4. Send data to slave.
Yabin Cui57a40062017-11-16 15:25:12 -0800152 // Send a bunch of data at a time, so it is easier to catch the bug that some data isn't seen
153 // by the reader thread on another cpu.
154 uint32_t counter_buf[100];
Yabin Cuif35c6bc2016-06-09 16:36:28 -0700155 uint32_t counter = 0;
156 while (counter <= TEST_DATA_COUNT) {
Yabin Cui57a40062017-11-16 15:25:12 -0800157 for (size_t i = 0; i < sizeof(counter_buf) / sizeof(counter_buf[0]); ++i) {
158 counter_buf[i] = counter++;
159 }
160 ASSERT_TRUE(android::base::WriteFully(master, &counter_buf, sizeof(counter_buf)));
Yabin Cuif35c6bc2016-06-09 16:36:28 -0700161 ASSERT_TRUE(arg.matched) << "failed at count = " << counter;
Yabin Cuif35c6bc2016-06-09 16:36:28 -0700162 }
163 ASSERT_EQ(0, pthread_join(thread, nullptr));
164 ASSERT_TRUE(arg.finished);
165 ASSERT_TRUE(arg.matched);
166 close(master);
167}