Blame src/libbluray/bdj/java/org/videolan/BDJActionQueue.java

Packit 5e46da
/*
Packit 5e46da
 * This file is part of libbluray
Packit 5e46da
 *
Packit 5e46da
 * This library is free software; you can redistribute it and/or
Packit 5e46da
 * modify it under the terms of the GNU Lesser General Public
Packit 5e46da
 * License as published by the Free Software Foundation; either
Packit 5e46da
 * version 2.1 of the License, or (at your option) any later version.
Packit 5e46da
 *
Packit 5e46da
 * This library is distributed in the hope that it will be useful,
Packit 5e46da
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5e46da
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 5e46da
 * Lesser General Public License for more details.
Packit 5e46da
 *
Packit 5e46da
 * You should have received a copy of the GNU Lesser General Public
Packit 5e46da
 * License along with this library. If not, see
Packit 5e46da
 * <http://www.gnu.org/licenses/>.
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
package org.videolan;
Packit 5e46da
Packit 5e46da
import java.util.LinkedList;
Packit 5e46da
Packit 5e46da
public class BDJActionQueue implements Runnable {
Packit 5e46da
Packit 5e46da
    public static BDJActionQueue create(String name) {
Packit 5e46da
        return create(null, name);
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    public static BDJActionQueue create(BDJThreadGroup threadGroup, String name) {
Packit 5e46da
        BDJActionQueue aq = new BDJActionQueue(threadGroup, name);
Packit 5e46da
        aq.startThread(threadGroup, name);
Packit 5e46da
        return aq;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    private BDJActionQueue(BDJThreadGroup threadGroup, String name) {
Packit 5e46da
        if (threadGroup == null) {
Packit 5e46da
            if (BDJXletContext.getCurrentContext() != null) {
Packit 5e46da
                logger.error("BDJActionQueue " + name + " created from wrong context: " + Logger.dumpStack());
Packit 5e46da
                // throw new SecurityException();
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    private void startThread(BDJThreadGroup threadGroup, String name) {
Packit 5e46da
        /* run all actions in given thread group / xlet context */
Packit 5e46da
        thread = new Thread(threadGroup, this, name + ".BDJActionQueue");
Packit 5e46da
        thread.setDaemon(true);
Packit 5e46da
        thread.start();
Packit 5e46da
Packit 5e46da
        watchdog = new Watchdog();
Packit 5e46da
        watchdog.start(name);
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    public void shutdown() {
Packit 5e46da
Packit 5e46da
        synchronized (actions) {
Packit 5e46da
            terminated = true;
Packit 5e46da
            actions.addLast(null);
Packit 5e46da
            actions.notifyAll();
Packit 5e46da
        }
Packit 5e46da
        watchdog.shutdown();
Packit 5e46da
        try {
Packit 5e46da
            thread.join();
Packit 5e46da
        } catch (InterruptedException t) {
Packit 5e46da
            logger.error("Error joining thread: " + t);
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    public void run() {
Packit 5e46da
        while (true) {
Packit 5e46da
            Object action;
Packit 5e46da
            synchronized (actions) {
Packit 5e46da
                while (actions.isEmpty()) {
Packit 5e46da
                    try {
Packit 5e46da
                        actions.wait();
Packit 5e46da
                    } catch (InterruptedException e) {
Packit 5e46da
                    }
Packit 5e46da
                }
Packit 5e46da
                action = actions.removeFirst();
Packit 5e46da
            }
Packit 5e46da
            if (action == null)
Packit 5e46da
                return;
Packit 5e46da
            try {
Packit 5e46da
                watchdog.startAction(action);
Packit 5e46da
Packit 5e46da
                ((BDJAction)action).process();
Packit 5e46da
Packit 5e46da
                watchdog.endAction();
Packit 5e46da
            } catch (ThreadDeath d) {
Packit 5e46da
                System.err.println("action failed: " + d + "\n");
Packit 5e46da
                throw d;
Packit 5e46da
            } catch (Throwable e) {
Packit 5e46da
                System.err.println("action failed: " + e + "\n" + Logger.dumpStack(e));
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    public void put(BDJAction action) {
Packit 5e46da
        if (action != null) {
Packit 5e46da
            synchronized (actions) {
Packit 5e46da
                if (!terminated) {
Packit 5e46da
                    actions.addLast(action);
Packit 5e46da
                    actions.notifyAll();
Packit 5e46da
                } else {
Packit 5e46da
                    logger.error("Action skipped (queue stopped): " + action);
Packit 5e46da
                    action.abort();
Packit 5e46da
                }
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    private boolean terminated = false;
Packit 5e46da
    private Thread thread;
Packit 5e46da
    private LinkedList actions = new LinkedList();
Packit 5e46da
Packit 5e46da
    private static final Logger logger = Logger.getLogger(BDJActionQueue.class.getName());
Packit 5e46da
Packit 5e46da
    /*
Packit 5e46da
     *
Packit 5e46da
     */
Packit 5e46da
Packit 5e46da
    private Watchdog watchdog = null;
Packit 5e46da
Packit 5e46da
    class Watchdog implements Runnable {
Packit 5e46da
Packit 5e46da
        private Object currentAction = null;
Packit 5e46da
        private boolean terminate = false;
Packit 5e46da
Packit 5e46da
        Watchdog() {}
Packit 5e46da
Packit 5e46da
        synchronized void start(String name) {
Packit 5e46da
            Thread t = new Thread(null, this, name + ".BDJActionQueue.Monitor");
Packit 5e46da
            t.setDaemon(true);
Packit 5e46da
            t.start();
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        public synchronized void shutdown() {
Packit 5e46da
            terminate = true;
Packit 5e46da
            notifyAll();
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        public synchronized void startAction(Object action) {
Packit 5e46da
            currentAction = action;
Packit 5e46da
            notifyAll();
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        public synchronized void endAction() {
Packit 5e46da
            currentAction = null;
Packit 5e46da
            notifyAll();
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        public void run() {
Packit 5e46da
            Object loggedAction = null;
Packit 5e46da
            synchronized (this) {
Packit 5e46da
                while (!terminate) {
Packit 5e46da
Packit 5e46da
                    if (loggedAction != null && currentAction != loggedAction) {
Packit 5e46da
                        loggedAction = null;
Packit 5e46da
                        logger.info("Callback returned (" + thread + ")");
Packit 5e46da
                    }
Packit 5e46da
Packit 5e46da
                    try {
Packit 5e46da
                        if (currentAction == null) {
Packit 5e46da
                            wait();
Packit 5e46da
                        } else {
Packit 5e46da
                            Object cachedAction = currentAction;
Packit 5e46da
                            wait(5000);
Packit 5e46da
                            if (currentAction == cachedAction && loggedAction != cachedAction) {
Packit 5e46da
                                logger.error("Callback timeout in " + thread + ", callback=" + currentAction + "\n" +
Packit 5e46da
                                             PortingHelper.dumpStack(thread));
Packit 5e46da
                                loggedAction = cachedAction;
Packit 5e46da
                            }
Packit 5e46da
                        }
Packit 5e46da
                    } catch (InterruptedException e) {
Packit 5e46da
                    }
Packit 5e46da
                }
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
}