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: 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 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 template <typename T> 93 inline void ZMessagePort<T>::send_async(T message) { 94 MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag); 95 if (!_has_message) { 96 // Post message 97 _message = message; 98 _has_message = true; 99 ml.notify(); 100 } 101 } 102 103 template <typename T> 104 inline T ZMessagePort<T>::receive() { 105 MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag); 106 107 // Wait for message 108 while (!_has_message && _queue.is_empty()) { 109 ml.wait(Monitor::_no_safepoint_check_flag); 110 } 111 112 // Increment request sequence number 113 _seqnum++; 114 115 if (!_has_message) { 116 // Message available in the queue 117 _message = _queue.first()->message(); 118 _has_message = true; 119 } 120 121 return _message; 122 } 123 124 template <typename T> 125 inline void ZMessagePort<T>::ack() { 126 MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag); 127 128 if (!_has_message) { 129 // Nothing to ack 130 return; 131 } 132 133 // Satisfy requests (and duplicates) in queue 134 ZListIterator<Request> iter(&_queue); 135 for (Request* request; iter.next(&request);) { 136 if (request->message() == _message && request->seqnum() < _seqnum) { 137 // Dequeue and satisfy request. Note that the dequeue operation must 138 // happen first, since the request will immediately be deallocated 139 // once it has been satisfied. 140 _queue.remove(request); 141 request->satisfy(_message); 142 } 143 } 144 145 if (_queue.is_empty()) { 146 // Queue is empty 147 _has_message = false; 148 } else { 149 // Post first message in queue 150 _message = _queue.first()->message(); 151 } 152 } 153 154 inline void ZRendezvousPort::signal() { 155 _port.send_sync(true /* ignored */); 156 } 157 158 inline void ZRendezvousPort::wait() { 159 _port.receive(); 160 } 161 162 inline void ZRendezvousPort::ack() { 163 _port.ack(); 164 } 165 166 #endif // SHARE_GC_Z_ZMESSAGEPORT_INLINE_HPP