diff --git a/src/shared/mgmt.c b/src/shared/mgmt.c
index ef9b0d1..8fb7aa7 100644
--- a/src/shared/mgmt.c
+++ b/src/shared/mgmt.c
GQueue *request_queue;
GList *pending_list;
GList *notify_list;
+ GList *notify_destroyed;
unsigned int next_request_id;
unsigned int next_notify_id;
+ bool in_notify;
+ bool destroyed;
void *buf;
uint16_t len;
mgmt_debug_func_t debug_callback;
{
GList *list;
+ mgmt->in_notify = true;
+
for (list = g_list_first(mgmt->notify_list); list;
list = g_list_next(list)) {
struct mgmt_notify *notify = list->data;
notify->callback(index, length, param,
notify->user_data);
}
+
+ mgmt->in_notify = false;
+
+ g_list_foreach(mgmt->notify_destroyed, destroy_notify, NULL);
+ g_list_free(mgmt->notify_destroyed);
+
+ mgmt->notify_destroyed = NULL;
+
+ if (mgmt->destroyed)
+ g_free(mgmt);
}
static void read_watch_destroy(gpointer user_data)
if (__sync_sub_and_fetch(&mgmt->ref_count, 1))
return;
- g_list_foreach(mgmt->notify_list, destroy_notify, NULL);
- g_list_free(mgmt->notify_list);
-
- g_list_foreach(mgmt->pending_list, destroy_request, NULL);
- g_list_free(mgmt->pending_list);
-
- g_queue_foreach(mgmt->request_queue, destroy_request, NULL);
- g_queue_free(mgmt->request_queue);
+ mgmt_unregister_all(mgmt);
+ mgmt_cancel_all(mgmt);
- if (mgmt->write_watch > 0)
+ if (mgmt->write_watch > 0) {
g_source_remove(mgmt->write_watch);
+ mgmt->write_watch = 0;
+ }
- if (mgmt->read_watch > 0)
+ if (mgmt->read_watch > 0) {
g_source_remove(mgmt->read_watch);
+ mgmt->read_watch = 0;
+ }
g_io_channel_unref(mgmt->io);
+ mgmt->io = NULL;
if (mgmt->close_on_unref)
close(mgmt->fd);
mgmt->debug_destroy(mgmt->debug_data);
g_free(mgmt->buf);
- g_free(mgmt);
+ mgmt->buf = NULL;
+
+ if (!mgmt->in_notify) {
+ g_free(mgmt);
+ return;
+ }
+
+ mgmt->destroyed = true;
}
bool mgmt_set_debug(struct mgmt *mgmt, mgmt_debug_func_t callback,
return true;
}
+bool mgmt_cancel_all(struct mgmt *mgmt)
+{
+ if (!mgmt)
+ return false;
+
+ g_list_foreach(mgmt->pending_list, destroy_request, NULL);
+ g_list_free(mgmt->pending_list);
+
+ g_queue_foreach(mgmt->request_queue, destroy_request, NULL);
+ g_queue_free(mgmt->request_queue);
+
+ return true;
+}
+
unsigned int mgmt_register(struct mgmt *mgmt, uint16_t event, uint16_t index,
mgmt_notify_func_t callback,
void *user_data, mgmt_destroy_func_t destroy)
notify = list->data;
- mgmt->notify_list = g_list_delete_link(mgmt->notify_list, list);
+ mgmt->notify_list = g_list_remove_link(mgmt->notify_list, list);
+
+ if (!mgmt->in_notify) {
+ g_list_free_1(list);
+ destroy_notify(notify, NULL);
+ return true;
+ }
- destroy_notify(notify, NULL);
+ mgmt->notify_destroyed = g_list_concat(mgmt->notify_destroyed, list);
return true;
}
if (notify->index != index)
continue;
- mgmt->notify_list = g_list_delete_link(mgmt->notify_list, list);
+ mgmt->notify_list = g_list_remove_link(mgmt->notify_list, list);
- destroy_notify(notify, NULL);
+ if (!mgmt->in_notify) {
+ g_list_free_1(list);
+ destroy_notify(notify, NULL);
+ continue;
+ }
+
+ mgmt->notify_destroyed = g_list_concat(mgmt->notify_destroyed,
+ list);
}
return true;
if (!mgmt)
return false;
- g_list_foreach(mgmt->notify_list, destroy_notify, NULL);
- g_list_free(mgmt->notify_list);
+ if (!mgmt->in_notify) {
+ g_list_foreach(mgmt->notify_list, destroy_notify, NULL);
+ g_list_free(mgmt->notify_list);
+ } else
+ mgmt->notify_destroyed = g_list_concat(mgmt->notify_destroyed,
+ mgmt->notify_list);
mgmt->notify_list = NULL;
diff --git a/src/shared/mgmt.h b/src/shared/mgmt.h
index 33190b5..a43de10 100644
--- a/src/shared/mgmt.h
+++ b/src/shared/mgmt.h
mgmt_request_func_t callback,
void *user_data, mgmt_destroy_func_t destroy);
bool mgmt_cancel(struct mgmt *mgmt, unsigned int id);
+bool mgmt_cancel_all(struct mgmt *mgmt);
typedef void (*mgmt_notify_func_t)(uint16_t index, uint16_t length,
const void *param, void *user_data);