/* * Copyright (c) 2013-2014, Pierre Laporte * * 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 3 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 * for more details. * * You should have received a copy of the GNU General Public License * along with this work; if not, see <http://www.gnu.org/licenses/>. */ package fr.pingtimeout.tyrion.util; import fj.data.List; import fr.pingtimeout.tyrion.model.CriticalSectionEntered; import fr.pingtimeout.tyrion.model.CriticalSectionEntering; import fr.pingtimeout.tyrion.model.CriticalSectionEvent; import fr.pingtimeout.tyrion.model.CriticalSectionExit; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; public enum EventsHolderSingleton implements EventsHolder { INSTANCE; private Map<Long, AtomicReference<List<CriticalSectionEvent>>> events = new ConcurrentHashMap<>(); @Override public void recordNewEntering(Thread accessor, Object objectUnderLock) { add(accessor, new CriticalSectionEntering(accessor, objectUnderLock)); } @Override public void recordNewEntry(Thread accessor, Class<?> classUnderLock) { add(accessor, new CriticalSectionEntered(accessor, classUnderLock)); } @Override public void recordNewExit(Thread accessor, Class<?> classUnderLock) { add(accessor, new CriticalSectionExit(accessor, classUnderLock)); } @Override public void recordNewEntry(Thread accessor, Object objectUnderLock) { add(accessor, new CriticalSectionEntered(accessor, objectUnderLock)); } @Override public void recordNewExit(Thread accessor, Object objectUnderLock) { add(accessor, new CriticalSectionExit(accessor, objectUnderLock)); } private void add(Thread accessor, CriticalSectionEvent newEvent) { AtomicReference<List<CriticalSectionEvent>> accessorEventsRef = safeGet(accessor); List<CriticalSectionEvent> currentEventsList; List<CriticalSectionEvent> updatedEventsList; do { currentEventsList = accessorEventsRef.get(); updatedEventsList = currentEventsList.cons(newEvent); } while (!accessorEventsRef.compareAndSet(currentEventsList, updatedEventsList)); } private AtomicReference<List<CriticalSectionEvent>> safeGet(Thread accessor) { long accessorId = accessor.getId(); if (events.get(accessorId) == null) { List<CriticalSectionEvent> accessorEvents = List.nil(); AtomicReference<List<CriticalSectionEvent>> reference = new AtomicReference<>(accessorEvents); events.put(accessorId, reference); } return events.get(accessorId); } public Set<Long> getThreadIds() { return events.keySet(); } public List<CriticalSectionEvent> getAndClearEventsListOf(Long threadId) { AtomicReference<List<CriticalSectionEvent>> accessorEventsRef = events.get(threadId); List<CriticalSectionEvent> currentEventsList; List<CriticalSectionEvent> emptyEventsList = List.nil(); do { currentEventsList = accessorEventsRef.get(); } while (!accessorEventsRef.compareAndSet(currentEventsList, emptyEventsList)); return currentEventsList; } }