void FileRegion::FileWriteRequest::FileReadHandler::handlerReady( uint16_t events) noexcept { CHECK(events & EventHandler::WRITE); if (bytesToRead_ == 0) { unregisterHandler(); return; } int flags = SPLICE_F_NONBLOCK | SPLICE_F_MORE; ssize_t spliced = ::splice(req_->readFd_, &req_->offset_, pipe_in_, nullptr, bytesToRead_, flags); if (spliced == -1) { if (errno == EAGAIN) { return; } else { req_->fail(__func__, AsyncSocketException( AsyncSocketException::INTERNAL_ERROR, "splice failed", errno)); return; } } if (spliced > 0) { bytesToRead_ -= spliced; try { req_->queue_.putMessage(static_cast<size_t>(spliced)); } catch (...) { req_->fail(__func__, AsyncSocketException( AsyncSocketException::INTERNAL_ERROR, "putMessage failed")); return; } } }
void TunIntf::handlerReady(uint16_t events) noexcept { CHECK(fd_ != -1); const int MaxSentOneTime = 16; // TODO: The packet size should be as same as MTU (hard code 1500 for now). // Since this is L3 packet size, we should also reserve some space for L2 // header, which is 18 bytes (including one vlan tag) const int l3Len = 1500; int sent = 0; int dropped = 0; uint64_t bytes = 0; bool fdFail = false; try { while (sent + dropped < MaxSentOneTime) { std::unique_ptr<TxPacket> pkt; pkt = sw_->allocateL3TxPacket(l3Len); auto buf = pkt->buf(); int ret = 0; do { ret = read(fd_, buf->writableTail(), buf->tailroom()); } while (ret == -1 && errno == EINTR); if (ret < 0) { if (errno != EAGAIN) { sysLogError(ret, "Failed to read on ", fd_); // Cannot continue read on this fd fdFail = true; } break; } else if (ret == 0) { // Nothing to read. It shall not happen as the fd is non-blocking. // Just add this case to be safe. break; } else if (ret > buf->tailroom()) { // The pkt is larger than the buffer. We don't have complete packet. // It shall not happen unless the MTU is mis-match. Drop the packet. LOG(ERROR) << "Too large packet (" << ret << " > " << buf->tailroom() << ") received from host. Drop the packet."; dropped++; } else { bytes += ret; buf->append(ret); sw_->sendL3Packet(rid_, std::move(pkt)); sent++; } } } catch (const std::exception& ex) { LOG(ERROR) << "Hit some error when forwarding packets :" << folly::exceptionStr(ex); } if (fdFail) { unregisterHandler(); } VLOG(4) << "Forwarded " << sent << " packets (" << bytes << " bytes) from host @ fd " << fd_ << " for router " << rid_ << " dropped:" << dropped; }
void AsyncPipeReader::close() { unregisterHandler(); if (fd_ != NetworkSocket()) { changeHandlerFD(NetworkSocket()); if (closeCb_) { closeCb_(fd_); } else { netops::close(fd_); } fd_ = NetworkSocket(); } }
void AsyncPipeReader::close() { unregisterHandler(); if (fd_ >= 0) { changeHandlerFD(-1); if (closeCb_) { closeCb_(fd_); } else { ::close(fd_); } fd_ = -1; } }
void AsyncPipeWriter::handleWrite() { DestructorGuard dg(this); assert(!queue_.empty()); do { auto& front = queue_.front(); folly::IOBufQueue& curQueue = front.first; DCHECK(!curQueue.empty()); // someday, support writev. The logic for partial writes is a bit complex const IOBuf* head = curQueue.front(); CHECK(head->length()); #if _WIN32 // On Windows you can't call write on a socket. ssize_t rc = folly::fileutil_detail::wrapNoInt( send_internal, fd_, head->data(), head->length()); #else ssize_t rc = folly::writeNoInt(fd_.toFd(), head->data(), head->length()); #endif if (rc < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // pipe is full VLOG(5) << "write blocked"; registerHandler(EventHandler::WRITE); return; } else { failAllWrites(AsyncSocketException( AsyncSocketException::INTERNAL_ERROR, "write failed", errno)); closeNow(); return; } } else if (rc == 0) { registerHandler(EventHandler::WRITE); return; } curQueue.trimStart(size_t(rc)); if (curQueue.empty()) { auto cb = front.second; queue_.pop_front(); if (cb) { cb->writeSuccess(); } } else { VLOG(5) << "partial write blocked"; } } while (!queue_.empty()); if (closeOnEmpty_) { closeNow(); } else { unregisterHandler(); } }
/* * unhookSSPInterrupt * unregister SSP Interrupt function. */ unsigned short unhookSSPInterrupt( ssp_ctrl_t sspControl, void (*handler)(void) ) { ssp_interrupt_t *pfnHandler, *prev, *pfnInterruptHandler; uint32_t mask; if (sspControl == SSP1) pfnInterruptHandler = ssp1IntHandlers; else pfnInterruptHandler = ssp0IntHandlers; /* Find the requested handle to unregister */ for (pfnHandler = pfnInterruptHandler, prev = ((ssp_interrupt_t *)0); pfnHandler != ((ssp_interrupt_t *)0); prev = pfnHandler, pfnHandler = pfnHandler->next) { if (pfnHandler->handler == handler) { /* Remove the interrupt handler */ if (prev == ((ssp_interrupt_t *)0)) { pfnInterruptHandler = pfnHandler->next; /* Update the actual handler */ if (sspControl == SSP1) ssp1IntHandlers = pfnInterruptHandler; else ssp0IntHandlers = pfnInterruptHandler; } else { prev->next = pfnHandler->next; } free(pfnHandler); /* If this was the last interrupt handler, remove the IRQ handler */ if (pfnInterruptHandler == ((ssp_interrupt_t *)0)) { unregisterHandler((sspControl == SSP1) ? ssp1ISR : ssp0ISR); } /* Success */ return (0); } } /* Oops, handler is not registered */ return (-1); }
void AsyncPipeWriter::closeNow() { VLOG(5) << "close now"; if (!queue_.empty()) { failAllWrites(AsyncSocketException( AsyncSocketException::NOT_OPEN, "closed with pending writes")); } if (fd_ != NetworkSocket()) { unregisterHandler(); changeHandlerFD(NetworkSocket()); if (closeCb_) { closeCb_(fd_); } else { netops::close(fd_); } fd_ = NetworkSocket(); } }
void AsyncUDPSocket::close() { eventBase_->dcheckIsInEventBaseThread(); if (readCallback_) { auto cob = readCallback_; readCallback_ = nullptr; cob->onReadClosed(); } // Unregister any events we are registered for unregisterHandler(); if (fd_ != -1 && ownership_ == FDOwnership::OWNS) { ::close(fd_); } fd_ = -1; }
/* * This function un-register 2D Interrupt handler. */ int32_t unhookDEInterrupt( uint32_t deMask, void (*handler)(void) ) { de_interrupt_t *pfnHandler, *prev; uint32_t mask; if (deMask == 0) mask = FIELD_SET(0, DE_STATUS, 2D, ACTIVE); else mask = FIELD_SET(0, DE_STATUS, CSC, ACTIVE); /* Find the requested handle to unregister */ for (pfnHandler = pDEIntHandlers, prev = ((de_interrupt_t *)0); pfnHandler != ((de_interrupt_t *)0); prev = pfnHandler, pfnHandler = pfnHandler->next) { if ((pfnHandler->deMask == mask) && (pfnHandler->handler == handler)) { /* Remove the interrupt handler */ if (prev == ((de_interrupt_t *)0)) pDEIntHandlers = pfnHandler->next; else prev->next = pfnHandler->next; free(pfnHandler); /* If this was the last interrupt handler, remove the IRQ handler */ if (pDEIntHandlers == ((de_interrupt_t *)0)) unregisterHandler(deISR); /* Success */ return (0); } } /* Oops, handler is not registered */ return (-1); }
EventHandler::~EventHandler() { unregisterHandler(); }
void AsyncPipeReader::handlerReady(uint16_t events) noexcept { DestructorGuard dg(this); CHECK(events & EventHandler::READ); VLOG(5) << "AsyncPipeReader::handlerReady() this=" << this << ", fd=" << fd_; assert(readCallback_ != nullptr); while (readCallback_) { // - What API does callback support? const auto movable = readCallback_->isBufferMovable(); // noexcept // Get the buffer to read into. void* buf = nullptr; size_t buflen = 0; std::unique_ptr<IOBuf> ioBuf; if (movable) { ioBuf = IOBuf::create(readCallback_->maxBufferSize()); buf = ioBuf->writableBuffer(); buflen = ioBuf->capacity(); } else { try { readCallback_->getReadBuffer(&buf, &buflen); } catch (const std::exception& ex) { AsyncSocketException aex( AsyncSocketException::BAD_ARGS, string("ReadCallback::getReadBuffer() " "threw exception: ") + ex.what()); failRead(aex); return; } catch (...) { AsyncSocketException aex( AsyncSocketException::BAD_ARGS, string("ReadCallback::getReadBuffer() " "threw non-exception type")); failRead(aex); return; } if (buf == nullptr || buflen == 0) { AsyncSocketException aex( AsyncSocketException::INVALID_STATE, string("ReadCallback::getReadBuffer() " "returned empty buffer")); failRead(aex); return; } } // Perform the read #if _WIN32 // On Windows you can't call read on a socket, so call recv instead. ssize_t bytesRead = folly::fileutil_detail::wrapNoInt(recv_internal, fd_, buf, buflen); #else ssize_t bytesRead = folly::readNoInt(fd_.toFd(), buf, buflen); #endif if (bytesRead > 0) { if (movable) { ioBuf->append(std::size_t(bytesRead)); readCallback_->readBufferAvailable(std::move(ioBuf)); } else { readCallback_->readDataAvailable(size_t(bytesRead)); } // Fall through and continue around the loop if the read // completely filled the available buffer. // Note that readCallback_ may have been uninstalled or changed inside // readDataAvailable(). if (static_cast<size_t>(bytesRead) < buflen) { return; } } else if (bytesRead < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { // No more data to read right now. return; } else if (bytesRead < 0) { AsyncSocketException ex( AsyncSocketException::INVALID_STATE, "read failed", errno); failRead(ex); return; } else { assert(bytesRead == 0); // EOF unregisterHandler(); AsyncReader::ReadCallback* callback = readCallback_; readCallback_ = nullptr; callback->readEOF(); return; } // Max reads per loop? } }
MessageHandler::~MessageHandler() { unregisterHandler(this); }
FileRegion::FileWriteRequest::FileReadHandler::~FileReadHandler() { CHECK(req_->readBase_->isInEventBaseThread()); unregisterHandler(); ::close(pipe_in_); }
void EventManager::unregisterHandler(std::function<void(void*, Event*)> handler) { for(HandlerMap::iterator ite = handlers.begin(); ite != handlers.end(); ite++) unregisterHandler(ite->first, handler); }
void AsyncPipeReader::handlerReady(uint16_t events) noexcept { DestructorGuard dg(this); CHECK(events & EventHandler::READ); VLOG(5) << "AsyncPipeReader::handlerReady() this=" << this << ", fd=" << fd_; assert(readCallback_ != nullptr); while (readCallback_) { // Get the buffer to read into. void* buf = nullptr; size_t buflen = 0; try { readCallback_->getReadBuffer(&buf, &buflen); } catch (const std::exception& ex) { AsyncSocketException aex(AsyncSocketException::BAD_ARGS, string("ReadCallback::getReadBuffer() " "threw exception: ") + ex.what()); failRead(aex); return; } catch (...) { AsyncSocketException ex(AsyncSocketException::BAD_ARGS, string("ReadCallback::getReadBuffer() " "threw non-exception type")); failRead(ex); return; } if (buf == nullptr || buflen == 0) { AsyncSocketException ex(AsyncSocketException::INVALID_STATE, string("ReadCallback::getReadBuffer() " "returned empty buffer")); failRead(ex); return; } // Perform the read ssize_t bytesRead = folly::readNoInt(fd_, buf, buflen); if (bytesRead > 0) { readCallback_->readDataAvailable(bytesRead); // Fall through and continue around the loop if the read // completely filled the available buffer. // Note that readCallback_ may have been uninstalled or changed inside // readDataAvailable(). if (static_cast<size_t>(bytesRead) < buflen) { return; } } else if (bytesRead < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { // No more data to read right now. return; } else if (bytesRead < 0) { AsyncSocketException ex(AsyncSocketException::INVALID_STATE, "read failed", errno); failRead(ex); return; } else { assert(bytesRead == 0); // EOF unregisterHandler(); AsyncReader::ReadCallback* callback = readCallback_; readCallback_ = nullptr; callback->readEOF(); return; } // Max reads per loop? } }
void TunIntf::stop() { unregisterHandler(); }