/* Thread eval for VIPS.
 *
 * 29/9/99 JC
 *	- from thread.h
 */

/*

    This file is part of VIPS.
    
    VIPS is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 */

/*

    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk

 */

#ifndef IM_THREADGROUP_H
#define IM_THREADGROUP_H

#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/

#include <vips/semaphore.h>

/* Stack size for each thread. Need to set this explicitly because some
 * systems have a very low default.

 	FIXME ...  should have an environment variable for this?

 */
#define IM__DEFAULT_STACK_SIZE (2 * 1024 * 1024)

/* A work function.
 */
typedef int (*im__work_fn)( REGION *, void *, void *, void * );

/* What we track for each thread.
 */
typedef struct {
	REGION *reg;		/* Region this thread operates on */
	struct im__threadgroup_t *tg; /* Thread group we are part of */

        GThread *thread;  	/* Thread for this region */
        im_semaphore_t go;   	/* Thread waits here to start work */
        volatile int idle;	/* Thread sets this when idle */
	int kill;		/* Set this to make thread exit */
	int error;		/* Set by thread if work fn fails */

	REGION *oreg;		/* If part of an inplace threadgroup, */
	Rect pos;		/* where this thread should write */
	int x, y;		/* it's result */

        void *a, *b, *c; 	/* User arguments to work fns */

#ifdef TIME_THREAD
	hrtime_t *btime, *etime;
	int tpos;
#endif /*TIME_THREAD*/
} im_thread_t;

/* What we track for a group of threads working together.
 */
typedef struct im__threadgroup_t {
	int zombie;		/* Set if has been freed */

	IMAGE *im;		/* Image we are calculating */
	int pw, ph;		/* Tile size */
	int nlines;		/* Scanlines-at-once we prefer for iteration */

	im_semaphore_t idle;	/* The number of idle threads */
	im__work_fn work;	/* Work fn for this threadgroup */
	int inplace;		/* Regions should be contiguous */

	int nthr;		/* Number of threads in group */
	im_thread_t **thr;	/* Threads */

	int kill;		/* Set this to stop threadgroup early */
} im_threadgroup_t;

/* Thread group functions.
 */
extern im_threadgroup_t *im_threadgroup_create( IMAGE *im );
extern int im_threadgroup_free( im_threadgroup_t *tg );

/* Internal eval funcs ... used by generate/iterate.
 */
extern int im__eval_to_region( im_threadgroup_t *tg, REGION *oreg );
extern int im__eval_to_image( im_threadgroup_t *tg, IMAGE *im );

/* Threaded im_prepare()
 */
extern int im_prepare_thread( im_threadgroup_t *tg, REGION *oreg, Rect *r );

#ifdef __cplusplus
}
#endif /*__cplusplus*/

#endif /*IM_THREADGROUP_H*/
