1/*
2 * Copyright (c) 2015, 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#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
32template <typename T>
33class ZMessageRequest : public StackObj {
34 friend class ZList<ZMessageRequest>;
35
36private:
37 T _message;
38 uint64_t _seqnum;
39 ZFuture<T> _result;
40 ZListNode<ZMessageRequest> _node;
41
42public:
43 void initialize(T message, uint64_t seqnum) {
44 _message = message;
45 _seqnum = seqnum;
46 }
47
48 T message() const {
49 return _message;
50 }
51
52 uint64_t seqnum() const {
53 return _seqnum;
54 }
55
56 void wait() {
57 const T message = _result.get();
58 assert(message == _message, "Message mismatch");
59 }
60
61 void satisfy(T message) {
62 _result.set(message);
63 }
64};
65
66template <typename T>
67inline 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
76template <typename T>
77inline void ZMessagePort<T>::send_sync(T message) {
78 Request request;
79
80 {
81 // Enqueue message
82 MonitorLocker 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 MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag);
100 }
101}
102
103template <typename T>
104inline void ZMessagePort<T>::send_async(T message) {
105 MonitorLocker 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
114template <typename T>
115inline T ZMessagePort<T>::receive() {
116 MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag);
117
118 // Wait for message
119 while (!_has_message && _queue.is_empty()) {
120 ml.wait();
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
135template <typename T>
136inline void ZMessagePort<T>::ack() {
137 MonitorLocker 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
165inline void ZRendezvousPort::signal() {
166 _port.send_sync(true /* ignored */);
167}
168
169inline void ZRendezvousPort::wait() {
170 _port.receive();
171}
172
173inline void ZRendezvousPort::ack() {
174 _port.ack();
175}
176
177#endif // SHARE_GC_Z_ZMESSAGEPORT_INLINE_HPP
178