// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LIBRADOS_AIOCOMPLETIONIMPL_H #define CEPH_LIBRADOS_AIOCOMPLETIONIMPL_H #include "common/ceph_mutex.h" #include "include/buffer.h" #include "include/xlist.h" #include "osd/osd_types.h" class IoCtxImpl; struct librados::AioCompletionImpl { ceph::mutex lock = ceph::make_mutex("AioCompletionImpl lock", false); ceph::condition_variable cond; int ref = 1, rval = 0; bool released = false; bool complete = false; version_t objver = 0; ceph_tid_t tid = 0; rados_callback_t callback_complete = nullptr, callback_safe = nullptr; void *callback_complete_arg = nullptr, *callback_safe_arg = nullptr; // for read bool is_read = false; bufferlist bl; bufferlist *blp = nullptr; char *out_buf = nullptr; IoCtxImpl *io = nullptr; ceph_tid_t aio_write_seq = 0; xlist::item aio_write_list_item; AioCompletionImpl() : aio_write_list_item(this) { } int set_complete_callback(void *cb_arg, rados_callback_t cb) { std::scoped_lock l{lock}; callback_complete = cb; callback_complete_arg = cb_arg; return 0; } int set_safe_callback(void *cb_arg, rados_callback_t cb) { std::scoped_lock l{lock}; callback_safe = cb; callback_safe_arg = cb_arg; return 0; } int wait_for_complete() { std::unique_lock l{lock}; cond.wait(l, [this] { return complete; }); return 0; } int wait_for_safe() { return wait_for_complete(); } int is_complete() { std::scoped_lock l{lock}; return complete; } int is_safe() { return is_complete(); } int wait_for_complete_and_cb() { std::unique_lock l{lock}; cond.wait(l, [this] { return complete && !callback_complete && !callback_safe; }); return 0; } int wait_for_safe_and_cb() { return wait_for_complete_and_cb(); } int is_complete_and_cb() { std::scoped_lock l{lock}; return complete && !callback_complete && !callback_safe; } int is_safe_and_cb() { return is_complete_and_cb(); } int get_return_value() { std::scoped_lock l{lock}; return rval; } uint64_t get_version() { std::scoped_lock l{lock}; return objver; } void get() { std::scoped_lock l{lock}; _get(); } void _get() { ceph_assert(ceph_mutex_is_locked(lock)); ceph_assert(ref > 0); ++ref; } void release() { lock.lock(); ceph_assert(!released); released = true; put_unlock(); } void put() { lock.lock(); put_unlock(); } void put_unlock() { ceph_assert(ref > 0); int n = --ref; lock.unlock(); if (!n) delete this; } }; namespace librados { struct CB_AioComplete { AioCompletionImpl *c; explicit CB_AioComplete(AioCompletionImpl *cc) : c(cc) { c->_get(); } void operator()() { rados_callback_t cb_complete = c->callback_complete; void *cb_complete_arg = c->callback_complete_arg; if (cb_complete) cb_complete(c, cb_complete_arg); rados_callback_t cb_safe = c->callback_safe; void *cb_safe_arg = c->callback_safe_arg; if (cb_safe) cb_safe(c, cb_safe_arg); c->lock.lock(); c->callback_complete = NULL; c->callback_safe = NULL; c->cond.notify_all(); c->put_unlock(); } }; /** * Fills in all completed request data, and calls both * complete and safe callbacks if they exist. * * Not useful for usual I/O, but for special things like * flush where we only want to wait for things to be safe, * but allow users to specify any of the callbacks. */ struct CB_AioCompleteAndSafe { AioCompletionImpl *c; explicit CB_AioCompleteAndSafe(AioCompletionImpl *cc) : c(cc) { c->get(); } CB_AioCompleteAndSafe(const CB_AioCompleteAndSafe&) = delete; CB_AioCompleteAndSafe& operator =(const CB_AioCompleteAndSafe&) = delete; CB_AioCompleteAndSafe(CB_AioCompleteAndSafe&& rhs) { c = rhs.c; rhs.c = nullptr; } CB_AioCompleteAndSafe& operator =(CB_AioCompleteAndSafe&& rhs) { c = rhs.c; rhs.c = nullptr; return *this; } void operator()(int r = 0) { c->lock.lock(); c->rval = r; c->complete = true; c->lock.unlock(); rados_callback_t cb_complete = c->callback_complete; void *cb_complete_arg = c->callback_complete_arg; if (cb_complete) cb_complete(c, cb_complete_arg); rados_callback_t cb_safe = c->callback_safe; void *cb_safe_arg = c->callback_safe_arg; if (cb_safe) cb_safe(c, cb_safe_arg); c->lock.lock(); c->callback_complete = NULL; c->callback_safe = NULL; c->cond.notify_all(); c->put_unlock(); } }; } #endif