/*   MyThreads : A small, efficient, and fast threadpool implementation in C
 *   Copyright (C) 2017  Subhranil Mukherjee (https://github.com/iamsubhranil)
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, version 3 of the License.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef MYTHREADS_H
#define MYTHREADS_H

#include <stdint.h> // Standard integer

//#define DEBUG // The debug switch

/* The main pool structure
 *
 * To find member descriptions, see mythreads.c .
 */
typedef struct ThreadPool ThreadPool;

/* The status enum to indicate any failure.
 *
 * These values can be compared to all the functions
 * that returns an integer, to findout the status of
 * the execution of the function.
 */
typedef enum Status {
	MEMORY_UNAVAILABLE,
	QUEUE_LOCK_FAILED,
	QUEUE_UNLOCK_FAILED,
	SIGNALLING_FAILED,
	BROADCASTING_FAILED,
	COND_WAIT_FAILED,
	THREAD_CREATION_FAILED,
	POOL_NOT_INITIALIZED,
	POOL_STOPPED,
	INVALID_NUMBER,
	WAIT_ISSUED,
	COMPLETED
} ThreadPoolStatus;

/* Creates a new thread pool with argument number of threads.
 *
 * When this method returns, and if the return value is not
 * NULL, it is assured that all threads are initialized and
 * in waiting state. If any thread fails to initialize,
 * typically if the pthread_create method fails, a warning
 * message is print on the stdout. This method also can fail
 * in case of insufficient memory, which is rare, and a NULL
 * is returned in that case.
 */
ThreadPool *mt_create_pool(uint64_t);

/* Waits till all the threads in the pool are finished.
 *
 * When this method returns, it is assured that all threads
 * in the pool have finished executing, and in waiting state.
 */
void mt_join(ThreadPool *);

/* Destroys the argument pool.
 *
 * This method tries to stop all threads in the pool
 * immediately, and destroys any resource that the pool has
 * used in its lifetime. However, this method will not
 * return until all threads have finished processing their
 * present work. That is, this method will not halt any
 * actively executing thread. Rather, it'll wait for the
 * present jobs to complete, and will keep the threads from
 * running any new jobs. This method then joins all the
 * threads, destroys all synchronization objects, and frees
 * any remaining jobs, finally freeing the pool itself.
 */
void mt_destroy_pool(ThreadPool *);

/* Add a new job to the pool.
 *
 * This method adds a new job, that is a worker function,
 * to the pool. The execution of the function is performed
 * asynchronously, however. This method only assures the
 * addition of the job to the job queue. The job queue is
 * ordered in FIFO style, i.e., for this job to execute,
 * all the jobs that has been added previously has to be
 * executed first. This method doesn't guarantee the thread
 * on which the job may execute. Rather, when its turn comes,
 * the thread which first becomes idle, executes this job.
 * When all threads are idle, any one of them wakes up and
 * executes this function asynchronously.
 */
ThreadPoolStatus mt_add_job(ThreadPool *, void (*func)(void *), void *);

/* Add some new threads to the pool.
 *
 * This function adds specified number of new threads to the
 * argument threadpool. When this function returns, it is
 * ensured that a new thread has been added to the pool.
 * However, this new thread will only come to effect if there
 * are remainder jobs, that is the job queue is not presently
 * empty. This new thread will not steal any running jobs
 * from the running threads. Occasionally, this method will
 * return some error codes, typically due to the failure of
 * pthread_create, or for insufficient memory. These error
 * codes can be compared using the Status enum above.
 */
ThreadPoolStatus mt_add_thread(ThreadPool *, uint64_t);

/* Suspend all currently executing threads in the pool.
 *
 * This method pauses all currently executing threads in
 * the pool. When the method call returns, it is guaranteed
 * that all threads have been suspended at appropiate
 * breakpoints. However, if a thread is presently executing,
 * it is not forcefully suspended. Rather, the call waits
 * till the thread completes the present job, and then
 * halts the thread.
 */
void mt_suspend(ThreadPool *);

/* Resume a suspended pool.
 *
 * This method resumes a pool, aynchronously, if and only
 * if the pool was suspended before. When the method returns,
 * it is guaranteed the all the threads of the pool will
 * wake up from suspend very soon in future. This method
 * fails if the pool was not previously suspended.
 */
void mt_resume(ThreadPool *);

/* Remove an existing thread from the pool.
 *
 * This function will remove one thread from the threadpool,
 * asynchronously. That is, this method will not stop any
 * active threads, rather it'll merely indicate the wish.
 * When any active thread will become idle, before becoming
 * active again the thread will check if removal is wished.
 * If it is wished, then thread will immediately exit. This
 * method can run N times to remove N threads, however it
 * has some serious consequences. If N is greater than the
 * number of threads present in the pool, say M, then all
 * M threads will be stopped. However, next (N-M) threads
 * will also immediately exit when added to the pool. If
 * all M threads are removed from the queue, then the job
 * queue will halt, and when a new thread will be added to
 * the pool, the queue will automatically resume from the
 * position where it stopped.
 */
void mt_remove_thread(ThreadPool *);

/* Returns the number of pending jobs in the pool.
 *
 * This method returns the number of pending jobs in the
 * pool, at the instant of the issue of this call. This
 * denotes the number of jobs the pool will  finish before
 * idlement if no new jobs are added to the pool from this
 * instant.
 */
uint64_t mt_get_job_count(ThreadPool *pool);

/* Returns the number of threads present in the pool.
 *
 * The number returned by this method is aware of all
 * thread addition and removal calls. Hence only the number
 * of threads that are "active" in the pool, either by
 * executing a worker function or in idle wait, will be
 * returned by this method.
 */
uint64_t mt_get_thread_count(ThreadPool *);

#endif