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