1 /* 2 * Copyright (c) 2018, 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/waitBarrier_generic.hpp" 32 33 #if defined(LINUX) 34 #include "waitBarrier_linux.hpp" 35 typedef LinuxWaitBarrier WaitBarrierDefault; 36 #else 37 typedef GenericWaitBarrier WaitBarrierDefault; 38 #endif 39 40 // Platform independent WaitBarrier API. 41 // An armed WaitBarrier prevents threads from advancing until the threads are 42 // woken by calling wake(). The barrier is armed by setting a non-zero value 43 // - the tag. When the WaitBarrier is created, a thread is designated the owner 44 // and is the thread that should arm and wake the WaitBarrier. In debug builds 45 // this is enforced. 46 // 47 // Expected Usage: 48 // - Arming thread: 49 // tag = ...; // non-zero value 50 // barrier.arm(tag); 51 // <publish tag> 52 // <work> 53 // barrier.wake(); 54 // 55 // - After arm(tag) returns any thread calling wait(tag) will block. 56 // - Calling wake() guarantees any thread calling or called wait(tag) will 57 // return. Either they will see the WaitBarrier as disarmed or they will be 58 // unblocked and eligible to execute again when wake() returns. 59 // - After calling wake() the barrier is ready to be re-armed with a new tag. 60 // (may not be re-armed with last used tag) 61 // 62 // - Waiting threads 63 // wait(tag); // don't execute following code unless 'safe' 64 // <work> 65 // 66 // - A call to wait(tag) will block if the barrier is armed with the value 67 // 'tag'; else it will return immediately. 68 // - A blocked thread is eligible to execute again once the barrier is 69 // disarmed when wake() has been called. 70 // 71 // It is a usage error to: 72 // - call arm on a barrier that is already armed 73 // - call wake on a barrier that is not armed 74 // - arm with the same tag as last used 75 // Usage errors are checked in debug builds but may be ignored otherwise. 76 // 77 // A primary goal of the WaitBarrier implementation is to wake all waiting 78 // threads as fast, and as concurrently, as possible. 79 // 80 template <typename WaitBarrierImpl> 81 class WaitBarrierType : public CHeapObj<mtInternal> { 82 WaitBarrierImpl _impl; 83 84 // Prevent copying and assignment of WaitBarrier instances. 85 WaitBarrierType(const WaitBarrierDefault&); 86 WaitBarrierType& operator=(const WaitBarrierDefault&); 87 88 #ifdef ASSERT 89 int _last_arm_tag; 90 Thread* _owner; 91 #endif 92 93 public: 94 WaitBarrierType(Thread* owner) : _impl() { 95 #ifdef ASSERT 96 _last_arm_tag = 0; 97 _owner = owner; 98 #endif 99 } 100 ~WaitBarrierType() {} 101 102 // Returns implementation type. 103 const char* description() { return _impl.description(); } 104 105 // Guarantees any thread calling wait() with same tag will be blocked. 106 // Provides a trailing fence. 107 void arm(int barrier_tag) { 108 #ifdef ASSERT 109 assert(_last_arm_tag != barrier_tag, "Re-arming with same tag"); 110 _last_arm_tag = barrier_tag; 111 assert(_owner == Thread::current(), "Not owner thread"); 112 #endif 113 _impl.arm(barrier_tag); 114 } 115 116 // Guarantees any thread called wait() will be awake when it returns. 117 // Provides a trailing fence. 118 void wake() { 119 assert(_owner == Thread::current(), "Not owner thread"); 120 _impl.wake(); 121 } 122 123 // Guarantees not to return until wake() is called, 124 // if called with currently armed tag (otherwise returns immediately). 125 // Implementations must guarantee no spurious wakeups. 126 // Provides a trailing fence. 127 void wait(int barrier_tag) { 128 assert(_owner != Thread::current(), "Trying to wait with owner thread"); 129 _impl.wait(barrier_tag); 130 } 131 }; 132 133 typedef WaitBarrierType<WaitBarrierDefault> WaitBarrier; 134 135 #endif // SHARE_UTILITIES_WAITBARRIER_HPP