interprocess_sync_file_unittest.cc 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include "util/interprocess_sync_file.h"
  15. #include <gtest/gtest.h>
  16. #include <unistd.h>
  17. using namespace std;
  18. namespace isc {
  19. namespace util {
  20. namespace {
  21. unsigned char
  22. parentReadLockedState (int fd) {
  23. unsigned char locked = 0xff;
  24. fd_set rfds;
  25. FD_ZERO(&rfds);
  26. FD_SET(fd, &rfds);
  27. // We use select() here to wait for new data on the input end of
  28. // the pipe. We wait for 5 seconds (an arbitrary value) for input
  29. // data, and continue if no data is available. This is done so
  30. // that read() is not blocked due to some issue in the child
  31. // process (and the tests continue running).
  32. struct timeval tv;
  33. tv.tv_sec = 5;
  34. tv.tv_usec = 0;
  35. const int nfds = select(fd + 1, &rfds, NULL, NULL, &tv);
  36. EXPECT_EQ(1, nfds);
  37. if (nfds == 1) {
  38. // Read status
  39. read(fd, &locked, sizeof(locked));
  40. }
  41. return (locked);
  42. }
  43. TEST(InterprocessSyncFileTest, TestLock) {
  44. InterprocessSyncFile sync("test");
  45. InterprocessSyncLocker locker(sync);
  46. EXPECT_FALSE(locker.isLocked());
  47. EXPECT_TRUE(locker.lock());
  48. EXPECT_TRUE(locker.isLocked());
  49. int fds[2];
  50. // Here, we check that a lock has been taken by forking and
  51. // checking from the child that a lock exists. This has to be
  52. // done from a separate process as we test by trying to lock the
  53. // range again on the lock file. The lock attempt would pass if
  54. // done from the same process for the granted range. The lock
  55. // attempt must fail to pass our check.
  56. pipe(fds);
  57. if (fork() == 0) {
  58. unsigned char locked = 0;
  59. // Child writes to pipe
  60. close(fds[0]);
  61. InterprocessSyncFile sync2("test");
  62. InterprocessSyncLocker locker2(sync2);
  63. if (!locker2.tryLock()) {
  64. EXPECT_FALSE(locker2.isLocked());
  65. locked = 1;
  66. } else {
  67. EXPECT_TRUE(locker2.isLocked());
  68. }
  69. write(fds[1], &locked, sizeof(locked));
  70. close(fds[1]);
  71. exit(0);
  72. } else {
  73. // Parent reads from pipe
  74. close(fds[1]);
  75. const unsigned char locked = parentReadLockedState(fds[0]);
  76. close(fds[0]);
  77. EXPECT_EQ(1, locked);
  78. }
  79. EXPECT_TRUE(locker.unlock());
  80. EXPECT_FALSE(locker.isLocked());
  81. EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test_lockfile"));
  82. }
  83. TEST(InterprocessSyncFileTest, TestMultipleFilesDirect) {
  84. InterprocessSyncFile sync("test1");
  85. InterprocessSyncLocker locker(sync);
  86. EXPECT_TRUE(locker.lock());
  87. InterprocessSyncFile sync2("test2");
  88. InterprocessSyncLocker locker2(sync2);
  89. EXPECT_TRUE(locker2.lock());
  90. EXPECT_TRUE(locker2.unlock());
  91. EXPECT_TRUE(locker.unlock());
  92. EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test1_lockfile"));
  93. EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test2_lockfile"));
  94. }
  95. TEST(InterprocessSyncFileTest, TestMultipleFilesForked) {
  96. InterprocessSyncFile sync("test1");
  97. InterprocessSyncLocker locker(sync);
  98. EXPECT_TRUE(locker.lock());
  99. int fds[2];
  100. pipe(fds);
  101. if (fork() == 0) {
  102. unsigned char locked = 0xff;
  103. // Child writes to pipe
  104. close(fds[0]);
  105. InterprocessSyncFile sync2("test2");
  106. InterprocessSyncLocker locker2(sync2);
  107. if (locker2.tryLock()) {
  108. locked = 0;
  109. }
  110. write(fds[1], &locked, sizeof(locked));
  111. close(fds[1]);
  112. exit(0);
  113. } else {
  114. // Parent reads from pipe
  115. close(fds[1]);
  116. const unsigned char locked = parentReadLockedState(fds[0]);
  117. close(fds[0]);
  118. EXPECT_EQ(0, locked);
  119. }
  120. EXPECT_TRUE(locker.unlock());
  121. EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test1_lockfile"));
  122. EXPECT_EQ (0, unlink(TEST_DATA_TOPBUILDDIR "/test2_lockfile"));
  123. }
  124. }
  125. } // namespace util
  126. } // namespace isc