/** * Wait several IO(s) completed. * * @nr number of waiting IO(s). * @events event array for temporary use. * @aioQueue AioDataPtr of completed IO will be pushed into it. */ void wait(size_t nr, std::queue<AioData>& aioDataQueue) { size_t done = 0; bool isError = false; while (done < nr) { int tmpNr = ::io_getevents(ctx_, 1, nr - done, &ioEvents_[done], NULL); if (tmpNr < 1) { throw std::runtime_error("io_getevents failed."); } double endTime = getTime(); for (size_t i = done; i < done + tmpNr; i++) { auto* iocb = static_cast<struct iocb *>(ioEvents_[i].obj); auto* ptr = static_cast<AioData *>(iocb->data); if (ioEvents_[i].res != ptr->iocb.u.c.nbytes) { isError = true; } ptr->endTime = endTime; aioDataQueue.push(*ptr); } done += tmpNr; } if (isError) { // ::printf("wait error.\n"); throw EofError(); } }
// // TBuf::AcceptPunct // // Calls NextToken, and generates error if not punctuation // void TBuf::AcceptPunct() { // Get next token switch (NextToken()) { case TR_OK : ExpectError("punctuation", lastToken); case TR_PUN : break; case TR_EOF : EofError("punctuation"); } }
/** * Read data and fill a buffer. */ void read(off_t oft, size_t size, char* buf) { if (deviceSize_ < oft + size) { throw EofError(); } ::lseek(fd_, oft, SEEK_SET); size_t s = 0; while (s < size) { ssize_t ret = ::read(fd_, &buf[s], size - s); if (ret < 0) { std::string e("read failed: "); e += strerror(errno); throw std::runtime_error(e); } s += ret; } }
/** * Write data of a buffer. */ void write(off_t oft, size_t size, char* buf) { if (deviceSize_ < oft + size) { throw EofError(); } if (mode_ == READ_MODE) { throw std::runtime_error("write is not permitted."); } ::lseek(fd_, oft, SEEK_SET); size_t s = 0; while (s < size) { ssize_t ret = ::write(fd_, &buf[s], size - s); if (ret < 0) { std::string e("write failed: "); e += ::strerror(errno); throw std::runtime_error(e); } s += ret; } }
// // TBuf::AcceptIdent // // Calls NextToken, and generates error if punctuation or EOF // void TBuf::AcceptIdent() { // Get next token switch (NextToken()) { case TR_OK : break; case TR_PUN : ExpectError("identifier", lastToken); break; case TR_EOF : EofError("identifier"); break; } }
/** * Wait just one IO completed. * * @return aio data pointer. * This data is available at least before calling * queueSize_ times of prepareWrite/prepareRead. */ AioData* waitOne() { auto& event = ioEvents_[0]; int err = ::io_getevents(ctx_, 1, 1, &event, NULL); double endTime = getTime(); if (err != 1) { throw std::runtime_error("io_getevents failed."); } auto* iocb = static_cast<struct iocb *>(event.obj); auto* ptr = static_cast<AioData *>(iocb->data); if (event.res != ptr->iocb.u.c.nbytes) { // ::printf("waitOne error %lu\n", event.res); throw EofError(); } ptr->endTime = endTime; return ptr; }
/** * Discard request. */ void discard(off_t oft, size_t size) { uint64_t range[2]; range[0] = oft; range[1] = size; if (deviceSize_ < oft + size) { throw EofError(); } if (mode_ != DISCARD_MODE) { throw std::runtime_error("discard is not permitted."); } int ret = ::ioctl(fd_, BLKDISCARD, &range); if (ret) { std::string e("discard failed: "); e += ::strerror(errno); throw std::runtime_error(e); } }
// // TBuf::Accept // // Accept token 'accept', or generate error if different // void TBuf::Accept(const char *accept) { ASSERT(accept); // get next token switch (NextToken()) { case TR_OK : case TR_PUN : if (Utils::Strcmp(accept, lastToken)) { TokenError("Expecting '%s' but found '%s'", accept, lastToken); } break; case TR_EOF : EofError(accept); } }
/** * Submit all prepared IO(s). */ void submit() { size_t nr = aioQueue_.size(); if (nr == 0) { return; } assert(iocbs_.size() >= nr); double beginTime = getTime(); for (size_t i = 0; i < nr; i++) { auto* ptr = aioQueue_.front(); aioQueue_.pop(); iocbs_[i] = &ptr->iocb; ptr->beginTime = beginTime; } assert(aioQueue_.empty()); int err = ::io_submit(ctx_, nr, &iocbs_[0]); if (err != static_cast<int>(nr)) { /* ::printf("submit error %d.\n", err); */ throw EofError(); } }