KPty
kptydevice.cpp
Go to the documentation of this file.
00001 /* 00002 00003 This file is part of the KDE libraries 00004 Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org> 00005 Copyright (C) 2010 KDE e.V. <kde-ev-board@kde.org> 00006 Author Adriaan de Groot <groot@kde.org> 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include "kptydevice.h" 00025 #include "kpty_p.h" 00026 00027 #include <config.h> 00028 #include <config-pty.h> 00029 00030 #include <QSocketNotifier> 00031 00032 #include <klocale.h> 00033 00034 #include <unistd.h> 00035 #include <errno.h> 00036 #include <signal.h> 00037 #include <termios.h> 00038 #include <fcntl.h> 00039 #include <sys/ioctl.h> 00040 #ifdef HAVE_SYS_FILIO_H 00041 # include <sys/filio.h> 00042 #endif 00043 #ifdef HAVE_SYS_TIME_H 00044 # include <sys/time.h> 00045 #endif 00046 00047 #if defined(Q_OS_FREEBSD) || defined(Q_OS_MAC) 00048 // "the other end's output queue size" - kinda braindead, huh? 00049 # define PTY_BYTES_AVAILABLE TIOCOUTQ 00050 #elif defined(TIOCINQ) 00051 // "our end's input queue size" 00052 # define PTY_BYTES_AVAILABLE TIOCINQ 00053 #else 00054 // likewise. more generic ioctl (theoretically) 00055 # define PTY_BYTES_AVAILABLE FIONREAD 00056 #endif 00057 00058 #define KMAXINT ((int)(~0U >> 1)) 00059 00061 // Helper. Remove when QRingBuffer becomes public. // 00063 00064 #include <QtCore/qbytearray.h> 00065 #include <QtCore/qlinkedlist.h> 00066 00067 #define CHUNKSIZE 4096 00068 00069 class KRingBuffer 00070 { 00071 public: 00072 KRingBuffer() 00073 { 00074 clear(); 00075 } 00076 00077 void clear() 00078 { 00079 buffers.clear(); 00080 QByteArray tmp; 00081 tmp.resize(CHUNKSIZE); 00082 buffers << tmp; 00083 head = tail = 0; 00084 totalSize = 0; 00085 } 00086 00087 inline bool isEmpty() const 00088 { 00089 return buffers.count() == 1 && !tail; 00090 } 00091 00092 inline int size() const 00093 { 00094 return totalSize; 00095 } 00096 00097 inline int readSize() const 00098 { 00099 return (buffers.count() == 1 ? tail : buffers.first().size()) - head; 00100 } 00101 00102 inline const char *readPointer() const 00103 { 00104 Q_ASSERT(totalSize > 0); 00105 return buffers.first().constData() + head; 00106 } 00107 00108 void free(int bytes) 00109 { 00110 totalSize -= bytes; 00111 Q_ASSERT(totalSize >= 0); 00112 00113 forever { 00114 int nbs = readSize(); 00115 00116 if (bytes < nbs) { 00117 head += bytes; 00118 if (head == tail && buffers.count() == 1) { 00119 buffers.first().resize(CHUNKSIZE); 00120 head = tail = 0; 00121 } 00122 break; 00123 } 00124 00125 bytes -= nbs; 00126 if (buffers.count() == 1) { 00127 buffers.first().resize(CHUNKSIZE); 00128 head = tail = 0; 00129 break; 00130 } 00131 00132 buffers.removeFirst(); 00133 head = 0; 00134 } 00135 } 00136 00137 char *reserve(int bytes) 00138 { 00139 totalSize += bytes; 00140 00141 char *ptr; 00142 if (tail + bytes <= buffers.last().size()) { 00143 ptr = buffers.last().data() + tail; 00144 tail += bytes; 00145 } else { 00146 buffers.last().resize(tail); 00147 QByteArray tmp; 00148 tmp.resize(qMax(CHUNKSIZE, bytes)); 00149 ptr = tmp.data(); 00150 buffers << tmp; 00151 tail = bytes; 00152 } 00153 return ptr; 00154 } 00155 00156 // release a trailing part of the last reservation 00157 inline void unreserve(int bytes) 00158 { 00159 totalSize -= bytes; 00160 tail -= bytes; 00161 } 00162 00163 inline void write(const char *data, int len) 00164 { 00165 memcpy(reserve(len), data, len); 00166 } 00167 00168 // Find the first occurrence of c and return the index after it. 00169 // If c is not found until maxLength, maxLength is returned, provided 00170 // it is smaller than the buffer size. Otherwise -1 is returned. 00171 int indexAfter(char c, int maxLength = KMAXINT) const 00172 { 00173 int index = 0; 00174 int start = head; 00175 QLinkedList<QByteArray>::ConstIterator it = buffers.begin(); 00176 forever { 00177 if (!maxLength) 00178 return index; 00179 if (index == size()) 00180 return -1; 00181 const QByteArray &buf = *it; 00182 ++it; 00183 int len = qMin((it == buffers.end() ? tail : buf.size()) - start, 00184 maxLength); 00185 const char *ptr = buf.data() + start; 00186 if (const char *rptr = (const char *)memchr(ptr, c, len)) 00187 return index + (rptr - ptr) + 1; 00188 index += len; 00189 maxLength -= len; 00190 start = 0; 00191 } 00192 } 00193 00194 inline int lineSize(int maxLength = KMAXINT) const 00195 { 00196 return indexAfter('\n', maxLength); 00197 } 00198 00199 inline bool canReadLine() const 00200 { 00201 return lineSize() != -1; 00202 } 00203 00204 int read(char *data, int maxLength) 00205 { 00206 int bytesToRead = qMin(size(), maxLength); 00207 int readSoFar = 0; 00208 while (readSoFar < bytesToRead) { 00209 const char *ptr = readPointer(); 00210 int bs = qMin(bytesToRead - readSoFar, readSize()); 00211 memcpy(data + readSoFar, ptr, bs); 00212 readSoFar += bs; 00213 free(bs); 00214 } 00215 return readSoFar; 00216 } 00217 00218 int readLine(char *data, int maxLength) 00219 { 00220 return read(data, lineSize(qMin(maxLength, size()))); 00221 } 00222 00223 private: 00224 QLinkedList<QByteArray> buffers; 00225 int head, tail; 00226 int totalSize; 00227 }; 00228 00230 // private data // 00232 00233 // Lifted from Qt. I don't think they would mind. ;) 00234 // Re-lift again from Qt whenever a proper replacement for pthread_once appears 00235 static void qt_ignore_sigpipe() 00236 { 00237 static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0); 00238 if (atom.testAndSetRelaxed(0, 1)) { 00239 struct sigaction noaction; 00240 memset(&noaction, 0, sizeof(noaction)); 00241 noaction.sa_handler = SIG_IGN; 00242 sigaction(SIGPIPE, &noaction, 0); 00243 } 00244 } 00245 00246 #define NO_INTR(ret,func) do { ret = func; } while (ret < 0 && errno == EINTR) 00247 00248 struct KPtyDevicePrivate : public KPtyPrivate { 00249 Q_DECLARE_PUBLIC(KPtyDevice) 00250 00251 KPtyDevicePrivate(KPty* parent) : 00252 KPtyPrivate(parent), 00253 emittedReadyRead(false), emittedBytesWritten(false), 00254 readNotifier(0), writeNotifier(0) 00255 { 00256 } 00257 00258 bool _k_canRead(); 00259 bool _k_canWrite(); 00260 00261 bool doWait(int msecs, bool reading); 00262 void finishOpen(QIODevice::OpenMode mode); 00263 00264 bool emittedReadyRead; 00265 bool emittedBytesWritten; 00266 QSocketNotifier *readNotifier; 00267 QSocketNotifier *writeNotifier; 00268 KRingBuffer readBuffer; 00269 KRingBuffer writeBuffer; 00270 }; 00271 00272 bool KPtyDevicePrivate::_k_canRead() 00273 { 00274 Q_Q(KPtyDevice); 00275 qint64 readBytes = 0; 00276 00277 #ifdef Q_OS_IRIX // this should use a config define, but how to check it? 00278 size_t available; 00279 #else 00280 int available; 00281 #endif 00282 if (!::ioctl(q->masterFd(), PTY_BYTES_AVAILABLE, (char *) &available)) { 00283 #ifdef Q_OS_SOLARIS 00284 // A Pty is a STREAMS module, and those can be activated 00285 // with 0 bytes available. This happens either when ^C is 00286 // pressed, or when an application does an explicit write(a,b,0) 00287 // which happens in experiments fairly often. When 0 bytes are 00288 // available, you must read those 0 bytes to clear the STREAMS 00289 // module, but we don't want to hit the !readBytes case further down. 00290 if (!available) { 00291 char c; 00292 // Read the 0-byte STREAMS message 00293 NO_INTR(readBytes, read(q->masterFd(), &c, 0)); 00294 // Should return 0 bytes read; -1 is error 00295 if (readBytes < 0) { 00296 readNotifier->setEnabled(false); 00297 emit q->readEof(); 00298 return false; 00299 } 00300 return true; 00301 } 00302 #endif 00303 00304 char *ptr = readBuffer.reserve(available); 00305 #ifdef Q_OS_SOLARIS 00306 // Even if available > 0, it is possible for read() 00307 // to return 0 on Solaris, due to 0-byte writes in the stream. 00308 // Ignore them and keep reading until we hit *some* data. 00309 // In Solaris it is possible to have 15 bytes available 00310 // and to (say) get 0, 0, 6, 0 and 9 bytes in subsequent reads. 00311 // Because the stream is set to O_NONBLOCK in finishOpen(), 00312 // an EOF read will return -1. 00313 readBytes = 0; 00314 while (!readBytes) 00315 #endif 00316 // Useless block braces except in Solaris 00317 { 00318 NO_INTR(readBytes, read(q->masterFd(), ptr, available)); 00319 } 00320 if (readBytes < 0) { 00321 readBuffer.unreserve(available); 00322 q->setErrorString(i18n("Error reading from PTY")); 00323 return false; 00324 } 00325 readBuffer.unreserve(available - readBytes); // *should* be a no-op 00326 } 00327 00328 if (!readBytes) { 00329 readNotifier->setEnabled(false); 00330 emit q->readEof(); 00331 return false; 00332 } else { 00333 if (!emittedReadyRead) { 00334 emittedReadyRead = true; 00335 emit q->readyRead(); 00336 emittedReadyRead = false; 00337 } 00338 return true; 00339 } 00340 } 00341 00342 bool KPtyDevicePrivate::_k_canWrite() 00343 { 00344 Q_Q(KPtyDevice); 00345 00346 writeNotifier->setEnabled(false); 00347 if (writeBuffer.isEmpty()) 00348 return false; 00349 00350 qt_ignore_sigpipe(); 00351 int wroteBytes; 00352 NO_INTR(wroteBytes, 00353 write(q->masterFd(), 00354 writeBuffer.readPointer(), writeBuffer.readSize())); 00355 if (wroteBytes < 0) { 00356 q->setErrorString(i18n("Error writing to PTY")); 00357 return false; 00358 } 00359 writeBuffer.free(wroteBytes); 00360 00361 if (!emittedBytesWritten) { 00362 emittedBytesWritten = true; 00363 emit q->bytesWritten(wroteBytes); 00364 emittedBytesWritten = false; 00365 } 00366 00367 if (!writeBuffer.isEmpty()) 00368 writeNotifier->setEnabled(true); 00369 return true; 00370 } 00371 00372 #ifndef timeradd 00373 // Lifted from GLIBC 00374 # define timeradd(a, b, result) \ 00375 do { \ 00376 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ 00377 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ 00378 if ((result)->tv_usec >= 1000000) { \ 00379 ++(result)->tv_sec; \ 00380 (result)->tv_usec -= 1000000; \ 00381 } \ 00382 } while (0) 00383 # define timersub(a, b, result) \ 00384 do { \ 00385 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ 00386 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ 00387 if ((result)->tv_usec < 0) { \ 00388 --(result)->tv_sec; \ 00389 (result)->tv_usec += 1000000; \ 00390 } \ 00391 } while (0) 00392 #endif 00393 00394 bool KPtyDevicePrivate::doWait(int msecs, bool reading) 00395 { 00396 Q_Q(KPtyDevice); 00397 #ifndef __linux__ 00398 struct timeval etv; 00399 #endif 00400 struct timeval tv, *tvp; 00401 00402 if (msecs < 0) 00403 tvp = 0; 00404 else { 00405 tv.tv_sec = msecs / 1000; 00406 tv.tv_usec = (msecs % 1000) * 1000; 00407 #ifndef __linux__ 00408 gettimeofday(&etv, 0); 00409 timeradd(&tv, &etv, &etv); 00410 #endif 00411 tvp = &tv; 00412 } 00413 00414 while (reading ? readNotifier->isEnabled() : !writeBuffer.isEmpty()) { 00415 fd_set rfds; 00416 fd_set wfds; 00417 00418 FD_ZERO(&rfds); 00419 FD_ZERO(&wfds); 00420 00421 if (readNotifier->isEnabled()) 00422 FD_SET(q->masterFd(), &rfds); 00423 if (!writeBuffer.isEmpty()) 00424 FD_SET(q->masterFd(), &wfds); 00425 00426 #ifndef __linux__ 00427 if (tvp) { 00428 gettimeofday(&tv, 0); 00429 timersub(&etv, &tv, &tv); 00430 if (tv.tv_sec < 0) 00431 tv.tv_sec = tv.tv_usec = 0; 00432 } 00433 #endif 00434 00435 switch (select(q->masterFd() + 1, &rfds, &wfds, 0, tvp)) { 00436 case -1: 00437 if (errno == EINTR) 00438 break; 00439 return false; 00440 case 0: 00441 q->setErrorString(i18n("PTY operation timed out")); 00442 return false; 00443 default: 00444 if (FD_ISSET(q->masterFd(), &rfds)) { 00445 bool canRead = _k_canRead(); 00446 if (reading && canRead) 00447 return true; 00448 } 00449 if (FD_ISSET(q->masterFd(), &wfds)) { 00450 bool canWrite = _k_canWrite(); 00451 if (!reading) 00452 return canWrite; 00453 } 00454 break; 00455 } 00456 } 00457 return false; 00458 } 00459 00460 void KPtyDevicePrivate::finishOpen(QIODevice::OpenMode mode) 00461 { 00462 Q_Q(KPtyDevice); 00463 00464 q->QIODevice::open(mode); 00465 fcntl(q->masterFd(), F_SETFL, O_NONBLOCK); 00466 readBuffer.clear(); 00467 readNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Read, q); 00468 writeNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Write, q); 00469 QObject::connect(readNotifier, SIGNAL(activated(int)), q, SLOT(_k_canRead())); 00470 QObject::connect(writeNotifier, SIGNAL(activated(int)), q, SLOT(_k_canWrite())); 00471 readNotifier->setEnabled(true); 00472 } 00473 00475 // public member functions // 00477 00478 KPtyDevice::KPtyDevice(QObject *parent) : 00479 QIODevice(parent), 00480 KPty(new KPtyDevicePrivate(this)) 00481 { 00482 } 00483 00484 KPtyDevice::~KPtyDevice() 00485 { 00486 close(); 00487 } 00488 00489 bool KPtyDevice::open(OpenMode mode) 00490 { 00491 Q_D(KPtyDevice); 00492 00493 if (masterFd() >= 0) 00494 return true; 00495 00496 if (!KPty::open()) { 00497 setErrorString(i18n("Error opening PTY")); 00498 return false; 00499 } 00500 00501 d->finishOpen(mode); 00502 00503 return true; 00504 } 00505 00506 bool KPtyDevice::open(int fd, OpenMode mode) 00507 { 00508 Q_D(KPtyDevice); 00509 00510 if (!KPty::open(fd)) { 00511 setErrorString(i18n("Error opening PTY")); 00512 return false; 00513 } 00514 00515 d->finishOpen(mode); 00516 00517 return true; 00518 } 00519 00520 void KPtyDevice::close() 00521 { 00522 Q_D(KPtyDevice); 00523 00524 if (masterFd() < 0) 00525 return; 00526 00527 delete d->readNotifier; 00528 delete d->writeNotifier; 00529 00530 QIODevice::close(); 00531 00532 KPty::close(); 00533 } 00534 00535 bool KPtyDevice::isSequential() const 00536 { 00537 return true; 00538 } 00539 00540 bool KPtyDevice::canReadLine() const 00541 { 00542 Q_D(const KPtyDevice); 00543 return QIODevice::canReadLine() || d->readBuffer.canReadLine(); 00544 } 00545 00546 bool KPtyDevice::atEnd() const 00547 { 00548 Q_D(const KPtyDevice); 00549 return QIODevice::atEnd() && d->readBuffer.isEmpty(); 00550 } 00551 00552 qint64 KPtyDevice::bytesAvailable() const 00553 { 00554 Q_D(const KPtyDevice); 00555 return QIODevice::bytesAvailable() + d->readBuffer.size(); 00556 } 00557 00558 qint64 KPtyDevice::bytesToWrite() const 00559 { 00560 Q_D(const KPtyDevice); 00561 return d->writeBuffer.size(); 00562 } 00563 00564 bool KPtyDevice::waitForReadyRead(int msecs) 00565 { 00566 Q_D(KPtyDevice); 00567 return d->doWait(msecs, true); 00568 } 00569 00570 bool KPtyDevice::waitForBytesWritten(int msecs) 00571 { 00572 Q_D(KPtyDevice); 00573 return d->doWait(msecs, false); 00574 } 00575 00576 void KPtyDevice::setSuspended(bool suspended) 00577 { 00578 Q_D(KPtyDevice); 00579 d->readNotifier->setEnabled(!suspended); 00580 } 00581 00582 bool KPtyDevice::isSuspended() const 00583 { 00584 Q_D(const KPtyDevice); 00585 return !d->readNotifier->isEnabled(); 00586 } 00587 00588 // protected 00589 qint64 KPtyDevice::readData(char *data, qint64 maxlen) 00590 { 00591 Q_D(KPtyDevice); 00592 return d->readBuffer.read(data, (int)qMin<qint64>(maxlen, KMAXINT)); 00593 } 00594 00595 // protected 00596 qint64 KPtyDevice::readLineData(char *data, qint64 maxlen) 00597 { 00598 Q_D(KPtyDevice); 00599 return d->readBuffer.readLine(data, (int)qMin<qint64>(maxlen, KMAXINT)); 00600 } 00601 00602 // protected 00603 qint64 KPtyDevice::writeData(const char *data, qint64 len) 00604 { 00605 Q_D(KPtyDevice); 00606 Q_ASSERT(len <= KMAXINT); 00607 00608 d->writeBuffer.write(data, len); 00609 d->writeNotifier->setEnabled(true); 00610 return len; 00611 } 00612 00613 #include "kptydevice.moc"
KDE 4.6 API Reference