acorn@2233: /* coleenp@5614: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. acorn@2233: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. acorn@2233: * acorn@2233: * This code is free software; you can redistribute it and/or modify it acorn@2233: * under the terms of the GNU General Public License version 2 only, as acorn@2233: * published by the Free Software Foundation. acorn@2233: * acorn@2233: * This code is distributed in the hope that it will be useful, but WITHOUT acorn@2233: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or acorn@2233: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License acorn@2233: * version 2 for more details (a copy is included in the LICENSE file that acorn@2233: * accompanied this code). acorn@2233: * acorn@2233: * You should have received a copy of the GNU General Public License version acorn@2233: * 2 along with this work; if not, write to the Free Software Foundation, acorn@2233: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. acorn@2233: * acorn@2233: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA acorn@2233: * or visit www.oracle.com if you need additional information or have any acorn@2233: * questions. acorn@2233: * acorn@2233: */ acorn@2233: stefank@2314: #include "precompiled.hpp" stefank@2314: #include "runtime/thread.hpp" acorn@2233: acorn@2233: acorn@2233: acorn@2233: // Lifecycle management for TSM ParkEvents. acorn@2233: // ParkEvents are type-stable (TSM). acorn@2233: // In our particular implementation they happen to be immortal. acorn@2233: // acorn@2233: // We manage concurrency on the FreeList with a CAS-based acorn@2233: // detach-modify-reattach idiom that avoids the ABA problems acorn@2233: // that would otherwise be present in a simple CAS-based acorn@2233: // push-pop implementation. (push-one and pop-all) acorn@2233: // acorn@2233: // Caveat: Allocate() and Release() may be called from threads acorn@2233: // other than the thread associated with the Event! acorn@2233: // If we need to call Allocate() when running as the thread in acorn@2233: // question then look for the PD calls to initialize native TLS. acorn@2233: // Native TLS (Win32/Linux/Solaris) can only be initialized or acorn@2233: // accessed by the associated thread. acorn@2233: // See also pd_initialize(). acorn@2233: // acorn@2233: // Note that we could defer associating a ParkEvent with a thread acorn@2233: // until the 1st time the thread calls park(). unpark() calls to acorn@2233: // an unprovisioned thread would be ignored. The first park() call acorn@2233: // for a thread would allocate and associate a ParkEvent and return acorn@2233: // immediately. acorn@2233: acorn@2233: volatile int ParkEvent::ListLock = 0 ; acorn@2233: ParkEvent * volatile ParkEvent::FreeList = NULL ; acorn@2233: acorn@2233: ParkEvent * ParkEvent::Allocate (Thread * t) { acorn@2233: // In rare cases -- JVM_RawMonitor* operations -- we can find t == null. acorn@2233: ParkEvent * ev ; acorn@2233: acorn@2233: // Start by trying to recycle an existing but unassociated acorn@2233: // ParkEvent from the global free list. dsimms@6348: // Using a spin lock since we are part of the mutex impl. dsimms@6348: // 8028280: using concurrent free list without memory management can leak dsimms@6348: // pretty badly it turns out. dsimms@6348: Thread::SpinAcquire(&ListLock, "ParkEventFreeListAllocate"); dsimms@6348: { dsimms@6348: ev = FreeList; dsimms@6348: if (ev != NULL) { dsimms@6348: FreeList = ev->FreeNext; acorn@2233: } acorn@2233: } dsimms@6348: Thread::SpinRelease(&ListLock); acorn@2233: acorn@2233: if (ev != NULL) { acorn@2233: guarantee (ev->AssociatedWith == NULL, "invariant") ; acorn@2233: } else { acorn@2233: // Do this the hard way -- materialize a new ParkEvent. acorn@2233: ev = new ParkEvent () ; acorn@2233: guarantee ((intptr_t(ev) & 0xFF) == 0, "invariant") ; acorn@2233: } acorn@2233: ev->reset() ; // courtesy to caller acorn@2233: ev->AssociatedWith = t ; // Associate ev with t acorn@2233: ev->FreeNext = NULL ; acorn@2233: return ev ; acorn@2233: } acorn@2233: acorn@2233: void ParkEvent::Release (ParkEvent * ev) { acorn@2233: if (ev == NULL) return ; acorn@2233: guarantee (ev->FreeNext == NULL , "invariant") ; acorn@2233: ev->AssociatedWith = NULL ; dsimms@6348: // Note that if we didn't have the TSM/immortal constraint, then dsimms@6348: // when reattaching we could trim the list. dsimms@6348: Thread::SpinAcquire(&ListLock, "ParkEventFreeListRelease"); dsimms@6348: { dsimms@6348: ev->FreeNext = FreeList; dsimms@6348: FreeList = ev; acorn@2233: } dsimms@6348: Thread::SpinRelease(&ListLock); acorn@2233: } acorn@2233: acorn@2233: // Override operator new and delete so we can ensure that the acorn@2233: // least significant byte of ParkEvent addresses is 0. acorn@2233: // Beware that excessive address alignment is undesirable acorn@2233: // as it can result in D$ index usage imbalance as acorn@2233: // well as bank access imbalance on Niagara-like platforms, acorn@2233: // although Niagara's hash function should help. acorn@2233: coleenp@5614: void * ParkEvent::operator new (size_t sz) throw() { zgu@3900: return (void *) ((intptr_t (AllocateHeap(sz + 256, mtInternal, CALLER_PC)) + 256) & -256) ; acorn@2233: } acorn@2233: acorn@2233: void ParkEvent::operator delete (void * a) { acorn@2233: // ParkEvents are type-stable and immortal ... acorn@2233: ShouldNotReachHere(); acorn@2233: } acorn@2233: acorn@2233: acorn@2233: // 6399321 As a temporary measure we copied & modified the ParkEvent:: acorn@2233: // allocate() and release() code for use by Parkers. The Parker:: forms acorn@2233: // will eventually be removed as we consolide and shift over to ParkEvents acorn@2233: // for both builtin synchronization and JSR166 operations. acorn@2233: acorn@2233: volatile int Parker::ListLock = 0 ; acorn@2233: Parker * volatile Parker::FreeList = NULL ; acorn@2233: acorn@2233: Parker * Parker::Allocate (JavaThread * t) { acorn@2233: guarantee (t != NULL, "invariant") ; acorn@2233: Parker * p ; acorn@2233: acorn@2233: // Start by trying to recycle an existing but unassociated acorn@2233: // Parker from the global free list. dsimms@6348: // 8028280: using concurrent free list without memory management can leak dsimms@6348: // pretty badly it turns out. dsimms@6348: Thread::SpinAcquire(&ListLock, "ParkerFreeListAllocate"); dsimms@6348: { dsimms@6348: p = FreeList; dsimms@6348: if (p != NULL) { dsimms@6348: FreeList = p->FreeNext; acorn@2233: } acorn@2233: } dsimms@6348: Thread::SpinRelease(&ListLock); acorn@2233: acorn@2233: if (p != NULL) { acorn@2233: guarantee (p->AssociatedWith == NULL, "invariant") ; acorn@2233: } else { acorn@2233: // Do this the hard way -- materialize a new Parker.. acorn@2233: p = new Parker() ; acorn@2233: } acorn@2233: p->AssociatedWith = t ; // Associate p with t acorn@2233: p->FreeNext = NULL ; acorn@2233: return p ; acorn@2233: } acorn@2233: acorn@2233: acorn@2233: void Parker::Release (Parker * p) { acorn@2233: if (p == NULL) return ; acorn@2233: guarantee (p->AssociatedWith != NULL, "invariant") ; acorn@2233: guarantee (p->FreeNext == NULL , "invariant") ; acorn@2233: p->AssociatedWith = NULL ; dsimms@6348: dsimms@6348: Thread::SpinAcquire(&ListLock, "ParkerFreeListRelease"); dsimms@6348: { dsimms@6348: p->FreeNext = FreeList; dsimms@6348: FreeList = p; acorn@2233: } dsimms@6348: Thread::SpinRelease(&ListLock); acorn@2233: } acorn@2233: