/* * We carry on writing whilst we have data to write and we can write */ void AsynchIO::writeable(DispatchHandle& h) { AbsTime writeStartTime = AbsTime::now(); size_t total = 0; int writeCalls = 0; do { // See if we've got something to write if (!writeQueue.empty()) { // Write buffer BufferBase* buff = writeQueue.back(); writeQueue.pop_back(); errno = 0; assert(buff->dataStart+buff->dataCount <= buff->byteCount); int rc = socket.write(buff->bytes+buff->dataStart, buff->dataCount); int64_t duration = Duration(writeStartTime, AbsTime::now()); ++writeCalls; if (rc >= 0) { threadWriteTotal += rc; total += rc; // If we didn't write full buffer put rest back if (rc != buff->dataCount) { buff->dataStart += rc; buff->dataCount -= rc; writeQueue.push_back(buff); QPID_PROBE4(asynchio_write_finished_done, &h, duration, total, writeCalls); break; } // Recycle the buffer queueReadBuffer(buff); // Stop writing if we've overrun our timeslot if (duration > threadMaxIoTimeNs) { QPID_PROBE4(asynchio_write_finished_maxtime, &h, duration, total, writeCalls); break; } } else { // Put buffer back writeQueue.push_back(buff); QPID_PROBE5(asynchio_write_finished_error, &h, duration, total, writeCalls, errno); if (errno == ECONNRESET || errno == EPIPE) { // Just stop watching for write here - we'll get a // disconnect callback soon enough h.unwatchWrite(); break; } else if (errno == EAGAIN) { // We have just put a buffer back so we know // we can carry on watching for writes break; } else { // Report error then just treat as a socket disconnect QPID_LOG(error, "Error writing socket: " << qpid::sys::strError(errno) << "(" << errno << ")" ); h.unwatchWrite(); break; } } } else { int64_t duration = Duration(writeStartTime, AbsTime::now()); (void) duration; // force duration to be used if no probes are compiled // If we're waiting to close the socket then can do it now as there is nothing to write if (queuedClose) { close(h); QPID_PROBE4(asynchio_write_finished_closed, &h, duration, total, writeCalls); break; } // Fd is writable, but nothing to write if (idleCallback) { writePending = false; idleCallback(*this); } // If we still have no buffers to write we can't do anything more if (writeQueue.empty() && !writePending && !queuedClose) { h.unwatchWrite(); // The following handles the case where writePending is // set to true after the test above; in this case its // possible that the unwatchWrite overwrites the // desired rewatchWrite so we correct that here if (writePending) h.rewatchWrite(); QPID_PROBE4(asynchio_write_finished_nodata, &h, duration, total, writeCalls); break; } } } while (true); ++threadWriteCount; return; }
/* * We carry on writing whilst we have data to write and we can write */ void SslIO::writeable(DispatchHandle& h) { AbsTime writeStartTime = AbsTime::now(); do { // See if we've got something to write if (!writeQueue.empty()) { // Write buffer BufferBase* buff = writeQueue.back(); writeQueue.pop_back(); errno = 0; assert(buff->dataStart+buff->dataCount <= buff->byteCount); int rc = socket.write(buff->bytes+buff->dataStart, buff->dataCount); if (rc >= 0) { threadWriteTotal += rc; // If we didn't write full buffer put rest back if (rc != buff->dataCount) { buff->dataStart += rc; buff->dataCount -= rc; writeQueue.push_back(buff); break; } // Recycle the buffer queueReadBuffer(buff); // Stop writing if we've overrun our timeslot if (Duration(writeStartTime, AbsTime::now()) > threadMaxIoTimeNs) { break; } } else { // Put buffer back writeQueue.push_back(buff); if (errno == ECONNRESET || errno == EPIPE) { // Just stop watching for write here - we'll get a // disconnect callback soon enough h.unwatchWrite(); break; } else if (errno == EAGAIN) { // We have just put a buffer back so we know // we can carry on watching for writes break; } else { QPID_LOG(error, "Error writing to socket: " << getErrorString(PR_GetError())); h.unwatchWrite(); break; } } } else { // If we're waiting to close the socket then can do it now as there is nothing to write if (queuedClose) { close(h); break; } // Fd is writable, but nothing to write if (idleCallback) { writePending = false; idleCallback(*this); } // If we still have no buffers to write we can't do anything more if (writeQueue.empty() && !writePending && !queuedClose) { h.unwatchWrite(); // The following handles the case where writePending is // set to true after the test above; in this case its // possible that the unwatchWrite overwrites the // desired rewatchWrite so we correct that here if (writePending) h.rewatchWrite(); break; } } } while (true); ++threadWriteCount; return; }