Hi Daniel, I think drm_pending_state_apply_atomic (or its callers) leak pending_state:
On Wed, 2017-12-20 at 12:26 +0000, Daniel Stone wrote: > +static int > +drm_pending_state_apply_atomic(struct drm_pending_state *pending_state, > + enum drm_state_apply_mode mode) > +{ > + struct drm_backend *b = pending_state->backend; > + struct drm_output_state *output_state, *tmp; > + struct drm_plane *plane; > + drmModeAtomicReq *req = drmModeAtomicAlloc(); > + uint32_t flags = 0; > + int ret = 0; > + > + if (!req) > + return -1; > + > + if (b->state_invalid) { > + uint32_t *unused; > + int err; > + > + /* If we need to reset all our state (e.g. because we've > + * just started, or just been VT-switched in), explicitly > + * disable all the CRTCs and connectors we aren't using. */ > + wl_array_for_each(unused, &b->unused_connectors) { > + struct drm_property_info infos[WDRM_CONNECTOR__COUNT]; > + struct drm_property_info *info; > + drmModeObjectProperties *props; > + > + memset(infos, 0, sizeof(infos)); > + > + props = drmModeObjectGetProperties(b->drm.fd, > + *unused, > + > DRM_MODE_OBJECT_CONNECTOR); > + if (!props) { > + ret = -1; > + continue; > + } > + > + drm_property_info_populate(b, connector_props, infos, > + WDRM_CONNECTOR__COUNT, > + props); > + drmModeFreeObjectProperties(props); > + > + info = &infos[WDRM_CONNECTOR_CRTC_ID]; > + err = drmModeAtomicAddProperty(req, *unused, > + info->prop_id, 0); > + if (err <= 0) > + ret = -1; > + > + info = &infos[WDRM_CONNECTOR_DPMS]; > + if (info->prop_id > 0) > + err = drmModeAtomicAddProperty(req, *unused, > + info->prop_id, > + > DRM_MODE_DPMS_OFF); > + if (err <= 0) > + ret = -1; > + > + drm_property_info_free(infos, WDRM_CONNECTOR__COUNT); > + } > + > + wl_array_for_each(unused, &b->unused_crtcs) { > + struct drm_property_info infos[WDRM_CRTC__COUNT]; > + struct drm_property_info *info; > + drmModeObjectProperties *props; > + uint64_t active; > + > + memset(infos, 0, sizeof(infos)); > + > + /* We can't emit a disable on a CRTC that's already > + * off, as the kernel will refuse to generate an event > + * for an off->off state and fail the commit. > + */ > + props = drmModeObjectGetProperties(b->drm.fd, > + *unused, > + > DRM_MODE_OBJECT_CRTC); > + if (!props) { > + ret = -1; > + continue; > + } > + > + drm_property_info_populate(b, crtc_props, infos, > + WDRM_CRTC__COUNT, > + props); > + > + info = &infos[WDRM_CRTC_ACTIVE]; > + active = drm_property_get_value(info, props, 0); > + drmModeFreeObjectProperties(props); > + if (active == 0) { > + drm_property_info_free(infos, WDRM_CRTC__COUNT); > + continue; > + } > + > + err = drmModeAtomicAddProperty(req, *unused, > + info->prop_id, 0); > + if (err <= 0) > + ret = -1; > + > + info = &infos[WDRM_CRTC_MODE_ID]; > + err = drmModeAtomicAddProperty(req, *unused, > + info->prop_id, 0); > + if (err <= 0) > + ret = -1; > + > + drm_property_info_free(infos, WDRM_CRTC__COUNT); > + } > + > + /* Disable all the planes; planes which are being used will > + * override this state in the output-state application. */ > + wl_list_for_each(plane, &b->plane_list, link) { > + plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0); > + plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0); > + } > + > + flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; > + } > + > + wl_list_for_each(output_state, &pending_state->output_list, link) { > + if (mode == DRM_STATE_APPLY_SYNC) > + assert(output_state->dpms == WESTON_DPMS_OFF); > + ret |= drm_output_apply_state_atomic(output_state, req, &flags); > + } > + > + if (ret != 0) { > + weston_log("atomic: couldn't compile atomic state\n"); > + goto out; > + } > + > + switch (mode) { > + case DRM_STATE_APPLY_SYNC: > + break; > + case DRM_STATE_APPLY_ASYNC: > + flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK; > + break; > + } > + > + ret = drmModeAtomicCommit(b->drm.fd, req, flags, b); > + if (ret != 0) { > + weston_log("atomic: couldn't commit new state: %m\n"); > + goto out; > + } > + > + wl_list_for_each_safe(output_state, tmp, &pending_state->output_list, > + link) > + drm_output_assign_state(output_state, mode); > + > + b->state_invalid = false; > + > + assert(wl_list_empty(&pending_state->output_list)); > + > +out: This looks like it is missing drm_pending_state_free(pending_state); either here or at the callsites (will be made conditional here by the introduction of DRM_STATE_TEST_ONLY later). > + drmModeAtomicFree(req); > + return ret; > +} > +#endif > + > static int > drm_pending_state_apply(struct drm_pending_state *pending_state) > { > @@ -1940,6 +2278,12 @@ drm_pending_state_apply(struct drm_pending_state > *pending_state) > struct drm_output_state *output_state, *tmp; > uint32_t *unused; > > +#ifdef HAVE_DRM_ATOMIC > + if (b->atomic_modeset) > + return drm_pending_state_apply_atomic(pending_state, > + DRM_STATE_APPLY_ASYNC); It can't be seen from the context, but drm_pending_state_apply calls drm_pending_state_free(pending_state); before returning. In the atomic modeset path we don't free pending_state anymore. Apart from drm_repaint_cancel, I don't see any other place where drm_pending_state_free is called. Is there any reason to keep pending_state around beyond the end of this function? [...] > @@ -1979,6 +2323,12 @@ drm_pending_state_apply_sync(struct drm_pending_state > *pending_state) > struct drm_output_state *output_state, *tmp; > uint32_t *unused; > > +#ifdef HAVE_DRM_ATOMIC > + if (b->atomic_modeset) > + return drm_pending_state_apply_atomic(pending_state, > + DRM_STATE_APPLY_SYNC); Same as drm_pending_state_apply, the way drm_pending_state_apply_sync is called makes it look like it is supposed to take ownership of pending_state and free it before returning. This does not happen in the atomic modeset path. regards Philipp _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel