This is a partial revert of
87a43a907f0ad4897a28ad7c216bc70f37270b93
The change to use g_clear_pointer() in more places was accidentally
applied to cases involving vir_g_source_unref().
In some cases, the ordering of g_source_destroy() and
vir_g_source_unref() was reversed, which resulted in the source being
marked as destroyed, after it is already unreferenced. This
use-after-free case might work in many cases, but with versions of
glib older than 2.64.0 it may defer unref to run within the main
thread to avoid a race condition, which creates a large distance
between the g_source_unref() and g_source_destroy().
In some cases, the call to vir_g_source_unref() was replaced with a
second call to g_source_destroy(), leading to a memory leak or worse.
In our experience, the symptoms were that use of libvirt-python became
slower over time, with OpenStack nova-compute initially taking around
one second to periodically query the host PCI devices, and within an
hour it was taking over a minute to complete the same operation, until
it is was eventually running this query back-to-back, resulting in the
nova-compute process consuming 100% of one CPU thread, losing its
RabbitMQ connection frequently, and showing up as down to the control
plane.
Signed-off-by: Mark Mielke <mark.mielke@gmail.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Signed-off-by: Ján Tomko <jtomko@redhat.com>
qemuAgentUnregister(qemuAgent *agent)
{
if (agent->watch) {
+ g_source_destroy(agent->watch);
vir_g_source_unref(agent->watch, agent->context);
- g_clear_pointer(&agent->watch, g_source_destroy);
+ agent->watch = NULL;
}
}
qemuMonitorUnregister(qemuMonitor *mon)
{
if (mon->watch) {
+ g_source_destroy(mon->watch);
vir_g_source_unref(mon->watch, mon->context);
- g_clear_pointer(&mon->watch, g_source_destroy);
+ mon->watch = NULL;
}
}
VIR_DEBUG("Removed old handle source=%p", data->source);
g_source_destroy(data->source);
- g_clear_pointer(&data->source, g_source_destroy);
+ vir_g_source_unref(data->source, NULL);
+ data->source = NULL;
data->events = 0;
}
data, watch, data->fd);
if (data->source != NULL) {
+ g_source_destroy(data->source);
vir_g_source_unref(data->source, NULL);
- g_clear_pointer(&data->source, g_source_destroy);
+ data->source = NULL;
data->events = 0;
}
if (data->source == NULL)
goto cleanup;
+ g_source_destroy(data->source);
vir_g_source_unref(data->source, NULL);
- g_clear_pointer(&data->source, g_source_destroy);
+ data->source = NULL;
}
cleanup:
data, timer);
if (data->source != NULL) {
+ g_source_destroy(data->source);
vir_g_source_unref(data->source, NULL);
- g_clear_pointer(&data->source, g_source_destroy);
+ data->source = NULL;
}
/* since the actual timeout deletion is done asynchronously, a timeoutUpdate call may