park.cpp 5.6 KB
Newer Older
A
acorn 已提交
1
/*
2
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
A
acorn 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * 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.
 *
 */

25 26
#include "precompiled.hpp"
#include "runtime/thread.hpp"
A
acorn 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61



// Lifecycle management for TSM ParkEvents.
// ParkEvents are type-stable (TSM).
// In our particular implementation they happen to be immortal.
//
// We manage concurrency on the FreeList with a CAS-based
// detach-modify-reattach idiom that avoids the ABA problems
// that would otherwise be present in a simple CAS-based
// push-pop implementation.   (push-one and pop-all)
//
// Caveat: Allocate() and Release() may be called from threads
// other than the thread associated with the Event!
// If we need to call Allocate() when running as the thread in
// question then look for the PD calls to initialize native TLS.
// Native TLS (Win32/Linux/Solaris) can only be initialized or
// accessed by the associated thread.
// See also pd_initialize().
//
// Note that we could defer associating a ParkEvent with a thread
// until the 1st time the thread calls park().  unpark() calls to
// an unprovisioned thread would be ignored.  The first park() call
// for a thread would allocate and associate a ParkEvent and return
// immediately.

volatile int ParkEvent::ListLock = 0 ;
ParkEvent * volatile ParkEvent::FreeList = NULL ;

ParkEvent * ParkEvent::Allocate (Thread * t) {
  // In rare cases -- JVM_RawMonitor* operations -- we can find t == null.
  ParkEvent * ev ;

  // Start by trying to recycle an existing but unassociated
  // ParkEvent from the global free list.
62 63 64 65 66 67 68 69
  // Using a spin lock since we are part of the mutex impl.
  // 8028280: using concurrent free list without memory management can leak
  // pretty badly it turns out.
  Thread::SpinAcquire(&ListLock, "ParkEventFreeListAllocate");
  {
    ev = FreeList;
    if (ev != NULL) {
      FreeList = ev->FreeNext;
A
acorn 已提交
70 71
    }
  }
72
  Thread::SpinRelease(&ListLock);
A
acorn 已提交
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

  if (ev != NULL) {
    guarantee (ev->AssociatedWith == NULL, "invariant") ;
  } else {
    // Do this the hard way -- materialize a new ParkEvent.
    ev = new ParkEvent () ;
    guarantee ((intptr_t(ev) & 0xFF) == 0, "invariant") ;
  }
  ev->reset() ;                     // courtesy to caller
  ev->AssociatedWith = t ;          // Associate ev with t
  ev->FreeNext       = NULL ;
  return ev ;
}

void ParkEvent::Release (ParkEvent * ev) {
  if (ev == NULL) return ;
  guarantee (ev->FreeNext == NULL      , "invariant") ;
  ev->AssociatedWith = NULL ;
91 92 93 94 95 96
  // Note that if we didn't have the TSM/immortal constraint, then
  // when reattaching we could trim the list.
  Thread::SpinAcquire(&ListLock, "ParkEventFreeListRelease");
  {
    ev->FreeNext = FreeList;
    FreeList = ev;
A
acorn 已提交
97
  }
98
  Thread::SpinRelease(&ListLock);
A
acorn 已提交
99 100 101 102 103 104 105 106 107
}

// Override operator new and delete so we can ensure that the
// least significant byte of ParkEvent addresses is 0.
// Beware that excessive address alignment is undesirable
// as it can result in D$ index usage imbalance as
// well as bank access imbalance on Niagara-like platforms,
// although Niagara's hash function should help.

108
void * ParkEvent::operator new (size_t sz) throw() {
Z
zgu 已提交
109
  return (void *) ((intptr_t (AllocateHeap(sz + 256, mtInternal, CALLER_PC)) + 256) & -256) ;
A
acorn 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
}

void ParkEvent::operator delete (void * a) {
  // ParkEvents are type-stable and immortal ...
  ShouldNotReachHere();
}


// 6399321 As a temporary measure we copied & modified the ParkEvent::
// allocate() and release() code for use by Parkers.  The Parker:: forms
// will eventually be removed as we consolide and shift over to ParkEvents
// for both builtin synchronization and JSR166 operations.

volatile int Parker::ListLock = 0 ;
Parker * volatile Parker::FreeList = NULL ;

Parker * Parker::Allocate (JavaThread * t) {
  guarantee (t != NULL, "invariant") ;
  Parker * p ;

  // Start by trying to recycle an existing but unassociated
  // Parker from the global free list.
132 133 134 135 136 137 138
  // 8028280: using concurrent free list without memory management can leak
  // pretty badly it turns out.
  Thread::SpinAcquire(&ListLock, "ParkerFreeListAllocate");
  {
    p = FreeList;
    if (p != NULL) {
      FreeList = p->FreeNext;
A
acorn 已提交
139 140
    }
  }
141
  Thread::SpinRelease(&ListLock);
A
acorn 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

  if (p != NULL) {
    guarantee (p->AssociatedWith == NULL, "invariant") ;
  } else {
    // Do this the hard way -- materialize a new Parker..
    p = new Parker() ;
  }
  p->AssociatedWith = t ;          // Associate p with t
  p->FreeNext       = NULL ;
  return p ;
}


void Parker::Release (Parker * p) {
  if (p == NULL) return ;
  guarantee (p->AssociatedWith != NULL, "invariant") ;
  guarantee (p->FreeNext == NULL      , "invariant") ;
  p->AssociatedWith = NULL ;
160 161 162 163 164

  Thread::SpinAcquire(&ListLock, "ParkerFreeListRelease");
  {
    p->FreeNext = FreeList;
    FreeList = p;
A
acorn 已提交
165
  }
166
  Thread::SpinRelease(&ListLock);
A
acorn 已提交
167 168
}