fix printf() in interrupts

This commit is contained in:
Robert Morris 2020-07-22 10:31:46 -04:00
parent 823864099d
commit db0f092ae4
3 changed files with 29 additions and 25 deletions

View file

@ -42,9 +42,9 @@ consputc(int c)
if(c == BACKSPACE){
// if the user typed backspace, overwrite with a space.
uartputc('\b', 0); uartputc(' ', 0); uartputc('\b', 0);
uartputc_sync('\b'); uartputc_sync(' '); uartputc_sync('\b');
} else {
uartputc(c, 0);
uartputc_sync(c);
}
}
@ -72,7 +72,7 @@ consolewrite(int user_src, uint64 src, int n)
char c;
if(either_copyin(&c, user_src, src+i, 1) == -1)
break;
uartputc(c, 1);
uartputc(c);
}
release(&cons.lock);

View file

@ -149,7 +149,8 @@ void usertrapret(void);
// uart.c
void uartinit(void);
void uartintr(void);
void uartputc(int, int);
void uartputc(int);
void uartputc_sync(int);
int uartgetc(void);
// vm.c

View file

@ -69,33 +69,19 @@ uartinit(void)
// add a character to the output buffer and tell the
// UART to start sending if it isn't already.
//
// usually called from the top-half -- by a process
// calling write(). can also be called from a uart
// interrupt to echo a received character, or by printf
// or panic from anywhere in the kernel.
//
// the block argument controls what happens if the
// buffer is full. for write(), block is 1, and the
// process waits. for kernel printf's and echoed
// characters, block is 0, and the character is
// discarded; this is necessary since sleep() is
// not possible in interrupts.
// blocks if the output buffer is full.
// because it may block, it can't be called
// from interrupts; it's only suitable for use
// by write().
void
uartputc(int c, int block)
uartputc(int c)
{
acquire(&uart_tx_lock);
while(1){
if(((uart_tx_w + 1) % UART_TX_BUF_SIZE) == uart_tx_r){
// buffer is full.
if(block){
// wait for uartstart() to open up space in the buffer.
sleep(&uart_tx_r, &uart_tx_lock);
} else {
// caller does not want us to wait.
release(&uart_tx_lock);
return;
}
// wait for uartstart() to open up space in the buffer.
sleep(&uart_tx_r, &uart_tx_lock);
} else {
uart_tx_buf[uart_tx_w] = c;
uart_tx_w = (uart_tx_w + 1) % UART_TX_BUF_SIZE;
@ -106,6 +92,23 @@ uartputc(int c, int block)
}
}
// alternate version of uartputc() that doesn't
// use interrupts, for use by kernel printf() and
// to echo characters. it spins waiting for the uart's
// output register to be empty.
void
uartputc_sync(int c)
{
push_off();
// wait for Transmit Holding Empty to be set in LSR.
while((ReadReg(LSR) & (1 << 5)) == 0)
;
WriteReg(THR, c);
pop_off();
}
// if the UART is idle, and a character is waiting
// in the transmit buffer, send it.
// caller must hold uart_tx_lock.