WriterLocker mixed up source and target and always locked the wrong one.

tty_write_to_tty() now takes the extra character into account that may be
inserted with OPOST and ONLCR and don't write more characters as there is
space.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9151 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2004-10-01 17:27:57 +00:00
parent 549360d822
commit 87df3fdab8

View File

@ -80,12 +80,11 @@ WriterLocker::WriterLocker(struct tty *source, struct tty *target, bool echo, bo
fTarget(target), fTarget(target),
fEcho(echo) fEcho(echo)
{ {
if (echo) { if (echo && sourceIsMaster) {
if (!sourceIsMaster) { // just switch the two, we have to lock both of
// just switch the two, we have to lock both of them anyway // them anyway - master is always locked first
fSource = target; fSource = target;
fTarget = source; fTarget = source;
}
} }
Lock(); Lock();
@ -98,22 +97,22 @@ WriterLocker::~WriterLocker()
} }
void void
WriterLocker::Lock() WriterLocker::Lock()
{ {
mutex_lock(&fSource->lock); mutex_lock(&fTarget->lock);
if (fEcho) if (fEcho)
mutex_lock(&fTarget->lock); mutex_lock(&fSource->lock);
} }
void void
WriterLocker::Unlock() WriterLocker::Unlock()
{ {
if (fEcho) if (fEcho)
mutex_unlock(&fTarget->lock); mutex_unlock(&fSource->lock);
mutex_unlock(&fSource->lock); mutex_unlock(&fTarget->lock);
} }
@ -125,14 +124,14 @@ WriterLocker::AcquireWriter(bool dontBlock)
if (!dontBlock) if (!dontBlock)
Unlock(); Unlock();
status_t status = acquire_sem_etc(fSource->write_sem, 1, (dontBlock ? B_TIMEOUT : 0) | B_CAN_INTERRUPT, 0); status_t status = acquire_sem_etc(fTarget->write_sem, 1, (dontBlock ? B_TIMEOUT : 0) | B_CAN_INTERRUPT, 0);
if (status == B_OK && fEcho) { if (status == B_OK && fEcho) {
// We need to hold two write semaphores in order to echo the output to // We need to hold two write semaphores in order to echo the output to
// the local TTY as well. We need to make sure that these semaphores // the local TTY as well. We need to make sure that these semaphores
// are always acquired in the same order to prevent deadlocks // are always acquired in the same order to prevent deadlocks
status = acquire_sem_etc(fTarget->write_sem, 1, (dontBlock ? B_TIMEOUT : 0) | B_CAN_INTERRUPT, 0); status = acquire_sem_etc(fSource->write_sem, 1, (dontBlock ? B_TIMEOUT : 0) | B_CAN_INTERRUPT, 0);
if (status != B_OK) if (status != B_OK)
release_sem(fSource->write_sem); release_sem(fTarget->write_sem);
} }
// reacquire TTY lock // reacquire TTY lock
@ -140,9 +139,9 @@ WriterLocker::AcquireWriter(bool dontBlock)
Lock(); Lock();
if (status == B_OK) { if (status == B_OK) {
fSourceBytes = line_buffer_writable(fSource->input_buffer); fTargetBytes = line_buffer_writable(fTarget->input_buffer);
if (fEcho) if (fEcho)
fTargetBytes = line_buffer_writable(fTarget->input_buffer); fSourceBytes = line_buffer_writable(fSource->input_buffer);
} }
return status; return status;
} }
@ -151,11 +150,11 @@ WriterLocker::AcquireWriter(bool dontBlock)
void void
WriterLocker::ReportWritten(size_t written) WriterLocker::ReportWritten(size_t written)
{ {
if (written < fSourceBytes) if (written < fTargetBytes)
release_sem_etc(fSource->write_sem, 1, fTarget ? B_DO_NOT_RESCHEDULE : 0); release_sem_etc(fTarget->write_sem, 1, fEcho ? B_DO_NOT_RESCHEDULE : 0);
if (fEcho && written < fTargetBytes) if (fEcho && written < fSourceBytes)
release_sem(fTarget->write_sem); release_sem(fSource->write_sem);
// there is now probably something to read, too // there is now probably something to read, too
@ -521,7 +520,7 @@ tty_input_read(struct tty *tty, void *buffer, size_t *_length, uint32 mode)
// ToDo: add support for ICANON mode // ToDo: add support for ICANON mode
ssize_t bytesRead = line_buffer_user_read(tty->input_buffer, (char *)buffer, length); bytesRead = line_buffer_user_read(tty->input_buffer, (char *)buffer, length);
if (bytesRead < B_OK) { if (bytesRead < B_OK) {
*_length = 0; *_length = 0;
locker.ReportRead(0); locker.ReportRead(0);
@ -562,10 +561,8 @@ tty_write_to_tty(struct tty *source, struct tty *target, const void *buffer, siz
} }
size_t writable = line_buffer_writable(target->input_buffer); size_t writable = line_buffer_writable(target->input_buffer);
if (writable > length)
writable = length;
if (echo) { if (echo) {
// we can only write as much as is available on both ends
size_t locallyWritable = line_buffer_writable(source->input_buffer); size_t locallyWritable = line_buffer_writable(source->input_buffer);
if (locallyWritable < writable) if (locallyWritable < writable)
writable = locallyWritable; writable = locallyWritable;
@ -576,7 +573,7 @@ tty_write_to_tty(struct tty *source, struct tty *target, const void *buffer, siz
continue; continue;
} }
while (writable > bytesWritten) { while (writable > bytesWritten && bytesWritten < length) {
char c = data[0]; char c = data[0];
if (c == '\n' && (source->termios.c_oflag & (OPOST | ONLCR)) == OPOST | ONLCR) { if (c == '\n' && (source->termios.c_oflag & (OPOST | ONLCR)) == OPOST | ONLCR) {
@ -584,6 +581,9 @@ tty_write_to_tty(struct tty *source, struct tty *target, const void *buffer, siz
tty_input_putc_locked(target, '\r'); tty_input_putc_locked(target, '\r');
if (echo) if (echo)
tty_input_putc_locked(source, '\r'); tty_input_putc_locked(source, '\r');
if (--writable == 0)
continue;
} }
tty_input_putc_locked(target, c); tty_input_putc_locked(target, c);