* Renamed GetReaderBuf() to _NextParseChar().
* Introduced a small (64 byte) buffer for the parser thread. Instead of directly reading single characters out of the reader buffer, we read a full parser buffer and process the characters from the parser buffer. Thus _NextParseChar() could be inlined, since it merely consists of a conditional method call and an access to the parser buffer, now. * Improved the locking of the terminal buffer. Instead of unlocking and relocking after every multi-byte char or escape sequence, we only unlock while refilling the parser buffer. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25911 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -49,6 +49,23 @@ extern int gMbcsTable[]; /* ESC $ */
|
|||||||
#define NPARAM 10 // Max parameters
|
#define NPARAM 10 // Max parameters
|
||||||
|
|
||||||
|
|
||||||
|
//! Get char from pty reader buffer.
|
||||||
|
inline status_t
|
||||||
|
TermParse::_NextParseChar(uchar &c)
|
||||||
|
{
|
||||||
|
if (fParserBufferOffset >= fParserBufferSize) {
|
||||||
|
// parser buffer empty
|
||||||
|
status_t error = _ReadParserBuffer();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = fParserBuffer[fParserBufferOffset++];
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TermParse::TermParse(int fd)
|
TermParse::TermParse(int fd)
|
||||||
:
|
:
|
||||||
fFd(fd),
|
fFd(fd),
|
||||||
@@ -58,6 +75,8 @@ TermParse::TermParse(int fd)
|
|||||||
fReaderLocker(-1),
|
fReaderLocker(-1),
|
||||||
fBufferPosition(0),
|
fBufferPosition(0),
|
||||||
fReadBufferSize(0),
|
fReadBufferSize(0),
|
||||||
|
fParserBufferSize(0),
|
||||||
|
fParserBufferOffset(0),
|
||||||
fParserWaiting(false),
|
fParserWaiting(false),
|
||||||
fBuffer(NULL),
|
fBuffer(NULL),
|
||||||
fQuitting(true)
|
fQuitting(true)
|
||||||
@@ -114,45 +133,6 @@ TermParse::StopThreads()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Get char from pty reader buffer.
|
|
||||||
status_t
|
|
||||||
TermParse::GetReaderBuf(uchar &c)
|
|
||||||
{
|
|
||||||
// wait for new input from pty
|
|
||||||
if (fReadBufferSize == 0) {
|
|
||||||
fBuffer->Unlock();
|
|
||||||
|
|
||||||
fParserWaiting = true;
|
|
||||||
|
|
||||||
status_t status = B_OK;
|
|
||||||
while (fReadBufferSize == 0 && status == B_OK) {
|
|
||||||
do {
|
|
||||||
status = acquire_sem(fReaderSem);
|
|
||||||
} while (status == B_INTERRUPTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
fParserWaiting = false;
|
|
||||||
|
|
||||||
fBuffer->Lock();
|
|
||||||
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
c = fReadBuffer[fBufferPosition];
|
|
||||||
fBufferPosition = (fBufferPosition + 1) % READ_BUF_SIZE;
|
|
||||||
|
|
||||||
int32 bufferSize = atomic_add(&fReadBufferSize, -1) - 1;
|
|
||||||
|
|
||||||
// If the pty reader thread waits and we have made enough space in the
|
|
||||||
// buffer now, let it run again.
|
|
||||||
if (READ_BUF_SIZE - bufferSize == MIN_PTY_BUFFER_SPACE)
|
|
||||||
release_sem(fReaderLocker);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//! Initialize and spawn EscParse thread.
|
//! Initialize and spawn EscParse thread.
|
||||||
status_t
|
status_t
|
||||||
TermParse::InitTermParse()
|
TermParse::InitTermParse()
|
||||||
@@ -346,12 +326,11 @@ TermParse::EscParse()
|
|||||||
int *groundtable = gUTF8GroundTable;
|
int *groundtable = gUTF8GroundTable;
|
||||||
int *parsestate = groundtable;
|
int *parsestate = groundtable;
|
||||||
|
|
||||||
while (!fQuitting) {
|
BAutolock locker(fBuffer);
|
||||||
// TODO: Fix the locking!
|
|
||||||
BAutolock locker(fBuffer);
|
|
||||||
|
|
||||||
|
while (!fQuitting) {
|
||||||
uchar c;
|
uchar c;
|
||||||
if (GetReaderBuf(c) < B_OK)
|
if (_NextParseChar(c) < B_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//DumpState(groundtable, parsestate, c);
|
//DumpState(groundtable, parsestate, c);
|
||||||
@@ -412,7 +391,7 @@ TermParse::EscParse()
|
|||||||
case CASE_SS3: /* JIS X 0212 */
|
case CASE_SS3: /* JIS X 0212 */
|
||||||
*ptr++ = curess;
|
*ptr++ = curess;
|
||||||
*ptr++ = c;
|
*ptr++ = c;
|
||||||
GetReaderBuf(c);
|
_NextParseChar(c);
|
||||||
*ptr++ = c;
|
*ptr++ = c;
|
||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
curess = 0;
|
curess = 0;
|
||||||
@@ -420,7 +399,7 @@ TermParse::EscParse()
|
|||||||
|
|
||||||
default: /* JIS X 0208 */
|
default: /* JIS X 0208 */
|
||||||
*ptr++ = c;
|
*ptr++ = c;
|
||||||
GetReaderBuf(c);
|
_NextParseChar(c);
|
||||||
*ptr++ = c;
|
*ptr++ = c;
|
||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
break;
|
break;
|
||||||
@@ -443,7 +422,7 @@ TermParse::EscParse()
|
|||||||
|
|
||||||
case CASE_PRINT_CS96:
|
case CASE_PRINT_CS96:
|
||||||
cbuf[0] = c | 0x80;
|
cbuf[0] = c | 0x80;
|
||||||
GetReaderBuf(c);
|
_NextParseChar(c);
|
||||||
cbuf[1] = c | 0x80;
|
cbuf[1] = c | 0x80;
|
||||||
cbuf[2] = 0;
|
cbuf[2] = 0;
|
||||||
CodeConv::ConvertToInternal(cbuf, 2, dstbuf, B_EUC_CONVERSION);
|
CodeConv::ConvertToInternal(cbuf, 2, dstbuf, B_EUC_CONVERSION);
|
||||||
@@ -467,7 +446,7 @@ TermParse::EscParse()
|
|||||||
|
|
||||||
case CASE_SJIS_INSTRING:
|
case CASE_SJIS_INSTRING:
|
||||||
cbuf[0] = c;
|
cbuf[0] = c;
|
||||||
GetReaderBuf(c);
|
_NextParseChar(c);
|
||||||
cbuf[1] = c;
|
cbuf[1] = c;
|
||||||
cbuf[2] = '\0';
|
cbuf[2] = '\0';
|
||||||
CodeConv::ConvertToInternal(cbuf, 2, dstbuf, now_coding);
|
CodeConv::ConvertToInternal(cbuf, 2, dstbuf, now_coding);
|
||||||
@@ -476,7 +455,7 @@ TermParse::EscParse()
|
|||||||
|
|
||||||
case CASE_UTF8_2BYTE:
|
case CASE_UTF8_2BYTE:
|
||||||
cbuf[0] = c;
|
cbuf[0] = c;
|
||||||
GetReaderBuf(c);
|
_NextParseChar(c);
|
||||||
if (groundtable[c] != CASE_UTF8_INSTRING)
|
if (groundtable[c] != CASE_UTF8_INSTRING)
|
||||||
break;
|
break;
|
||||||
cbuf[1] = c;
|
cbuf[1] = c;
|
||||||
@@ -487,12 +466,12 @@ TermParse::EscParse()
|
|||||||
|
|
||||||
case CASE_UTF8_3BYTE:
|
case CASE_UTF8_3BYTE:
|
||||||
cbuf[0] = c;
|
cbuf[0] = c;
|
||||||
GetReaderBuf(c);
|
_NextParseChar(c);
|
||||||
if (groundtable[c] != CASE_UTF8_INSTRING)
|
if (groundtable[c] != CASE_UTF8_INSTRING)
|
||||||
break;
|
break;
|
||||||
cbuf[1] = c;
|
cbuf[1] = c;
|
||||||
|
|
||||||
GetReaderBuf(c);
|
_NextParseChar(c);
|
||||||
if (groundtable[c] != CASE_UTF8_INSTRING)
|
if (groundtable[c] != CASE_UTF8_INSTRING)
|
||||||
break;
|
break;
|
||||||
cbuf[2] = c;
|
cbuf[2] = c;
|
||||||
@@ -515,7 +494,7 @@ TermParse::EscParse()
|
|||||||
{
|
{
|
||||||
cs96 = 0;
|
cs96 = 0;
|
||||||
uchar dummy;
|
uchar dummy;
|
||||||
GetReaderBuf(dummy);
|
_NextParseChar(dummy);
|
||||||
parsestate = groundtable;
|
parsestate = groundtable;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -881,7 +860,7 @@ TermParse::EscParse()
|
|||||||
char string[512];
|
char string[512];
|
||||||
uint32 len = 0;
|
uint32 len = 0;
|
||||||
uchar mode_char;
|
uchar mode_char;
|
||||||
GetReaderBuf(mode_char);
|
_NextParseChar(mode_char);
|
||||||
if (mode_char != '0'
|
if (mode_char != '0'
|
||||||
&& mode_char != '1'
|
&& mode_char != '1'
|
||||||
&& mode_char != '2') {
|
&& mode_char != '2') {
|
||||||
@@ -889,8 +868,8 @@ TermParse::EscParse()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
uchar current_char;
|
uchar current_char;
|
||||||
GetReaderBuf(current_char);
|
_NextParseChar(current_char);
|
||||||
while (GetReaderBuf(current_char) == B_OK
|
while (_NextParseChar(current_char) == B_OK
|
||||||
&& current_char != 0x7) {
|
&& current_char != 0x7) {
|
||||||
if (!isprint(current_char & 0x7f)
|
if (!isprint(current_char & 0x7f)
|
||||||
|| len+2 >= sizeof(string))
|
|| len+2 >= sizeof(string))
|
||||||
@@ -988,6 +967,59 @@ TermParse::_escparse_thread(void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
TermParse::_ReadParserBuffer()
|
||||||
|
{
|
||||||
|
// We have to unlock the terminal buffer while waiting for data from the
|
||||||
|
// PTY. We don't have to unlock when we don't need to wait, but we do it
|
||||||
|
// anyway, so that TermView won't be starved when trying to synchronize.
|
||||||
|
fBuffer->Unlock();
|
||||||
|
|
||||||
|
// wait for new input from pty
|
||||||
|
if (fReadBufferSize == 0) {
|
||||||
|
fParserWaiting = true;
|
||||||
|
|
||||||
|
status_t status = B_OK;
|
||||||
|
while (fReadBufferSize == 0 && status == B_OK) {
|
||||||
|
do {
|
||||||
|
status = acquire_sem(fReaderSem);
|
||||||
|
} while (status == B_INTERRUPTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
fParserWaiting = false;
|
||||||
|
|
||||||
|
if (status < B_OK) {
|
||||||
|
fBuffer->Lock();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 toRead = fReadBufferSize;
|
||||||
|
if (toRead > ESC_PARSER_BUFFER_SIZE)
|
||||||
|
toRead = ESC_PARSER_BUFFER_SIZE;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < toRead; i++) {
|
||||||
|
fParserBuffer[i] = fReadBuffer[fBufferPosition];
|
||||||
|
fBufferPosition = (fBufferPosition + 1) % READ_BUF_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 bufferSize = atomic_add(&fReadBufferSize, -toRead);
|
||||||
|
|
||||||
|
// If the pty reader thread waits and we have made enough space in the
|
||||||
|
// buffer now, let it run again.
|
||||||
|
if (bufferSize > READ_BUF_SIZE - MIN_PTY_BUFFER_SPACE
|
||||||
|
&& bufferSize - toRead <= READ_BUF_SIZE - MIN_PTY_BUFFER_SPACE) {
|
||||||
|
release_sem(fReaderLocker);
|
||||||
|
}
|
||||||
|
|
||||||
|
fParserBufferSize = toRead;
|
||||||
|
fParserBufferOffset = 0;
|
||||||
|
|
||||||
|
fBuffer->Lock();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TermParse::_DeviceStatusReport(int n)
|
TermParse::_DeviceStatusReport(int n)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
// pty read buffer size
|
// pty read buffer size
|
||||||
#define MIN_PTY_BUFFER_SPACE 16
|
#define MIN_PTY_BUFFER_SPACE 16
|
||||||
// minimal space left before the reader tries to read more
|
// minimal space left before the reader tries to read more
|
||||||
|
#define ESC_PARSER_BUFFER_SIZE 64
|
||||||
|
// size of the parser buffer
|
||||||
|
|
||||||
|
|
||||||
class TerminalBuffer;
|
class TerminalBuffer;
|
||||||
@@ -54,6 +56,8 @@ public:
|
|||||||
status_t StopThreads();
|
status_t StopThreads();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
inline status_t _NextParseChar(uchar &c);
|
||||||
|
|
||||||
// Initialize TermParse and PtyReader thread.
|
// Initialize TermParse and PtyReader thread.
|
||||||
status_t InitTermParse();
|
status_t InitTermParse();
|
||||||
status_t InitPtyReader();
|
status_t InitPtyReader();
|
||||||
@@ -69,8 +73,7 @@ private:
|
|||||||
static int32 _ptyreader_thread(void *);
|
static int32 _ptyreader_thread(void *);
|
||||||
static int32 _escparse_thread(void *);
|
static int32 _escparse_thread(void *);
|
||||||
|
|
||||||
// Reading ReadBuf at one Char.
|
status_t _ReadParserBuffer();
|
||||||
status_t GetReaderBuf(uchar &c);
|
|
||||||
|
|
||||||
void _DeviceStatusReport(int n);
|
void _DeviceStatusReport(int n);
|
||||||
|
|
||||||
@@ -84,6 +87,10 @@ private:
|
|||||||
uint fBufferPosition;
|
uint fBufferPosition;
|
||||||
uchar fReadBuffer[READ_BUF_SIZE];
|
uchar fReadBuffer[READ_BUF_SIZE];
|
||||||
vint32 fReadBufferSize;
|
vint32 fReadBufferSize;
|
||||||
|
|
||||||
|
uchar fParserBuffer[ESC_PARSER_BUFFER_SIZE];
|
||||||
|
int32 fParserBufferSize;
|
||||||
|
int32 fParserBufferOffset;
|
||||||
volatile bool fParserWaiting;
|
volatile bool fParserWaiting;
|
||||||
|
|
||||||
int fLockFlag;
|
int fLockFlag;
|
||||||
|
|||||||
Reference in New Issue
Block a user