summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux/flock.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls/linux/flock.cc')
-rw-r--r--test/syscalls/linux/flock.cc714
1 files changed, 0 insertions, 714 deletions
diff --git a/test/syscalls/linux/flock.cc b/test/syscalls/linux/flock.cc
deleted file mode 100644
index 686b779be..000000000
--- a/test/syscalls/linux/flock.cc
+++ /dev/null
@@ -1,714 +0,0 @@
-// Copyright 2018 The gVisor Authors.
-//
-// 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 <sys/file.h>
-
-#include <string>
-
-#include "gtest/gtest.h"
-#include "absl/time/clock.h"
-#include "absl/time/time.h"
-#include "test/syscalls/linux/file_base.h"
-#include "test/util/file_descriptor.h"
-#include "test/util/socket_util.h"
-#include "test/util/temp_path.h"
-#include "test/util/test_util.h"
-#include "test/util/thread_util.h"
-#include "test/util/timer_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class FlockTest : public FileTest {};
-
-TEST_F(FlockTest, InvalidOpCombinations) {
- // The operation cannot be both exclusive and shared.
- EXPECT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_SH | LOCK_NB),
- SyscallFailsWithErrno(EINVAL));
-
- // Locking and Unlocking doesn't make sense.
- EXPECT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_UN | LOCK_NB),
- SyscallFailsWithErrno(EINVAL));
- EXPECT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_UN | LOCK_NB),
- SyscallFailsWithErrno(EINVAL));
-}
-
-TEST_F(FlockTest, NoOperationSpecified) {
- // Not specifying an operation is invalid.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB),
- SyscallFailsWithErrno(EINVAL));
-}
-
-TEST_F(FlockTest, TestSimpleExLock) {
- // Test that we can obtain an exclusive lock (no other holders)
- // and that we can unlock it.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestSimpleShLock) {
- // Test that we can obtain a shared lock (no other holders)
- // and that we can unlock it.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestLockableAnyMode) {
- // flock(2): A shared or exclusive lock can be placed on a file
- // regardless of the mode in which the file was opened.
- const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(
- Open(test_file_name_, O_RDONLY)); // open read only to test
-
- // Mode shouldn't prevent us from taking an exclusive lock.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceedsWithValue(0));
-
- // Unlock
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestUnlockWithNoHolders) {
- // Test that unlocking when no one holds a lock succeeeds.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestRepeatedExLockingBySameHolder) {
- // Test that repeated locking by the same holder for the
- // same type of lock works correctly.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_EX),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_EX),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestRepeatedExLockingSingleUnlock) {
- // Test that repeated locking by the same holder for the
- // same type of lock works correctly and that a single unlock is required.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_EX),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_EX),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDONLY));
-
- // Should be unlocked at this point
- ASSERT_THAT(flock(fd.get(), LOCK_NB | LOCK_EX), SyscallSucceedsWithValue(0));
-
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestRepeatedShLockingBySameHolder) {
- // Test that repeated locking by the same holder for the
- // same type of lock works correctly.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_SH),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_SH),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestSingleHolderUpgrade) {
- // Test that a shared lock is upgradable when no one else holds a lock.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_SH),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_EX),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestSingleHolderDowngrade) {
- // Test single holder lock downgrade case.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB),
- SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestMultipleShared) {
- // This is a simple test to verify that multiple independent shared
- // locks will be granted.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // A shared lock should be granted as there only exists other shared locks.
- ASSERT_THAT(flock(fd.get(), LOCK_SH | LOCK_NB), SyscallSucceedsWithValue(0));
-
- // Unlock both.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-/*
- * flock(2): If a process uses open(2) (or similar) to obtain more than one
- * descriptor for the same file, these descriptors are treated
- * independently by flock(). An attempt to lock the file using one of
- * these file descriptors may be denied by a lock that the calling process
- * has already placed via another descriptor.
- */
-TEST_F(FlockTest, TestMultipleHolderSharedExclusive) {
- // This test will verify that an exclusive lock will not be granted
- // while a shared is held.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Verify We're unable to get an exlcusive lock via the second FD.
- // because someone is holding a shared lock.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB),
- SyscallFailsWithErrno(EWOULDBLOCK));
-
- // Unlock
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestSharedLockFailExclusiveHolderNonblocking) {
- // This test will verify that a shared lock is denied while
- // someone holds an exclusive lock.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Verify we're unable to get an shared lock via the second FD.
- // because someone is holding an exclusive lock.
- ASSERT_THAT(flock(fd.get(), LOCK_SH | LOCK_NB),
- SyscallFailsWithErrno(EWOULDBLOCK));
-
- // Unlock
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-void trivial_handler(int signum) {}
-
-TEST_F(FlockTest, TestSharedLockFailExclusiveHolderBlocking) {
- const DisableSave ds; // Timing-related.
-
- // This test will verify that a shared lock is denied while
- // someone holds an exclusive lock.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Make sure that a blocking flock() call will return EINTR when interrupted
- // by a signal. Create a timer that will go off while blocking on flock(), and
- // register the corresponding signal handler.
- auto timer = ASSERT_NO_ERRNO_AND_VALUE(
- TimerCreate(CLOCK_MONOTONIC, sigevent_t{
- .sigev_signo = SIGALRM,
- .sigev_notify = SIGEV_SIGNAL,
- }));
-
- struct sigaction act = {};
- act.sa_handler = trivial_handler;
- ASSERT_THAT(sigaction(SIGALRM, &act, NULL), SyscallSucceeds());
-
- // Now that the signal handler is registered, set the timer. Set an interval
- // so that it's ok if the timer goes off before we call flock.
- ASSERT_NO_ERRNO(
- timer.Set(0, itimerspec{
- .it_interval = absl::ToTimespec(absl::Milliseconds(10)),
- .it_value = absl::ToTimespec(absl::Milliseconds(10)),
- }));
-
- ASSERT_THAT(flock(fd.get(), LOCK_SH), SyscallFailsWithErrno(EINTR));
- timer.reset();
-
- // Unlock
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestExclusiveLockFailExclusiveHolderNonblocking) {
- // This test will verify that an exclusive lock is denied while
- // someone already holds an exclsuive lock.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Verify we're unable to get an exclusive lock via the second FD
- // because someone is already holding an exclusive lock.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB),
- SyscallFailsWithErrno(EWOULDBLOCK));
-
- // Unlock
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestExclusiveLockFailExclusiveHolderBlocking) {
- const DisableSave ds; // Timing-related.
-
- // This test will verify that an exclusive lock is denied while
- // someone already holds an exclsuive lock.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Make sure that a blocking flock() call will return EINTR when interrupted
- // by a signal. Create a timer that will go off while blocking on flock(), and
- // register the corresponding signal handler.
- auto timer = ASSERT_NO_ERRNO_AND_VALUE(
- TimerCreate(CLOCK_MONOTONIC, sigevent_t{
- .sigev_signo = SIGALRM,
- .sigev_notify = SIGEV_SIGNAL,
- }));
-
- struct sigaction act = {};
- act.sa_handler = trivial_handler;
- ASSERT_THAT(sigaction(SIGALRM, &act, NULL), SyscallSucceeds());
-
- // Now that the signal handler is registered, set the timer. Set an interval
- // so that it's ok if the timer goes off before we call flock.
- ASSERT_NO_ERRNO(
- timer.Set(0, itimerspec{
- .it_interval = absl::ToTimespec(absl::Milliseconds(10)),
- .it_value = absl::ToTimespec(absl::Milliseconds(10)),
- }));
-
- ASSERT_THAT(flock(fd.get(), LOCK_EX), SyscallFailsWithErrno(EINTR));
- timer.reset();
-
- // Unlock
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestMultipleHolderSharedExclusiveUpgrade) {
- // This test will verify that we cannot obtain an exclusive lock while
- // a shared lock is held by another descriptor, then verify that an upgrade
- // is possible on a shared lock once all other shared locks have closed.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Verify we're unable to get an exclusive lock via the second FD because
- // a shared lock is held.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB),
- SyscallFailsWithErrno(EWOULDBLOCK));
-
- // Verify that we can get a shared lock via the second descriptor instead
- ASSERT_THAT(flock(fd.get(), LOCK_SH | LOCK_NB), SyscallSucceedsWithValue(0));
-
- // Unlock the first and there will only be one shared lock remaining.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-
- // Upgrade 2nd fd.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceedsWithValue(0));
-
- // Finally unlock the second
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestMultipleHolderSharedExclusiveDowngrade) {
- // This test will verify that a shared lock is not obtainable while an
- // exclusive lock is held but that once the first is downgraded that
- // the second independent file descriptor can also get a shared lock.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Verify We're unable to get a shared lock via the second FD because
- // an exclusive lock is held.
- ASSERT_THAT(flock(fd.get(), LOCK_SH | LOCK_NB),
- SyscallFailsWithErrno(EWOULDBLOCK));
-
- // Verify that we can downgrade the first.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- // Now verify that we can obtain a shared lock since the first was downgraded.
- ASSERT_THAT(flock(fd.get(), LOCK_SH | LOCK_NB), SyscallSucceedsWithValue(0));
-
- // Finally unlock both.
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-/*
- * flock(2): Locks created by flock() are associated with an open file table
- * entry. This means that duplicate file descriptors (created by, for example,
- * fork(2) or dup(2)) refer to the same lock, and this lock may be modified or
- * released using any of these descriptors. Furthermore, the lock is released
- * either by an explicit LOCK_UN operation on any of these duplicate descriptors
- * or when all such descriptors have been closed.
- */
-TEST_F(FlockTest, TestDupFdUpgrade) {
- // This test will verify that a shared lock is upgradeable via a dupped
- // file descriptor, if the FD wasn't dupped this would fail.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor dup_fd = ASSERT_NO_ERRNO_AND_VALUE(test_file_fd_.Dup());
-
- // Now we should be able to upgrade via the dupped fd.
- ASSERT_THAT(flock(dup_fd.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- // Validate unlock via dupped fd.
- ASSERT_THAT(flock(dup_fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestDupFdDowngrade) {
- // This test will verify that a exclusive lock is downgradable via a dupped
- // file descriptor, if the FD wasn't dupped this would fail.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor dup_fd = ASSERT_NO_ERRNO_AND_VALUE(test_file_fd_.Dup());
-
- // Now we should be able to downgrade via the dupped fd.
- ASSERT_THAT(flock(dup_fd.get(), LOCK_SH | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- // Validate unlock via dupped fd
- ASSERT_THAT(flock(dup_fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestDupFdCloseRelease) {
- // flock(2): Furthermore, the lock is released either by an explicit LOCK_UN
- // operation on any of these duplicate descriptors, or when all such
- // descriptors have been closed.
- //
- // This test will verify that a dupped fd closing will not release the
- // underlying lock until all such dupped fds have closed.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- FileDescriptor dup_fd = ASSERT_NO_ERRNO_AND_VALUE(test_file_fd_.Dup());
-
- // At this point we have ONE exclusive locked referenced by two different fds.
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Validate that we cannot get a lock on a new unrelated FD.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB),
- SyscallFailsWithErrno(EWOULDBLOCK));
-
- // Closing the dupped fd shouldn't affect the lock until all are closed.
- dup_fd.reset(); // Closed the duped fd.
-
- // Validate that we still cannot get a lock on a new unrelated FD.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB),
- SyscallFailsWithErrno(EWOULDBLOCK));
-
- // Closing the first fd
- CloseFile(); // Will validate the syscall succeeds.
-
- // Now we should actually be able to get a lock since all fds related to
- // the first lock are closed.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceedsWithValue(0));
-
- // Unlock.
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestDupFdUnlockRelease) {
- /* flock(2): Furthermore, the lock is released either by an explicit LOCK_UN
- * operation on any of these duplicate descriptors, or when all such
- * descriptors have been closed.
- */
- // This test will verify that an explict unlock on a dupped FD will release
- // the underlying lock unlike the previous case where close on a dup was
- // not enough to release the lock.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
- SyscallSucceedsWithValue(0));
-
- const FileDescriptor dup_fd = ASSERT_NO_ERRNO_AND_VALUE(test_file_fd_.Dup());
-
- // At this point we have ONE exclusive locked referenced by two different fds.
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Validate that we cannot get a lock on a new unrelated FD.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB),
- SyscallFailsWithErrno(EWOULDBLOCK));
-
- // Explicitly unlock via the dupped descriptor.
- ASSERT_THAT(flock(dup_fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-
- // Validate that we can now get the lock since we explicitly unlocked.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceedsWithValue(0));
-
- // Unlock
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(FlockTest, TestDupFdFollowedByLock) {
- // This test will verify that taking a lock on a file descriptor that has
- // already been dupped means that the lock is shared between both. This is
- // slightly different than than duping on an already locked FD.
- FileDescriptor dup_fd = ASSERT_NO_ERRNO_AND_VALUE(test_file_fd_.Dup());
-
- // Take a lock.
- ASSERT_THAT(flock(dup_fd.get(), LOCK_EX | LOCK_NB), SyscallSucceeds());
-
- // Now dup_fd and test_file_ should both reference the same lock.
- // We shouldn't be able to obtain a lock until both are closed.
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Closing the first fd
- dup_fd.reset(); // Close the duped fd.
-
- // Validate that we cannot get a lock yet because the dupped descriptor.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB),
- SyscallFailsWithErrno(EWOULDBLOCK));
-
- // Closing the second fd.
- CloseFile(); // CloseFile() will validate the syscall succeeds.
-
- // Now we should be able to get the lock.
- ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceeds());
-
- // Unlock.
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0));
-}
-
-// NOTE: These blocking tests are not perfect. Unfortunately it's very hard to
-// determine if a thread was actually blocked in the kernel so we're forced
-// to use timing.
-TEST_F(FlockTest, BlockingLockNoBlockingForSharedLocks) {
- // This test will verify that although LOCK_NB isn't specified
- // two different fds can obtain shared locks without blocking.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH), SyscallSucceeds());
-
- // kHoldLockTime is the amount of time we will hold the lock before releasing.
- constexpr absl::Duration kHoldLockTime = absl::Seconds(30);
-
- const DisableSave ds; // Timing-related.
-
- // We do this in another thread so we can determine if it was actually
- // blocked by timing the amount of time it took for the syscall to complete.
- ScopedThread t([&] {
- MonotonicTimer timer;
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // Only a single shared lock is held, the lock will be granted immediately.
- // This should be granted without any blocking. Don't save here to avoid
- // wild discrepencies on timing.
- timer.Start();
- ASSERT_THAT(flock(fd.get(), LOCK_SH), SyscallSucceeds());
-
- // We held the lock for 30 seconds but this thread should not have
- // blocked at all so we expect a very small duration on syscall completion.
- ASSERT_LT(timer.Duration(),
- absl::Seconds(1)); // 1000ms is much less than 30s.
-
- // We can release our second shared lock
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceeds());
- });
-
- // Sleep before unlocking.
- absl::SleepFor(kHoldLockTime);
-
- // Release the first shared lock. Don't save in this situation to avoid
- // discrepencies in timing.
- EXPECT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceeds());
-}
-
-TEST_F(FlockTest, BlockingLockFirstSharedSecondExclusive) {
- // This test will verify that if someone holds a shared lock any attempt to
- // obtain an exclusive lock will result in blocking.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH), SyscallSucceeds());
-
- // kHoldLockTime is the amount of time we will hold the lock before releasing.
- constexpr absl::Duration kHoldLockTime = absl::Seconds(2);
-
- const DisableSave ds; // Timing-related.
-
- // We do this in another thread so we can determine if it was actually
- // blocked by timing the amount of time it took for the syscall to complete.
- ScopedThread t([&] {
- MonotonicTimer timer;
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // This exclusive lock should block because someone is already holding a
- // shared lock. We don't save here to avoid wild discrepencies on timing.
- timer.Start();
- ASSERT_THAT(RetryEINTR(flock)(fd.get(), LOCK_EX), SyscallSucceeds());
-
- // We should be blocked, we will expect to be blocked for more than 1.0s.
- ASSERT_GT(timer.Duration(), absl::Seconds(1));
-
- // We can release our exclusive lock.
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceeds());
- });
-
- // Sleep before unlocking.
- absl::SleepFor(kHoldLockTime);
-
- // Release the shared lock allowing the thread to proceed.
- // We don't save here to avoid wild discrepencies in timing.
- EXPECT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceeds());
-}
-
-TEST_F(FlockTest, BlockingLockFirstExclusiveSecondShared) {
- // This test will verify that if someone holds an exclusive lock any attempt
- // to obtain a shared lock will result in blocking.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX), SyscallSucceeds());
-
- // kHoldLockTime is the amount of time we will hold the lock before releasing.
- constexpr absl::Duration kHoldLockTime = absl::Seconds(2);
-
- const DisableSave ds; // Timing-related.
-
- // We do this in another thread so we can determine if it was actually
- // blocked by timing the amount of time it took for the syscall to complete.
- ScopedThread t([&] {
- MonotonicTimer timer;
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // This shared lock should block because someone is already holding an
- // exclusive lock. We don't save here to avoid wild discrepencies on timing.
- timer.Start();
- ASSERT_THAT(RetryEINTR(flock)(fd.get(), LOCK_SH), SyscallSucceeds());
-
- // We should be blocked, we will expect to be blocked for more than 1.0s.
- ASSERT_GT(timer.Duration(), absl::Seconds(1));
-
- // We can release our shared lock.
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceeds());
- });
-
- // Sleep before unlocking.
- absl::SleepFor(kHoldLockTime);
-
- // Release the exclusive lock allowing the blocked thread to proceed.
- // We don't save here to avoid wild discrepencies in timing.
- EXPECT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceeds());
-}
-
-TEST_F(FlockTest, BlockingLockFirstExclusiveSecondExclusive) {
- // This test will verify that if someone holds an exclusive lock any attempt
- // to obtain another exclusive lock will result in blocking.
- ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX), SyscallSucceeds());
-
- // kHoldLockTime is the amount of time we will hold the lock before releasing.
- constexpr absl::Duration kHoldLockTime = absl::Seconds(2);
-
- const DisableSave ds; // Timing-related.
-
- // We do this in another thread so we can determine if it was actually
- // blocked by timing the amount of time it took for the syscall to complete.
- ScopedThread t([&] {
- MonotonicTimer timer;
- const FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
-
- // This exclusive lock should block because someone is already holding an
- // exclusive lock.
- timer.Start();
- ASSERT_THAT(RetryEINTR(flock)(fd.get(), LOCK_EX), SyscallSucceeds());
-
- // We should be blocked, we will expect to be blocked for more than 1.0s.
- ASSERT_GT(timer.Duration(), absl::Seconds(1));
-
- // We can release our exclusive lock.
- ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceeds());
- });
-
- // Sleep before unlocking.
- absl::SleepFor(kHoldLockTime);
-
- // Release the exclusive lock allowing the blocked thread to proceed.
- // We don't save to avoid wild discrepencies in timing.
- EXPECT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceeds());
-}
-
-TEST(FlockTestNoFixture, BadFD) {
- // EBADF: fd is not an open file descriptor.
- ASSERT_THAT(flock(-1, 0), SyscallFailsWithErrno(EBADF));
-}
-
-TEST(FlockTestNoFixture, FlockDir) {
- auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_RDONLY, 0000));
- EXPECT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceeds());
-}
-
-TEST(FlockTestNoFixture, FlockSymlink) {
- SKIP_IF(IsRunningWithVFS1());
-
- auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
- auto symlink = ASSERT_NO_ERRNO_AND_VALUE(
- TempPath::CreateSymlinkTo(GetAbsoluteTestTmpdir(), file.path()));
-
- auto fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(symlink.path(), O_RDONLY | O_PATH, 0000));
- EXPECT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallFailsWithErrno(EBADF));
-}
-
-TEST(FlockTestNoFixture, FlockProc) {
- auto fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/self/status", O_RDONLY, 0000));
- EXPECT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceeds());
-}
-
-TEST(FlockTestNoFixture, FlockPipe) {
- int fds[2];
- ASSERT_THAT(pipe(fds), SyscallSucceeds());
-
- EXPECT_THAT(flock(fds[0], LOCK_EX | LOCK_NB), SyscallSucceeds());
- // Check that the pipe was locked above.
- EXPECT_THAT(flock(fds[1], LOCK_EX | LOCK_NB), SyscallFailsWithErrno(EAGAIN));
-
- EXPECT_THAT(flock(fds[0], LOCK_UN), SyscallSucceeds());
- EXPECT_THAT(flock(fds[1], LOCK_EX | LOCK_NB), SyscallSucceeds());
-
- EXPECT_THAT(close(fds[0]), SyscallSucceeds());
- EXPECT_THAT(close(fds[1]), SyscallSucceeds());
-}
-
-TEST(FlockTestNoFixture, FlockSocket) {
- int sock = socket(AF_UNIX, SOCK_STREAM, 0);
- ASSERT_THAT(sock, SyscallSucceeds());
-
- struct sockaddr_un addr =
- ASSERT_NO_ERRNO_AND_VALUE(UniqueUnixAddr(true /* abstract */, AF_UNIX));
- ASSERT_THAT(
- bind(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)),
- SyscallSucceeds());
-
- EXPECT_THAT(flock(sock, LOCK_EX | LOCK_NB), SyscallSucceeds());
- EXPECT_THAT(close(sock), SyscallSucceeds());
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor