Files
MoGoEagleEye/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/MessageTask.java
donghongyu b10306fc45 [Change]
开始USB摄像头的功能集成,还无法获取usb连接广播需要调试

Signed-off-by: donghongyu <donghongyu@zhidaoauto.com>
2022-02-10 18:47:07 +08:00

516 lines
14 KiB
Java
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.serenegiant.utils;
import android.util.Log;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
public abstract class MessageTask implements Runnable {
// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること
private static final String TAG = MessageTask.class.getSimpleName();
public static class TaskBreak extends RuntimeException {
}
protected static final class Request {
int request;
int arg1;
int arg2;
Object obj;
int request_for_result;
Object result;
private Request() {
request = request_for_result = REQUEST_TASK_NON;
}
/**
* @param _request minus value is reserved internal use
* @param _arg1
* @param _arg2
* @param _obj
*/
public Request(final int _request, final int _arg1, final int _arg2, final Object _obj) {
request = _request;
arg1 = _arg1;
arg2 = _arg2;
obj = _obj;
request_for_result = REQUEST_TASK_NON;
}
public void setResult(final Object result) {
synchronized (this) {
this.result = result;
request = request_for_result = REQUEST_TASK_NON;
notifyAll();
}
}
@Override
public boolean equals(final Object o) {
return (o instanceof Request)
? (request == ((Request) o).request)
&& (request_for_result == ((Request)o).request_for_result)
&& (arg1 == ((Request) o).arg1)
&& (arg2 == ((Request) o).arg2)
&& (obj == ((Request) o).obj)
: super.equals(o);
}
}
// minus values and zero are reserved for internal use
protected static final int REQUEST_TASK_NON = 0;
protected static final int REQUEST_TASK_RUN = -1;
protected static final int REQUEST_TASK_RUN_AND_WAIT = -2;
protected static final int REQUEST_TASK_START = -8;
protected static final int REQUEST_TASK_QUIT = -9;
private final Object mSync = new Object();
/** プール/キューのサイズ, -1なら無制限 */
private final int mMaxRequest;
private final LinkedBlockingQueue<Request> mRequestPool; // FIXME これはArrayListにした方が速いかも
private final LinkedBlockingDeque<Request> mRequestQueue;
private volatile boolean mIsRunning, mFinished;
private Thread mWorkerThread;
/**
* コンストラクタ
* プール&キューのサイズは無制限
* プールは空で生成
*/
public MessageTask() {
mMaxRequest = -1;
mRequestPool = new LinkedBlockingQueue<Request>();
mRequestQueue = new LinkedBlockingDeque<Request>();
}
/**
* コンストラクタ
* プール&キューのサイズは無制限
* @param init_num プールするRequestの初期数を指定
*/
public MessageTask(final int init_num) {
mMaxRequest = -1;
mRequestPool = new LinkedBlockingQueue<Request>();
mRequestQueue = new LinkedBlockingDeque<Request>();
for (int i = 0; i < init_num; i++) {
if (!mRequestPool.offer(new Request())) break;
}
}
/**
* コンストラクタ
* プール及びキュー可能な最大サイズを指定して初期化
* @param max_request キューの最大サイズを指定
* @param init_num プールするRequestの初期数を指定, max_requestよりも大きければ切り捨てる
*/
public MessageTask(final int max_request, final int init_num) {
mMaxRequest = max_request;
mRequestPool = new LinkedBlockingQueue<Request>(max_request);
mRequestQueue = new LinkedBlockingDeque<Request>(max_request);
for (int i = 0; i < init_num; i++) {
if (!mRequestPool.offer(new Request())) break;
}
}
/**
* 初期化要求。継承クラスのコンストラクタから呼び出すこと
* パラメータはonInitに引き渡される
* @param arg1
* @param arg2
* @param obj
*/
protected void init(final int arg1, final int arg2, final Object obj) {
mFinished = false;
mRequestQueue.offer(obtain(REQUEST_TASK_START, arg1, arg2, obj));
// offer(REQUEST_TASK_START, arg1, arg2, obj);
}
/** 初期化処理 */
protected abstract void onInit(final int arg1, final int arg2, final Object obj);
/** 要求処理ループ開始直前に呼ばれる */
protected abstract void onStart();
/** onStopの直前に呼び出される, interruptされた時は呼び出されない */
protected void onBeforeStop() {}
/** 停止処理, interruptされた時は呼び出されない */
protected abstract void onStop();
/** onStop後に呼び出される。onStopで例外発生しても呼ばれる */
protected abstract void onRelease();
/**
* メッセージ処理ループ中でのエラー発生時の処理
* デフフォルトはtrueを返しメッセージ処理ループを終了する
* @return trueを返すとメッセージ処理ループを終了する
*/
protected boolean onError(final Exception e) {
// if (DEBUG) Log.w(TAG, e);
return true;
}
/** 要求メッセージの処理(内部メッセージは来ない)
* TaskBreakをthrowすると要求メッセージ処理ループを終了する */
protected abstract Object processRequest(final int request, final int arg1, final int arg2, final Object obj) throws TaskBreak;
/** 要求メッセージを取り出す処理(要求メッセージがなければブロックされる) */
protected Request takeRequest() throws InterruptedException {
return mRequestQueue.take();
}
public boolean waitReady() {
synchronized (mSync) {
for ( ; !mIsRunning && !mFinished ; ) {
try {
mSync.wait(500);
} catch (final InterruptedException e) {
break;
}
}
return mIsRunning;
}
}
public boolean isRunning() {
return mIsRunning;
}
public boolean isFinished() {
return mFinished;
}
@Override
public void run() {
Request request = null;
mIsRunning = true;
try {
request = mRequestQueue.take();
} catch (final InterruptedException e) {
mIsRunning = false;
mFinished = true;
}
synchronized (mSync) {
if (mIsRunning) {
mWorkerThread = Thread.currentThread();
try {
onInit(request.arg1, request.arg2, request.obj);
} catch (final Exception e) {
Log.w(TAG, e);
mIsRunning = false;
mFinished = true;
}
}
mSync.notifyAll();
}
if (mIsRunning) {
try {
onStart();
} catch (final Exception e) {
if (callOnError(e)) {
mIsRunning = false;
mFinished = true;
}
}
}
LOOP: for (; mIsRunning; ) {
try {
request = takeRequest();
switch (request.request) {
case REQUEST_TASK_NON:
break;
case REQUEST_TASK_QUIT:
break LOOP;
case REQUEST_TASK_RUN:
if (request.obj instanceof Runnable)
try {
((Runnable)request.obj).run();
} catch (final Exception e) {
if (callOnError(e))
break LOOP;
}
break;
case REQUEST_TASK_RUN_AND_WAIT:
try {
request.setResult(processRequest(request.request_for_result, request.arg1, request.arg2, request.obj));
} catch (final TaskBreak e) {
request.setResult(null);
break LOOP;
} catch (final Exception e) {
request.setResult(null);
if (callOnError(e))
break LOOP;
}
break;
default:
try {
processRequest(request.request, request.arg1, request.arg2, request.obj);
} catch (final TaskBreak e) {
break LOOP;
} catch (final Exception e) {
if (callOnError(e))
break LOOP;
}
break;
}
request.request = request.request_for_result = REQUEST_TASK_NON;
// プールへ返却する
mRequestPool.offer(request);
} catch (final InterruptedException e) {
break;
}
}
final boolean interrupted = Thread.interrupted();
synchronized (mSync) {
mWorkerThread = null;
mIsRunning = false;
mFinished = true;
}
if (!interrupted) {
try {
onBeforeStop();
onStop();
} catch (final Exception e) {
callOnError(e);
}
}
try {
onRelease();
} catch (final Exception e) {
// callOnError(e);
}
synchronized (mSync) {
mSync.notifyAll();
}
}
/**
* エラー処理。onErrorを呼び出す。
* trueを返すと要求メッセージ処理ループを終了する
* @param e
* @return
*/
protected boolean callOnError(final Exception e) {
try {
return onError(e);
} catch (final Exception e2) {
// if (DEBUG) Log.e(TAG, "exception occurred in callOnError", e);
}
return true;
}
/**
* RequestプールからRequestを取得する
* プールが空の場合は新規に生成する
* @param request minus values and zero are reserved
* @param arg1
* @param arg2
* @param obj
* @return Request
*/
protected Request obtain(final int request, final int arg1, final int arg2, final Object obj) {
Request req = mRequestPool.poll();
if (req != null) {
req.request = request;
req.arg1 = arg1;
req.arg2 = arg2;
req.obj = obj;
} else {
req = new Request(request, arg1, arg2, obj);
}
return req;
}
/**
* offer request to run on worker thread
* @param request minus values and zero are reserved
* @param arg1
* @param arg2
* @param obj
* @return true if success offer
*/
public boolean offer(final int request, final int arg1, final int arg2, final Object obj) {
return !mFinished && mRequestQueue.offer(obtain(request, arg1, arg2, obj));
}
/**
* offer request to run on worker thread
* @param request minus values and zero are reserved
* @param arg1
* @param obj
* @return true if success offer
*/
public boolean offer(final int request, final int arg1, final Object obj) {
return !mFinished && mRequestQueue.offer(obtain(request, arg1, 0, obj));
}
/**
* offer request to run on worker thread
* @param request minus values and zero are reserved
* @param arg1
* @param arg2
* @return true if success offer
*/
public boolean offer(final int request, final int arg1, final int arg2) {
return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, arg1, arg2, null));
}
/**
* offer request to run on worker thread
* @param request minus values and zero are reserved
* @param arg1
* @return true if success offer
*/
public boolean offer(final int request, final int arg1) {
return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, arg1, 0, null));
}
/**
* offer request to run on worker thread
* @param request minus values and zero are reserved
* @return true if success offer
*/
public boolean offer(final int request) {
return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, 0, 0, null));
}
/**
* offer request to run on worker thread
* @param request minus values and zero are reserved
* @param obj
* @return true if success offer
*/
public boolean offer(final int request, final Object obj) {
return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, 0, 0, obj));
}
/**
* offer request to run on worker thread on top of the request queue
* @param request minus values and zero are reserved
* @param arg1
* @param arg2
*/
public boolean offerFirst(final int request, final int arg1, final int arg2, final Object obj) {
return !mFinished && mIsRunning && mRequestQueue.offerFirst(obtain(request, arg1, arg2, obj));
}
/**
* offer request to run on worker thread and wait for result
* caller thread is blocked until the request finished running on worker thread
* FIXME このメソッドはMessageTaskを実行中のスレッド上で呼び出すとデッドロックする
* @param request
* @param arg1
* @param arg2
* @param obj
* @return
*/
public Object offerAndWait(final int request, final int arg1, final int arg2, final Object obj) {
if (!mFinished && (request > REQUEST_TASK_NON)) {
final Request req = obtain(REQUEST_TASK_RUN_AND_WAIT, arg1, arg2, obj);
synchronized (req) {
req.request_for_result = request;
req.result = null;
mRequestQueue.offer(req);
for (; mIsRunning && (req.request_for_result != REQUEST_TASK_NON); ) {
try {
req.wait(100);
} catch (final InterruptedException e) {
break;
}
}
}
return req.result;
} else {
return null;
}
}
/**
* request to run on worker thread
* @param task
* @return true if success queue
*/
public boolean queueEvent(final Runnable task) {
return !mFinished && (task != null) && offer(REQUEST_TASK_RUN, task);
}
public void removeRequest(final Request request) {
for (final Request req: mRequestQueue) {
if (!mIsRunning || mFinished) break;
if (req.equals(request)) {
mRequestQueue.remove(req);
mRequestPool.offer(req);
}
}
}
public void removeRequest(final int request) {
for (final Request req: mRequestQueue) {
if (!mIsRunning || mFinished) break;
if (req.request == request) {
mRequestQueue.remove(req);
mRequestPool.offer(req);
}
}
}
/**
* request terminate worker thread and release all related resources
*/
public void release() {
release(false);
}
/**
* request terminate worker thread and release all related resources
* @param interrupt trueなら実行中のタスクをinterruptする
*/
public void release(final boolean interrupt) {
final boolean b = mIsRunning;
mIsRunning = false;
if (!mFinished) {
mRequestQueue.clear();
mRequestQueue.offerFirst(obtain(REQUEST_TASK_QUIT, 0, 0, null));
synchronized (mSync) {
if (b) {
final long current = Thread.currentThread().getId();
final long id = mWorkerThread != null ? mWorkerThread.getId() : current;
if (id != current) {
if (interrupt && (mWorkerThread != null)) {
mWorkerThread.interrupt();
}
for ( ; !mFinished ; ) {
try {
mSync.wait(300);
} catch (final InterruptedException e) {
// ignore
}
}
}
}
}
}
}
/**
* 実行中のタスクが終了後開放する
*/
public void releaseSelf() {
mIsRunning = false;
if (!mFinished) {
mRequestQueue.clear();
mRequestQueue.offerFirst(obtain(REQUEST_TASK_QUIT, 0, 0, null));
}
}
/**
* processRequest内でメッセージループを非常終了させるためのヘルパーメソッド
* 単にTaskBreakをthrowするだけ
* @throws TaskBreak
*/
public void userBreak() throws TaskBreak {
throw new TaskBreak();
}
}