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

kilim.concurrent.MPSCQueue Maven / Gradle / Ivy

Go to download

Coroutines, continuations, fibers, actors and message passing for the JVM

There is a newer version: 2.0.2-jdk7
Show newest version
// Copyright 2014 nilangshah - offered under the terms of the MIT License

package kilim.concurrent;

import java.util.NoSuchElementException;
import java.util.concurrent.locks.LockSupport;

// "Inspired directly by Nitasan's work --> https://github.com/nitsanw/QueueEvolution"
abstract class MPSCQueueL0Pad {
	public long p00, p01, p02, p03, p04, p05, p06, p07;
	public long p30, p31, p32, p33, p34, p35, p36, p37;
}

abstract class MPSCQueueColdFields extends MPSCQueueL0Pad {
	protected static final int BUFFER_PAD = 64; // to
												// pad
												// queue
												// ends
	protected static final int SPARSE_SHIFT = Integer.getInteger(
			"sparse.shift", 0); // pad
								// each
								// element
								// of
								// queue
	protected final int capacity;
	protected final long mask;
	protected final E[] buffer;

	@SuppressWarnings("unchecked")
	public MPSCQueueColdFields(int capacity) {
		if (isPowerOf2(capacity)) {
			this.capacity = capacity;
		} else {
			this.capacity = findNextPositivePowerOfTwo(capacity);
		}
		mask = this.capacity - 1;
		// pad data on either end with some empty slots.
		buffer = (E[]) new Object[(this.capacity << SPARSE_SHIFT) + BUFFER_PAD
				* 2];
	}

	public static int findNextPositivePowerOfTwo(final int value) {
		return 1 << (32 - Integer.numberOfLeadingZeros(value - 1));
	}

	public static boolean isPowerOf2(final int value) {
		return (value & (value - 1)) == 0;
	}
}

abstract class MPSCQueueL1Pad extends MPSCQueueColdFields {
	public long p10, p11, p12, p13, p14, p15, p16;
	public long p30, p31, p32, p33, p34, p35, p36, p37;

	public MPSCQueueL1Pad(int capacity) {
		super(capacity);
	}
}

abstract class MPSCQueueTailField extends MPSCQueueL1Pad {
	protected volatile long tail;

	public MPSCQueueTailField(int capacity) {
		super(capacity);
	}
}

abstract class MPSCQueueL2Pad extends MPSCQueueTailField {
	public long p20, p21, p22, p23, p24, p25, p26;
	public long p30, p31, p32, p33, p34, p35, p36, p37;

	public MPSCQueueL2Pad(int capacity) {
		super(capacity);
	}
}

abstract class MPSCQueueHeadField extends MPSCQueueL2Pad {
	protected long head;

	public MPSCQueueHeadField(int capacity) {
		super(capacity);
	}
}

abstract class MPSCQueueL3Pad extends MPSCQueueHeadField {
	protected final static long TAIL_OFFSET;
	protected final static long HEAD_OFFSET;
	protected static final long ARRAY_BASE;
	protected static final int ELEMENT_SHIFT;
	static {
		try {
			TAIL_OFFSET = UnsafeAccess.UNSAFE
					.objectFieldOffset(MPSCQueueTailField.class
							.getDeclaredField("tail"));
			HEAD_OFFSET = UnsafeAccess.UNSAFE
					.objectFieldOffset(MPSCQueueHeadField.class
							.getDeclaredField("head"));
			final int scale = UnsafeAccess.UNSAFE
					.arrayIndexScale(Object[].class);
			if (4 == scale) {
				ELEMENT_SHIFT = 2 + SPARSE_SHIFT;
			} else if (8 == scale) {
				ELEMENT_SHIFT = 3 + SPARSE_SHIFT;
			} else {
				throw new IllegalStateException("Unknown pointer size");
			}
			// Including the buffer pad in the array base offset
			ARRAY_BASE = UnsafeAccess.UNSAFE.arrayBaseOffset(Object[].class)
					+ (BUFFER_PAD << (ELEMENT_SHIFT - SPARSE_SHIFT));
		} catch (NoSuchFieldException e) {
			throw new RuntimeException(e);
		}
	}
	public long p40, p41, p42, p43, p44, p45, p46;
	public long p30, p31, p32, p33, p34, p35, p36, p37;

	public MPSCQueueL3Pad(int capacity) {
		super(capacity);
	}
}

public class MPSCQueue extends MPSCQueueL3Pad {
	private static final BackOffStrategy CAS_BACKOFF = BackOffStrategy
			.getStrategy("cas.backoff", BackOffStrategy.SPIN); // set property to change backoff strategy

	
	public MPSCQueue(final int capacity) {
		super(capacity);
	}

	private long getHead() {
		return UnsafeAccess.UNSAFE.getLongVolatile(this, HEAD_OFFSET);
	}

	private void lazySetHead(long l) {
		UnsafeAccess.UNSAFE.putOrderedLong(this, HEAD_OFFSET, l);
	}

	private long getTail() {
		return UnsafeAccess.UNSAFE.getLongVolatile(this, TAIL_OFFSET);
	}

	private boolean casTail(long expect, long newValue) {
		return UnsafeAccess.UNSAFE.compareAndSwapLong(this, TAIL_OFFSET,
				expect, newValue);
	}

	public boolean add(final E e) {
		if (offer(e)) {
			return true;
		}
		throw new IllegalStateException("Queue is full");
	}

	private long elementOffsetInBuffer(long index) {
		return ARRAY_BASE + ((index & mask) << ELEMENT_SHIFT);
	}

	public boolean offer(final E e) {
		if (null == e) {
			throw new NullPointerException("Null is not a valid element");
		}
		long currentTail;
		for (int missCount = 0;;) {
			currentTail = getTail();
			if(currentTail==Long.MAX_VALUE){
				System.out.println("bug");
			}
			final long wrapPoint = currentTail - capacity;
			if (getHead() <= wrapPoint) {
				return false;
			}
			if (casTail(currentTail, currentTail + 1)) {
				break;
			} else {
				missCount = CAS_BACKOFF.backoff(missCount);
			}
		}
		UnsafeAccess.UNSAFE.putOrderedObject(buffer,
				elementOffsetInBuffer(currentTail), e);
		return true;
	}

	public boolean hasSpace() {
		long currentTail;
		currentTail = getTail();
		@SuppressWarnings("unchecked")
		final E e = (E) UnsafeAccess.UNSAFE.getObjectVolatile(buffer,
				elementOffsetInBuffer(currentTail));
		if (e == null) {
			return true;
		} else {
			return false;
		}
	}

	public E poll() {
		final long offset = elementOffsetInBuffer(head);
		@SuppressWarnings("unchecked")
		final E e = (E) UnsafeAccess.UNSAFE.getObjectVolatile(buffer, offset);
		if (null == e) {
			return null;
		}
		UnsafeAccess.UNSAFE.putObject(buffer, offset, null);
		lazySetHead(head + 1);
		return e;
	}

	public void fill(E []buf){
		int n=buf.length;
		for(int i=0;i 1000)
					Thread.yield();
				return called++;
			}
		};
		public abstract int backoff(int called);

		public static BackOffStrategy getStrategy(String propertyName,
				BackOffStrategy defaultS) {
			try {
				return BackOffStrategy
						.valueOf(System.getProperty(propertyName));
			} catch (Exception e) {
				return defaultS;
			}
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy