* 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:
parent
a9591c50fd
commit
a8b3406203
@ -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()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user