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