* Added debugger command "tty", which dumps some info about a tty.

* RequestOwner was removing the wrong request from the second queue,
  which could cause the list structure to become invalid and result in
  bug #1526.
* In the writer loops we do now call tty_notify_if_available() when
  we're potentially going to wait and had written something before, so
  that a waiting reader will be woken up also when we write more bytes
  than fit into the ring buffer.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22421 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2007-10-03 19:04:44 +00:00
parent 2f28a3f623
commit e8429ec9e6
3 changed files with 133 additions and 1 deletions

View File

@ -100,6 +100,8 @@ init_driver(void)
} }
} }
tty_add_debugger_commands();
return B_OK; return B_OK;
} }
@ -109,6 +111,8 @@ uninit_driver(void)
{ {
TRACE((DRIVER_NAME ": uninit_driver()\n")); TRACE((DRIVER_NAME ": uninit_driver()\n"));
tty_remove_debugger_commands();
for (int32 i = 0; i < (int32)kNumTTYs * 2; i++) for (int32 i = 0; i < (int32)kNumTTYs * 2; i++)
free(sDeviceNames[i]); free(sDeviceNames[i]);

View File

@ -223,6 +223,18 @@ Request::NotifyError(status_t error)
} }
void
Request::Dump(const char* prefix)
{
kprintf("%srequest: %p\n", prefix, this);
kprintf("%s owner: %p\n", prefix, fOwner);
kprintf("%s cookie: %p\n", prefix, fCookie);
kprintf("%s bytes needed: %lu\n", prefix, fBytesNeeded);
kprintf("%s notified: %s\n", prefix, fNotified ? "true" : "false");
kprintf("%s error: %s\n", prefix, fError ? "true" : "false");
}
// #pragma mark - // #pragma mark -
@ -290,6 +302,15 @@ RequestQueue::NotifyError(tty_cookie *cookie, status_t error)
} }
void
RequestQueue::Dump(const char* prefix)
{
RequestList::Iterator it = fRequests.GetIterator();
while (Request* request = it.Next())
request->Dump(prefix);
}
// #pragma mark - // #pragma mark -
@ -345,7 +366,10 @@ RequestOwner::Dequeue()
if (fRequestQueues[0]) if (fRequestQueues[0])
fRequestQueues[0]->Remove(&fRequests[0]); fRequestQueues[0]->Remove(&fRequests[0]);
if (fRequestQueues[1]) if (fRequestQueues[1])
fRequestQueues[1]->Remove(&fRequests[0]); fRequestQueues[1]->Remove(&fRequests[1]);
fRequestQueues[0] = NULL;
fRequestQueues[1] = NULL;
} }
@ -1458,12 +1482,15 @@ tty_write_to_tty_master_unsafe(tty_cookie *sourceCookie, const char *data,
"length = %lu%s)\n", source, target, length, "length = %lu%s)\n", source, target, length,
(echo ? ", echo mode" : ""))); (echo ? ", echo mode" : "")));
// Make sure we are first in the writer queue(s) and AvailableBytes() is
// initialized.
status_t status = locker.AcquireWriter(dontBlock, 0); status_t status = locker.AcquireWriter(dontBlock, 0);
if (status != B_OK) { if (status != B_OK) {
*_length = 0; *_length = 0;
return status; return status;
} }
size_t writable = locker.AvailableBytes(); size_t writable = locker.AvailableBytes();
size_t writtenSinceLastNotify = 0;
while (bytesWritten < length) { while (bytesWritten < length) {
// fetch next char and do input processing // fetch next char and do input processing
@ -1489,6 +1516,13 @@ tty_write_to_tty_master_unsafe(tty_cookie *sourceCookie, const char *data,
// If there's not enough space to write what we have, we need to wait // If there's not enough space to write what we have, we need to wait
// until it is available. // until it is available.
if (writable < bytesNeeded) { if (writable < bytesNeeded) {
if (writtenSinceLastNotify > 0) {
tty_notify_if_available(target, source, true);
if (echo)
tty_notify_if_available(source, target, true);
writtenSinceLastNotify = 0;
}
status = locker.AcquireWriter(dontBlock, bytesNeeded); status = locker.AcquireWriter(dontBlock, bytesNeeded);
if (status != B_OK) { if (status != B_OK) {
*_length = bytesWritten; *_length = bytesWritten;
@ -1514,6 +1548,7 @@ tty_write_to_tty_master_unsafe(tty_cookie *sourceCookie, const char *data,
writable -= bytesNeeded; writable -= bytesNeeded;
data++; data++;
bytesWritten++; bytesWritten++;
writtenSinceLastNotify++;
} }
return B_OK; return B_OK;
@ -1582,12 +1617,15 @@ tty_write_to_tty_slave_unsafe(tty_cookie *sourceCookie, const char *data,
TRACE(("tty_write_to_tty_slave(source = %p, target = %p, length = %lu)\n", TRACE(("tty_write_to_tty_slave(source = %p, target = %p, length = %lu)\n",
sourceCookie->tty, target, length)); sourceCookie->tty, target, length));
// Make sure we are first in the writer queue(s) and AvailableBytes() is
// initialized.
status_t status = locker.AcquireWriter(dontBlock, 0); status_t status = locker.AcquireWriter(dontBlock, 0);
if (status != B_OK) { if (status != B_OK) {
*_length = 0; *_length = 0;
return status; return status;
} }
size_t writable = locker.AvailableBytes(); size_t writable = locker.AvailableBytes();
size_t writtenSinceLastNotify = 0;
while (bytesWritten < length) { while (bytesWritten < length) {
// fetch next char and do output processing // fetch next char and do output processing
@ -1598,6 +1636,11 @@ tty_write_to_tty_slave_unsafe(tty_cookie *sourceCookie, const char *data,
// If there's not enough space to write what we have, we need to wait // If there's not enough space to write what we have, we need to wait
// until it is available. // until it is available.
if (writable < bytesNeeded) { if (writable < bytesNeeded) {
if (writtenSinceLastNotify > 0) {
tty_notify_if_available(target, sourceCookie->tty, true);
writtenSinceLastNotify = 0;
}
status = locker.AcquireWriter(dontBlock, bytesNeeded); status = locker.AcquireWriter(dontBlock, bytesNeeded);
if (status != B_OK) { if (status != B_OK) {
*_length = bytesWritten; *_length = bytesWritten;
@ -1618,6 +1661,7 @@ tty_write_to_tty_slave_unsafe(tty_cookie *sourceCookie, const char *data,
writable -= bytesNeeded; writable -= bytesNeeded;
data++; data++;
bytesWritten++; bytesWritten++;
writtenSinceLastNotify++;
} }
return B_OK; return B_OK;
@ -1771,3 +1815,80 @@ tty_deselect(tty_cookie *cookie, uint8 event, selectsync *sync)
return remove_select_sync_pool_entry(&tty->select_pool, sync, event); return remove_select_sync_pool_entry(&tty->select_pool, sync, event);
} }
static void
dump_tty_settings(struct tty_settings& settings)
{
kprintf(" pgrp_id: %ld\n", settings.pgrp_id);
kprintf(" session_id: %ld\n", settings.session_id);
// struct termios termios;
// struct winsize window_size;
}
static void
dump_tty_struct(struct tty& tty)
{
kprintf(" index: %ld\n", tty.index);
kprintf(" is_master: %s\n", tty.is_master ? "true" : "false");
kprintf(" open_count: %ld\n", tty.open_count);
kprintf(" select_pool: %p\n", tty.select_pool);
kprintf(" pending_eof: %lu\n", tty.pending_eof);
kprintf(" lock.sem: %ld\n", tty.lock->sem);
kprintf(" input_buffer:\n");
kprintf(" first: %ld\n", tty.input_buffer.first);
kprintf(" in: %lu\n", tty.input_buffer.in);
kprintf(" size: %lu\n", tty.input_buffer.size);
kprintf(" buffer: %p\n", tty.input_buffer.buffer);
kprintf(" reader queue:\n");
tty.reader_queue.Dump(" ");
kprintf(" writer queue:\n");
tty.writer_queue.Dump(" ");
kprintf(" cookies: ");
TTYCookieList::Iterator it = tty.cookies.GetIterator();
while (tty_cookie* cookie = it.Next())
kprintf(" %p", cookie);
kprintf("\n");
}
static int
dump_tty(int argc, char** argv)
{
if (argc < 2) {
kprintf("Usage: %s <tty index>\n", argv[0]);
return 0;
}
int32 index = atol(argv[1]);
if (index < 0 || index >= (int32)kNumTTYs) {
kprintf("Invalid tty index.\n");
return 0;
}
kprintf("master:\n");
dump_tty_struct(gMasterTTYs[index]);
kprintf("slave:\n");
dump_tty_struct(gSlaveTTYs[index]);
kprintf("settings:\n");
dump_tty_settings(gTTYSettings[index]);
return 0;
}
void
tty_add_debugger_commands()
{
add_debugger_command("tty", &dump_tty, "Dump info on a tty");
}
void
tty_remove_debugger_commands()
{
remove_debugger_command("tty", &dump_tty);
}

View File

@ -47,6 +47,8 @@ class Request : public DoublyLinkedListLinkImpl<Request> {
bool WasNotified() const { return fNotified; } bool WasNotified() const { return fNotified; }
bool HasError() const { return fError; } bool HasError() const { return fError; }
void Dump(const char* prefix);
private: private:
RequestOwner *fOwner; RequestOwner *fOwner;
tty_cookie *fCookie; tty_cookie *fCookie;
@ -70,6 +72,8 @@ class RequestQueue {
void NotifyError(status_t error); void NotifyError(status_t error);
void NotifyError(tty_cookie *cookie, status_t error); void NotifyError(tty_cookie *cookie, status_t error);
void Dump(const char* prefix);
private: private:
typedef DoublyLinkedList<Request> RequestList; typedef DoublyLinkedList<Request> RequestList;
@ -181,4 +185,7 @@ extern status_t tty_select(tty_cookie *cookie, uint8 event, uint32 ref,
selectsync *sync); selectsync *sync);
extern status_t tty_deselect(tty_cookie *cookie, uint8 event, selectsync *sync); extern status_t tty_deselect(tty_cookie *cookie, uint8 event, selectsync *sync);
extern void tty_add_debugger_commands();
extern void tty_remove_debugger_commands();
#endif /* TTY_PRIVATE_H */ #endif /* TTY_PRIVATE_H */