* Cleanup, no functional change.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34142 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2009-11-19 22:00:24 +00:00
parent a9591c50fd
commit a8b3406203

View File

@ -1,14 +1,17 @@
/*
* Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
// This file could be moved into a generic tty module.
// The whole hardware signaling stuff is missing, though - it's currently
// tailored for pseudo-TTYs. Have a look at Be's TTY includes (drivers/tty/*)
#include "tty_private.h"
#include <ctype.h>
#include <errno.h>
#include <signal.h>
@ -24,8 +27,6 @@
#include <tty.h>
#include "tty_private.h"
//#define TTY_TRACE
#ifdef TTY_TRACE
@ -96,13 +97,21 @@ static void tty_notify_if_available(struct tty *tty, struct tty *otherTTY,
class AbstractLocker {
public:
AbstractLocker(tty_cookie *cookie) : fCookie(cookie), fBytes(0) {}
AbstractLocker(tty_cookie* cookie)
:
fCookie(cookie),
fBytes(0)
{
}
size_t AvailableBytes() const { return fBytes; }
size_t AvailableBytes() const
{ return fBytes; }
protected:
void Lock() { mutex_lock(fCookie->tty->lock); }
void Unlock() { mutex_unlock(fCookie->tty->lock); }
void Lock()
{ mutex_lock(fCookie->tty->lock); }
void Unlock()
{ mutex_unlock(fCookie->tty->lock); }
tty_cookie* fCookie;
size_t fBytes;
@ -114,7 +123,8 @@ class WriterLocker : public AbstractLocker {
WriterLocker(tty_cookie* sourceCookie);
~WriterLocker();
status_t AcquireWriter(bool dontBlock, size_t bytesNeeded);
status_t AcquireWriter(bool dontBlock,
size_t bytesNeeded);
private:
size_t _CheckAvailableBytes() const;
@ -132,7 +142,8 @@ class ReaderLocker : public AbstractLocker {
ReaderLocker(tty_cookie* cookie);
~ReaderLocker();
status_t AcquireReader(bigtime_t timeout, size_t minBytes);
status_t AcquireReader(bigtime_t timeout,
size_t minBytes);
status_t AcquireReader(bool dontBlock);
private:
@ -329,8 +340,7 @@ RequestOwner::RequestOwner()
}
/**
* The caller must already hold the request lock.
/*! The caller must already hold the request lock.
*/
void
RequestOwner::Enqueue(tty_cookie* cookie, RequestQueue* queue1,
@ -358,8 +368,7 @@ RequestOwner::Enqueue(tty_cookie *cookie, RequestQueue *queue1,
}
/**
* The caller must already hold the request lock.
/*! The caller must already hold the request lock.
*/
void
RequestOwner::Dequeue()
@ -387,8 +396,7 @@ RequestOwner::SetBytesNeeded(size_t bytesNeeded)
}
/**
* The request lock MUST NOT be held!
/*! The request lock MUST NOT be held!
*/
status_t
RequestOwner::Wait(bool interruptable, bigtime_t timeout)
@ -495,7 +503,8 @@ RequestOwner::NotifyError(Request *request, status_t error)
WriterLocker::WriterLocker(tty_cookie* sourceCookie)
: AbstractLocker(sourceCookie),
:
AbstractLocker(sourceCookie),
fSource(fCookie->tty),
fTarget(fCookie->other_tty),
fRequestOwner(),
@ -646,7 +655,8 @@ WriterLocker::_CheckBackgroundWrite() const
ReaderLocker::ReaderLocker(tty_cookie* cookie)
: AbstractLocker(cookie),
:
AbstractLocker(cookie),
fTTY(cookie->tty),
fRequestOwner()
{
@ -837,9 +847,9 @@ tty_output_getc(struct tty *tty, int *_c)
}
/** Processes the input character and puts it into the TTY's input buffer.
* Depending on the termios flags set, signals may be sent, the input
* character changed or removed, etc.
/*! Processes the input character and puts it into the TTY's input buffer.
Depending on the termios flags set, signals may be sent, the input
character changed or removed, etc.
*/
static void
tty_input_putc_locked(struct tty* tty, int c)
@ -984,8 +994,7 @@ uninit_tty_cookie(tty_cookie *cookie)
}
/**
* The global lock must be held.
/*! The global lock must be held.
*/
void
add_tty_cookie(tty_cookie* cookie)
@ -998,8 +1007,7 @@ add_tty_cookie(tty_cookie *cookie)
}
/**
* The global lock must be held.
/*! The global lock must be held.
*/
void
tty_close_cookie(struct tty_cookie* cookie)
@ -1128,15 +1136,15 @@ tty_notify_select_event(struct tty *tty, uint8 event)
}
/** \brief Checks whether bytes can be read from/written to the line buffer of
* the given TTY and notifies the respective queues.
*
* Also sends out \c B_SELECT_READ and \c B_SELECT_WRITE events as needed.
*
* The TTY and the request lock must be held.
*
* \param tty The TTY.
* \param otherTTY The connected TTY.
/*! \brief Checks whether bytes can be read from/written to the line buffer of
the given TTY and notifies the respective queues.
Also sends out \c B_SELECT_READ and \c B_SELECT_WRITE events as needed.
The TTY and the request lock must be held.
\param tty The TTY.
\param otherTTY The connected TTY.
*/
static void
tty_notify_if_available(struct tty* tty, struct tty* otherTTY,
@ -1169,8 +1177,7 @@ tty_notify_if_available(struct tty *tty, struct tty *otherTTY,
}
/*!
\brief Performs input character conversion and writes the result to
/*! \brief Performs input character conversion and writes the result to
\a buffer.
\param tty The master tty.
\param c The input character.
@ -1216,7 +1223,7 @@ process_input_char(struct tty* tty, char c, char* buffer,
} else if (c == '\n') {
if (flags & INLCR) // NL -> CR
c = '\r';
} else if (flags & ISTRIP) // strip of eighth bit
} else if ((flags & ISTRIP) != 0) // strip off eighth bit
c &= 0x7f;
*buffer = c;
@ -1224,8 +1231,8 @@ process_input_char(struct tty* tty, char c, char* buffer,
return true;
}
/*!
\brief Performs output character conversion and writes the result to
/*! \brief Performs output character conversion and writes the result to
\a buffer.
\param tty The master tty.
\param c The output character.
@ -1293,8 +1300,269 @@ process_output_char(struct tty* tty, char c, char* buffer,
}
// #pragma mark -
// device functions
static status_t
tty_write_to_tty_master_unsafe(tty_cookie* sourceCookie, const char* data,
size_t* _length)
{
struct tty* source = sourceCookie->tty;
struct tty* target = sourceCookie->other_tty;
size_t length = *_length;
size_t bytesWritten = 0;
uint32 mode = sourceCookie->open_mode;
bool dontBlock = (mode & O_NONBLOCK) != 0;
// bail out, if source is already closed
TTYReference sourceTTYReference(sourceCookie);
if (!sourceTTYReference.IsLocked())
return B_FILE_ERROR;
if (length == 0)
return B_OK;
WriterLocker locker(sourceCookie);
// if the target is not open, fail now
if (target->open_count <= 0)
return B_FILE_ERROR;
bool echo = (source->settings->termios.c_lflag & ECHO) != 0;
TRACE(("tty_write_to_tty_master(source = %p, target = %p, "
"length = %lu%s)\n", source, target, length,
(echo ? ", echo mode" : "")));
// Make sure we are first in the writer queue(s) and AvailableBytes() is
// initialized.
status_t status = locker.AcquireWriter(dontBlock, 0);
if (status != B_OK) {
*_length = 0;
return status;
}
size_t writable = locker.AvailableBytes();
size_t writtenSinceLastNotify = 0;
while (bytesWritten < length) {
// fetch next char and do input processing
char c;
size_t bytesNeeded;
if (!process_input_char(source, *data, &c, &bytesNeeded)) {
// input char shall be skipped
data++;
bytesWritten++;
continue;
}
// If in echo mode, we do the output conversion and need to update
// the needed bytes count.
char echoBuffer[3];
size_t echoBytes;
if (echo) {
process_output_char(source, c, echoBuffer, &echoBytes, true);
if (echoBytes > bytesNeeded)
bytesNeeded = echoBytes;
}
// If there's not enough space to write what we have, we need to wait
// until it is available.
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);
if (status != B_OK) {
*_length = bytesWritten;
return status;
}
writable = locker.AvailableBytes();
// XXX: do we need to support VMIN & VTIME for write() ?
// We need to restart the loop, since the termios flags might have
// changed in the meantime (while we've unlocked the tty). Note,
// that we don't re-get "echo" -- maybe we should.
continue;
}
// write the bytes
tty_input_putc_locked(target, c);
if (echo) {
for (size_t i = 0; i < echoBytes; i++)
line_buffer_putc(source->input_buffer, echoBuffer[i]);
}
writable -= bytesNeeded;
data++;
bytesWritten++;
writtenSinceLastNotify++;
}
return B_OK;
}
static status_t
tty_write_to_tty_slave_unsafe(tty_cookie* sourceCookie, const char* data,
size_t* _length)
{
struct tty* target = sourceCookie->other_tty;
size_t length = *_length;
size_t bytesWritten = 0;
uint32 mode = sourceCookie->open_mode;
bool dontBlock = (mode & O_NONBLOCK) != 0;
// bail out, if source is already closed
TTYReference sourceTTYReference(sourceCookie);
if (!sourceTTYReference.IsLocked())
return B_FILE_ERROR;
if (length == 0)
return B_OK;
WriterLocker locker(sourceCookie);
// if the target is not open, fail now
if (target->open_count <= 0)
return B_FILE_ERROR;
TRACE(("tty_write_to_tty_slave(source = %p, target = %p, length = %lu)\n",
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);
if (status != B_OK) {
*_length = 0;
return status;
}
size_t writable = locker.AvailableBytes();
size_t writtenSinceLastNotify = 0;
while (bytesWritten < length) {
// fetch next char and do output processing
char buffer[3];
size_t bytesNeeded;
process_output_char(target, *data, buffer, &bytesNeeded, false);
// If there's not enough space to write what we have, we need to wait
// until it is available.
if (writable < bytesNeeded) {
if (writtenSinceLastNotify > 0) {
tty_notify_if_available(target, sourceCookie->tty, true);
writtenSinceLastNotify = 0;
}
status = locker.AcquireWriter(dontBlock, bytesNeeded);
if (status != B_OK) {
*_length = bytesWritten;
return status;
}
writable = locker.AvailableBytes();
// We need to restart the loop, since the termios flags might have
// changed in the meantime (while we've unlocked the tty).
continue;
}
// write the bytes
for (size_t i = 0; i < bytesNeeded; i++)
line_buffer_putc(target->input_buffer, buffer[i]);
writable -= bytesNeeded;
data++;
bytesWritten++;
writtenSinceLastNotify++;
}
return B_OK;
}
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);
kprintf(" termios:\n");
kprintf(" c_iflag: 0x%08lx\n", settings.termios.c_iflag);
kprintf(" c_oflag: 0x%08lx\n", settings.termios.c_oflag);
kprintf(" c_cflag: 0x%08lx\n", settings.termios.c_cflag);
kprintf(" c_lflag: 0x%08lx\n", settings.termios.c_lflag);
kprintf(" c_line: %d\n", settings.termios.c_line);
kprintf(" c_ispeed: %u\n", settings.termios.c_ispeed);
kprintf(" c_ospeed: %u\n", settings.termios.c_ospeed);
for (int i = 0; i < NCCS; i++)
kprintf(" c_cc[%02d]: %d\n", i, settings.termios.c_cc[i]);
kprintf(" wsize: %u x %u c, %u x %u pxl\n",
settings.window_size.ws_row, settings.window_size.ws_col,
settings.window_size.ws_xpixel, settings.window_size.ws_ypixel);
}
static void
dump_tty_struct(struct tty& tty)
{
kprintf(" tty @: %p\n", &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: %p\n", tty.lock);
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;
}
// #pragma mark - device functions
status_t
@ -1343,7 +1611,7 @@ tty_ioctl(tty_cookie *cookie, uint32 op, void *buffer, size_t length)
// values marked BeOS are non-standard codes we support for legacy apps
switch (op) {
/* blocking/non-blocking mode */
// blocking/non-blocking mode
case B_SET_BLOCKING_IO:
cookie->open_mode &= ~O_NONBLOCK;
@ -1352,7 +1620,7 @@ tty_ioctl(tty_cookie *cookie, uint32 op, void *buffer, size_t length)
cookie->open_mode |= O_NONBLOCK;
return B_OK;
/* get and set TTY attributes */
// get and set TTY attributes
case TCGETA:
TRACE(("tty: get attributes\n"));
@ -1370,7 +1638,7 @@ tty_ioctl(tty_cookie *cookie, uint32 op, void *buffer, size_t length)
return user_memcpy(&tty->settings->termios, buffer,
sizeof(struct termios));
/* get and set process group ID */
// get and set process group ID
case TIOCGPGRP:
TRACE(("tty: get pgrp_id\n"));
@ -1392,7 +1660,7 @@ tty_ioctl(tty_cookie *cookie, uint32 op, void *buffer, size_t length)
return error;
}
/* get and set window size */
// get and set window size
case TIOCGWINSZ:
TRACE(("tty: set window size\n"));
@ -1601,112 +1869,6 @@ tty_input_read(tty_cookie *cookie, void *buffer, size_t *_length)
}
static status_t
tty_write_to_tty_master_unsafe(tty_cookie *sourceCookie, const char *data,
size_t *_length)
{
struct tty *source = sourceCookie->tty;
struct tty *target = sourceCookie->other_tty;
size_t length = *_length;
size_t bytesWritten = 0;
uint32 mode = sourceCookie->open_mode;
bool dontBlock = (mode & O_NONBLOCK) != 0;
// bail out, if source is already closed
TTYReference sourceTTYReference(sourceCookie);
if (!sourceTTYReference.IsLocked())
return B_FILE_ERROR;
if (length == 0)
return B_OK;
WriterLocker locker(sourceCookie);
// if the target is not open, fail now
if (target->open_count <= 0)
return B_FILE_ERROR;
bool echo = (source->settings->termios.c_lflag & ECHO) != 0;
TRACE(("tty_write_to_tty_master(source = %p, target = %p, "
"length = %lu%s)\n", source, target, length,
(echo ? ", echo mode" : "")));
// Make sure we are first in the writer queue(s) and AvailableBytes() is
// initialized.
status_t status = locker.AcquireWriter(dontBlock, 0);
if (status != B_OK) {
*_length = 0;
return status;
}
size_t writable = locker.AvailableBytes();
size_t writtenSinceLastNotify = 0;
while (bytesWritten < length) {
// fetch next char and do input processing
char c;
size_t bytesNeeded;
if (!process_input_char(source, *data, &c, &bytesNeeded)) {
// input char shall be skipped
data++;
bytesWritten++;
continue;
}
// If in echo mode, we do the output conversion and need to update
// the needed bytes count.
char echoBuffer[3];
size_t echoBytes;
if (echo) {
process_output_char(source, c, echoBuffer, &echoBytes, true);
if (echoBytes > bytesNeeded)
bytesNeeded = echoBytes;
}
// If there's not enough space to write what we have, we need to wait
// until it is available.
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);
if (status != B_OK) {
*_length = bytesWritten;
return status;
}
writable = locker.AvailableBytes();
// XXX: do we need to support VMIN & VTIME for write() ?
// We need to restart the loop, since the termios flags might have
// changed in the meantime (while we've unlocked the tty). Note,
// that we don't re-get "echo" -- maybe we should.
continue;
}
// write the bytes
tty_input_putc_locked(target, c);
if (echo) {
for (size_t i = 0; i < echoBytes; i++)
line_buffer_putc(source->input_buffer, echoBuffer[i]);
}
writable -= bytesNeeded;
data++;
bytesWritten++;
writtenSinceLastNotify++;
}
return B_OK;
}
status_t
tty_write_to_tty_master(tty_cookie* sourceCookie, const void* _buffer,
size_t* _length)
@ -1742,84 +1904,6 @@ tty_write_to_tty_master(tty_cookie *sourceCookie, const void *_buffer,
}
static status_t
tty_write_to_tty_slave_unsafe(tty_cookie *sourceCookie, const char *data,
size_t *_length)
{
struct tty *target = sourceCookie->other_tty;
size_t length = *_length;
size_t bytesWritten = 0;
uint32 mode = sourceCookie->open_mode;
bool dontBlock = (mode & O_NONBLOCK) != 0;
// bail out, if source is already closed
TTYReference sourceTTYReference(sourceCookie);
if (!sourceTTYReference.IsLocked())
return B_FILE_ERROR;
if (length == 0)
return B_OK;
WriterLocker locker(sourceCookie);
// if the target is not open, fail now
if (target->open_count <= 0)
return B_FILE_ERROR;
TRACE(("tty_write_to_tty_slave(source = %p, target = %p, length = %lu)\n",
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);
if (status != B_OK) {
*_length = 0;
return status;
}
size_t writable = locker.AvailableBytes();
size_t writtenSinceLastNotify = 0;
while (bytesWritten < length) {
// fetch next char and do output processing
char buffer[3];
size_t bytesNeeded;
process_output_char(target, *data, buffer, &bytesNeeded, false);
// If there's not enough space to write what we have, we need to wait
// until it is available.
if (writable < bytesNeeded) {
if (writtenSinceLastNotify > 0) {
tty_notify_if_available(target, sourceCookie->tty, true);
writtenSinceLastNotify = 0;
}
status = locker.AcquireWriter(dontBlock, bytesNeeded);
if (status != B_OK) {
*_length = bytesWritten;
return status;
}
writable = locker.AvailableBytes();
// We need to restart the loop, since the termios flags might have
// changed in the meantime (while we've unlocked the tty).
continue;
}
// write the bytes
for (size_t i = 0; i < bytesNeeded; i++)
line_buffer_putc(target->input_buffer, buffer[i]);
writable -= bytesNeeded;
data++;
bytesWritten++;
writtenSinceLastNotify++;
}
return B_OK;
}
status_t
tty_write_to_tty_slave(tty_cookie* sourceCookie, const void* _buffer,
size_t* _length)
@ -1957,83 +2041,6 @@ tty_deselect(tty_cookie *cookie, uint8 event, selectsync *sync)
}
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);
kprintf(" termios:\n");
kprintf(" c_iflag: 0x%08lx\n", settings.termios.c_iflag);
kprintf(" c_oflag: 0x%08lx\n", settings.termios.c_oflag);
kprintf(" c_cflag: 0x%08lx\n", settings.termios.c_cflag);
kprintf(" c_lflag: 0x%08lx\n", settings.termios.c_lflag);
kprintf(" c_line: %d\n", settings.termios.c_line);
kprintf(" c_ispeed: %u\n", settings.termios.c_ispeed);
kprintf(" c_ospeed: %u\n", settings.termios.c_ospeed);
for (int i = 0; i < NCCS; i++)
kprintf(" c_cc[%02d]: %d\n", i, settings.termios.c_cc[i]);
kprintf(" wsize: %u x %u c, %u x %u pxl\n",
settings.window_size.ws_row, settings.window_size.ws_col,
settings.window_size.ws_xpixel, settings.window_size.ws_ypixel);
}
static void
dump_tty_struct(struct tty& tty)
{
kprintf(" tty @: %p\n", &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: %p\n", tty.lock);
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()
{