2019-04-29 21:25:05 +00:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-12-10 22:41:40 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/epoll.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
2019-01-29 16:00:33 +00:00
|
|
|
#include "test/util/epoll_util.h"
|
|
|
|
#include "test/util/eventfd_util.h"
|
2018-12-10 22:41:40 +00:00
|
|
|
#include "test/util/test_util.h"
|
|
|
|
#include "test/util/thread_util.h"
|
|
|
|
|
|
|
|
namespace gvisor {
|
|
|
|
namespace testing {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
TEST(EventfdTest, Nonblock) {
|
2019-01-29 16:00:33 +00:00
|
|
|
FileDescriptor efd =
|
|
|
|
ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
uint64_t l;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(read(efd.get(), &l, sizeof(l)), SyscallFailsWithErrno(EAGAIN));
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
l = 1;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(write(efd.get(), &l, sizeof(l)), SyscallSucceeds());
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
l = 0;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(read(efd.get(), &l, sizeof(l)), SyscallSucceeds());
|
2018-12-10 22:41:40 +00:00
|
|
|
EXPECT_EQ(l, 1);
|
|
|
|
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(read(efd.get(), &l, sizeof(l)), SyscallFailsWithErrno(EAGAIN));
|
2018-12-10 22:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void* read_three_times(void* arg) {
|
|
|
|
int efd = *reinterpret_cast<int*>(arg);
|
|
|
|
uint64_t l;
|
2019-06-18 23:20:42 +00:00
|
|
|
EXPECT_THAT(read(efd, &l, sizeof(l)), SyscallSucceedsWithValue(sizeof(l)));
|
|
|
|
EXPECT_THAT(read(efd, &l, sizeof(l)), SyscallSucceedsWithValue(sizeof(l)));
|
|
|
|
EXPECT_THAT(read(efd, &l, sizeof(l)), SyscallSucceedsWithValue(sizeof(l)));
|
2018-12-10 22:41:40 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(EventfdTest, BlockingWrite) {
|
2019-01-29 16:00:33 +00:00
|
|
|
FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_SEMAPHORE));
|
|
|
|
int efd = fd.get();
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
pthread_t p;
|
|
|
|
ASSERT_THAT(pthread_create(&p, nullptr, read_three_times,
|
|
|
|
reinterpret_cast<void*>(&efd)),
|
|
|
|
SyscallSucceeds());
|
|
|
|
|
|
|
|
uint64_t l = 1;
|
|
|
|
ASSERT_THAT(write(efd, &l, sizeof(l)), SyscallSucceeds());
|
|
|
|
EXPECT_EQ(l, 1);
|
|
|
|
|
|
|
|
ASSERT_THAT(write(efd, &l, sizeof(l)), SyscallSucceeds());
|
|
|
|
EXPECT_EQ(l, 1);
|
|
|
|
|
|
|
|
ASSERT_THAT(write(efd, &l, sizeof(l)), SyscallSucceeds());
|
|
|
|
EXPECT_EQ(l, 1);
|
|
|
|
|
|
|
|
ASSERT_THAT(pthread_join(p, nullptr), SyscallSucceeds());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(EventfdTest, SmallWrite) {
|
2019-01-29 16:00:33 +00:00
|
|
|
FileDescriptor efd =
|
|
|
|
ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
uint64_t l = 16;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(write(efd.get(), &l, 4), SyscallFailsWithErrno(EINVAL));
|
2018-12-10 22:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(EventfdTest, SmallRead) {
|
2019-01-29 16:00:33 +00:00
|
|
|
FileDescriptor efd =
|
|
|
|
ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
uint64_t l = 1;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(write(efd.get(), &l, sizeof(l)), SyscallSucceeds());
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
l = 0;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(read(efd.get(), &l, 4), SyscallFailsWithErrno(EINVAL));
|
2018-12-10 22:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(EventfdTest, BigWrite) {
|
2019-01-29 16:00:33 +00:00
|
|
|
FileDescriptor efd =
|
|
|
|
ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
uint64_t big[16];
|
|
|
|
big[0] = 16;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(write(efd.get(), big, sizeof(big)), SyscallSucceeds());
|
2018-12-10 22:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(EventfdTest, BigRead) {
|
2019-01-29 16:00:33 +00:00
|
|
|
FileDescriptor efd =
|
|
|
|
ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
uint64_t l = 1;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(write(efd.get(), &l, sizeof(l)), SyscallSucceeds());
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
uint64_t big[16];
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(read(efd.get(), big, sizeof(big)), SyscallSucceeds());
|
2018-12-10 22:41:40 +00:00
|
|
|
EXPECT_EQ(big[0], 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(EventfdTest, BigWriteBigRead) {
|
2019-01-29 16:00:33 +00:00
|
|
|
FileDescriptor efd =
|
|
|
|
ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_NONBLOCK | EFD_SEMAPHORE));
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
uint64_t l[16];
|
|
|
|
l[0] = 16;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(write(efd.get(), l, sizeof(l)), SyscallSucceeds());
|
|
|
|
ASSERT_THAT(read(efd.get(), l, sizeof(l)), SyscallSucceeds());
|
2018-12-10 22:41:40 +00:00
|
|
|
EXPECT_EQ(l[0], 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// NotifyNonZero is inherently racy, so random save is disabled.
|
|
|
|
TEST(EventfdTest, NotifyNonZero_NoRandomSave) {
|
|
|
|
// Waits will time out at 10 seconds.
|
|
|
|
constexpr int kEpollTimeoutMs = 10000;
|
|
|
|
// Create an eventfd descriptor.
|
2019-01-29 16:00:33 +00:00
|
|
|
FileDescriptor efd =
|
|
|
|
ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(7, EFD_NONBLOCK | EFD_SEMAPHORE));
|
2018-12-10 22:41:40 +00:00
|
|
|
// Create an epoll fd to listen to efd.
|
2019-01-29 16:00:33 +00:00
|
|
|
FileDescriptor epollfd = ASSERT_NO_ERRNO_AND_VALUE(NewEpollFD());
|
2018-12-10 22:41:40 +00:00
|
|
|
// Add efd to epoll.
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_NO_ERRNO(
|
|
|
|
RegisterEpollFD(epollfd.get(), efd.get(), EPOLLIN | EPOLLET, efd.get()));
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
// Use epoll to get a value from efd.
|
|
|
|
struct epoll_event out_ev;
|
2019-01-29 16:00:33 +00:00
|
|
|
int wait_out = epoll_wait(epollfd.get(), &out_ev, 1, kEpollTimeoutMs);
|
2018-12-10 22:41:40 +00:00
|
|
|
EXPECT_EQ(wait_out, 1);
|
2019-01-29 16:00:33 +00:00
|
|
|
EXPECT_EQ(efd.get(), out_ev.data.fd);
|
2018-12-10 22:41:40 +00:00
|
|
|
uint64_t val = 0;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(read(efd.get(), &val, sizeof(val)), SyscallSucceeds());
|
2018-12-10 22:41:40 +00:00
|
|
|
EXPECT_EQ(val, 1);
|
|
|
|
|
|
|
|
// Start a thread that, after this thread blocks on epoll_wait, will write to
|
|
|
|
// efd. This is racy -- it's possible that this write will happen after
|
|
|
|
// epoll_wait times out.
|
2019-01-29 16:00:33 +00:00
|
|
|
ScopedThread t([&efd] {
|
2018-12-10 22:41:40 +00:00
|
|
|
sleep(5);
|
|
|
|
uint64_t val = 1;
|
2019-06-18 23:20:42 +00:00
|
|
|
EXPECT_THAT(write(efd.get(), &val, sizeof(val)),
|
|
|
|
SyscallSucceedsWithValue(sizeof(val)));
|
2018-12-10 22:41:40 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// epoll_wait should return once the thread writes.
|
2019-01-29 16:00:33 +00:00
|
|
|
wait_out = epoll_wait(epollfd.get(), &out_ev, 1, kEpollTimeoutMs);
|
2018-12-10 22:41:40 +00:00
|
|
|
EXPECT_EQ(wait_out, 1);
|
2019-01-29 16:00:33 +00:00
|
|
|
EXPECT_EQ(efd.get(), out_ev.data.fd);
|
2018-12-10 22:41:40 +00:00
|
|
|
|
|
|
|
val = 0;
|
2019-01-29 16:00:33 +00:00
|
|
|
ASSERT_THAT(read(efd.get(), &val, sizeof(val)), SyscallSucceeds());
|
2018-12-10 22:41:40 +00:00
|
|
|
EXPECT_EQ(val, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
} // namespace testing
|
|
|
|
} // namespace gvisor
|