Description: Don't leak memory on long chains of events Delete event->depend_events when no longer needed to avoid keeping the whole dependency tree in memory as long as the final event exists Author: Rebecca N. Palmer Bug-Ubuntu: https://launchpad.net/bugs/1354086 Forwarded: https://lists.freedesktop.org/archives/beignet/2018-July/009209.html --- a/src/cl_event.c +++ b/src/cl_event.c @@ -184,6 +184,25 @@ cl_event_new(cl_context ctx, cl_command_ return e; } +/* This exists to prevent long chains of events from filling up memory (https://bugs.launchpad.net/ubuntu/+source/beignet/+bug/1354086). Call only after the dependencies are complete, or failed and marked as such in this event's status, or when this event is being destroyed */ +LOCAL void +cl_event_delete_depslist(cl_event event) +{ + CL_OBJECT_LOCK(event); + cl_event *old_depend_events = event->depend_events; + int depend_count = event->depend_event_num; + event->depend_event_num = 0; + event->depend_events = NULL; + CL_OBJECT_UNLOCK(event); + if (old_depend_events) { + assert(depend_count); + for (int i = 0; i < depend_count; i++) { + cl_event_delete(old_depend_events[i]); + } + cl_free(old_depend_events); + } +} + LOCAL void cl_event_delete(cl_event event) { @@ -200,13 +219,7 @@ cl_event_delete(cl_event event) assert(list_node_out_of_list(&event->enqueue_node)); - if (event->depend_events) { - assert(event->depend_event_num); - for (i = 0; i < event->depend_event_num; i++) { - cl_event_delete(event->depend_events[i]); - } - cl_free(event->depend_events); - } + cl_event_delete_depslist(event); /* Free all the callbacks. Last ref, no need to lock. */ while (!list_empty(&event->callbacks)) { @@ -566,8 +579,12 @@ cl_event_exec(cl_event event, cl_int exe assert(depend_status <= CL_COMPLETE || ignore_depends || exec_to_status == CL_QUEUED); if (depend_status < CL_COMPLETE) { // Error happend, cancel exec. ret = cl_event_set_status(event, depend_status); + cl_event_delete_depslist(event); return depend_status; } + if (depend_status == CL_COMPLETE) { // Avoid memory leak + cl_event_delete_depslist(event); + } if (cur_status <= exec_to_status) { return ret; --- a/src/cl_event.h +++ b/src/cl_event.h @@ -44,7 +44,7 @@ typedef struct _cl_event { cl_command_type event_type; /* Event type. */ cl_bool is_barrier; /* Is this event a barrier */ cl_int status; /* The execution status */ - cl_event *depend_events; /* The events must complete before this. */ + cl_event *depend_events; /* The events must complete before this. May disappear after they have completed - see cl_event_delete_depslist*/ cl_uint depend_event_num; /* The depend events number. */ list_head callbacks; /* The events The event callback functions */ list_node enqueue_node; /* The node in the enqueue list. */