Ejemplo n.º 1
0
/* Make Q able to have more characters added to it. */
struct queue *
reallocate_queue (struct queue *q)
{
  int len;
  struct queue *newq;

  len = qsize (q);

  if (len < q->arraylen / 2)
    {
      /* Shift the characters to the front of
	 the queue. */
      memmove (q->array, q->cs, len * sizeof (quoted_char));
      q->cs = q->array;
      q->ce = q->cs + len;
    }
  else
    {
      /* Make the queue twice as large. */
      newq = malloc (sizeof (struct queue)
		     + q->arraylen * 2 * sizeof (quoted_char));
      newq->susp = q->susp;
      newq->lowat = q->lowat;
      newq->hiwat = q->hiwat;
      newq->cs = newq->array;
      newq->ce = newq->array + len;
      newq->arraylen = q->arraylen * 2;
      newq->wait = q->wait;
      memmove (newq->array, q->cs, len * sizeof (quoted_char));
      free (q);
      q = newq;
    }
  return q;
}
Ejemplo n.º 2
0
/* Erase a single character off the end of the rawq, and delete
   it from the screen appropriately.  Set ERASE_CHAR if this
   is being done by the VERASE character, to that character. */
static void
erase_1 (char erase_char)
{
  int quoted;
  char c;
  quoted_char cq;

  if (qsize (rawq) == 0)
    return;

  cq = queue_erase (rawq);
  c = unquote_char (cq);
  quoted = char_quoted_p (cq);

  if (!echo_p (c, quoted))
    return;

  /* The code for WERASE knows that we echo erase_char iff
     !ECHOPRT && !ECHO.  */

  if (echo_qsize--)
    {
      if (termstate.c_lflag & ECHOPRT)
	echo_char (c, 1, quoted);
      else if (!(termstate.c_lflag & ECHOE) && erase_char)
	echo_char (erase_char, 0, 0);
      else
	{
	  int nerase;

	  if (echo_double (c, quoted))
	    nerase = 2;
	  else if (c == '\t')
	    {
	      quoted_char *cp;
	      int loc = echo_pstart;

	      for (cp = rawq->ce - echo_qsize; cp != rawq->ce; cp++)
		loc += (echo_double (unquote_char (*cp), char_quoted_p (*cp))
			? 2
			: output_width (*cp, loc));
	      nerase = output_psize - loc;
	    }
	  else
	    nerase = output_width (c, output_psize);

	  while (nerase--)
	    write_erase_sequence ();
	}
      if (echo_qsize == 0)
	assert (echo_pstart == output_psize);
    }
  else
    reprint_line ();
}
Ejemplo n.º 3
0
error_t
drain_output ()
{
  int cancel = 0;

  while ((qsize (outputq) || (*bottom->pending_output_size) ())
	 && (!(termflags & NO_CARRIER) || (termstate.c_cflag & CLOCAL))
	 && !cancel)
    cancel = pthread_hurd_cond_wait_np (outputq->wait, &global_lock);

  return cancel ? EINTR : 0;
}
Ejemplo n.º 4
0
int ttwait(TTY tp)
{
	while (qsize(&tp->outq) != 0 && ISSET(tp->state,ST_COPEN) &&
	       ISSET(tp->state,ST_SOPEN))
  {
		BSET(tp->state,ST_DRAIN);
		/* Wait until output is empty */
		if (Block(&tp->outq,-1l,0)==2)
			return RP_EINTR;
	}
	return RPDONE;
}
Ejemplo n.º 5
0
/* get queue size */
int lqsize(void * qp){
    if(NULL != qp){
        pthread_mutex_t *q_lock = &(((lqtype *)qp)->q_lock);
        int rc = pthread_mutex_lock(q_lock);
        int ret = qsize(((lqtype *)qp)->queue);
        rc = pthread_mutex_unlock(q_lock);

	return ret;
    } else {
        printf("should open queue before using it\n");
	return -1;
    }
}
Ejemplo n.º 6
0
void run_read(CQ qp, RPQ rside, RPQ wside)
{
	/* more data in queue? run more reader threads */
	if (qsize(qp) > 0)
	{
		/* run more readers */
		start_reader(rside);
	}

	/* some space freed? run some writer threads */
	if (!rpqempty(wside) && !qfull(qp))
		Run(rpqtop(wside));
}
Ejemplo n.º 7
0
/* Process all the characters in INPUTQ as if they had just been read. */
void
rescan_inputq ()
{
  short *buf;
  int i, n;

  n = qsize (inputq);
  buf = alloca (n * sizeof (quoted_char));
  memcpy (buf, inputq->cs, n * sizeof (quoted_char));
  clear_queue (inputq);

  for (i = 0; i < n; i++)
    input_character (unquote_char (buf[i]));
}
Ejemplo n.º 8
0
int
codel_add_altq(struct ifnet *ifp, struct pf_altq *a)
{
	struct codel_if	*cif;
	struct codel_opts	*opts;

	if (ifp == NULL)
		return (EINVAL);
	if (!ALTQ_IS_READY(&ifp->if_snd))
		return (ENODEV);

	opts = &a->pq_u.codel_opts;

	cif = malloc(sizeof(struct codel_if), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (cif == NULL)
		return (ENOMEM);
	cif->cif_bandwidth = a->ifbandwidth;
	cif->cif_ifq = &ifp->if_snd;

	cif->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (cif->cl_q == NULL) {
		free(cif, M_DEVBUF);
		return (ENOMEM);
	}

	if (a->qlimit == 0)
		a->qlimit = 50;	/* use default. */
	qlimit(cif->cl_q) = a->qlimit;
	qtype(cif->cl_q) = Q_CODEL;
	qlen(cif->cl_q) = 0;
	qsize(cif->cl_q) = 0;

	if (opts->target == 0)
		opts->target = 5;
	if (opts->interval == 0)
		opts->interval = 100;
	cif->codel.params.target = machclk_freq * opts->target / 1000;
	cif->codel.params.interval = machclk_freq * opts->interval / 1000;
	cif->codel.params.ecn = opts->ecn;
	cif->codel.stats.maxpacket = 256;

	cif->cl_stats.qlength = qlen(cif->cl_q);
	cif->cl_stats.qlimit = qlimit(cif->cl_q);

	/* keep the state in pf_altq */
	a->altq_disc = cif;

	return (0);
}
Ejemplo n.º 9
0
static int
codel_should_drop(struct codel *c, class_queue_t *q, struct mbuf *m,
    u_int64_t now)
{
	struct m_tag *mtag;
	uint64_t *enqueue_time;

	if (m == NULL) {
		c->vars.first_above_time = 0;
		return (0);
	}

	mtag = m_tag_locate(m, MTAG_CODEL, 0, NULL);
	if (mtag == NULL) {
		/* Only one warning per second. */
		if (ppsratecheck(&c->last_log, &c->last_pps, 1))
			printf("%s: could not found the packet mtag!\n",
			    __func__);
		c->vars.first_above_time = 0;
		return (0);
	}
	enqueue_time = (uint64_t *)(mtag + 1);
	c->vars.ldelay = now - *enqueue_time;
	c->stats.maxpacket = MAX(c->stats.maxpacket, m_pktlen(m));

	if (codel_time_before(c->vars.ldelay, c->params.target) ||
	    qsize(q) <= c->stats.maxpacket) {
		/* went below - stay below for at least interval */
		c->vars.first_above_time = 0;
		return (0);
	}
	if (c->vars.first_above_time == 0) {
		/* just went above from below. If we stay above
		 * for at least interval we'll say it's ok to drop
		 */
		c->vars.first_above_time = now + c->params.interval;
		return (0);
	}
	if (codel_time_after(now, c->vars.first_above_time))
		return (1);

	return (0);
}
void Source_QVideoFrame::present(QVideoFrame &frame)
{
    qDebug() << Q_FUNC_INFO;
    m_VideoFrame = frame;

    QSize qsize(1280, 720);

    QVideoSurfaceFormat now(qsize, QVideoFrame::Format_YUV420P);
    if(!m_VideoSurface->isActive() )
    {
        m_format = now;
        m_VideoSurface->start(m_format);
    }

    if(m_VideoSurface){
        qDebug() << Q_FUNC_INFO << "------------------------";
        m_VideoSurface->present(frame);
    }
}
Ejemplo n.º 11
0
static int
priq_stat_sc(struct priq_if *pif, cqrq_stat_sc_t *sr)
{
	struct ifclassq *ifq = pif->pif_ifq;
	struct priq_class *cl;
	u_int32_t i;

	IFCQ_LOCK_ASSERT_HELD(ifq);

	VERIFY(sr->sc == MBUF_SC_UNSPEC || MBUF_VALID_SC(sr->sc));

	i = MBUF_SCIDX(sr->sc);
	VERIFY(i < IFCQ_SC_MAX);

	cl = ifq->ifcq_disc_slots[i].cl;
	sr->packets = qlen(&cl->cl_q);
	sr->bytes = qsize(&cl->cl_q);

	return (0);
}
Ejemplo n.º 12
0
void CyclingAgenda::remove_worst() {
	assert(!this->empty());

	std::vector<SetAgenda>::iterator qworst = _qs.begin();
	//std::vector<PriorityQueueAgenda>::iterator qworst = _qs.begin();
	Tiebreak<unsigned> qworst_size(qworst->size());

	// Find the longest Agenda
	std::vector<SetAgenda>::iterator q;
	//std::vector<PriorityQueueAgenda>::iterator q;
	for (q = _qs.begin(); q != _qs.end(); q++) {
		Tiebreak<unsigned> qsize(q->size());
		if (qsize > qworst_size) {
			qworst_size = qsize;
			qworst = q;
		}
	}
	// ...and remove the worst element from it.
	assert(!qworst->empty());
	qworst->remove_worst();
}
Ejemplo n.º 13
0
static struct priq_class *
priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid)
{
	struct priq_class *cl;
	int s;

#ifndef ALTQ_RED
	if (flags & PRCF_RED) {
#ifdef ALTQ_DEBUG
		printf("priq_class_create: RED not configured for PRIQ!\n");
#endif
		return (NULL);
	}
#endif
#ifndef ALTQ_CODEL
	if (flags & PRCF_CODEL) {
#ifdef ALTQ_DEBUG
		printf("priq_class_create: CODEL not configured for PRIQ!\n");
#endif
		return (NULL);
	}
#endif

	if ((cl = pif->pif_classes[pri]) != NULL) {
		/* modify the class instead of creating a new one */
		s = splnet();
		IFQ_LOCK(cl->cl_pif->pif_ifq);
		if (!qempty(cl->cl_q))
			priq_purgeq(cl);
		IFQ_UNLOCK(cl->cl_pif->pif_ifq);
		splx(s);
#ifdef ALTQ_RIO
		if (q_is_rio(cl->cl_q))
			rio_destroy((rio_t *)cl->cl_red);
#endif
#ifdef ALTQ_RED
		if (q_is_red(cl->cl_q))
			red_destroy(cl->cl_red);
#endif
#ifdef ALTQ_CODEL
		if (q_is_codel(cl->cl_q))
			codel_destroy(cl->cl_codel);
#endif
	} else {
		cl = malloc(sizeof(struct priq_class), M_DEVBUF,
		    M_NOWAIT | M_ZERO);
		if (cl == NULL)
			return (NULL);

		cl->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF,
		    M_NOWAIT | M_ZERO);
		if (cl->cl_q == NULL)
			goto err_ret;
	}

	pif->pif_classes[pri] = cl;
	if (flags & PRCF_DEFAULTCLASS)
		pif->pif_default = cl;
	if (qlimit == 0)
		qlimit = 50;  /* use default */
	qlimit(cl->cl_q) = qlimit;
	qtype(cl->cl_q) = Q_DROPTAIL;
	qlen(cl->cl_q) = 0;
	qsize(cl->cl_q) = 0;
	cl->cl_flags = flags;
	cl->cl_pri = pri;
	if (pri > pif->pif_maxpri)
		pif->pif_maxpri = pri;
	cl->cl_pif = pif;
	cl->cl_handle = qid;

#ifdef ALTQ_RED
	if (flags & (PRCF_RED|PRCF_RIO)) {
		int red_flags, red_pkttime;

		red_flags = 0;
		if (flags & PRCF_ECN)
			red_flags |= REDF_ECN;
#ifdef ALTQ_RIO
		if (flags & PRCF_CLEARDSCP)
			red_flags |= RIOF_CLEARDSCP;
#endif
		if (pif->pif_bandwidth < 8)
			red_pkttime = 1000 * 1000 * 1000; /* 1 sec */
		else
			red_pkttime = (int64_t)pif->pif_ifq->altq_ifp->if_mtu
			  * 1000 * 1000 * 1000 / (pif->pif_bandwidth / 8);
#ifdef ALTQ_RIO
		if (flags & PRCF_RIO) {
			cl->cl_red = (red_t *)rio_alloc(0, NULL,
						red_flags, red_pkttime);
			if (cl->cl_red == NULL)
				goto err_ret;
			qtype(cl->cl_q) = Q_RIO;
		} else
#endif
		if (flags & PRCF_RED) {
			cl->cl_red = red_alloc(0, 0,
			    qlimit(cl->cl_q) * 10/100,
			    qlimit(cl->cl_q) * 30/100,
			    red_flags, red_pkttime);
			if (cl->cl_red == NULL)
				goto err_ret;
			qtype(cl->cl_q) = Q_RED;
		}
	}
#endif /* ALTQ_RED */
#ifdef ALTQ_CODEL
	if (flags & PRCF_CODEL) {
		cl->cl_codel = codel_alloc(5, 100, 0);
		if (cl->cl_codel != NULL)
			qtype(cl->cl_q) = Q_CODEL;
	}
#endif

	return (cl);

 err_ret:
	if (cl->cl_red != NULL) {
#ifdef ALTQ_RIO
		if (q_is_rio(cl->cl_q))
			rio_destroy((rio_t *)cl->cl_red);
#endif
#ifdef ALTQ_RED
		if (q_is_red(cl->cl_q))
			red_destroy(cl->cl_red);
#endif
#ifdef ALTQ_CODEL
		if (q_is_codel(cl->cl_q))
			codel_destroy(cl->cl_codel);
#endif
	}
	if (cl->cl_q != NULL)
		free(cl->cl_q, M_DEVBUF);
	free(cl, M_DEVBUF);
	return (NULL);
}
Ejemplo n.º 14
0
/* Copy the characters in RAWQ to the end of INPUTQ and clear RAWQ. */
void
copy_rawq ()
{
  while (qsize (rawq))
    enqueue (&inputq, dequeue (rawq));
}
Ejemplo n.º 15
0
/* Place newly input character C on the input queue.  If all remaining
   pending input characters should be dropped, return 1; else return
   0.  */
int
input_character (int c)
{
  int lflag = termstate.c_lflag;
  int iflag = termstate.c_iflag;
  int cflag = termstate.c_cflag;
  cc_t *cc = termstate.c_cc;
  struct queue **qp = (lflag & ICANON) ? &rawq : &inputq;
  int flush = 0;

  /* Handle parity errors */
  if ((iflag & INPCK)
      && ((cflag & PARODD) ? checkoddpar (c) : checkevenpar (c)))
    {
      if (iflag & IGNPAR)
	goto alldone;
      else if (iflag & PARMRK)
	{
	  enqueue_quote (qp, CHAR_USER_QUOTE);
	  enqueue_quote (qp, '\0');
	  enqueue_quote (qp, c);
	  goto alldone;
	}
      else
	c = 0;
    }

  /* Check to see if we should send IXOFF */
  if ((iflag & IXOFF)
      && !qavail (*qp)
      && (cc[VSTOP] != _POSIX_VDISABLE))
    {
      poutput (cc[VSTOP]);
      termflags |= SENT_VSTOP;
    }

  /* Character mutations */
  if (!(iflag & ISTRIP) && (iflag & PARMRK) && (c == CHAR_USER_QUOTE))
    enqueue_quote (qp, CHAR_USER_QUOTE); /* cause doubling */

  if (iflag & ISTRIP)
    c &= 0x7f;

  /* Handle LNEXT right away */
  if (!external_processing && (termflags & LAST_LNEXT))
    {
      enqueue_quote (qp, c);
      echo_char (c, 0, 1);
      termflags &= ~LAST_LNEXT;
      goto alldone;
    }

  /* Mutate ILCASE */
  if (!external_processing && (iflag & ILCASE) && isalpha(c))
    {
      if (termflags & LAST_SLASH)
	erase_1 (0);	/* remove the slash from input */
      else
	c = isupper(c) ? tolower (c) : c;
    }

  /* IEXTEN control chars */
  if (!external_processing && (lflag & IEXTEN))
    {
      if (CCEQ (cc[VLNEXT], c))
	{
	  if (lflag & ECHO)
	    {
	      poutput ('^');
	      poutput ('\b');
	    }
	  termflags |= LAST_LNEXT;
	  goto alldone;
	}

      if (CCEQ (cc[VDISCARD], c))
	{
	  if (termflags & FLUSH_OUTPUT)
	    termflags &= ~FLUSH_OUTPUT;
	  else
	    {
	      drop_output ();
	      poutput (cc[VDISCARD]);
	      termflags |= FLUSH_OUTPUT;
	    }
	  goto alldone;
	}
    }

  /* Signals */
  if (!external_processing && (lflag & ISIG))
    {
      if (CCEQ (cc[VINTR], c) || CCEQ (cc[VQUIT], c))
	{
	  if (!(lflag & NOFLSH))
	    {
	      drop_output ();
	      clear_queue (inputq);
	      clear_queue (rawq);
	      flush = 1;
	    }
	  echo_char (c, 0, 0);
	  echo_qsize = 0;
	  echo_pstart = output_psize;
	  send_signal (CCEQ (cc[VINTR], c) ? SIGINT : SIGQUIT);
	  goto alldone;
	}

      if (CCEQ (cc[VSUSP], c))
	{
	  if (!(lflag & NOFLSH))
	    {
	      flush = 1;
	      clear_queue (inputq);
	      clear_queue (rawq);
	    }
	  echo_char (c, 0, 0);
	  echo_qsize = 0;
	  echo_pstart = output_psize;
	  send_signal (SIGTSTP);
	  goto alldone;
	}
    }

  /* IXON */
  if (!external_processing && (iflag & IXON))
    {
      if (CCEQ (cc[VSTOP], c))
	{
	  if (CCEQ(cc[VSTART], c) && (termflags & USER_OUTPUT_SUSP))
	    /* Toggle if VSTART == VSTOP.  Alldone code always turns
	       off USER_OUTPUT_SUSP. */
	    goto alldone;

	  termflags |= USER_OUTPUT_SUSP;
	  (*bottom->suspend_physical_output) ();
	  return flush;
	}
      if (CCEQ (cc[VSTART], c))
	goto alldone;
    }

  if (!external_processing)
    {
      /* Newline and carriage-return frobbing */
      if (c == '\r')
	{
	  if (iflag & ICRNL)
	    c = '\n';
	  else if (iflag & IGNCR)
	    goto alldone;
	}
      else if ((c == '\n') && (iflag & INLCR))
	c = '\r';

    }

  /* Canonical mode processing */
  if (!external_processing && (lflag & ICANON))
    {
      if (CCEQ (cc[VERASE], c))
	{
	  if (qsize(rawq))
	    erase_1 (c);
	  if (!(termflags & LAST_SLASH)
	      || !(lflag & IEXTEN))
	    goto alldone;
	}

      if (CCEQ (cc[VKILL], c))
	{
	  if (!(termflags & LAST_SLASH)
	      || !(lflag & IEXTEN))
	    {
	      if ((lflag & ECHOKE) && !(lflag & ECHOPRT)
		  && (echo_qsize == qsize (rawq)))
		{
		  while (output_psize > echo_pstart)
		    write_erase_sequence ();
		}
	      else
		{
		  echo_char (c, 0, 0);
		  if ((lflag & ECHOK) || (lflag & ECHOKE))
		    echo_char ('\n', 0, 0);
		}
	      clear_queue (rawq);
	      echo_qsize = 0;
	      echo_pstart = output_psize;
	      termflags &= ~(LAST_SLASH|LAST_LNEXT|INSIDE_HDERASE);
	      goto alldone;
	    }
	  else
	    erase_1 (0);	/* remove \ */
	}

      if (CCEQ (cc[VWERASE], c))
	{
	  /* If we are not going to echo the erase, then
	     echo a WERASE character right now.  (If we
	     passed it to erase_1; it would echo it multiple
	     times.) */
	  if (!(lflag & (ECHOPRT|ECHOE)))
	    echo_char (cc[VWERASE], 0, 1);

	  /* Erase whitespace */
	  while (qsize (rawq) && isblank (unquote_char (rawq->ce[-1])))
	    erase_1 (0);

	  /* Erase word. */
	  if (lflag & ALTWERASE)
	    /* For ALTWERASE, we erase back to the first blank */
	    while (qsize (rawq) && !isblank (unquote_char (rawq->ce[-1])))
	      erase_1 (0);
	  else
	    /* For regular WERASE, we erase back to the first nonalpha/_ */
	    while (qsize (rawq) && !isblank (unquote_char (rawq->ce[-1]))
		   && (isalnum (unquote_char (rawq->ce[-1]))
		       || (unquote_char (rawq->ce[-1]) != '_')))
	      erase_1 (0);

	  goto alldone;
	}

      if (CCEQ (cc[VREPRINT], c) && (lflag & IEXTEN))
	{
	  reprint_line ();
	  goto alldone;
	}

      if (CCEQ (cc[VSTATUS], c) && (lflag & ISIG) && (lflag & IEXTEN))
	{
	  send_signal (SIGINFO);
	  goto alldone;
	}
    }

  /* Now we have a character intended as input.  See if it will fit. */
  if (!qavail (*qp))
    {
      if (iflag & IMAXBEL)
	poutput ('\a');
      else
	{
	  /* Drop everything */
	  drop_output ();
	  clear_queue (inputq);
	  clear_queue (rawq);
	  echo_pstart = 0;
	  echo_qsize = 0;
	  flush = 1;
	}
      goto alldone;
    }

  /* Echo */
  echo_char (c, 0, 0);
  if (CCEQ (cc[VEOF], c) && (lflag & ECHO))
    {
      /* Special bizarre echo processing for VEOF character. */
      int n;
      n = echo_double (c, 0) ? 2 : output_width (c, output_psize);
      while (n--)
	poutput ('\b');
    }

  /* Put character on input queue */
  enqueue (qp, c);

  /* Check for break characters in canonical input processing */
  if (lflag & ICANON)
    {
      if (CCEQ (cc[VEOL], c)
	  || CCEQ (cc[VEOL2], c)
	  || CCEQ (cc[VEOF], c)
	  || c == '\n')
	/* Make input available */
	while (qsize (rawq))
	  enqueue (&inputq, dequeue (rawq));
    }

alldone:
  /* Restart output */
  if ((iflag & IXANY) || (CCEQ (cc[VSTART], c)))
    termflags &= ~USER_OUTPUT_SUSP;
  (*bottom->start_output) ();

  return flush;
}
Ejemplo n.º 16
0
/* Output characters.  */
static any_t
hurdio_writer_loop (any_t arg)
{
  /* XXX The output buffer has 256 bytes.  */
#define BUFFER_SIZE 256
  char *bufp;
  char pending_output[BUFFER_SIZE];
  size_t amount;
  error_t err;
  int size;
  int npending_output_copy;
  mach_port_t ioport_copy;

  mutex_lock (&global_lock);
  writer_thread = mach_thread_self ();

  while (1)
    {
      while (writer_thread != MACH_PORT_NULL
	     && (ioport == MACH_PORT_NULL || !qsize (outputq)
		 || output_stopped))
	hurd_condition_wait (&hurdio_writer_condition, &global_lock);
      if (writer_thread == MACH_PORT_NULL) /* A sign to die.  */
	return 0;

      /* Copy characters onto PENDING_OUTPUT, not bothering
	 those already there. */
      size = qsize (outputq);

      if (size + npending_output > BUFFER_SIZE)
	size = BUFFER_SIZE - npending_output;

      bufp = pending_output + npending_output;
      npending_output += size;
      /* We need to save these values, as otherwise there are races
	 with hurdio_abandon_physical_output or hurdio_desert_dtr,
	 which might overwrite the static variables.  */
      npending_output_copy = npending_output;
      ioport_copy = ioport;
      mach_port_mod_refs (mach_task_self (), ioport_copy,
			  MACH_PORT_RIGHT_SEND, 1);

      while (size--)
	*bufp++ = dequeue (outputq);

      /* Submit all the outstanding characters to the I/O port.  */
      mutex_unlock (&global_lock);
      err = io_write (ioport_copy, pending_output, npending_output_copy,
		      -1, &amount);
      mutex_lock (&global_lock);

      mach_port_mod_refs (mach_task_self (), ioport_copy,
			  MACH_PORT_RIGHT_SEND, -1);
      if (err)
	hurdio_desert_dtr ();
      else
	{
	  /* Note that npending_output might be set to null in the
	     meantime by hurdio_abandon_physical_output.  */
	  if (amount >= npending_output)
	    {
	      npending_output = 0;
	      condition_broadcast (outputq->wait);
	    }
	  else
	    {
	      /* Copy the characters that didn't get output
		 to the front of the array.  */
	      npending_output -= amount;
	      memmove (pending_output, pending_output + amount,
		       npending_output);
	    }
	}
    }
#undef BUFFER_SIZE

  return 0;
}