TaskFinisher: cancel all tasks wait until finisher done

Otherwise, caller may think pending task won't be executed but actually
finisher may execute callback which may cause refer to freed object.

Signed-off-by: Haomai Wang <haomai@xsky.com>
This commit is contained in:
Haomai Wang 2016-06-14 11:03:19 +08:00
parent e7aff3da8b
commit 40c5679ef0
2 changed files with 18 additions and 10 deletions

View File

@ -31,6 +31,7 @@ namespace librbd {
using namespace image_watcher;
using namespace watch_notify;
using util::create_async_context_callback;
using util::create_context_callback;
using util::create_rados_safe_callback;
@ -120,7 +121,10 @@ void ImageWatcher::unregister_watch(Context *on_finish) {
ldout(m_image_ctx.cct, 10) << this << " unregistering image watcher" << dendl;
cancel_async_requests();
m_task_finisher->cancel_all();
C_Gather *g = new C_Gather(m_image_ctx.cct, create_async_context_callback(
m_image_ctx, on_finish));
m_task_finisher->cancel_all(g->new_sub());
{
RWLock::WLocker l(m_watch_lock);
@ -128,17 +132,17 @@ void ImageWatcher::unregister_watch(Context *on_finish) {
m_watch_state = WATCH_STATE_UNREGISTERED;
librados::AioCompletion *aio_comp = create_rados_safe_callback(
new C_UnwatchAndFlush(m_image_ctx.md_ctx, on_finish));
new C_UnwatchAndFlush(m_image_ctx.md_ctx, g->new_sub()));
int r = m_image_ctx.md_ctx.aio_unwatch(m_watch_handle, aio_comp);
assert(r == 0);
aio_comp->release();
g->activate();
return;
} else if (m_watch_state == WATCH_STATE_ERROR) {
m_watch_state = WATCH_STATE_UNREGISTERED;
}
}
on_finish->complete(0);
g->activate();
}
void ImageWatcher::flush(Context *on_finish) {

View File

@ -63,13 +63,17 @@ public:
}
}
void cancel_all() {
Mutex::Locker l(*m_lock);
for (typename TaskContexts::iterator it = m_task_contexts.begin();
it != m_task_contexts.end(); ++it) {
delete it->second.first;
void cancel_all(Context *comp) {
{
Mutex::Locker l(*m_lock);
for (typename TaskContexts::iterator it = m_task_contexts.begin();
it != m_task_contexts.end(); ++it) {
delete it->second.first;
m_safe_timer->cancel_event(it->second.second);
}
m_task_contexts.clear();
}
m_task_contexts.clear();
m_finisher->queue(comp);
}
bool add_event_after(const Task& task, double seconds, Context *ctx) {