| Index: ipc/ipc_send_fds_test.cc
|
| diff --git a/ipc/ipc_send_fds_test.cc b/ipc/ipc_send_fds_test.cc
|
| index 635b80a6365e124b5a53269fb5aaea10d34160ae..f648b6411ab27c9c6e150f700e89adb00949feb6 100644
|
| --- a/ipc/ipc_send_fds_test.cc
|
| +++ b/ipc/ipc_send_fds_test.cc
|
| @@ -213,182 +213,6 @@ DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(
|
| }
|
| #endif // defined(OS_MACOSX)
|
|
|
| -
|
| -class MyCBListener : public MyChannelDescriptorListenerBase {
|
| - public:
|
| - MyCBListener(base::Callback<void(int)> cb, int fds_to_send)
|
| - : MyChannelDescriptorListenerBase(),
|
| - cb_(cb) {
|
| - }
|
| -
|
| - protected:
|
| - void HandleFD(int fd) override { cb_.Run(fd); }
|
| - private:
|
| - base::Callback<void(int)> cb_;
|
| -};
|
| -
|
| -std::pair<int, int> make_socket_pair() {
|
| - int pipe_fds[2];
|
| - CHECK_EQ(0, HANDLE_EINTR(socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds)));
|
| - return std::pair<int, int>(pipe_fds[0], pipe_fds[1]);
|
| -}
|
| -
|
| -static void null_cb(int unused_fd) {
|
| - NOTREACHED();
|
| -}
|
| -
|
| -class PipeChannelHelper {
|
| - public:
|
| - PipeChannelHelper(base::Thread* in_thread,
|
| - base::Thread* out_thread,
|
| - base::Callback<void(int)> cb,
|
| - int fds_to_send) :
|
| - in_thread_(in_thread),
|
| - out_thread_(out_thread),
|
| - cb_listener_(cb, fds_to_send),
|
| - null_listener_(base::Bind(&null_cb), 0) {
|
| - }
|
| -
|
| - void Init() {
|
| - IPC::ChannelHandle in_handle("IN");
|
| - in = IPC::Channel::CreateServer(
|
| - in_handle, &null_listener_, in_thread_->task_runner());
|
| - IPC::ChannelHandle out_handle(
|
| - "OUT", base::FileDescriptor(in->TakeClientFileDescriptor()));
|
| - out = IPC::Channel::CreateClient(
|
| - out_handle, &cb_listener_, out_thread_->task_runner());
|
| - // PostTask the connect calls to make sure the callbacks happens
|
| - // on the right threads.
|
| - in_thread_->task_runner()->PostTask(
|
| - FROM_HERE, base::Bind(&PipeChannelHelper::Connect, in.get()));
|
| - out_thread_->task_runner()->PostTask(
|
| - FROM_HERE, base::Bind(&PipeChannelHelper::Connect, out.get()));
|
| - }
|
| -
|
| - static void DestroyChannel(std::unique_ptr<IPC::Channel>* c,
|
| - base::WaitableEvent* event) {
|
| - c->reset(0);
|
| - event->Signal();
|
| - }
|
| -
|
| - ~PipeChannelHelper() {
|
| - base::WaitableEvent a(base::WaitableEvent::ResetPolicy::MANUAL,
|
| - base::WaitableEvent::InitialState::NOT_SIGNALED);
|
| - base::WaitableEvent b(base::WaitableEvent::ResetPolicy::MANUAL,
|
| - base::WaitableEvent::InitialState::NOT_SIGNALED);
|
| - in_thread_->task_runner()->PostTask(
|
| - FROM_HERE, base::Bind(&PipeChannelHelper::DestroyChannel, &in, &a));
|
| - out_thread_->task_runner()->PostTask(
|
| - FROM_HERE, base::Bind(&PipeChannelHelper::DestroyChannel, &out, &b));
|
| - a.Wait();
|
| - b.Wait();
|
| - }
|
| -
|
| - static void Connect(IPC::Channel *channel) {
|
| - EXPECT_TRUE(channel->Connect());
|
| - }
|
| -
|
| - void Send(int fd) {
|
| - CHECK_EQ(base::MessageLoop::current(), in_thread_->message_loop());
|
| -
|
| - ASSERT_GE(fd, 0);
|
| - base::FileDescriptor descriptor(fd, true);
|
| -
|
| - IPC::Message* message =
|
| - new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL);
|
| - IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
|
| - ASSERT_TRUE(in->Send(message));
|
| - }
|
| -
|
| - private:
|
| - std::unique_ptr<IPC::Channel> in, out;
|
| - base::Thread* in_thread_;
|
| - base::Thread* out_thread_;
|
| - MyCBListener cb_listener_;
|
| - MyCBListener null_listener_;
|
| -};
|
| -
|
| -// This test is meant to provoke a kernel bug on OSX, and to prove
|
| -// that the workaround for it is working. It sets up two pipes and three
|
| -// threads, the producer thread creates socketpairs and sends one of the fds
|
| -// over pipe1 to the middleman thread. The middleman thread simply takes the fd
|
| -// sends it over pipe2 to the consumer thread. The consumer thread writes a byte
|
| -// to each fd it receives and then closes the pipe. The producer thread reads
|
| -// the bytes back from each pair of pipes and make sure that everything worked.
|
| -// This feedback mechanism makes sure that not too many file descriptors are
|
| -// in flight at the same time. For more info on the bug, see:
|
| -// http://crbug.com/298276
|
| -class IPCMultiSendingFdsTest : public testing::Test {
|
| - public:
|
| - IPCMultiSendingFdsTest()
|
| - : received_(base::WaitableEvent::ResetPolicy::MANUAL,
|
| - base::WaitableEvent::InitialState::NOT_SIGNALED) {}
|
| -
|
| - void Producer(PipeChannelHelper* dest,
|
| - base::Thread* t,
|
| - int pipes_to_send) {
|
| - for (int i = 0; i < pipes_to_send; i++) {
|
| - received_.Reset();
|
| - std::pair<int, int> pipe_fds = make_socket_pair();
|
| - t->task_runner()->PostTask(
|
| - FROM_HERE, base::Bind(&PipeChannelHelper::Send,
|
| - base::Unretained(dest), pipe_fds.second));
|
| - char tmp = 'x';
|
| - CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds.first, &tmp, 1)));
|
| - CHECK_EQ(0, IGNORE_EINTR(close(pipe_fds.first)));
|
| - received_.Wait();
|
| - }
|
| - }
|
| -
|
| - void ConsumerHandleFD(int fd) {
|
| - char tmp = 'y';
|
| - CHECK_EQ(1, HANDLE_EINTR(read(fd, &tmp, 1)));
|
| - CHECK_EQ(tmp, 'x');
|
| - CHECK_EQ(0, IGNORE_EINTR(close(fd)));
|
| - received_.Signal();
|
| - }
|
| -
|
| - base::Thread* CreateThread(const char* name) {
|
| - base::Thread* ret = new base::Thread(name);
|
| - base::Thread::Options options;
|
| - options.message_loop_type = base::MessageLoop::TYPE_IO;
|
| - ret->StartWithOptions(options);
|
| - return ret;
|
| - }
|
| -
|
| - void Run() {
|
| - // On my mac, this test fails roughly 35 times per
|
| - // million sends with low load, but much more with high load.
|
| - // Unless the workaround is in place. With 10000 sends, we
|
| - // should see at least a 3% failure rate.
|
| - const int pipes_to_send = 20000;
|
| - std::unique_ptr<base::Thread> producer(CreateThread("producer"));
|
| - std::unique_ptr<base::Thread> middleman(CreateThread("middleman"));
|
| - std::unique_ptr<base::Thread> consumer(CreateThread("consumer"));
|
| - PipeChannelHelper pipe1(
|
| - middleman.get(),
|
| - consumer.get(),
|
| - base::Bind(&IPCMultiSendingFdsTest::ConsumerHandleFD,
|
| - base::Unretained(this)),
|
| - pipes_to_send);
|
| - PipeChannelHelper pipe2(
|
| - producer.get(),
|
| - middleman.get(),
|
| - base::Bind(&PipeChannelHelper::Send, base::Unretained(&pipe1)),
|
| - pipes_to_send);
|
| - pipe1.Init();
|
| - pipe2.Init();
|
| - Producer(&pipe2, producer.get(), pipes_to_send);
|
| - }
|
| -
|
| - private:
|
| - base::WaitableEvent received_;
|
| -};
|
| -
|
| -TEST_F(IPCMultiSendingFdsTest, StressTest) {
|
| - Run();
|
| -}
|
| -
|
| } // namespace
|
|
|
| #endif // defined(OS_POSIX)
|
|
|