1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_UTILITIES_WAITBARRIER_HPP 26 #define SHARE_UTILITIES_WAITBARRIER_HPP 27 28 #include "memory/allocation.hpp" 29 #include "runtime/thread.hpp" 30 #include "utilities/debug.hpp" 31 #include "utilities/globalDefinitions.hpp" 32 #include "utilities/waitBarrier_generic.hpp" 33 34 #if defined(LINUX) 35 #include "waitBarrier_linux.hpp" 36 typedef LinuxWaitBarrier WaitBarrierDefault; 37 #else 38 typedef GenericWaitBarrier WaitBarrierDefault; 39 #endif 40 41 // Platform independent WaitBarrier API. 42 // An armed WaitBarrier prevents threads from advancing until the threads are 43 // woken by calling disarm(). The barrier is armed by setting a non-zero value 44 // - the tag. When the WaitBarrier is created, a thread is designated the owner 45 // and is the thread that should arm and disarm the WaitBarrier. In debug builds 46 // this is enforced. 47 // 48 // Expected Usage: 49 // - Arming thread: 50 // tag = ...; // non-zero value 51 // barrier.arm(tag); 52 // <publish tag> 53 // <work> 54 // barrier.disarm(); 55 // 56 // - After arm(tag) returns any thread calling wait(tag) will block. 57 // - Calling disarm() guarantees any thread calling or that has wait(tag) will 58 // return. Either they will see the WaitBarrier as disarmed or they will be 59 // unblocked and eligible to execute again when disarm() returns. 60 // - After calling disarm() the barrier is ready to be re-armed with a new tag. 61 // (may not be re-armed with last used tag) 62 // 63 // - Waiting threads 64 // wait(tag); // don't execute following code unless 'safe' 65 // <work> 66 // 67 // - A call to wait(tag) will block if the barrier is armed with the value 68 // 'tag'; else it will return immediately. 69 // - A blocked thread is eligible to execute again once the barrier is 70 // disarmed when disarm() has been called. 71 // 72 // It is a usage error to: 73 // - call arm on a barrier that is already armed 74 // - call disarm on a barrier that is not armed 75 // - arm with the same tag as last used 76 // Usage errors are checked in debug builds but may be ignored otherwise. 77 // 78 // A primary goal of the WaitBarrier implementation is to wake all waiting 79 // threads as fast, and as concurrently, as possible. 80 // 81 template <typename WaitBarrierImpl> 82 class WaitBarrierType : public CHeapObj<mtInternal> { 83 WaitBarrierImpl _impl; 84 85 NONCOPYABLE(WaitBarrierType); 86 87 #ifdef ASSERT 88 int _last_arm_tag; 89 Thread* _owner; 90 #endif 91 92 public: WaitBarrierType(Thread * owner)93 WaitBarrierType(Thread* owner) : _impl() { 94 #ifdef ASSERT 95 _last_arm_tag = 0; 96 _owner = owner; 97 #endif 98 } ~WaitBarrierType()99 ~WaitBarrierType() {} 100 101 // Returns implementation description. description()102 const char* description() { return _impl.description(); } 103 104 // Guarantees any thread calling wait() with same tag will be blocked. 105 // Provides a trailing fence. arm(int barrier_tag)106 void arm(int barrier_tag) { 107 #ifdef ASSERT 108 assert(_last_arm_tag != barrier_tag, "Re-arming with same tag"); 109 _last_arm_tag = barrier_tag; 110 assert(_owner == Thread::current(), "Not owner thread"); 111 #endif 112 _impl.arm(barrier_tag); 113 } 114 115 // Guarantees any thread that called wait() will be awake when it returns. 116 // Provides a trailing fence. disarm()117 void disarm() { 118 assert(_owner == Thread::current(), "Not owner thread"); 119 _impl.disarm(); 120 } 121 122 // Guarantees not to return until disarm() is called, 123 // if called with currently armed tag (otherwise returns immediately). 124 // Implementations must guarantee no spurious wakeups. 125 // Provides a trailing fence. wait(int barrier_tag)126 void wait(int barrier_tag) { 127 assert(_owner != Thread::current(), "Trying to wait with owner thread"); 128 _impl.wait(barrier_tag); 129 } 130 }; 131 132 typedef WaitBarrierType<WaitBarrierDefault> WaitBarrier; 133 134 #endif // SHARE_UTILITIES_WAITBARRIER_HPP 135