1 /*
2  * Copyright (c) 2015, 2017, 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 #ifndef SHARE_GC_Z_ZMESSAGEPORT_INLINE_HPP
25 #define SHARE_GC_Z_ZMESSAGEPORT_INLINE_HPP
26 
27 #include "gc/z/zMessagePort.hpp"
28 #include "gc/z/zFuture.inline.hpp"
29 #include "gc/z/zList.inline.hpp"
30 #include "runtime/mutexLocker.hpp"
31 
32 template <typename T>
33 class ZMessageRequest : public StackObj {
34   friend class ZList<ZMessageRequest>;
35 
36 private:
37   T                          _message;
38   uint64_t                   _seqnum;
39   ZFuture<T>                 _result;
40   ZListNode<ZMessageRequest> _node;
41 
42 public:
initialize(T message,uint64_t seqnum)43   void initialize(T message, uint64_t seqnum) {
44     _message = message;
45     _seqnum = seqnum;
46   }
47 
message() const48   T message() const {
49     return _message;
50   }
51 
seqnum() const52   uint64_t seqnum() const {
53     return _seqnum;
54   }
55 
wait()56   void wait() {
57     const T message = _result.get();
58     assert(message == _message, "Message mismatch");
59   }
60 
satisfy(T message)61   void satisfy(T message) {
62     _result.set(message);
63   }
64 };
65 
66 template <typename T>
ZMessagePort()67 inline ZMessagePort<T>::ZMessagePort() :
68     _monitor(Monitor::leaf,
69              "ZMessagePort",
70              Monitor::_allow_vm_block_flag,
71              Monitor::_safepoint_check_never),
72     _has_message(false),
73     _seqnum(0),
74     _queue() {}
75 
76 template <typename T>
send_sync(T message)77 inline void ZMessagePort<T>::send_sync(T message) {
78   Request request;
79 
80   {
81     // Enqueue message
82     MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag);
83     request.initialize(message, _seqnum);
84     _queue.insert_last(&request);
85     ml.notify();
86   }
87 
88   // Wait for completion
89   request.wait();
90 
91   {
92     // Guard deletion of underlying semaphore. This is a workaround for a
93     // bug in sem_post() in glibc < 2.21, where it's not safe to destroy
94     // the semaphore immediately after returning from sem_wait(). The
95     // reason is that sem_post() can touch the semaphore after a waiting
96     // thread have returned from sem_wait(). To avoid this race we are
97     // forcing the waiting thread to acquire/release the lock held by the
98     // posting thread. https://sourceware.org/bugzilla/show_bug.cgi?id=12674
99     MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag);
100   }
101 }
102 
103 template <typename T>
send_async(T message)104 inline void ZMessagePort<T>::send_async(T message) {
105   MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag);
106   if (!_has_message) {
107     // Post message
108     _message = message;
109     _has_message = true;
110     ml.notify();
111   }
112 }
113 
114 template <typename T>
receive()115 inline T ZMessagePort<T>::receive() {
116   MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag);
117 
118   // Wait for message
119   while (!_has_message && _queue.is_empty()) {
120     ml.wait(Monitor::_no_safepoint_check_flag);
121   }
122 
123   // Increment request sequence number
124   _seqnum++;
125 
126   if (!_has_message) {
127     // Message available in the queue
128     _message = _queue.first()->message();
129     _has_message = true;
130   }
131 
132   return _message;
133 }
134 
135 template <typename T>
ack()136 inline void ZMessagePort<T>::ack() {
137   MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag);
138 
139   if (!_has_message) {
140     // Nothing to ack
141     return;
142   }
143 
144   // Satisfy requests (and duplicates) in queue
145   ZListIterator<Request> iter(&_queue);
146   for (Request* request; iter.next(&request);) {
147     if (request->message() == _message && request->seqnum() < _seqnum) {
148       // Dequeue and satisfy request. Note that the dequeue operation must
149       // happen first, since the request will immediately be deallocated
150       // once it has been satisfied.
151       _queue.remove(request);
152       request->satisfy(_message);
153     }
154   }
155 
156   if (_queue.is_empty()) {
157     // Queue is empty
158     _has_message = false;
159   } else {
160     // Post first message in queue
161     _message = _queue.first()->message();
162   }
163 }
164 
signal()165 inline void ZRendezvousPort::signal() {
166   _port.send_sync(true /* ignored */);
167 }
168 
wait()169 inline void ZRendezvousPort::wait() {
170   _port.receive();
171 }
172 
ack()173 inline void ZRendezvousPort::ack() {
174   _port.ack();
175 }
176 
177 #endif // SHARE_GC_Z_ZMESSAGEPORT_INLINE_HPP
178