diff options
author | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-11 04:22:34 +0000 |
---|---|---|
committer | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-11 04:22:34 +0000 |
commit | 787f5e460f6265f961f88b75391edeb6eeb8a720 (patch) | |
tree | 4bd626c508e2b76b83a2d7131c832f0cac70c52c /ipc/ipc_send_fds_test.cc | |
parent | 29dd580cd7a471d5760649a8546459f31382244b (diff) | |
download | chromium_src-787f5e460f6265f961f88b75391edeb6eeb8a720.zip chromium_src-787f5e460f6265f961f88b75391edeb6eeb8a720.tar.gz chromium_src-787f5e460f6265f961f88b75391edeb6eeb8a720.tar.bz2 |
Revert 227999 "Alternative workaround for mac kernel bug."
> Alternative workaround for mac kernel bug.
>
> BUG=298276
>
> Review URL: https://codereview.chromium.org/25325002
This change seemed to cause the Mac ASAN bot to timeout when running
the ipc_tests.
TBR=hubbe@chromium.org
Review URL: https://codereview.chromium.org/26384003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@228110 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ipc/ipc_send_fds_test.cc')
-rw-r--r-- | ipc/ipc_send_fds_test.cc | 255 |
1 files changed, 29 insertions, 226 deletions
diff --git a/ipc/ipc_send_fds_test.cc b/ipc/ipc_send_fds_test.cc index 20c3ed5..4cddc1c 100644 --- a/ipc/ipc_send_fds_test.cc +++ b/ipc/ipc_send_fds_test.cc @@ -11,18 +11,13 @@ extern "C" { } #endif #include <fcntl.h> -#include <sys/socket.h> #include <sys/stat.h> #include <unistd.h> -#include <queue> - -#include "base/callback.h" #include "base/file_descriptor_posix.h" #include "base/message_loop/message_loop.h" #include "base/pickle.h" #include "base/posix/eintr_wrapper.h" -#include "base/synchronization/waitable_event.h" #include "ipc/ipc_message_utils.h" #include "ipc/ipc_test_base.h" @@ -31,59 +26,50 @@ namespace { const unsigned kNumFDsToSend = 20; const char* kDevZeroPath = "/dev/zero"; -class MyChannelDescriptorListenerBase : public IPC::Listener { +static void VerifyAndCloseDescriptor(int fd, ino_t inode_num) { + // Check that we can read from the FD. + char buf; + ssize_t amt_read = read(fd, &buf, 1); + ASSERT_EQ(amt_read, 1); + ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes. + + struct stat st; + ASSERT_EQ(fstat(fd, &st), 0); + + ASSERT_EQ(close(fd), 0); + + // Compare inode numbers to check that the file sent over the wire is actually + // the one expected. + ASSERT_EQ(inode_num, st.st_ino); +} + +class MyChannelDescriptorListener : public IPC::Listener { public: + explicit MyChannelDescriptorListener(ino_t expected_inode_num) + : expected_inode_num_(expected_inode_num), + num_fds_received_(0) {} + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { PickleIterator iter(message); + ++num_fds_received_; base::FileDescriptor descriptor; IPC::ParamTraits<base::FileDescriptor>::Read(&message, &iter, &descriptor); - HandleFD(descriptor.fd); - return true; - } - - protected: - virtual void HandleFD(int fd) = 0; -}; - -class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase { - public: - explicit MyChannelDescriptorListener(ino_t expected_inode_num) - : MyChannelDescriptorListenerBase(), - expected_inode_num_(expected_inode_num), - num_fds_received_(0) { - } + VerifyAndCloseDescriptor(descriptor.fd, expected_inode_num_); + if (num_fds_received_ == kNumFDsToSend) + base::MessageLoop::current()->Quit(); - bool GotExpectedNumberOfDescriptors() const { - return num_fds_received_ == kNumFDsToSend; + return true; } virtual void OnChannelError() OVERRIDE { base::MessageLoop::current()->Quit(); } - protected: - virtual void HandleFD(int fd) OVERRIDE { - // Check that we can read from the FD. - char buf; - ssize_t amt_read = read(fd, &buf, 1); - ASSERT_EQ(amt_read, 1); - ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes. - - struct stat st; - ASSERT_EQ(fstat(fd, &st), 0); - - ASSERT_EQ(close(fd), 0); - - // Compare inode numbers to check that the file sent over the wire is - // actually the one expected. - ASSERT_EQ(expected_inode_num_, st.st_ino); - - ++num_fds_received_; - if (num_fds_received_ == kNumFDsToSend) - base::MessageLoop::current()->Quit(); + bool GotExpectedNumberOfDescriptors() const { + return num_fds_received_ == kNumFDsToSend; } private: @@ -91,7 +77,6 @@ class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase { unsigned num_fds_received_; }; - class IPCSendFdsTest : public IPCTestBase { protected: void RunServer() { @@ -193,188 +178,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient) { } #endif // defined(OS_MACOSX) - -class MyCBListener : public MyChannelDescriptorListenerBase { - public: - MyCBListener(base::Callback<void(int)> cb, int fds_to_send) - : MyChannelDescriptorListenerBase(), - cb_(cb) { - } - - protected: - virtual 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.reset(new IPC::Channel(in_handle, - IPC::Channel::MODE_SERVER, - &null_listener_)); - base::FileDescriptor out_fd(in->TakeClientFileDescriptor(), false); - IPC::ChannelHandle out_handle("OUT", out_fd); - out.reset(new IPC::Channel(out_handle, - IPC::Channel::MODE_CLIENT, - &cb_listener_)); - // PostTask the connect calls to make sure the callbacks happens - // on the right threads. - in_thread_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&PipeChannelHelper::Connect, in.get())); - out_thread_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&PipeChannelHelper::Connect, out.get())); - } - - static void DestroyChannel(scoped_ptr<IPC::Channel> *c, - base::WaitableEvent *event) { - c->reset(0); - event->Signal(); - } - - ~PipeChannelHelper() { - base::WaitableEvent a(true, false); - base::WaitableEvent b(true, false); - in_thread_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&PipeChannelHelper::DestroyChannel, &in, &a)); - out_thread_->message_loop()->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: - scoped_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_(true, false) {} - - 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->message_loop()->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, HANDLE_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, HANDLE_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; - scoped_ptr<base::Thread> producer(CreateThread("producer")); - scoped_ptr<base::Thread> middleman(CreateThread("middleman")); - scoped_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) |