Exemple #1
0
int rd_dealloc(int target)
{
    unsigned int i, j;

#ifdef DEBUG
    int a = 0;
#endif

    i = rd_info[target].index;
    debug3("RD: dealloc target = %d, first index = %d, size = %d blocks\n",
	   target, i, rd_info[target].size);
    while ((rd_segment[i].seg_size != 0) && (i != MAX_ENTRIES + 1)) {
	j = i;
	debug5("RD: dealloc pass: %d, purging rd_segment[%d].segment = 0x%x, next index %d, size = %d\n",
	     a, j, rd_segment[j].segment, rd_segment[j].next,
	     rd_segment[j].seg_size);
	mm_free(rd_segment[j].segment);
	rd_segment[j].segment = 0;
	rd_segment[j].seg_size = 0;
	i = rd_segment[j].next;
	rd_segment[j].next = MAX_ENTRIES + 1;
	debug5("RD: dealloc pass: %d, status rd_segment[%d].segment = 0x%x, next index %d, size = %d\n",
	     a++, j, rd_segment[j].segment, rd_segment[j].next,
	     rd_segment[j].seg_size);
    }
    rd_info[target].flags = 0;

    return 0;
}
Exemple #2
0
/* Throw away buffies that we passed. */
static void bc_forget(struct bufferchain *bc)
{
	struct buffy *b = bc->first;
	/* free all buffers that are def'n'tly outdated */
	/* we have buffers until filepos... delete all buffers fully below it */
	if(b) debug2("bc_forget: block %lu pos %lu", (unsigned long)b->size, (unsigned long)bc->pos);
	else debug("forget with nothing there!");

	while(b != NULL && bc->pos >= b->size)
	{
		struct buffy *n = b->next; /* != NULL or this is indeed the end and the last cycle anyway */
		if(n == NULL) bc->last = NULL; /* Going to delete the last buffy... */
		bc->fileoff += b->size;
		bc->pos  -= b->size;
		bc->size -= b->size;

		debug5("bc_forget: forgot %p with %lu, pos=%li, size=%li, fileoff=%li", (void*)b->data, (long)b->size, (long)bc->pos,  (long)bc->size, (long)bc->fileoff);

		free(b->data);
		free(b);
		b = n;
	}
	bc->first = b;
	bc->firstpos = bc->pos;
}
Exemple #3
0
bool cSatipRtsp::Teardown(const char *uriP)
{
  debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
  bool result = false;

  if (handleM && !isempty(uriP)) {
     long rc = 0;
     cTimeMs processing(0);
     CURLcode res = CURLE_OK;

     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
     SATIP_CURL_EASY_PERFORM(handleM);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
     if (dataBufferM.Size() > 0) {
        ParseData();
        dataBufferM.Reset();
        }

     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_CLIENT_CSEQ, 1L);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL);

     result = ValidateLatestResponse(&rc);
     debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
     }

  return result;
}
Exemple #4
0
/* Adds character c, waiting if wait=1 (or otherwise throws out new char) */
int chq_addch(register struct ch_queue *q, unsigned char c, int wait)
{
    unsigned int nhead;

    debug5("CHQ: chq_addch(%d, %c, %d) q->len=%d q->tail=%d\n", q, c, 0,
	   q->len, q->tail);

    if (q->len == q->size) {
	if (wait) {
	    debug("CHQ: addch sleeping\n");
	    interruptible_sleep_on(&q->wq);
	    debug("CHQ: addch waken up\n");
	}
    }

    if (q->len == q->size)
	return -1;

    nhead = (unsigned int) ((q->tail + q->len) & (q->size - 1));
    q->buf[nhead] = (char) c;
    q->len++;
    wake_up(&q->wq);

    return 0;
}
Exemple #5
0
static void PDF_PrintUnderline(FONT_NUM fnum, COLOUR_NUM col,
  FULL_LENGTH xstart, FULL_LENGTH xstop, FULL_LENGTH ymk)
{
  debug5(DPF, DD, "PDF_PrintUnderline(ft %d, co %d, xstrt %s, xstp %s, ymk %s)",
    fnum, col, EchoLength(xstart), EchoLength(xstop), EchoLength(ymk));
  PDFPage_PrintUnderline(out_fp,  xstart, xstop,
    ymk - finfo[fnum].underline_pos, finfo[fnum].underline_thick);
  debug0(DPF, DD, "PrintUnderline returning.");
} /* end PDF_PrintUnderline */
Exemple #6
0
static void do_rd_request(void)
{
    register char *buff;
    rd_sector_t start;		/* absolute offset from start of device */
    seg_t segnum;		/* segment index; segment = rd_segment[segnum].segment */
    segext_t offset;		/* relative offset (from start of segment) */
    int target;

    while (1) {
	if (!CURRENT || CURRENT->rq_dev < 0)
	    return;

	INIT_REQUEST;

	if (CURRENT == NULL || CURRENT->rq_sector == (sector_t) - 1)
	    return;

	if (rd_initialised != 1) {
	    end_request(0, CURRENT->rq_dev);
	    continue;
	}

	start = (rd_sector_t) CURRENT->rq_sector;
	buff = CURRENT->rq_buffer;
	target = DEVICE_NR(CURRENT->rq_dev);
	debug2("RD: request target: %d, start: %ld\n", target, (long) start);
	if ((rd_info[target].flags != RD_BUSY)
	    || (start >= rd_info[target].size)) {
	    debug4("RD: bad request on ram%d, flags: %d, size: %d, start: %d\n",
		 target, rd_info[target].flags, rd_info[target].size, start);
	    end_request(0, CURRENT->rq_dev);
	    continue;
	}
	offset = start;		/* offset from segment start */
	segnum = rd_info[target].index;	/* we want to know our starting index nr. */
	debug1("RD: request index = %d\n", segnum);
	while (offset > rd_segment[segnum].seg_size) {
	    offset -= rd_segment[segnum].seg_size;	/* recalculate offset */
	    segnum = rd_segment[segnum].next;	/* point to next segment in linked list */
	}
	debug5("RD: request entry = %d, segment = 0x%x, offset = %d (%x %x)\n",
	     segnum, rd_segment[segnum].segment, offset, CURRENT->rq_seg,
	     buff);
	if (CURRENT->rq_cmd == WRITE) {
	    debug1("RD: request writing to %ld\n", (long) start);
	    fmemcpy(rd_segment[segnum].segment, offset * SECTOR_SIZE,
		    CURRENT->rq_seg, buff, 1024);
	}
	if (CURRENT->rq_cmd == READ) {
	    debug1("RD_REQUEST reading from %ld\n", start);
	    fmemcpy(CURRENT->rq_seg, buff, rd_segment[segnum].segment,
		    offset * SECTOR_SIZE, 1024);
	}
	end_request(1, CURRENT->rq_dev);
    }
}
Exemple #7
0
static void PDF_LinkDest(OBJECT name, FULL_LENGTH llx, FULL_LENGTH lly,
  FULL_LENGTH urx, FULL_LENGTH ury)
{
  debug5(DPF, D, "PDF_LinkDest(%s, %d, %d, %d, %d)", EchoObject(name),
    llx, lly, urx, ury);

  /* still to do */

  debug0(DPF, D, "PDF_LinkDest returning.");
} /* end PDF_LinkDest */
Exemple #8
0
/* Adds character c if there is room (or otherwise throws out new char) */
void chq_addch(register struct ch_queue *q, unsigned char c)
{
    debug5("CHQ: chq_addch(%d, %c, %d) q->len=%d q->start=%d\n", q, c, 0,
	   q->len, q->start);

    if (q->len < q->size) {
	q->base[(unsigned int)((q->start + q->len) & (q->size - 1))] = (char)c;
	q->len++;
	wake_up(&q->wait);
    }
}
Exemple #9
0
bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP)
{
  debug1("%s (%s, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, tunerM.GetId());
  bool result = false;

  if (handleM && !isempty(uriP)) {
     cString transport;
     long rc = 0;
     cTimeMs processing(0);
     CURLcode res = CURLE_OK;

     switch (modeM) {
       case cmMulticast:
            // RTP/AVP;multicast;destination=<IP multicast address>;port=<RTP port>-<RTCP port>;ttl=<ttl>
            transport = cString::sprintf("RTP/AVP;multicast;port=%d-%d", rtpPortP, rtcpPortP);
            break;
       default:
       case cmUnicast:
            // RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port>
            transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPortP, rtcpPortP);
            break;
       }

     // Setup media stream
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_TRANSPORT, *transport);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
     // Set header callback for catching the session and timeout
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipRtsp::HeaderCallback);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
     SATIP_CURL_EASY_PERFORM(handleM);
     // Session id is now known - disable header parsing
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, NULL);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
     if (headerBufferM.Size() > 0) {
        ParseHeader();
        headerBufferM.Reset();
        }
     if (dataBufferM.Size() > 0) {
        ParseData();
        dataBufferM.Reset();
        }

     result = ValidateLatestResponse(&rc);
     debug5("%s (%s, %d, %d) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, rc, processing.Elapsed(), tunerM.GetId());
     }

  return result;
}
Exemple #10
0
void arch_setup_sighandler_stack(register struct task_struct *t,
				 __sighandler_t addr,unsigned signr)
{
    debug5("Stack %x was %x %x %x %x\n", addr, get_ustack(t,0), get_ustack(t,2),
	   get_ustack(t,4), get_ustack(t,6));
    put_ustack(t, -4, (int)get_ustack(t,0));
    put_ustack(t, -2, (int)addr);
    put_ustack(t, 0, (int)get_ustack(t,4));
    put_ustack(t, 4, (int)get_ustack(t,2));
    put_ustack(t, 2, (int)get_ustack(t,6));
    put_ustack(t, 6, (int)signr);
    t->t_regs.sp -= 4;
    debug6("Stack is %x %x %x %x %x %x\n", get_ustack(t,0), get_ustack(t,2),
	   get_ustack(t,4), get_ustack(t,6), get_ustack(t,8), get_ustack(t,10));
}
Exemple #11
0
OBJECT SearchGalley(OBJECT start, OBJECT sym, BOOLEAN forwards,
BOOLEAN subgalleys, BOOLEAN closures, BOOLEAN input)
{ OBJECT y, res, z, zlink, link;
  debug5(DGA, DD, "[ SearchGalley(start, %s, %s, %s, %s, %s)", SymName(sym),
	forwards ? "fwd" : "back", subgalleys ? "subgalleys" : "nosubgalleys",
	closures ? "closures" : "noclosures", input ? "input" : "noinput");
  assert( type(start) == LINK || type(start) == HEAD, "SearchGalley: start!" );

  link = forwards ? NextDown(start) : PrevDown(start);
  res = nilobj;
  while( res == nilobj && type(link) != HEAD )
  { Child(y, link);
    switch( type(y) )
    {
      case UNATTACHED:
      case RECEIVING:
	
        debug1(DGA, DD, "  examining %s", EchoIndex(y));
	if( subgalleys )
	for( zlink = Down(y); zlink!=y && res==nilobj; zlink=NextDown(zlink) )
	{ Child(z, zlink);
	  res = SearchGalley(z, sym, TRUE, TRUE, TRUE, input);
	}
	if( res == nilobj && input && type(y) == RECEIVING &&
	    actual(actual(y)) == InputSym )
	  res = y;
	break;


      case RECEPTIVE:
	
        debug1(DGA, DD, "  examining %s", EchoIndex(y));
	if( closures && type(actual(y)) == CLOSURE
		     && SearchUses(actual(actual(y)), sym) )  res = y;
	else if( input && actual(actual(y)) == InputSym )  res = y;
	break;


      default:
	
	break;

    }
    link = forwards ? NextDown(link) : PrevDown(link);
  }
  debug1(DGA, DD, "] SearchGalley returning %s", EchoIndex(res));
  return res;
} /* end SearchGalley */
Exemple #12
0
bool cSatipRtsp::Play(const char *uriP)
{
  debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
  bool result = false;

  if (handleM && !isempty(uriP)) {
     long rc = 0;
     cTimeMs processing(0);
     CURLcode res = CURLE_OK;

     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
     SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
     SATIP_CURL_EASY_PERFORM(handleM);

     result = ValidateLatestResponse(&rc);
     debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
     }

  return result;
}
/* This needs to have block_state_mutex locked before hand. */
extern int bridge_status_update_block_list_state(List block_list)
{
	int updated = 0;
#if defined HAVE_BG_FILES
	int rc;
	rm_partition_t *block_ptr = NULL;
	rm_partition_state_t state;
	uint16_t real_state;
	char *name = NULL;
	bg_record_t *bg_record = NULL;
	ListIterator itr = NULL;

	itr = list_iterator_create(block_list);
	while ((bg_record = (bg_record_t *) list_next(itr)) != NULL) {
		if (bg_record->magic != BLOCK_MAGIC) {
			/* block is gone */
			list_remove(itr);
			continue;
		} else if (!bg_record->bg_block_id)
			continue;

		name = bg_record->bg_block_id;
		real_state = bg_record->state & (~BG_BLOCK_ERROR_FLAG);
		if ((rc = bridge_get_block_info(name, &block_ptr))
		    != SLURM_SUCCESS) {
			if (bg_conf->layout_mode == LAYOUT_DYNAMIC) {
				switch(rc) {
				case BG_ERROR_INCONSISTENT_DATA:
					debug2("got inconsistent data when "
					       "querying block %s", name);
					continue;
					break;
				case BG_ERROR_BLOCK_NOT_FOUND:
					debug("block %s not found, removing "
					      "from slurm", name);
					/* Just set to free,
					   everything will be cleaned
					   up outside this.
					*/
					bg_record->state = BG_BLOCK_FREE;
					continue;
					break;
				default:
					break;
				}
			}
			/* If the call was busy, just skip this
			   iteration.  It usually means something like
			   rm_get_BG was called which can be a very
			   long call */
			if (rc == EBUSY) {
				debug5("lock was busy, aborting");
				break;
			}

			error("bridge_get_block_info(%s): %s",
			      name,
			      bg_err_str(rc));
			continue;
		}

		if ((rc = bridge_get_data(block_ptr, RM_PartitionState,
					  &state))
		    != SLURM_SUCCESS) {
			error("bridge_get_data(RM_PartitionState): %s",
			      bg_err_str(rc));
			updated = -1;
			goto next_block;
		} else if (real_state != state) {
			debug("freeing state of Block %s was %d and now is %d",
			      bg_record->bg_block_id,
			      bg_record->state,
			      state);

			if (bg_record->state & BG_BLOCK_ERROR_FLAG)
				state |= BG_BLOCK_ERROR_FLAG;
			bg_record->state = state;
			updated = 1;
		}
	next_block:
		if ((rc = bridge_free_block(block_ptr))
		    != SLURM_SUCCESS) {
			error("bridge_free_block(): %s",
			      bg_err_str(rc));
		}
	}
	list_iterator_destroy(itr);
#endif
	return updated;
}
static int _do_block_poll(void)
{
	int updated = 0;
#if defined HAVE_BG_FILES
	int rc;
	rm_partition_t *block_ptr = NULL;
#ifdef HAVE_BGL
	rm_partition_mode_t node_use;
#endif
	rm_partition_state_t state;
	char *name = NULL;
	bg_record_t *bg_record = NULL;
	ListIterator itr = NULL;

	if (!bg_lists->main)
		return updated;

	lock_slurmctld(job_read_lock);
	slurm_mutex_lock(&block_state_mutex);
	itr = list_iterator_create(bg_lists->main);
	while ((bg_record = (bg_record_t *) list_next(itr)) != NULL) {
		if (bg_record->magic != BLOCK_MAGIC) {
			/* block is gone */
			list_remove(itr);
			continue;
		} else if (!bg_record->bg_block_id)
			continue;

		name = bg_record->bg_block_id;
		if ((rc = bridge_get_block_info(name, &block_ptr))
		    != SLURM_SUCCESS) {
			if (bg_conf->layout_mode == LAYOUT_DYNAMIC) {
				switch(rc) {
				case BG_ERROR_INCONSISTENT_DATA:
					debug2("got inconsistent data when "
					       "querying block %s", name);
					continue;
					break;
				case BG_ERROR_BLOCK_NOT_FOUND:
					debug("block %s not found, removing "
					      "from slurm", name);
					list_remove(itr);
					destroy_bg_record(bg_record);
					continue;
					break;
				default:
					break;
				}
			}

			/* If the call was busy, just skip this
			   iteration.  It usually means something like
			   rm_get_BG was called which can be a very
			   long call */
			if (rc == EBUSY) {
				debug5("lock was busy, aborting");
				break;
			}

			error("bridge_get_block_info(%s): %s",
			      name,
			      bg_err_str(rc));
			continue;
		}

#ifdef HAVE_BGL
		if ((rc = bridge_get_data(block_ptr, RM_PartitionMode,
					  &node_use))
		    != SLURM_SUCCESS) {
			error("bridge_get_data(RM_PartitionMode): %s",
			      bg_err_str(rc));
			if (!updated)
				updated = -1;
			goto next_block;
		} else if (bg_record->node_use != node_use) {
			debug("node_use of Block %s was %d "
			      "and now is %d",
			      bg_record->bg_block_id,
			      bg_record->node_use,
			      node_use);
			bg_record->node_use = node_use;
			updated = 1;
		}
#else
		if ((bg_record->cnode_cnt < bg_conf->mp_cnode_cnt)
		    || (bg_conf->mp_cnode_cnt == bg_conf->nodecard_cnode_cnt)) {
			char *mode = NULL;
			uint16_t conn_type = SELECT_SMALL;
			if ((rc = bridge_get_data(block_ptr,
						  RM_PartitionOptions,
						  &mode))
			    != SLURM_SUCCESS) {
				error("bridge_get_data(RM_PartitionOptions): "
				      "%s", bg_err_str(rc));
				if (!updated)
					updated = -1;
				goto next_block;
			} else if (mode) {
				switch(mode[0]) {
				case 's':
					conn_type = SELECT_HTC_S;
					break;
				case 'd':
					conn_type = SELECT_HTC_D;
					break;
				case 'v':
					conn_type = SELECT_HTC_V;
					break;
				case 'l':
					conn_type = SELECT_HTC_L;
					break;
				default:
					conn_type = SELECT_SMALL;
					break;
				}
				free(mode);
			}

			if (bg_record->conn_type[0] != conn_type) {
				debug("mode of small Block %s was %u "
				      "and now is %u",
				      bg_record->bg_block_id,
				      bg_record->conn_type[0],
				      conn_type);
				bg_record->conn_type[0] = conn_type;
				updated = 1;
			}
		}
#endif
		if ((rc = bridge_get_data(block_ptr, RM_PartitionState,
					  &state))
		    != SLURM_SUCCESS) {
			error("bridge_get_data(RM_PartitionState): %s",
			      bg_err_str(rc));
			if (!updated)
				updated = -1;
			goto next_block;
		} else if (bg_status_update_block_state(
				   bg_record, state, kill_job_list) == 1)
			updated = 1;

	next_block:
		if ((rc = bridge_free_block(block_ptr))
		    != SLURM_SUCCESS) {
			error("bridge_free_block(): %s",
			      bg_err_str(rc));
		}
	}
	list_iterator_destroy(itr);
	slurm_mutex_unlock(&block_state_mutex);
	unlock_slurmctld(job_read_lock);

	bg_status_process_kill_job_list(kill_job_list, JOB_FAILED, 0);

#endif
	return updated;
}
Exemple #15
0
void FlushGalley(OBJECT hd)
{ OBJECT dest;			/* the target galley hd empties into         */
  OBJECT dest_index;		/* the index of dest                         */
  OBJECT inners;		/* list of galleys and PRECEDES to flush     */
  OBJECT link, y;		/* for scanning through the components of hd */
  int dim;			/* direction of galley                       */
  CONSTRAINT dest_par_constr;	/* the parallel size constraint on dest      */
  CONSTRAINT dest_perp_constr;	/* the perpendicular size constraint on dest */
  int pb, pf, f;		/* candidate replacement sizes for dest      */

  OBJECT dest_encl;		/* the VCAT or ACAT enclosing dest, if any   */
  int    dest_side;		/* if dest_encl != nilobj, side dest is on   */
  BOOLEAN need_adjust;		/* TRUE as soon as dest_encl needs adjusting */
  FULL_LENGTH dest_back, dest_fwd; /* the current size of dest_encl or dest  */
  FULL_LENGTH frame_size;	/* the total constraint of dest_encl         */
  OBJECT prec_gap;		/* the gap preceding dest if any else nilobj */
  OBJECT prec_def;		/* the component preceding dest, if any      */
  OBJECT succ_gap;		/* the gap following dest if any else nilobj */
  OBJECT succ_def;		/* the component following dest, if any      */
  OBJECT stop_link;		/* most recently seen gap link of hd         */
  FULL_LENGTH stop_back;        /* back(dest_encl) incl all before stop_link */
  FULL_LENGTH stop_fwd;         /* fwd(dest_encl) incl. all before stop_link */
  FULL_LENGTH stop_perp_back;   /* back(dest_encl) in other direction        */
  FULL_LENGTH stop_perp_fwd;    /* fwd(dest_encl) in other direction         */
  BOOLEAN prnt_flush;		/* TRUE when the parent of hd needs a flush  */
  BOOLEAN target_is_internal;   /* TRUE if flushing into an internal target  */
  BOOLEAN headers_seen;		/* TRUE if a header is seen at all           */
  OBJECT zlink, z, tmp, prnt;  int attach_status;  BOOLEAN remove_target;
  OBJECT why;
  FULL_LENGTH perp_back, perp_fwd;  /* current perp size of dest_encl        */

  debug1(DGF, D, "[ FlushGalley %s (hd)", SymName(actual(hd)));
  prnt_flush = FALSE;
  dim = gall_dir(hd);

  RESUME:
  assert( type(hd) == HEAD, "FlushGalley: type(hd) != HEAD!" );
  debug1(DGF, D, "  resuming FlushGalley %s, hd =", SymName(actual(hd)));
  ifdebugcond(DGF, DD, actual(hd) == nilobj, DebugGalley(hd, nilobj, 4));
  assert( Up(hd) != hd, "FlushGalley: resume found no parent to hd!" );


  /*@@************************************************************************/
  /*                                                                         */
  /*  The first step is to examine the parent of galley hd to determine the  */
  /*  status of the galley.  If this is not suitable for flushing, we do     */
  /*  what we can to change the status.  If still no good, return; so if     */
  /*  this code does not return, then the galley is ready to flush into a    */
  /*  destination in the normal way, and the following variables are set:    */
  /*                                                                         */
  /*     dest_index   the parent of the galley and index of its destination  */
  /*     dest         the destination of the galley, a @Galley object        */
  /*                                                                         */
  /***************************************************************************/

  Parent(dest_index, Up(hd));
  switch( type(dest_index) )
  {

    case DEAD:
    
      /* the galley has been killed off while this process was sleeping */
      debug1(DGF, D, "] FlushGalley %s returning (DEAD)", SymName(actual(hd)));
      return;


    case UNATTACHED:
    
      /* the galley is currently not attached to a destination */
      attach_status = AttachGalley(hd, &inners, &y);
      debug1(DGF, DD, "  ex-AttachGalley inners: %s", DebugInnersNames(inners));
      Parent(dest_index, Up(hd));
      switch( attach_status )
      {

	case ATTACH_KILLED:

	  assert(inners==nilobj, "FlushGalley/ATTACH_KILLED: inners!=nilobj!");
	  debug1(DGF, D, "] FlushGalley %s returning (ATTACH_KILLED)",
	    SymName(actual(hd)));
	  debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
	  return;


	case ATTACH_INPUT:

	  ParentFlush(prnt_flush, dest_index, FALSE);
	  assert(inners==nilobj, "FlushGalley/ATTACH_INPUT: inners!=nilobj!");
	  debug1(DGF, D, "] FlushGalley %s returning (ATTACH_INPUT)",
	    SymName(actual(hd)));
	  return;


	case ATTACH_NOTARGET:

	  ParentFlush(prnt_flush, dest_index, FALSE);
	  assert(inners==nilobj, "FlushGalley/ATTACH_NOTARG: inners!=nilobj!");
	  debug1(DGF, D, "] FlushGalley %s returning (ATTACH_NOTARGET)",
	    SymName(actual(hd)));
	  return;


	case ATTACH_SUSPEND:

	  /* AttachGalley only returns inners here if they really need to */
	  /* be flushed; in particular the galley must be unsized before  */
	  if( inners != nilobj )
	  {
	    debug0(DGF, DD, "  calling FlushInners() from FlushGalley (a)");
	    FlushInners(inners, nilobj);
	    goto RESUME;
	  }
	  stop_link = nilobj;
	  goto SUSPEND;	/* nb y will be set by AttachGalley in this case */


	case ATTACH_NULL:

	  /* hd will have been linked to the unexpanded target in this case */
	  remove_target = (actual(actual(dest_index)) == whereto(hd));
          if( force_gall(hd) )
          {
            /* if hd is a forcing galley, close all predecessors */
	    debug3(DGA, D, "  forcing ATTACH_NULL case for %s into %s (%s)",
	      SymName(actual(hd)), SymName(whereto(hd)),
	      remove_target ? "remove_target" : "not remove_target");
	    Parent(prnt, Up(dest_index));
	    if( !non_blocking(dest_index) && remove_target )
	    {
	      /* ***
	      prnt_flush = TRUE;
	      *** */
	      prnt_flush = non_blocking(dest_index) = TRUE;
	    }
	    FreeGalley(prnt, Up(dest_index), &inners, Up(dest_index),
	      whereto(hd));
          }
          else
	  {
	    debug3(DGA, D, "  non-force ATTACH_NULL case for %s into %s (%s)",
	      SymName(actual(hd)), SymName(whereto(hd)),
	      remove_target ? "remove_target" : "not remove_target");
	    if( blocked(dest_index) && remove_target )  prnt_flush = TRUE;
	  }
	  DetachGalley(hd);
	  KillGalley(hd, TRUE);
          if( inners != nilobj )
	  {
	    debug0(DGF, DD, "  calling FlushInners() from FlushGalley (b)");
	    FlushInners(inners, nilobj);
	  }
	  else ParentFlush(prnt_flush, dest_index, remove_target);
	  debug0(DGF, D, "] FlushGalley returning ATTACH_NULL");
	  return;


	case ATTACH_ACCEPT:

          /* if hd is a forcing galley, or actual(dest_index) is   */
	  /* @ForceGalley, then close all predecessors             */
          if( force_gall(hd) || actual(actual(dest_index)) == ForceGalleySym )
          { Parent(prnt, Up(dest_index));
	    debug1(DGA, D, "  forcing ATTACH_ACCEPT case for %s",
	      SymName(actual(hd)));
	    /* debug0(DGA, DD, "  force: prnt ="); */
	    /* ifdebug(DGA, DD, DebugObject(prnt)); */
	    /* debug1(DGA, D,"  calling FreeGalley from FlushGalley(%s)", */
	    /*   SymName(actual(hd))); */
	    if( !non_blocking(dest_index) )  prnt_flush = TRUE; /* bug fix */
	    FreeGalley(prnt, Up(dest_index), &inners, Up(dest_index),
	      whereto(hd));
	    /* debug0(DGA, DD, "  force: after FreeGalley, prnt ="); */
	    /* ifdebug(DGA, DD, DebugObject(prnt)); */
          }
          else prnt_flush = prnt_flush || blocked(dest_index);
          debug1(DGF, DD, "    force: prnt_flush = %s", bool(prnt_flush));
          if( inners != nilobj )
	  {
	    debug0(DGF, DD, "  calling FlushInners() from FlushGalley (c)");
	    FlushInners(inners, nilobj);
	  }
          goto RESUME;


	default:

	  assert(FALSE, "FlushGalley: attach_status");
	  break;

      }
      break;


    case RECEIVING:
    
      if( actual(actual(dest_index)) == InputSym )
      { ParentFlush(prnt_flush, dest_index, FALSE);
	debug1(DGF, D, "] FlushGalley %s retn, input", SymName(actual(hd)));
	return;
      }
      break;


    default:
    
      assert1(FALSE, "FlushGalley: dest_index", Image(type(dest_index)));
      break;
  }
  dest = actual(dest_index);
  if( underline(dest) == UNDER_UNDEF )  underline(dest) = UNDER_OFF;
  target_is_internal =
    (dim==ROWM && !external_ver(dest)) || (dim==COLM && !external_hor(dest));
  headers_seen = FALSE;
  debug1(DGF, DD, "  dest_index: %s", EchoObject(dest_index));


  /*@@************************************************************************/
  /*                                                                         */
  /*  The second step is to examine the components of the galley one by one  */
  /*  to determine if they can be promoted.  Each component has the format   */
  /*                                                                         */
  /*    { <index> } <object>                                                 */
  /*                                                                         */
  /*  and is always followed by a gap object (except the last component).    */
  /*  An index indicates that the following object has some interesting      */
  /*  feature, and it points to that feature inside the object.  There are   */
  /*  two possible actions for each component, in addition to accepting it:  */
  /*                                                                         */
  /*    REJECT:   The component does not fit, so detach the galley           */
  /*    SUSPEND:  The component is incomplete; go to sleep and wait          */
  /*                                                                         */
  /***************************************************************************/

  stop_link = dest_encl = inners = nilobj;
  need_adjust = FALSE;

  /***************************************************************************/
  /*                                                                         */
  /*  Loop invariant                                                         */
  /*                                                                         */
  /*  The children of hd up to but not including Child(link) have been       */
  /*  examined and pronounced to be promotable, if unbreakable gaps are      */
  /*  ignored.  When unbreakable gaps are taken into account, the most       */
  /*  recent gap where a break is possible is at Child(stop_link), or        */
  /*  nowhere if stop_link == nilobj.                                        */
  /*                                                                         */
  /*  Case 1:  target_is_internal == FALSE                                   */
  /*                                                                         */
  /*  If this flag is FALSE, it means that the target of this galley is      */
  /*  external.  Consequently, there is no need to calculate sizes because   */
  /*  there is no constraint on them.  Also, a REJECT action is impossible   */
  /*  so unbreakable gaps are no impediment.  Variable dest_encl is nilobj.  */
  /*                                                                         */
  /*  Case 2:  target_is_internal == TRUE                                    */
  /*                                                                         */
  /*  If this flag is TRUE, it means that the target of this galley is       */
  /*  internal.  Consequently, sizes need to be calculated, and unbreakable  */
  /*  gaps need to be taken into account.  Variable dest_encl may be not     */
  /*  nilobj, in which case the following variables are defined:             */
  /*                                                                         */
  /*    dest_encl        the object enclosing dest (which must exist)        */
  /*    prec_gap         gap object preceding dest (which must exist)        */
  /*    prec_def         first definite object preceding dest (must exist)   */
  /*    dest_back        back(dest_encl) including effect of accepted compts */
  /*    dest_fwd         fwd(dest_encl) including effect of accepted compts  */
  /*    dest_side        BACK or FWD, i.e. which side of the mark dest is on */
  /*    dest_par_constr  the parallel size constraint on dest                */
  /*    dest_perp_constr the perpendicular size constraint on dest           */
  /*    frame_size       size of frame enclosing dest_encl                   */
  /*    perp_back        back(dest_encl) in other direction, incl accepteds  */
  /*    perp_fwd         fwd(dest_encl) in other direction,  incl accepteds  */
  /*                                                                         */
  /*  if dest_encl is nilobj, these variables are not defined.               */
  /*                                                                         */
  /*  If stop_link is non-nilobj, then in the internal case dest_encl must   */
  /*  be non-nilobj, and the following variables are defined:                */
  /*                                                                         */
  /*    stop_back        back(dest_encl) including all before stop_link      */
  /*    stop_fwd         fwd(dest_encl)  including all before stop_link      */
  /*    stop_perp_back   back(dest_encl) in other direction                  */
  /*    stop_perp_fwd    fwd(dest_encl) in other direction                   */
  /*                                                                         */
  /*  need_adjust is true if at least one definite component has been        */
  /*  accepted for promotion and the destination is internal; hence,         */
  /*  dest_encl is defined and its size needs to be adjusted.                */
  /*                                                                         */
  /*  inners is the set of all PRECEDES and UNATTACHED indexes found.        */
  /*                                                                         */
  /***************************************************************************/

  for( link = Down(hd);  link != hd;  link = NextDown(link) )
  {
    Child(y, link);
    if( type(y) == SPLIT )  Child(y, DownDim(y, dim));
    debug2(DGF, DD, "  examining %s %s", Image(type(y)), EchoObject(y));
    switch( type(y) )
    {

      case GAP_OBJ:

	underline(y) = underline(dest);
	prec_gap = y;
	if( target_is_internal )
	{
	  /* *** not necessarily true
	  assert( dest_encl != nilobj, "FlushGalley/GAP_OBJ: dest_encl!" );
	  *** */
	  if( dest_encl != nilobj && !nobreak(gap(prec_gap)) )
	  {
	    stop_link = link;
	    stop_back = dest_back;
	    stop_fwd  = dest_fwd;
	    stop_perp_back = perp_back;
	    stop_perp_fwd = perp_fwd;
	  }
	}
	else stop_link = link;
	if( !join(gap(y)) )  seen_nojoin(hd) = TRUE;
	break;


      case SCALE_IND:
      case COVER_IND:
      case EXPAND_IND:
      case GALL_PREC:
      case GALL_FOLL:
      case GALL_FOLL_OR_PREC:
      case GALL_TARG:
      case CROSS_PREC:
      case CROSS_FOLL:
      case CROSS_FOLL_OR_PREC:
      case CROSS_TARG:
      case PAGE_LABEL_IND:

	underline(y) = underline(dest);
	break;


      case PRECEDES:
      case UNATTACHED:
	  
	if( inners == nilobj )  New(inners, ACAT);
	Link(inners, y);
	break;


      case RECEIVING:
      case RECEPTIVE:
	  
	goto SUSPEND;


      case FOLLOWS:
	  
	Child(tmp, Down(y));
	if( Up(tmp) == LastUp(tmp) )
	{ link = PrevDown(link);
	  DisposeChild(NextDown(link));
	  break;
	}
	Parent(tmp, Up(tmp));
	assert(type(tmp) == PRECEDES, "Flush: PRECEDES!");
	switch( CheckComponentOrder(tmp, dest_index) )
	{
	  case CLEAR:	DeleteNode(tmp);
			link = PrevDown(link);
			DisposeChild(NextDown(link));
			break;

	  case PROMOTE:	break;

	  case BLOCK:	goto SUSPEND;

	  case CLOSE:	if( opt_components(hd) != nilobj )
			{ DisposeObject(opt_components(hd));
			  opt_components(hd) = nilobj;
			  debug2(DOG, D, "FlushGalley(%s) de-optimizing %s",
			    "(CLOSE problem)", SymName(actual(hd)));
			}
			debug1(DGF, DD, "  reject (a) %s", EchoObject(y));
			goto REJECT;
	}
	break;


      case BEGIN_HEADER:
      case END_HEADER:
      case SET_HEADER:
      case CLEAR_HEADER:

	/* do nothing except take note, until actually promoted out of here */
	headers_seen = TRUE;
	break;


      case NULL_CLOS:
      case PAGE_LABEL:
      case WORD:
      case QWORD:
      case ONE_COL:
      case ONE_ROW:
      case WIDE:
      case HIGH:
      case HSHIFT:
      case VSHIFT:
      case HSCALE:
      case VSCALE:
      case HCOVER:
      case VCOVER:
      case HCONTRACT:
      case VCONTRACT:
      case HLIMITED:
      case VLIMITED:
      case HEXPAND:
      case VEXPAND:
      case START_HVSPAN:
      case START_HSPAN:
      case START_VSPAN:
      case HSPAN:
      case VSPAN:
      case ROTATE:
      case BACKGROUND:
      case SCALE:
      case KERN_SHRINK:
      case INCGRAPHIC:
      case SINCGRAPHIC:
      case PLAIN_GRAPHIC:
      case GRAPHIC:
      case LINK_SOURCE:
      case LINK_DEST:
      case ACAT:
      case HCAT:
      case VCAT:
      case ROW_THR:
      case CLOSURE:
      case CROSS:
      case FORCE_CROSS:

	underline(y) = underline(dest);
	if( dim == ROWM )
	{
	  /* make sure y is not joined to a target below (vertical case only) */
	  for( zlink = NextDown(link); zlink != hd; zlink = NextDown(zlink) )
	  { Child(z, zlink);
	    switch( type(z) )
	    {
	      case RECEPTIVE:
	      case RECEIVING:	y = z;
				goto SUSPEND;

	      case GAP_OBJ:	if( !join(gap(z)) )  zlink = PrevDown(hd);
				break;

	      default:		break;
	    }
	  }

	  /* try vertical hyphenation before anything else */
	  if( type(y) == HCAT )  VerticalHyphenate(y);

	}

	/* check size constraint */
	if( target_is_internal )
	{
	  /* initialise dest_encl etc if not done yet */
	  if( dest_encl == nilobj )
	  { assert( UpDim(dest,1-dim) == UpDim(dest,dim), "FlushG: UpDims!" );
	    /* *** weird old code, trying for UpDim(dest, ROWM)?
	    Parent(dest_encl, NextDown(Up(dest)));
	    *** */
	    Parent(dest_encl, Up(dest));
	    debug4(DGF, DD, "  flush dest = %s %s, dest_encl = %s %s",
	      Image(type(dest)), EchoObject(dest),
	      Image(type(dest_encl)), EchoObject(dest_encl));
	    assert( (dim==ROWM && type(dest_encl)==VCAT) ||
	            (dim==COLM && type(dest_encl)==ACAT),
	      "FlushGalley: dest != VCAT or ACAT!" );
	    SetNeighbours(Up(dest), FALSE, &prec_gap, &prec_def,
	      &succ_gap, &succ_def, &dest_side);
	    assert(prec_gap != nilobj || is_indefinite(type(y)),
	      "FlushGalley: prec_gap == nilobj && !is_indefinite(type(y))!" );
	    assert(succ_gap == nilobj, "FlushGalley: succ_gap != nilobj!" );
	    assert(dest_side == FWD || is_indefinite(type(y)),
	      "FlushGalley: dest_side != FWD || !is_indefinite(type(y))!");
	    dest_back = back(dest_encl, dim);
	    dest_fwd  = fwd(dest_encl, dim);
	    perp_back = back(dest_encl, 1-dim);
	    perp_fwd  = fwd(dest_encl, 1-dim);
	    Constrained(dest_encl, &dest_par_constr, dim, &why);
	    Constrained(dest_encl, &dest_perp_constr, 1-dim, &why);
	    debug1(DGF, DD, "  setting dest_perp_constr = %s",
	      EchoConstraint(&dest_perp_constr));
	    frame_size = constrained(dest_par_constr) ? bfc(dest_par_constr) :0;
	  }

	  if( !is_indefinite(type(y)) )
	  {
	    ifdebugcond(DGF, DD,  mode(gap(prec_gap)) == NO_MODE,
	      DebugGalley(hd, y, 4));

	    /* calculate parallel effect of adding y to dest */
	    f = dest_fwd  + fwd(y, dim) - fwd(prec_def, dim) +
		  ActualGap(fwd(prec_def, dim), back(y, dim),
			fwd(y, dim), &gap(prec_gap), frame_size,
			dest_back + dest_fwd - fwd(prec_def, dim));
	    debug5(DGF, DD, "  f = %s + %s - %s + %s (prec_gap %s)",
	      EchoLength(dest_fwd), EchoLength(fwd(y, dim)),
	      EchoLength(fwd(prec_def, dim)), EchoLength(
		  ActualGap(fwd(prec_def, dim), back(y, dim),
			fwd(y, dim), &gap(prec_gap), frame_size,
			dest_back + dest_fwd - fwd(prec_def, dim))
	      ), EchoGap(&gap(prec_gap)));
	    debug3(DGF, DD, "  b,f: %s,%s;   dest_encl: %s",
			EchoLength(dest_back), EchoLength(f),
			EchoConstraint(&dest_par_constr));

	    /* check new size against parallel constraint */
	    if( (units(gap(prec_gap))==FRAME_UNIT && width(gap(prec_gap)) > FR)
	        || !FitsConstraint(dest_back, f, dest_par_constr)
		|| (opt_components(hd) != nilobj && opt_comps_permitted(hd)<=0)
	      )
	    {
	      if( opt_components(hd) != nilobj )
	      { OBJECT z;

		/* record the size of this just-completed target area for hd */
		New(z, WIDE);
		CopyConstraint(constraint(z), dest_par_constr);
		Link(opt_constraints(hd), z);
		ifdebug(DOG, D,
		  debug2(DOG, D, "FlushGalley(%s) adding constraint %s",
		    SymName(actual(hd)), EchoConstraint(&constraint(z)));
		  if( units(gap(prec_gap))==FRAME_UNIT &&
		      width(gap(prec_gap)) > FR ) 
		  { debug1(DOG, D, "  prec_gap = %s", EchoGap(&gap(prec_gap)));
		  }
		  if( !FitsConstraint(dest_back, f, dest_par_constr) )
		  { debug3(DOG, D, "  !FitsConstraint(%s, %s, %s)",
		      EchoLength(dest_back), EchoLength(f),
		      EchoConstraint(&dest_par_constr));
		  }
		  if( opt_comps_permitted(hd) <= 0 )
		  { debug1(DOG, D, "  opt_comps_permitted = %2d",
		      opt_comps_permitted(hd));
		  }
		  debug4(DOG, D, "prec_gap = %s;  y = %s (%s,%s):",
		    EchoGap(&gap(prec_gap)), Image(type(y)),
		    EchoLength(back(y, dim)), EchoLength(fwd(y, dim)));
		  DebugObject(y);
		)

		/* refresh the number of components permitted into the next target */
		if( opt_counts(hd) != nilobj && Down(opt_counts(hd)) != opt_counts(hd) )
		{ Child(z, Down(opt_counts(hd)));
		  opt_comps_permitted(hd) += comp_count(z) - 1;
		  DisposeChild(Up(z));
		}
		else opt_comps_permitted(hd) = MAX_FILES;  /* a large number */
		debug1(DOG, D, "  REJECT permitted = %2d", opt_comps_permitted(hd));
	      }
	      debug1(DGF, DD, "  reject (b) %s", EchoObject(y));
	      goto REJECT;
	    }

	    /* calculate perpendicular effect of adding y to dest */
	    if( seen_nojoin(hd) )
	    {
	      pb = 0;
	      pf = find_max(perp_fwd,  size(y, 1-dim));
	    }
	    else
	    {
	      pb = find_max(perp_back, back(y, 1-dim));
	      pf = find_max(perp_fwd,  fwd(y,  1-dim));
	    }

	    /* check new size against perpendicular constraint */
	    if( !FitsConstraint(pb, pf, dest_perp_constr) )
	    {
	      if( opt_components(hd) != nilobj )
	      { DisposeObject(opt_components(hd));
		opt_components(hd) = nilobj;
		debug1(DOG, D, "FlushGalley(%s) de-optimizing (perp problem)",
		  SymName(actual(hd)));
	      }
	      if( dim == ROWM )
	      {
		Error(20, 3, "component too wide for available space",
		  WARN, &fpos(y));
		debug6(DGF, DD, "  %s,%s [%s,%s] too wide for %s, y = %s",
		  EchoLength(pb), EchoLength(pf),
		  EchoLength(back(y, 1-dim)), EchoLength(fwd(y, 1-dim)),
		  EchoConstraint(&dest_perp_constr), EchoObject(y));
	      }
	      debug1(DGF, DD, "  reject (c) %s", EchoObject(y));
	      goto REJECT;
	    }

	    /* accept definite component */
	    dest_fwd = f;  prec_def = y;
	    perp_back = pb;  perp_fwd = pf;
	    need_adjust = TRUE;
	    if( opt_components(hd) != nilobj )
	    { opt_comps_permitted(hd)--;
	      debug1(DOG, D, "  ACCEPT permitted = %2d", opt_comps_permitted(hd));
	    }
	  }
	  /* accept indefinite component */
	} /* end if( target_is_internal ) */