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.inline.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: 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 66 template <typename T> 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> 77 inline 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 103 template <typename T> 104 inline 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 114 template <typename T> 115 inline 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 135 template <typename T> 136 inline 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 165 inline void ZRendezvousPort::signal() { 166 _port.send_sync(true /* ignored */); 167 } 168 169 inline void ZRendezvousPort::wait() { 170 _port.receive(); 171 } 172 173 inline void ZRendezvousPort::ack() { 174 _port.ack(); 175 } 176 177 #endif // SHARE_GC_Z_ZMESSAGEPORT_INLINE_HPP