]>
Commit | Line | Data |
---|---|---|
7d3d7cb5 JB |
1 | Description: Don't leak memory on long chains of events |
2 | ||
3 | Delete event->depend_events when no longer needed to avoid keeping | |
4 | the whole dependency tree in memory as long as the final event exists | |
5 | ||
6 | Author: Rebecca N. Palmer <rebecca_palmer@zoho.com> | |
7 | Bug-Ubuntu: https://launchpad.net/bugs/1354086 | |
8 | Forwarded: https://lists.freedesktop.org/archives/beignet/2018-July/009209.html | |
9 | ||
10 | --- a/src/cl_event.c | |
11 | +++ b/src/cl_event.c | |
12 | @@ -184,6 +184,25 @@ cl_event_new(cl_context ctx, cl_command_ | |
13 | return e; | |
14 | } | |
15 | ||
16 | +/* 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 */ | |
17 | +LOCAL void | |
18 | +cl_event_delete_depslist(cl_event event) | |
19 | +{ | |
20 | + CL_OBJECT_LOCK(event); | |
21 | + cl_event *old_depend_events = event->depend_events; | |
22 | + int depend_count = event->depend_event_num; | |
23 | + event->depend_event_num = 0; | |
24 | + event->depend_events = NULL; | |
25 | + CL_OBJECT_UNLOCK(event); | |
26 | + if (old_depend_events) { | |
27 | + assert(depend_count); | |
28 | + for (int i = 0; i < depend_count; i++) { | |
29 | + cl_event_delete(old_depend_events[i]); | |
30 | + } | |
31 | + cl_free(old_depend_events); | |
32 | + } | |
33 | +} | |
34 | + | |
35 | LOCAL void | |
36 | cl_event_delete(cl_event event) | |
37 | { | |
38 | @@ -200,13 +219,7 @@ cl_event_delete(cl_event event) | |
39 | ||
40 | assert(list_node_out_of_list(&event->enqueue_node)); | |
41 | ||
42 | - if (event->depend_events) { | |
43 | - assert(event->depend_event_num); | |
44 | - for (i = 0; i < event->depend_event_num; i++) { | |
45 | - cl_event_delete(event->depend_events[i]); | |
46 | - } | |
47 | - cl_free(event->depend_events); | |
48 | - } | |
49 | + cl_event_delete_depslist(event); | |
50 | ||
51 | /* Free all the callbacks. Last ref, no need to lock. */ | |
52 | while (!list_empty(&event->callbacks)) { | |
53 | @@ -566,8 +579,12 @@ cl_event_exec(cl_event event, cl_int exe | |
54 | assert(depend_status <= CL_COMPLETE || ignore_depends || exec_to_status == CL_QUEUED); | |
55 | if (depend_status < CL_COMPLETE) { // Error happend, cancel exec. | |
56 | ret = cl_event_set_status(event, depend_status); | |
57 | + cl_event_delete_depslist(event); | |
58 | return depend_status; | |
59 | } | |
60 | + if (depend_status == CL_COMPLETE) { // Avoid memory leak | |
61 | + cl_event_delete_depslist(event); | |
62 | + } | |
63 | ||
64 | if (cur_status <= exec_to_status) { | |
65 | return ret; | |
66 | --- a/src/cl_event.h | |
67 | +++ b/src/cl_event.h | |
68 | @@ -44,7 +44,7 @@ typedef struct _cl_event { | |
69 | cl_command_type event_type; /* Event type. */ | |
70 | cl_bool is_barrier; /* Is this event a barrier */ | |
71 | cl_int status; /* The execution status */ | |
72 | - cl_event *depend_events; /* The events must complete before this. */ | |
73 | + cl_event *depend_events; /* The events must complete before this. May disappear after they have completed - see cl_event_delete_depslist*/ | |
74 | cl_uint depend_event_num; /* The depend events number. */ | |
75 | list_head callbacks; /* The events The event callback functions */ | |
76 | list_node enqueue_node; /* The node in the enqueue list. */ |