* 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 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.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// This file could be moved into a generic tty module.
|
// This file could be moved into a generic tty module.
|
||||||
// The whole hardware signaling stuff is missing, though - it's currently
|
// 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/*)
|
// tailored for pseudo-TTYs. Have a look at Be's TTY includes (drivers/tty/*)
|
||||||
|
|
||||||
|
|
||||||
|
#include "tty_private.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@ -24,8 +27,6 @@
|
|||||||
|
|
||||||
#include <tty.h>
|
#include <tty.h>
|
||||||
|
|
||||||
#include "tty_private.h"
|
|
||||||
|
|
||||||
|
|
||||||
//#define TTY_TRACE
|
//#define TTY_TRACE
|
||||||
#ifdef TTY_TRACE
|
#ifdef TTY_TRACE
|
||||||
@ -96,13 +97,21 @@ static void tty_notify_if_available(struct tty *tty, struct tty *otherTTY,
|
|||||||
|
|
||||||
class AbstractLocker {
|
class AbstractLocker {
|
||||||
public:
|
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:
|
protected:
|
||||||
void Lock() { mutex_lock(fCookie->tty->lock); }
|
void Lock()
|
||||||
void Unlock() { mutex_unlock(fCookie->tty->lock); }
|
{ mutex_lock(fCookie->tty->lock); }
|
||||||
|
void Unlock()
|
||||||
|
{ mutex_unlock(fCookie->tty->lock); }
|
||||||
|
|
||||||
tty_cookie* fCookie;
|
tty_cookie* fCookie;
|
||||||
size_t fBytes;
|
size_t fBytes;
|
||||||
@ -114,7 +123,8 @@ class WriterLocker : public AbstractLocker {
|
|||||||
WriterLocker(tty_cookie* sourceCookie);
|
WriterLocker(tty_cookie* sourceCookie);
|
||||||
~WriterLocker();
|
~WriterLocker();
|
||||||
|
|
||||||
status_t AcquireWriter(bool dontBlock, size_t bytesNeeded);
|
status_t AcquireWriter(bool dontBlock,
|
||||||
|
size_t bytesNeeded);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t _CheckAvailableBytes() const;
|
size_t _CheckAvailableBytes() const;
|
||||||
@ -132,7 +142,8 @@ class ReaderLocker : public AbstractLocker {
|
|||||||
ReaderLocker(tty_cookie* cookie);
|
ReaderLocker(tty_cookie* cookie);
|
||||||
~ReaderLocker();
|
~ReaderLocker();
|
||||||
|
|
||||||
status_t AcquireReader(bigtime_t timeout, size_t minBytes);
|
status_t AcquireReader(bigtime_t timeout,
|
||||||
|
size_t minBytes);
|
||||||
status_t AcquireReader(bool dontBlock);
|
status_t AcquireReader(bool dontBlock);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -329,8 +340,7 @@ RequestOwner::RequestOwner()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/*! The caller must already hold the request lock.
|
||||||
* The caller must already hold the request lock.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RequestOwner::Enqueue(tty_cookie* cookie, RequestQueue* queue1,
|
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
|
void
|
||||||
RequestOwner::Dequeue()
|
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
|
status_t
|
||||||
RequestOwner::Wait(bool interruptable, bigtime_t timeout)
|
RequestOwner::Wait(bool interruptable, bigtime_t timeout)
|
||||||
@ -495,7 +503,8 @@ RequestOwner::NotifyError(Request *request, status_t error)
|
|||||||
|
|
||||||
|
|
||||||
WriterLocker::WriterLocker(tty_cookie* sourceCookie)
|
WriterLocker::WriterLocker(tty_cookie* sourceCookie)
|
||||||
: AbstractLocker(sourceCookie),
|
:
|
||||||
|
AbstractLocker(sourceCookie),
|
||||||
fSource(fCookie->tty),
|
fSource(fCookie->tty),
|
||||||
fTarget(fCookie->other_tty),
|
fTarget(fCookie->other_tty),
|
||||||
fRequestOwner(),
|
fRequestOwner(),
|
||||||
@ -646,7 +655,8 @@ WriterLocker::_CheckBackgroundWrite() const
|
|||||||
|
|
||||||
|
|
||||||
ReaderLocker::ReaderLocker(tty_cookie* cookie)
|
ReaderLocker::ReaderLocker(tty_cookie* cookie)
|
||||||
: AbstractLocker(cookie),
|
:
|
||||||
|
AbstractLocker(cookie),
|
||||||
fTTY(cookie->tty),
|
fTTY(cookie->tty),
|
||||||
fRequestOwner()
|
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.
|
/*! 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
|
Depending on the termios flags set, signals may be sent, the input
|
||||||
* character changed or removed, etc.
|
character changed or removed, etc.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
tty_input_putc_locked(struct tty* tty, int c)
|
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
|
void
|
||||||
add_tty_cookie(tty_cookie* cookie)
|
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
|
void
|
||||||
tty_close_cookie(struct tty_cookie* cookie)
|
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
|
/*! \brief Checks whether bytes can be read from/written to the line buffer of
|
||||||
* the given TTY and notifies the respective queues.
|
the given TTY and notifies the respective queues.
|
||||||
*
|
|
||||||
* Also sends out \c B_SELECT_READ and \c B_SELECT_WRITE events as needed.
|
Also sends out \c B_SELECT_READ and \c B_SELECT_WRITE events as needed.
|
||||||
*
|
|
||||||
* The TTY and the request lock must be held.
|
The TTY and the request lock must be held.
|
||||||
*
|
|
||||||
* \param tty The TTY.
|
\param tty The TTY.
|
||||||
* \param otherTTY The connected TTY.
|
\param otherTTY The connected TTY.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
tty_notify_if_available(struct tty* tty, struct tty* otherTTY,
|
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.
|
\a buffer.
|
||||||
\param tty The master tty.
|
\param tty The master tty.
|
||||||
\param c The input character.
|
\param c The input character.
|
||||||
@ -1216,7 +1223,7 @@ process_input_char(struct tty* tty, char c, char* buffer,
|
|||||||
} else if (c == '\n') {
|
} else if (c == '\n') {
|
||||||
if (flags & INLCR) // NL -> CR
|
if (flags & INLCR) // NL -> CR
|
||||||
c = '\r';
|
c = '\r';
|
||||||
} else if (flags & ISTRIP) // strip of eighth bit
|
} else if ((flags & ISTRIP) != 0) // strip off eighth bit
|
||||||
c &= 0x7f;
|
c &= 0x7f;
|
||||||
|
|
||||||
*buffer = c;
|
*buffer = c;
|
||||||
@ -1224,8 +1231,8 @@ process_input_char(struct tty* tty, char c, char* buffer,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Performs output character conversion and writes the result to
|
/*! \brief Performs output character conversion and writes the result to
|
||||||
\a buffer.
|
\a buffer.
|
||||||
\param tty The master tty.
|
\param tty The master tty.
|
||||||
\param c The output character.
|
\param c The output character.
|
||||||
@ -1293,8 +1300,269 @@ process_output_char(struct tty* tty, char c, char* buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
static status_t
|
||||||
// device functions
|
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
|
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
|
// values marked BeOS are non-standard codes we support for legacy apps
|
||||||
switch (op) {
|
switch (op) {
|
||||||
/* blocking/non-blocking mode */
|
// blocking/non-blocking mode
|
||||||
|
|
||||||
case B_SET_BLOCKING_IO:
|
case B_SET_BLOCKING_IO:
|
||||||
cookie->open_mode &= ~O_NONBLOCK;
|
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;
|
cookie->open_mode |= O_NONBLOCK;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
/* get and set TTY attributes */
|
// get and set TTY attributes
|
||||||
|
|
||||||
case TCGETA:
|
case TCGETA:
|
||||||
TRACE(("tty: get attributes\n"));
|
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,
|
return user_memcpy(&tty->settings->termios, buffer,
|
||||||
sizeof(struct termios));
|
sizeof(struct termios));
|
||||||
|
|
||||||
/* get and set process group ID */
|
// get and set process group ID
|
||||||
|
|
||||||
case TIOCGPGRP:
|
case TIOCGPGRP:
|
||||||
TRACE(("tty: get pgrp_id\n"));
|
TRACE(("tty: get pgrp_id\n"));
|
||||||
@ -1392,7 +1660,7 @@ tty_ioctl(tty_cookie *cookie, uint32 op, void *buffer, size_t length)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get and set window size */
|
// get and set window size
|
||||||
|
|
||||||
case TIOCGWINSZ:
|
case TIOCGWINSZ:
|
||||||
TRACE(("tty: set window size\n"));
|
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
|
status_t
|
||||||
tty_write_to_tty_master(tty_cookie* sourceCookie, const void* _buffer,
|
tty_write_to_tty_master(tty_cookie* sourceCookie, const void* _buffer,
|
||||||
size_t* _length)
|
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
|
status_t
|
||||||
tty_write_to_tty_slave(tty_cookie* sourceCookie, const void* _buffer,
|
tty_write_to_tty_slave(tty_cookie* sourceCookie, const void* _buffer,
|
||||||
size_t* _length)
|
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
|
void
|
||||||
tty_add_debugger_commands()
|
tty_add_debugger_commands()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user