// vim: ts=4 sw=4 expandtab ft=java
//
// Copyright (C) 2014, 2016, 2018 The Mercury Team
// This file is distributed under the terms specified in COPYING.LIB.
//

package jmercury.runtime;

/**
 * Threads for the Mercury code running in Java.
 */
public class MercuryWorkerThread extends MercuryThread
{
    private MercuryThreadPool   pool;

    private ThreadStatus        status;

    /**
     * Construct a new MercuryThread with the given ID and runnable.
     * @param pool The Mercury thread pool.
     * @param id A numeric identifier (should be unique).
     */
    public MercuryWorkerThread(MercuryThreadPool pool, int id)
    {
        super("Mercury Worker Thread", id);
        this.pool = pool;
        this.status = ThreadStatus.OTHER;
    }

    /**
     * Run.
     * The worker thread executes tasks that it retrieves from the pool.
     */
    public void run()
    {
        Task task;

        try {
            do {
                task = null;
                try {
                    if (status != ThreadStatus.IDLE) {
                        setStatus(ThreadStatus.IDLE);
                    }
                    task = pool.workerGetTask();
                }
                catch (InterruptedException e) {
                    // A worker thread has no semantics for this,
                    // so we continue looping.
                    continue;
                }
                if (task != null) {
                    try {
                        setStatus(ThreadStatus.WORKING);
                        task.run();
                        pool.taskDone(task);
                    } catch (jmercury.runtime.Exception e) {
                        // The task threw a Mercury exception.
                        pool.taskFailed(task, e);
                        JavaInternal.reportUncaughtException(e);
                        // Make the thread exit after throwing an exception.
                        break;
                    } catch (Throwable e) {
                        // Some other error occured, bail out.
                        // XXX We should avoid calling exit() here.
                        System.err.println("Uncaught exception: " +
                            e.toString());
                        System.err.println(e.getMessage());
                        e.printStackTrace();
                        System.exit(1);
                    } finally {
                        setStatus(ThreadStatus.OTHER);
                    }
                }
            } while (task != null);
        } finally {
            pool.threadShutdown(this, status);
        }
    }

    protected void setStatus(ThreadStatus new_status) {
        pool.updateThreadCounts(status, new_status);
        status = new_status;
    }

    public void blocked() {
        pool.updateThreadCounts(status, ThreadStatus.BLOCKED);
        status = ThreadStatus.BLOCKED;
    }

    public void running() {
        pool.updateThreadCounts(status, ThreadStatus.WORKING);
        status = ThreadStatus.WORKING;
    }
}
