GSocketMonitor::~GSocketMonitor()
{
+ RELEASE_ASSERT(!m_isExecutingCallback);
stop();
}
{
if (g_cancellable_is_cancelled(monitor->m_cancellable.get()))
return G_SOURCE_REMOVE;
- return monitor->m_callback(condition);
+
+ monitor->m_isExecutingCallback = true;
+ gboolean result = monitor->m_callback(condition);
+ monitor->m_isExecutingCallback = false;
+
+ if (monitor->m_shouldDestroyCallback) {
+ monitor->m_callback = nullptr;
+ monitor->m_shouldDestroyCallback = false;
+ }
+
+ return result;
}
void GSocketMonitor::start(GSocket* socket, GIOCondition condition, RunLoop& runLoop, Function<gboolean(GIOCondition)>&& callback)
m_cancellable = nullptr;
g_source_destroy(m_source.get());
m_source = nullptr;
- m_callback = nullptr;
+
+ // It's normal to stop the socket monitor from inside its callback.
+ // Don't destroy the callback while it's still executing.
+ if (m_isExecutingCallback)
+ m_shouldDestroyCallback = true;
+ else
+ m_callback = nullptr;
}
} // namespace WTF
GRefPtr<GSource> m_source;
GRefPtr<GCancellable> m_cancellable;
Function<gboolean(GIOCondition)> m_callback;
+ bool m_isExecutingCallback { false };
+ bool m_shouldDestroyCallback { false };
};
} // namespace WTF