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