shared_mutex_test.cc 7.96 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * Copyright (c) 2014-2015, Siemens AG. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

27
#include <shared_mutex_test.h>
28 29 30 31 32
#include <embb/base/c/errors.h>

namespace embb {
namespace base {
namespace test {
33
SharedMutexTest::SharedMutexTest()
34
  : shared_mutex_(),
35
      counter_(0),
36 37 38
      num_threads_(partest::TestSuite::GetDefaultNumThreads()),
      num_iterations_(partest::TestSuite::GetDefaultNumIterations()) {
  CreateUnit("Shared read")
39 40
      .Pre(&SharedMutexTest::TestSharedReadPre, this)
      .Add(&SharedMutexTest::TestSharedReadThreadMethod, this,
41
           num_threads_, num_iterations_)
42 43
      .Post(&SharedMutexTest::TestSharedReadPost, this);
  CreateUnit("Multiple writer")
44 45
      .Pre(&SharedMutexTest::TestExclusiveWriterPre, this)
      .Add(&SharedMutexTest::TestExclusiveWriterReaderMethod, this,
46
           num_threads_ / 2, num_iterations_)
47
      .Add(&SharedMutexTest::TestExclusiveWriterWriterMethod, this,
48
           num_threads_ / 2, num_iterations_)
49
      .Post(&SharedMutexTest::TestExclusiveWriterPost, this);
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

  CreateUnit("Basic test: read lock after write lock fails")
    .Pre(&SharedMutexTest::TestLockedPre, this)
    .Add(&SharedMutexTest::TestLockedForWritingPreventsLockForReading
      , this, 2, num_iterations_)
     .Add(&SharedMutexTest::TestLockedPost, this);

  CreateUnit("Basic test: write lock after read lock fails")
    .Pre(&SharedMutexTest::TestLockedPre, this)
    .Add(&SharedMutexTest::TestLockedForReadingPreventsLockForWriting, this, 2,
    num_iterations_)
     .Add(&SharedMutexTest::TestLockedPost, this);
}

void SharedMutexTest::TestLockedPre() {
  embb_atomic_store_int(&synchronize_, 0);
  int success = embb_shared_mutex_init(&shared_mutex_);

  PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to initialize shared mutex.");
}

void SharedMutexTest::TestLockedForWritingPreventsLockForReading() {
  int expected = 0;
  int success = 0;
  int which_thread = 0;

  if (embb_atomic_compare_and_swap_int(&synchronize_, &expected, 1)) {
    // we are the write locking thread (will happen first)!
    success = embb_shared_mutex_lock(&shared_mutex_);

    PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS,
      "Failed to lock shared mutex for writing");

    // signal the second thread to continue
    embb_atomic_store_int(&synchronize_, 2);
  } else {
    while (embb_atomic_load_int(&synchronize_) != 2) {}
    // we are the read lock thread! (second thread)
    which_thread = 1;

    // the mutex is locked for writing... try lock for reading must fail now!
    success = embb_shared_mutex_try_lock_shared(&shared_mutex_);

    PT_ASSERT_EQ_MSG(success, EMBB_BUSY,
     "Not failed to lock shared mutex for reading");

    // synchronize, that first thread can unlock
    embb_atomic_store_int(&synchronize_, 3);
  }

  if (which_thread == 0) {
    // wait for second thread to finish!
    while (embb_atomic_load_int(&synchronize_) != 3) {}

    // the first thread unlocks the mutex...
    success = embb_shared_mutex_unlock(&shared_mutex_);

    PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS,
      "Failed to unlock mutex");

    // reset synchronize flag for next round...
    embb_atomic_store_int(&synchronize_, 0);
  } else {
    //wait for next round
    while (embb_atomic_load_int(&synchronize_) == 3) {}
  }
}

void SharedMutexTest::TestLockedForReadingPreventsLockForWriting() {
  int expected = 0;
  int success = 0;
  int which_thread = 0;

  if (embb_atomic_compare_and_swap_int(&synchronize_, &expected, 1)) {
    // we are the write locking thread (will happen first)!
    success = embb_shared_mutex_lock_shared(&shared_mutex_);

    PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS,
      "Failed to lock shared mutex for writing");

    // signal the second thread to continue
    embb_atomic_store_int(&synchronize_, 2);
  } else {
    while (embb_atomic_load_int(&synchronize_) != 2) {}
    // we are the read lock thread! (second thread)
    which_thread = 1;

    // the mutex is locked for writing... try lock for reading must fail now!
    success = embb_shared_mutex_try_lock(&shared_mutex_);

    PT_ASSERT_EQ_MSG(success, EMBB_BUSY,
     "Not failed to lock shared mutex for reading");

    // synchronize, that first thread can unlock
    embb_atomic_store_int(&synchronize_, 3);
  }

  if (which_thread == 0) {
    // wait for second thread to finish!
    while (embb_atomic_load_int(&synchronize_) != 3) {}

    // the first thread unlocks the mutex...
    success = embb_shared_mutex_unlock(&shared_mutex_);

    PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS,
      "Failed to unlock mutex");

    // reset synchronize flag for next round...
    embb_atomic_store_int(&synchronize_, 0);
  } else {
    //wait for next round
    while (embb_atomic_load_int(&synchronize_) == 3) {}
  }
}

void SharedMutexTest::TestLockedPost() {
  embb_shared_mutex_destroy(&shared_mutex_);
167 168
}

169
void SharedMutexTest::TestSharedReadPre() {
170 171
  int success = embb_shared_mutex_init(&shared_mutex_);
  PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to initialize shared mutex.");
172 173
}

174
void SharedMutexTest::TestSharedReadThreadMethod() {
175
  int success = embb_shared_mutex_try_lock_shared(&shared_mutex_);
176 177 178 179
  PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to try-lock for reading.");

  success = embb_shared_mutex_unlock_shared(&shared_mutex_);
  PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to unlock (reading).");
180

181 182
  success = embb_shared_mutex_lock_shared(&shared_mutex_);
  PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to lock for reading.");
183

184
  success = embb_shared_mutex_unlock_shared(&shared_mutex_);
185 186 187
  PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to unlock (reading).");
}

188
void SharedMutexTest::TestSharedReadPost() {
189
  embb_shared_mutex_destroy(&shared_mutex_);
190 191
}

192
void SharedMutexTest::TestExclusiveWriterPre() {
193 194
  int success = embb_shared_mutex_init(&shared_mutex_);
  PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to initialize shared mutex.");
195 196 197 198

  counter_ = 0;
}

199
void SharedMutexTest::TestExclusiveWriterReaderMethod() {
200 201
  // Just add some contention

202
  int success = embb_shared_mutex_lock_shared(&shared_mutex_);
203 204
  if (success != EMBB_SUCCESS) return;

205
  success = embb_shared_mutex_unlock_shared(&shared_mutex_);
206 207 208
  PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to unlock (reading).");
}

209
void SharedMutexTest::TestExclusiveWriterWriterMethod() {
210
  int success = embb_shared_mutex_lock(&shared_mutex_);
211 212 213 214
  PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to lock for writing.");

  ++counter_;

215
  success = embb_shared_mutex_unlock(&shared_mutex_);
216 217 218
  PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to unlock (writing).");
}

219
void SharedMutexTest::TestExclusiveWriterPost() {
220
  PT_ASSERT_EQ_MSG(counter_, num_iterations_ * (num_threads_ / 2),
221
                   "Counter value is inconsistent.");
222
  embb_shared_mutex_destroy(&shared_mutex_);
223 224 225 226
}
} // namespace test
} // namespace base
} // namespace embb