Path: blob/master/runtime/compiler/infra/J9MonitorTable.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "infra/MonitorTable.hpp"23#include "infra/Monitor.hpp"24#include "infra/CriticalSection.hpp"25#include "control/CompilationRuntime.hpp"2627#include "j9.h"28#include "j9cfg.h"29#include "j9thread.h"30#include "j9port.h"313233// allocated during codert_onload34TR::MonitorTable *35J9::MonitorTable::init(36J9PortLibrary *portLib,37J9JavaVM *javaVM)38{39if (_instance)40{41return _instance;42}4344PORT_ACCESS_FROM_PORT(portLib);45void *tableMem = j9mem_allocate_memory(sizeof(TR::MonitorTable), J9MEM_CATEGORY_JIT);46if (!tableMem) return 0;47TR::MonitorTable *table = new (tableMem) TR::MonitorTable();4849table->_portLib = portLib;50table->_monitors.setFirst(0);5152table->_numCompThreads = 0;53// Memory for classUnloadMonitorHolders will be allocated later in allocInitClassUnloadMonitorHolders()54// just before the compilation threads are started55table->_classUnloadMonitorHolders = NULL;5657// Initialize the Monitors58if (!table->_tableMonitor.init("JIT-MonitorTableMonitor")) return 0;59if (!table->_j9ScratchMemoryPoolMonitor.init("JIT-ScratchMemoryPoolMonitor")) return 0;60#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)61if (!table->_classUnloadMonitor.initFromVMMutex(javaVM->classUnloadMutex)) return 0;62#else63if (!table->_classUnloadMonitor.init("JIT-ClassUnloadMonitor")) return 0;64#endif65if (!table->_iprofilerPersistenceMonitor.init("JIT-IProfilerPersistenceMonitor")) return 0;6667// Setup a wrapper for VM's monitors that the JIT can acquire68if (!table->_classTableMutex.initFromVMMutex(javaVM->classTableMutex)) return 0;6970table->_scratchMemoryPoolMonitor = &table->_j9ScratchMemoryPoolMonitor; // export this value7172OMR::MonitorTable::_instance = table;73return table;74}7576bool77J9::MonitorTable::allocInitClassUnloadMonitorHolders(uint32_t allowedTotalCompThreads)78{79PORT_ACCESS_FROM_PORT(_portLib);8081_numCompThreads = allowedTotalCompThreads;82// Allocate and initialize the array of classUnloadMonitorHolders83_classUnloadMonitorHolders = (int32_t*)j9mem_allocate_memory(sizeof(*(_classUnloadMonitorHolders)) * _numCompThreads, J9MEM_CATEGORY_JIT);84if (!_classUnloadMonitorHolders)85return false;86for (int32_t i = 0; i < _numCompThreads; i++)87_classUnloadMonitorHolders[i] = 0;8889return true;90}9192TR::Monitor *93J9::MonitorTable::create(char *name)94{95PORT_ACCESS_FROM_PORT(_portLib);9697void *monMem = j9mem_allocate_memory(sizeof(TR::Monitor), J9MEM_CATEGORY_JIT);98if (!monMem)99{100return 0;101}102103TR::Monitor *m = new (monMem) TR::Monitor();104if (!m->init(name))105{106return 0;107}108109//fprintf(stderr, "ADDING MONITOR: %p, %s (first is %p)\n", m, name, _monitors.getFirst());110self()->insert(m);111return m;112}113114115void116J9::MonitorTable::insert(TR::Monitor *monitor)117{118OMR::CriticalSection insertingNewMonitor(&_tableMonitor);119monitor->setNext(_monitors.getFirst());120_monitors.setFirst(monitor);121}122123124void125J9::MonitorTable::removeAndDestroy(TR::Monitor *monitor)126{127TR::MonitorTable *table = TR::MonitorTable::get();128if (!table) return;129PORT_ACCESS_FROM_PORT(table->_portLib);130// search the table for my monitor131{132OMR::CriticalSection searchTableAndRemoveMonitor(&_tableMonitor);133TR::Monitor *prevMonitor = NULL;134TR::Monitor *crtMonitor = (TR::Monitor *)table->_monitors.getFirst();135while (crtMonitor)136{137if (crtMonitor == monitor)138break;139prevMonitor = crtMonitor;140crtMonitor = crtMonitor->getNext();141}142if (crtMonitor)143{144// I found my monitor, so take it out from the link list145if (prevMonitor)146prevMonitor->setNext(crtMonitor->getNext());147else148table->_monitors.setFirst(crtMonitor->getNext());149crtMonitor->destroy();150// free the memory151j9mem_free_memory(monitor);152}153}154}155156157// Note that the following method does not destroys the actual monitors158// If we do, we must make sure that the monitors created from VM mutex are not destroyed159void160J9::MonitorTable::free()161{162TR::MonitorTable *table = TR::MonitorTable::get();163if (!table) return;164165PORT_ACCESS_FROM_PORT(table->_portLib);166167TR::Monitor *monitor = (TR::Monitor *)table->_monitors.getFirst();168while (monitor)169{170TR::Monitor *next = monitor->getNext();171j9mem_free_memory(monitor);172monitor = next;173}174j9mem_free_memory(table->_classUnloadMonitorHolders);175_instance = 0;176j9mem_free_memory(table);177};178179180// Used to check if current thread holds any known monitors181bool182J9::MonitorTable::isThreadInSafeMonitorState(J9VMThread *vmThread)183{184// If we hold any of the following locks, return failure.185if (_tableMonitor.owned_by_self() ||186_j9ScratchMemoryPoolMonitor.owned_by_self() ||187_classTableMutex.owned_by_self() ||188_iprofilerPersistenceMonitor.owned_by_self()189)190return false;191{192OMR::CriticalSection walkingMonitorTable(&_tableMonitor);193for (TR::Monitor *monitor = (TR::Monitor *)_monitors.getFirst(); monitor; monitor = monitor->getNext())194{195if (monitor->owned_by_self())196{197return false;198}199}200return true;201}202}203204205// Return the address of the first monitor that is found locked206TR::Monitor *207J9::MonitorTable::monitorHeldByCurrentThread()208{209// If we hold any of the following locks, return failure.210if (_tableMonitor.owned_by_self())211return &_tableMonitor;212if (_j9ScratchMemoryPoolMonitor.owned_by_self())213return &_j9ScratchMemoryPoolMonitor;214if (_classTableMutex.owned_by_self())215return &_classTableMutex;216if (_iprofilerPersistenceMonitor.owned_by_self())217return &_iprofilerPersistenceMonitor;218{219OMR::CriticalSection walkMonitorTable(&_tableMonitor);220for (TR::Monitor *monitor = (TR::Monitor *)_monitors.getFirst(); monitor; monitor = monitor->getNext())221{222if (monitor->owned_by_self())223{224return monitor;225}226}227}228return NULL;229}230231232int32_t233J9::MonitorTable::readAcquireClassUnloadMonitor(int32_t compThreadIndex)234{235_classUnloadMonitor.enter_read();236// Need to determine the identity of the compilation thread237TR_ASSERT(compThreadIndex < _numCompThreads, "compThreadIndex is too high");238return ++(_classUnloadMonitorHolders[compThreadIndex]);239}240241242int32_t243J9::MonitorTable::readReleaseClassUnloadMonitor(int32_t compThreadIndex)244{245TR_ASSERT(compThreadIndex < _numCompThreads, "compThreadIndex is too high");246if (_classUnloadMonitorHolders[compThreadIndex] > 0)247{248_classUnloadMonitorHolders[compThreadIndex]--;249_classUnloadMonitor.exit_read();250return _classUnloadMonitorHolders[compThreadIndex];251}252else253{254TR_ASSERT(false, "comp thread %d does not have classUnloadMonitor", compThreadIndex);255return -1; // could not release monitor256}257}258259260