+static int wait_for_completions(struct thread_data *td, struct timeval *time)
+{
+ const int full = queue_full(td);
+ int min_evts = 0;
+ int ret;
+
+ /*
+ * if the queue is full, we MUST reap at least 1 event
+ */
+ min_evts = min(td->o.iodepth_batch_complete, td->cur_depth);
+ if ((full && !min_evts) || !td->o.iodepth_batch_complete)
+ min_evts = 1;
+
+ if (time && (__should_check_rate(td, DDIR_READ) ||
+ __should_check_rate(td, DDIR_WRITE) ||
+ __should_check_rate(td, DDIR_TRIM)))
+ fio_gettime(time, NULL);
+
+ do {
+ ret = io_u_queued_complete(td, min_evts);
+ if (ret < 0)
+ break;
+ } while (full && (td->cur_depth > td->o.iodepth_low));
+
+ return ret;
+}
+
+int io_queue_event(struct thread_data *td, struct io_u *io_u, int *ret,
+ enum fio_ddir ddir, uint64_t *bytes_issued, int from_verify,
+ struct timeval *comp_time)
+{
+ int ret2;
+
+ switch (*ret) {
+ case FIO_Q_COMPLETED:
+ if (io_u->error) {
+ *ret = -io_u->error;
+ clear_io_u(td, io_u);
+ } else if (io_u->resid) {
+ int bytes = io_u->xfer_buflen - io_u->resid;
+ struct fio_file *f = io_u->file;
+
+ if (bytes_issued)
+ *bytes_issued += bytes;
+
+ if (!from_verify)
+ trim_io_piece(td, io_u);
+
+ /*
+ * zero read, fail
+ */
+ if (!bytes) {
+ if (!from_verify)
+ unlog_io_piece(td, io_u);
+ td_verror(td, EIO, "full resid");
+ put_io_u(td, io_u);
+ break;
+ }
+
+ io_u->xfer_buflen = io_u->resid;
+ io_u->xfer_buf += bytes;
+ io_u->offset += bytes;
+
+ if (ddir_rw(io_u->ddir))
+ td->ts.short_io_u[io_u->ddir]++;
+
+ f = io_u->file;
+ if (io_u->offset == f->real_file_size)
+ goto sync_done;
+
+ requeue_io_u(td, &io_u);
+ } else {
+sync_done:
+ if (comp_time && (__should_check_rate(td, DDIR_READ) ||
+ __should_check_rate(td, DDIR_WRITE) ||
+ __should_check_rate(td, DDIR_TRIM)))
+ fio_gettime(comp_time, NULL);
+
+ *ret = io_u_sync_complete(td, io_u);
+ if (*ret < 0)
+ break;
+ }
+ return 0;
+ case FIO_Q_QUEUED:
+ /*
+ * if the engine doesn't have a commit hook,
+ * the io_u is really queued. if it does have such
+ * a hook, it has to call io_u_queued() itself.
+ */
+ if (td->io_ops->commit == NULL)
+ io_u_queued(td, io_u);
+ if (bytes_issued)
+ *bytes_issued += io_u->xfer_buflen;
+ break;
+ case FIO_Q_BUSY:
+ if (!from_verify)
+ unlog_io_piece(td, io_u);
+ requeue_io_u(td, &io_u);
+ ret2 = td_io_commit(td);
+ if (ret2 < 0)
+ *ret = ret2;
+ break;
+ default:
+ assert(*ret < 0);
+ td_verror(td, -(*ret), "td_io_queue");
+ break;
+ }
+
+ if (break_on_this_error(td, ddir, ret))
+ return 1;
+
+ return 0;
+}
+