Work around pty deadlock.
This commit is contained in:
parent
d222003590
commit
632b3ba422
2 changed files with 19 additions and 2 deletions
|
@ -50,6 +50,7 @@ LineBuffer::~LineBuffer()
|
||||||
|
|
||||||
bool LineBuffer::Push(uint32_t unicode)
|
bool LineBuffer::Push(uint32_t unicode)
|
||||||
{
|
{
|
||||||
|
// TODO: An infinite line buffer seems like a bad idea.
|
||||||
// Check if we need to allocate or resize the circular queue.
|
// Check if we need to allocate or resize the circular queue.
|
||||||
if ( bufferused == bufferlength )
|
if ( bufferused == bufferlength )
|
||||||
{
|
{
|
||||||
|
|
|
@ -477,6 +477,8 @@ private:
|
||||||
size_t output_offset;
|
size_t output_offset;
|
||||||
size_t output_used;
|
size_t output_used;
|
||||||
static const size_t output_size = 4096;
|
static const size_t output_size = 4096;
|
||||||
|
// TODO: This is not safe because ^W can produce unbounded output.
|
||||||
|
static const size_t output_probably_safe = 2048;
|
||||||
uint8_t output[output_size];
|
uint8_t output[output_size];
|
||||||
int ptynum;
|
int ptynum;
|
||||||
|
|
||||||
|
@ -538,6 +540,16 @@ ssize_t PTY::master_write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
ScopedLockSignal lock(&termlock);
|
ScopedLockSignal lock(&termlock);
|
||||||
if ( !lock.IsAcquired() )
|
if ( !lock.IsAcquired() )
|
||||||
return errno = EINTR, -1;
|
return errno = EINTR, -1;
|
||||||
|
// TODO: Work around deadlock by refusing writes when the buffer is starting
|
||||||
|
// to be too full. This can block / "deadlock" too if the caller
|
||||||
|
// didn't try to read the data written by a previous call.
|
||||||
|
while ( output_probably_safe <= output_used )
|
||||||
|
{
|
||||||
|
if ( ctx->dflags & O_NONBLOCK )
|
||||||
|
return errno = EWOULDBLOCK, -1;
|
||||||
|
if ( !kthread_cond_wait_signal(&output_ready_cond, &termlock) )
|
||||||
|
return errno = EINTR, -1;
|
||||||
|
}
|
||||||
size_t sofar = 0;
|
size_t sofar = 0;
|
||||||
while ( sofar < count )
|
while ( sofar < count )
|
||||||
{
|
{
|
||||||
|
@ -550,9 +562,13 @@ ssize_t PTY::master_write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
{
|
{
|
||||||
if ( Signal::IsPending() )
|
if ( Signal::IsPending() )
|
||||||
return sofar ? (ssize_t) sofar : (errno = EINTR, -1);
|
return sofar ? (ssize_t) sofar : (errno = EINTR, -1);
|
||||||
|
// TODO: Unfortunately sequences like ^W can cause an unbounded
|
||||||
|
// number of tty_output data causing a deadlock.
|
||||||
ProcessByte(input[i]);
|
ProcessByte(input[i]);
|
||||||
|
sofar++;
|
||||||
|
if ( output_probably_safe <= output_used )
|
||||||
|
return (ssize_t) sofar;
|
||||||
}
|
}
|
||||||
sofar += amount;
|
|
||||||
}
|
}
|
||||||
return (ssize_t) sofar;
|
return (ssize_t) sofar;
|
||||||
}
|
}
|
||||||
|
@ -599,7 +615,7 @@ short PTY::PollMasterEventStatus()
|
||||||
short status = 0;
|
short status = 0;
|
||||||
if ( output_used )
|
if ( output_used )
|
||||||
status |= POLLIN | POLLRDNORM;
|
status |= POLLIN | POLLRDNORM;
|
||||||
if ( true /* can always write */ )
|
if ( output_used < output_probably_safe )
|
||||||
status |= POLLOUT | POLLWRNORM;
|
status |= POLLOUT | POLLWRNORM;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue