src/hotspot/share/utilities/waitBarrier.hpp
author phh
Sat, 30 Nov 2019 14:33:05 -0800
changeset 59330 5b96c12f909d
parent 53254 47bc06170313
permissions -rw-r--r--
8234541: C1 emits an empty message when it inlines successfully Summary: Use "inline" as the message when successfull Reviewed-by: thartmann, mdoerr Contributed-by: navy.xliu@gmail.com

/*
 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#ifndef SHARE_UTILITIES_WAITBARRIER_HPP
#define SHARE_UTILITIES_WAITBARRIER_HPP

#include "memory/allocation.hpp"
#include "runtime/thread.hpp"
#include "utilities/debug.hpp"
#include "utilities/waitBarrier_generic.hpp"

#if defined(LINUX)
#include "waitBarrier_linux.hpp"
typedef LinuxWaitBarrier WaitBarrierDefault;
#else
typedef GenericWaitBarrier WaitBarrierDefault;
#endif

// Platform independent WaitBarrier API.
// An armed WaitBarrier prevents threads from advancing until the threads are
// woken by calling disarm(). The barrier is armed by setting a non-zero value
// - the tag. When the WaitBarrier is created, a thread is designated the owner
// and is the thread that should arm and disarm the WaitBarrier. In debug builds
// this is enforced.
//
// Expected Usage:
//  - Arming thread:
//     tag = ...;  // non-zero value
//     barrier.arm(tag);
//     <publish tag>
//     <work>
//     barrier.disarm();
//
//    - After arm(tag) returns any thread calling wait(tag) will block.
//    - Calling disarm() guarantees any thread calling or that has wait(tag) will
//      return. Either they will see the WaitBarrier as disarmed or they will be
//      unblocked and eligible to execute again when disarm() returns.
//    - After calling disarm() the barrier is ready to be re-armed with a new tag.
//      (may not be re-armed with last used tag)
//
//  - Waiting threads
//     wait(tag); // don't execute following code unless 'safe'
//     <work>
//
//    - A call to wait(tag) will block if the barrier is armed with the value
//      'tag'; else it will return immediately.
//    - A blocked thread is eligible to execute again once the barrier is
//      disarmed when disarm() has been called.
//
// It is a usage error to:
//  - call arm on a barrier that is already armed
//  - call disarm on a barrier that is not armed
//  - arm with the same tag as last used
// Usage errors are checked in debug builds but may be ignored otherwise.
//
// A primary goal of the WaitBarrier implementation is to wake all waiting
// threads as fast, and as concurrently, as possible.
//
template <typename WaitBarrierImpl>
class WaitBarrierType : public CHeapObj<mtInternal> {
  WaitBarrierImpl _impl;

  // Prevent copying and assignment of WaitBarrier instances.
  WaitBarrierType(const WaitBarrierDefault&);
  WaitBarrierType& operator=(const WaitBarrierDefault&);

#ifdef ASSERT
  int _last_arm_tag;
  Thread* _owner;
#endif

 public:
  WaitBarrierType(Thread* owner) : _impl() {
#ifdef ASSERT
    _last_arm_tag = 0;
    _owner = owner;
#endif
  }
  ~WaitBarrierType() {}

  // Returns implementation description.
  const char* description()    { return _impl.description(); }

  // Guarantees any thread calling wait() with same tag will be blocked.
  // Provides a trailing fence.
  void arm(int barrier_tag) {
#ifdef ASSERT
    assert(_last_arm_tag != barrier_tag, "Re-arming with same tag");
    _last_arm_tag = barrier_tag;
    assert(_owner == Thread::current(), "Not owner thread");
#endif
    _impl.arm(barrier_tag);
  }

  // Guarantees any thread that called wait() will be awake when it returns.
  // Provides a trailing fence.
  void disarm() {
    assert(_owner == Thread::current(), "Not owner thread");
    _impl.disarm();
  }

  // Guarantees not to return until disarm() is called,
  // if called with currently armed tag (otherwise returns immediately).
  // Implementations must guarantee no spurious wakeups.
  // Provides a trailing fence.
  void wait(int barrier_tag) {
    assert(_owner != Thread::current(), "Trying to wait with owner thread");
    _impl.wait(barrier_tag);
  }
};

typedef WaitBarrierType<WaitBarrierDefault> WaitBarrier;

#endif // SHARE_UTILITIES_WAITBARRIER_HPP