mirror of https://github.com/termux/termux-app
109 lines
3.7 KiB
Java
109 lines
3.7 KiB
Java
package com.termux.terminal;
|
|
|
|
/** A circular byte buffer allowing one producer and one consumer thread. */
|
|
final class ByteQueue {
|
|
|
|
private final byte[] mBuffer;
|
|
private int mHead;
|
|
private int mStoredBytes;
|
|
private boolean mOpen = true;
|
|
|
|
public ByteQueue(int size) {
|
|
mBuffer = new byte[size];
|
|
}
|
|
|
|
public synchronized void close() {
|
|
mOpen = false;
|
|
notify();
|
|
}
|
|
|
|
public synchronized int read(byte[] buffer, boolean block) {
|
|
while (mStoredBytes == 0 && mOpen) {
|
|
if (block) {
|
|
try {
|
|
wait();
|
|
} catch (InterruptedException e) {
|
|
// Ignore.
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
if (!mOpen) return -1;
|
|
|
|
int totalRead = 0;
|
|
int bufferLength = mBuffer.length;
|
|
boolean wasFull = bufferLength == mStoredBytes;
|
|
int length = buffer.length;
|
|
int offset = 0;
|
|
while (length > 0 && mStoredBytes > 0) {
|
|
int oneRun = Math.min(bufferLength - mHead, mStoredBytes);
|
|
int bytesToCopy = Math.min(length, oneRun);
|
|
System.arraycopy(mBuffer, mHead, buffer, offset, bytesToCopy);
|
|
mHead += bytesToCopy;
|
|
if (mHead >= bufferLength) mHead = 0;
|
|
mStoredBytes -= bytesToCopy;
|
|
length -= bytesToCopy;
|
|
offset += bytesToCopy;
|
|
totalRead += bytesToCopy;
|
|
}
|
|
if (wasFull) notify();
|
|
return totalRead;
|
|
}
|
|
|
|
/**
|
|
* Attempt to write the specified portion of the provided buffer to the queue.
|
|
* <p/>
|
|
* Returns whether the output was totally written, false if it was closed before.
|
|
*/
|
|
public boolean write(byte[] buffer, int offset, int lengthToWrite) {
|
|
if (lengthToWrite + offset > buffer.length) {
|
|
throw new IllegalArgumentException("length + offset > buffer.length");
|
|
} else if (lengthToWrite <= 0) {
|
|
throw new IllegalArgumentException("length <= 0");
|
|
}
|
|
|
|
final int bufferLength = mBuffer.length;
|
|
|
|
synchronized (this) {
|
|
while (lengthToWrite > 0) {
|
|
while (bufferLength == mStoredBytes && mOpen) {
|
|
try {
|
|
wait();
|
|
} catch (InterruptedException e) {
|
|
// Ignore.
|
|
}
|
|
}
|
|
if (!mOpen) return false;
|
|
final boolean wasEmpty = mStoredBytes == 0;
|
|
int bytesToWriteBeforeWaiting = Math.min(lengthToWrite, bufferLength - mStoredBytes);
|
|
lengthToWrite -= bytesToWriteBeforeWaiting;
|
|
|
|
while (bytesToWriteBeforeWaiting > 0) {
|
|
int tail = mHead + mStoredBytes;
|
|
int oneRun;
|
|
if (tail >= bufferLength) {
|
|
// Buffer: [.............]
|
|
// ________________H_______T
|
|
// =>
|
|
// Buffer: [.............]
|
|
// ___________T____H
|
|
// onRun= _____----_
|
|
tail = tail - bufferLength;
|
|
oneRun = mHead - tail;
|
|
} else {
|
|
oneRun = bufferLength - tail;
|
|
}
|
|
int bytesToCopy = Math.min(oneRun, bytesToWriteBeforeWaiting);
|
|
System.arraycopy(buffer, offset, mBuffer, tail, bytesToCopy);
|
|
offset += bytesToCopy;
|
|
bytesToWriteBeforeWaiting -= bytesToCopy;
|
|
mStoredBytes += bytesToCopy;
|
|
}
|
|
if (wasEmpty) notify();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|