[PATCH v14 17/41] compositor-drm: Atomic modesetting support
Philipp Zabel
p.zabel at pengutronix.de
Wed Jan 3 17:52:56 UTC 2018
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
More information about the wayland-devel
mailing list