All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.openhft.affinity.NonForkingAffinityLock Maven / Gradle / Ivy

There is a newer version: 3.27ea0
Show newest version
/*
 * Copyright 2016 higherfrequencytrading.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package net.openhft.affinity;

import net.openhft.affinity.impl.NoCpuLayout;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Field;

public class NonForkingAffinityLock extends AffinityLock implements ThreadLifecycleListener {

    private static final Field GROUP_FIELD = makeThreadFieldModifiable("group");

    private static final Field TARGET_FIELD = makeThreadFieldModifiable("target");

    private static final LockInventory LOCK_INVENTORY = new LockInventory(new NoCpuLayout(PROCESSORS)) {
        @Override
        protected AffinityLock newLock(int cpuId, boolean base, boolean reservable) {
            return new NonForkingAffinityLock(cpuId, base, reservable, this);
        }
    };

    NonForkingAffinityLock(int cpuId, boolean base, boolean reservable, LockInventory lockInventory) {
        super(cpuId, base, reservable, lockInventory);
    }

    /**
     * Assign any free cpu to this thread.
     *
     * @return A handle for the current AffinityLock.
     */
    public static AffinityLock acquireLock() {
        return acquireLock(true);
    }

    /**
     * Assign any free core to this thread.
     * 

* In reality, only one cpu is assigned, the rest of the threads for that core are reservable so they are not used. * * @return A handle for the current AffinityLock. */ public static AffinityLock acquireCore() { return acquireCore(true); } /** * Assign a cpu which can be bound to the current thread or another thread. *

* This can be used for defining your thread layout centrally and passing the handle via dependency injection. * * @param bind if true, bind the current thread, if false, reserve a cpu which can be bound later. * @return A handle for an affinity lock. */ public static AffinityLock acquireLock(boolean bind) { return acquireLock(bind, -1, AffinityStrategies.ANY); } /** * Assign a core(and all its cpus) which can be bound to the current thread or another thread. *

* This can be used for defining your thread layout centrally and passing the handle via dependency injection. * * @param bind if true, bind the current thread, if false, reserve a cpu which can be bound later. * @return A handle for an affinity lock. */ public static AffinityLock acquireCore(boolean bind) { return acquireCore(bind, -1, AffinityStrategies.ANY); } private static AffinityLock acquireLock(boolean bind, int cpuId, @NotNull AffinityStrategy... strategies) { return LOCK_INVENTORY.acquireLock(bind, cpuId, strategies); } private static AffinityLock acquireCore(boolean bind, int cpuId, @NotNull AffinityStrategy... strategies) { return LOCK_INVENTORY.acquireCore(bind, cpuId, strategies); } /** * Set the CPU layout for this machine. CPUs which are not mentioned will be ignored. *

* Changing the layout will have no impact on thread which have already been assigned. * It only affects subsequent assignments. * * @param cpuLayout for this application to use for this machine. */ public static void cpuLayout(@NotNull CpuLayout cpuLayout) { LOCK_INVENTORY.set(cpuLayout); } /** * @return The current CpuLayout for the application. */ @NotNull public static CpuLayout cpuLayout() { return LOCK_INVENTORY.getCpuLayout(); } /** * @return All the current locks as a String. */ @NotNull public static String dumpLocks() { return LOCK_INVENTORY.dumpLocks(); } private static Field makeThreadFieldModifiable(String fieldName) { try { Field field = Thread.class.getDeclaredField(fieldName); field.setAccessible(true); return field; } catch (NoSuchFieldException e) { throw new RuntimeException(Thread.class.getName() + " class doesn't have a " + fieldName + " field! Quite unexpected!"); } } private static void changeGroupOfThread(Thread thread, ThreadGroup group) { try { GROUP_FIELD.set(thread, group); } catch (IllegalAccessException e) { throw new RuntimeException("Failed changing " + Thread.class.getName() + "'s the '" + GROUP_FIELD.getName() + "' field! Reason: " + e.getMessage()); } } private static void wrapRunnableOfThread(Thread thread, final AffinityLock lock) { try { final Runnable originalRunnable = (Runnable) TARGET_FIELD.get(thread); TARGET_FIELD.set( thread, new Runnable() { @Override public void run() { lock.release(); originalRunnable.run(); } } ); } catch (IllegalAccessException e) { throw new RuntimeException("Failed wrapping " + Thread.class.getName() + "'s '" + TARGET_FIELD.getName() + "' field! Reason: " + e.getMessage()); } } @Override public void bind(boolean wholeCore) { super.bind(wholeCore); Thread thread = Thread.currentThread(); changeGroupOfThread(thread, new ThreadTrackingGroup(thread.getThreadGroup(), this)); } @Override public void release() { Thread thread = Thread.currentThread(); changeGroupOfThread(thread, thread.getThreadGroup().getParent()); super.release(); } @Override public void started(Thread t) { wrapRunnableOfThread(t, this); } @Override public void startFailed(Thread t) { } @Override public void terminated(Thread t) { } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy