/*! Sends BYTE to the serial port. */ void serial_putc(uint8_t byte) { enum intr_level old_level = intr_disable(); if (mode != QUEUE) { /* If we're not set up for interrupt-driven I/O yet, use dumb polling to transmit a byte. */ if (mode == UNINIT) init_poll(); putc_poll(byte); } else { /* Otherwise, queue a byte and update the interrupt enable register. */ if (old_level == INTR_OFF && intq_full(&txq)) { /* Interrupts are off and the transmit queue is full. If we wanted to wait for the queue to empty, we'd have to reenable interrupts. That's impolite, so we'll send a character via polling instead. */ putc_poll(intq_getc (&txq)); } intq_putc(&txq, byte); write_ier(); } intr_set_level(old_level); }
/* Adds BYTE to the end of Q. Q must not be full if called from an interrupt handler. Otherwise, if Q is full, first sleeps until a byte is removed. */ void intq_putc (struct intq *q, uint8_t byte) { ASSERT (intr_get_level () == INTR_OFF); while (intq_full (q)) { ASSERT (!intr_context ()); lock_acquire (&q->lock); wait (q, &q->not_full); lock_release_with_preemption (&q->lock); } q->buf[q->head] = byte; q->head = next (q->head); signal (q, &q->not_empty); }
/* Returns the position after POS within an intq. */ static int next (int pos) { return (pos + 1) % INTQ_BUFSIZE; } /* WAITER must be the address of Q's not_empty or not_full member. Waits until the given condition is true. */ static void wait (struct intq *q UNUSED, struct thread **waiter) { ASSERT (!intr_context ()); ASSERT (intr_get_level () == INTR_OFF); ASSERT ((waiter == &q->not_empty && intq_empty (q)) || (waiter == &q->not_full && intq_full (q))); *waiter = thread_current (); thread_block (); } /* WAITER must be the address of Q's not_empty or not_full member, and the associated condition must be true. If a thread is waiting for the condition, wakes it up and resets the waiting thread. */ static void signal (struct intq *q UNUSED, struct thread **waiter) { ASSERT (intr_get_level () == INTR_OFF); ASSERT ((waiter == &q->not_empty && !intq_empty (q)) || (waiter == &q->not_full && !intq_full (q)));