text: #line 233 "parmacs.pthreads.c.m4"
  
  #line 1 "workpool.C"
  /*************************************************************************/
  /*                                                                       */
  /*  Copyright (c) 1994 Stanford University                               */
  /*                                                                       */
  /*  All rights reserved.                                                 */
  /*                                                                       */
  /*  Permission is given to use, copy, and modify this software for any   */
  /*  non-commercial purpose as long as this copyright notice is not       */
  /*  removed.  All other uses, including redistribution in whole or in    */
  /*  part, are forbidden without prior written permission.                */
  /*                                                                       */
  /*  This software is provided with absolutely no warranty and no         */
  /*  support.                                                             */
  /*                                                                       */
  /*************************************************************************/
  
  
  /*
   * NAME
   *	workpool.c
   *
   * DESCRIPTION
   *	This file contains the private data definitions and code for the ray
   *	job work pool.	Each processor has its own workpool.
   *
   *	The workpool consists of a stack of pixel bundles.  Each bundle
   *	contains jobs for primary rays for a contiguous 2D pixel screen
   *	region.
   *
   */
  
  
  #include <stdio.h>
  #include <math.h>
  #include "rt.h"
  
  
  
  /*
   * NAME
   *	PutJob - put another job into pid's work pool
   *
   * SYNOPSIS
   *	VOID	PutJob(xs, ys, xe, ye, xbe, ybe, pid)
   *	INT	xs,  ys;		// Start of block.
   *	INT	xe,  ye;		// Extent of block.
   *	INT	xbe, ybe;		// Extent of bundle.
   *	INT	pid;			// Process id.
   *
   *  DESCRIPTION
   *	Given a block of image screen pixels, this routine generates pixel
   *	bundle entries that are inserted into pid's work pool stack.
   *
   *	A block includes the starting pixel address, the block size in x and y
   *	dimensions and the bundle size for making pixel jobs.
   *
   *	Pixel addresses are 0 relative.
   *
   *	Locking of workpools for job insertion is not required since a given
   *	process only inserts into its own pool and since we use a barrier
   *	before jobs can be removed from workpools.
   *
   * RETURNS
   *	Nothing.
   */
  
  VOID	PutJob(xs, ys, xe, ye, xbe, ybe, pid)
  INT	xs,  ys;
  INT	xe,  ye;
  INT	xbe, ybe;
  INT	pid;
  	{
  	INT	i, j;
  	INT	xb_addr, yb_addr;		/* Bundle pixel address.     */
  	INT	xb_end,  yb_end;		/* End bundle pixels.	     */
  	INT	xb_size, yb_size;		/* Bundle size. 	     */
  	WPJOB	*wpentry;			/* New work pool entry.      */
  
  	/* Starting block pixel address (upper left pixel). */
  
  	xb_addr = xs;
  	yb_addr = ys;
  
  	/* Ending block pixel address (lower right pixel). */
  
  	xb_end = xb_addr + xe - 1;
  	yb_end = yb_addr + ye - 1;
  
  	for (i = 0; i < ye; i += ybe)
  		{
  		for (j = 0; j < xe; j += xbe)
  			{
  			/* Determine bundle size. */
  
  			if ((xb_addr + xbe - 1) <= xb_end)
  				xb_size = xbe;
  			else
  				xb_size = xb_end - xb_addr + 1;
  
  			if ((yb_addr + ybe - 1) <= yb_end)
  				yb_size = ybe;
  			else
  				yb_size = yb_end - yb_addr + 1;
  
  
  			/* Initialize work pool entry. */
  
  			wpentry = GlobalMalloc(sizeof(WPJOB), "workpool.c");
  
  			wpentry->xpix = xb_addr;
  			wpentry->ypix = yb_addr;
  			wpentry->xdim = xb_size;
  			wpentry->ydim = yb_size;
  
  
  			/* Add to top of work pool stack. */
  
  			if (!gm->workpool[pid][0])
  				wpentry->next = NULL;
  			else
  				wpentry->next = gm->workpool[pid][0];
  
  			gm->workpool[pid][0] = wpentry;
  			xb_addr += xbe;
  			}
  
  		xb_addr  = xs;
  		yb_addr += ybe;
  		}
  	}
  
  
  
  /*
   * NAME
   *	GetJob - get next job from pid's work pool
   *
   * SYNOPSIS
   *	INT	GetJob(job, pid)
   *	RAYJOB	*job;			// Ray job description.
   *	INT	pid;			// Process id.
   *
   * DESCRIPTION
   *	Return a primary ray job bundle from the top of the stack.  A ray job
   *	bundle consists of the starting primary ray pixel address and the size
   *	of the pixel bundle.
   *
   * RETURNS
   *	Work pool status code.
   */
  
  INT	GetJob(job, pid)
  RAYJOB	*job;
  INT	pid;
  	{
  	WPJOB	*wpentry;			/* Work pool entry.	     */
  
  	{pthread_mutex_lock(&gm->wplock[pid]);}
  	wpentry = gm->workpool[pid][0];
  
  	if (!wpentry)
  		{
  		gm->wpstat[pid][0] = WPS_EMPTY;
  		{pthread_mutex_unlock(&gm->wplock[pid]);}
  		return (WPS_EMPTY);
  		}
  
  	gm->workpool[pid][0] = wpentry->next;
  	{pthread_mutex_unlock(&gm->wplock[pid]);}
  
  	/* Set up ray job information. */
  
  	job->x	   = wpentry->xpix;
  	job->y	   = wpentry->ypix;
  	job->xcurr = wpentry->xpix;
  	job->ycurr = wpentry->ypix;
  	job->xlen  = wpentry->xdim;
  	job->ylen  = wpentry->ydim;
  
  	GlobalFree(wpentry);
  	return (WPS_VALID);
  	}
  
  
  
  /*
   * NAME
   *	GetJobs - get next job for pid (with job stealing)
   *
   * SYNOPSIS
   *	INT	GetJobs(job, pid)
   *	RAYJOB	*job;			// Ray job pointer from work pool.
   *	INT	pid;			// Process id.
   *
   * DESCRIPTION
   *
   * RETURNS
   *	Workpool status.
   */
  
  INT	GetJobs(job, pid)
  RAYJOB	*job;
  INT	pid;
  	{
  	INT	i;
  
  	i = pid;
  
  	/* First, try to get job from pid's own pool (or pool 0). */
  
  	if (gm->wpstat[i][0] == WPS_VALID)
  		 if (GetJob(job, i) == WPS_VALID)
  			{
  			return (WPS_VALID);
  			}
  
  
  	/*
  	 *	If that failed, try to get job from another pid's work
  	 *	pool.
  	 */
  
  		i = (pid + 1) % gm->nprocs;
  
  		while (i != pid)
  			{
  			if (gm->wpstat[i][0] == WPS_VALID)
  				if (GetJob(job, i) == WPS_VALID)
  					{
  					return (WPS_VALID);
  					}
  
  			i = (i + 1) % gm->nprocs;
  			}
  
  	return (WPS_EMPTY);
  	}
  
  
  
  /*
   * NAME
   *	PrintWorkPool - print out the work pool entries for a given process
   *
   * SYNOPSIS
   *	VOID	PrintWorkPool(pid)
   *	INT	pid;			// Process id.
   *
   * RETURNS
   *	Nothing.
   */
  
  VOID	PrintWorkPool(pid)
  INT	pid;
  	{
  	WPJOB	*j;
  
  	j = gm->workpool[pid][0];
  
  	while (j)
  		{
  		printf("Workpool entry:    pid=%3ld    xs=%3ld    ys=%3ld    xe=%3ld    ye=%3ld\n", pid, j->xpix, j->ypix, j->xdim, j->ydim);
  		j = j->next;
  		}
  	}
  
  
  
  /*
   * NAME
   *	InitWorkPool - fill pid's work pool with jobs
   *
   * SYNOPSIS
   *	VOID	InitWorkPool(pid)
   *	INT	pid;			// Process id to initialize.
   *
   * RETURNS
   *	Nothing.
   */
  
  VOID	InitWorkPool(pid)
  INT	pid;
  	{
  	INT	i;
  	INT	x, y;
  	INT	xe, ye;
  	INT	xsize, ysize;
  
  	gm->wpstat[pid][0]   = WPS_VALID;
  	gm->workpool[pid][0] = NULL;
  
  	i      = 0;
  	xsize  = Display.xres/blockx;
  	ysize  = Display.yres/blocky;
  
  	for (y = 0; y < Display.yres; y += ysize)
  		{
  		if (y + ysize > Display.yres)
  			ye = Display.yres - y;
  		else
  			ye = ysize;
  
  		for (x = 0; x < Display.xres; x += xsize)
  			{
  			if (x + xsize > Display.xres)
  				xe = Display.xres - x;
  			else
  				xe = xsize;
  
  			if (i == pid)
  				PutJob(x, y, xe, ye, bundlex, bundley, pid);
  
  			i = (i + 1)%gm->nprocs;
  			}
  		}
  
  	}
  
  