| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 "fw_dunit.hpp" |
| |
| #include <mutex> |
| #include <util/concurrent/spinlock_mutex.hpp> |
| |
| #include <ace/Task.h> |
| #include <ace/Time_Value.h> |
| #include <ace/Guard_T.h> |
| |
| namespace { // NOLINT(google-build-namespaces) |
| |
| using apache::geode::util::concurrent::spinlock_mutex; |
| |
| DUNIT_TASK(s1p1, Basic) |
| { |
| spinlock_mutex s; |
| { std::lock_guard<spinlock_mutex> lk(s); } |
| } |
| END_TASK(Basic) |
| |
| perf::Semaphore *triggerA; |
| perf::Semaphore *triggerB; |
| perf::Semaphore *triggerM; |
| |
| spinlock_mutex lock; |
| ACE_Time_Value *btime; |
| |
| class ThreadA : public ACE_Task_Base { |
| public: |
| ThreadA() : ACE_Task_Base() {} |
| |
| int svc() { |
| { |
| std::lock_guard<spinlock_mutex> lk(lock); |
| LOG("ThreadA: Acquired lock x."); |
| triggerM->release(); |
| triggerA->acquire(); |
| } |
| LOG("ThreadA: Released lock."); |
| return 0; |
| } |
| }; |
| |
| class ThreadB : public ACE_Task_Base { |
| public: |
| ThreadB() : ACE_Task_Base() {} |
| |
| int svc() { |
| triggerB->acquire(); |
| { |
| std::lock_guard<spinlock_mutex> lk(lock); |
| btime = new ACE_Time_Value(ACE_OS::gettimeofday()); |
| LOG("ThreadB: Acquired lock."); |
| triggerM->release(); |
| } |
| return 0; |
| } |
| }; |
| |
| DUNIT_TASK(s1p1, TwoThreads) |
| { |
| triggerA = new perf::Semaphore(0); |
| triggerB = new perf::Semaphore(0); |
| triggerM = new perf::Semaphore(0); |
| |
| ThreadA *threadA = new ThreadA(); |
| ThreadB *threadB = new ThreadB(); |
| |
| threadA->activate(); |
| threadB->activate(); |
| |
| // A runs, locks the spinlock, and triggers me. B is idle. |
| triggerM->acquire(); |
| // A is now idle, but holds lock. Tell B to acquire the lock |
| ACE_Time_Value stime = ACE_OS::gettimeofday(); |
| triggerB->release(); |
| SLEEP(5000); |
| // B will be stuck until we tell A to release it. |
| triggerA->release(); |
| // wait until B tells us it has acquired the lock. |
| triggerM->acquire(); |
| |
| // Now diff btime (when B acquired the lock) and stime to see that it |
| // took longer than the 5000 seconds before A released it. |
| ACE_Time_Value delta = *btime - stime; |
| char msg[1024]; |
| sprintf(msg, "acquire delay was %lu\n", delta.msec()); |
| LOG(msg); |
| ASSERT(delta.msec() >= 4900, "Expected 5 second or more spinlock delay"); |
| // Note the test is against 4900 instead of 5000 as there are some |
| // measurement |
| // issues. Often delta comes back as 4999 on linux. |
| |
| threadA->wait(); |
| delete threadA; |
| threadB->wait(); |
| delete threadB; |
| } |
| END_TASK(TwoThreads) |
| |
| } // namespace |