Use weston_compositor_add_destroy_listener_once() in plugins

This introduces a new convention of checking through the compositor destroy
listener if the plugin is already initialized. If the plugin is already
initialized, then the plugin entry function succeeds as a no-op. This makes it
safe to load the same plugin multiple times in a running compositor.

Currently module loading functions return failure if a plugin is already
loaded, but that will change in the future. Therefore we need this other method
of ensuring we do not double-initialize a plugin which would lead to list
corruptions the very least.

All plugins are converted to use the new helper, except:
- those that do not have a destroy listener already, and
- hmi-controller which does the same open-coded as the common code pattern
  did not fit there.

Plugins should always have a compositor destroy listener registered since they
very least allocate a struct to hold their data. Hence omissions are
highlighted in code.

Backends do not need this because weston_compositor_load_backend() already
protects against double-init. GL-renderer does not export a standard module
init function so cannot be initialized the usual way and therefore is not
vulnerable to double-init.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
dev
Pekka Paalanen 5 years ago committed by Daniel Stone
parent 5caef6d355
commit 6ffbba3ac1
  1. 12
      compositor/cms-colord.c
  2. 9
      compositor/cms-static.c
  3. 3
      compositor/screen-share.c
  4. 10
      compositor/systemd-notify.c
  5. 9
      desktop-shell/shell.c
  6. 3
      fullscreen-shell/fullscreen-shell.c
  7. 5
      include/libweston/libweston.h
  8. 4
      ivi-shell/hmi-controller.c
  9. 10
      ivi-shell/ivi-shell.c
  10. 35
      libweston/compositor.c
  11. 10
      pipewire/pipewire-plugin.c
  12. 10
      remoting/remoting-plugin.c
  13. 8
      tests/weston-test-desktop-shell.c
  14. 3
      tests/weston-test.c
  15. 24
      xwayland/launcher.c

@ -528,6 +528,14 @@ wet_module_init(struct weston_compositor *ec,
if (cms == NULL) if (cms == NULL)
return -1; return -1;
cms->ec = ec; cms->ec = ec;
if (!weston_compositor_add_destroy_listener_once(ec,
&cms->destroy_listener,
colord_notifier_destroy)) {
free(cms);
return 0;
}
#if !GLIB_CHECK_VERSION(2,36,0) #if !GLIB_CHECK_VERSION(2,36,0)
g_type_init(); g_type_init();
#endif #endif
@ -543,10 +551,6 @@ wet_module_init(struct weston_compositor *ec,
cms->devices = g_hash_table_new_full(g_str_hash, g_str_equal, cms->devices = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, colord_cms_output_destroy); g_free, colord_cms_output_destroy);
/* destroy */
cms->destroy_listener.notify = colord_notifier_destroy;
wl_signal_add(&ec->destroy_signal, &cms->destroy_listener);
/* devices added */ /* devices added */
cms->output_created_listener.notify = colord_notifier_output_created; cms->output_created_listener.notify = colord_notifier_output_created;
wl_signal_add(&ec->output_created_signal, &cms->output_created_listener); wl_signal_add(&ec->output_created_signal, &cms->output_created_listener);

@ -105,8 +105,13 @@ wet_module_init(struct weston_compositor *ec,
return -1; return -1;
cms->ec = ec; cms->ec = ec;
cms->destroy_listener.notify = cms_notifier_destroy;
wl_signal_add(&ec->destroy_signal, &cms->destroy_listener); if (!weston_compositor_add_destroy_listener_once(ec,
&cms->destroy_listener,
cms_notifier_destroy)) {
free(cms);
return 0;
}
cms->output_created_listener.notify = cms_notifier_output_created; cms->output_created_listener.notify = cms_notifier_output_created;
wl_signal_add(&ec->output_created_signal, &cms->output_created_listener); wl_signal_add(&ec->output_created_signal, &cms->output_created_listener);

@ -114,6 +114,9 @@ struct ss_shm_buffer {
struct screen_share { struct screen_share {
struct weston_compositor *compositor; struct weston_compositor *compositor;
/* XXX: missing compositor destroy listener
* https://gitlab.freedesktop.org/wayland/weston/issues/298
*/
char *command; char *command;
}; };

@ -127,10 +127,12 @@ wet_module_init(struct weston_compositor *compositor,
if (notifier == NULL) if (notifier == NULL)
return -1; return -1;
notifier->compositor_destroy_listener.notify = if (!weston_compositor_add_destroy_listener_once(compositor,
weston_compositor_destroy_listener; &notifier->compositor_destroy_listener,
wl_signal_add(&compositor->destroy_signal, weston_compositor_destroy_listener)) {
&notifier->compositor_destroy_listener); free(notifier);
return 0;
}
if (add_systemd_sockets(compositor) < 0) if (add_systemd_sockets(compositor) < 0)
return -1; return -1;

@ -5090,8 +5090,13 @@ wet_shell_init(struct weston_compositor *ec,
shell->compositor = ec; shell->compositor = ec;
shell->destroy_listener.notify = shell_destroy; if (!weston_compositor_add_destroy_listener_once(ec,
wl_signal_add(&ec->destroy_signal, &shell->destroy_listener); &shell->destroy_listener,
shell_destroy)) {
free(shell);
return 0;
}
shell->idle_listener.notify = idle_handler; shell->idle_listener.notify = idle_handler;
wl_signal_add(&ec->idle_signal, &shell->idle_listener); wl_signal_add(&ec->idle_signal, &shell->idle_listener);
shell->wake_listener.notify = wake_handler; shell->wake_listener.notify = wake_handler;

@ -42,6 +42,9 @@ struct fullscreen_shell {
struct wl_client *client; struct wl_client *client;
struct wl_listener client_destroyed; struct wl_listener client_destroyed;
struct weston_compositor *compositor; struct weston_compositor *compositor;
/* XXX: missing compositor destroy listener
* https://gitlab.freedesktop.org/wayland/weston/issues/299
*/
struct weston_layer layer; struct weston_layer layer;
struct wl_list output_list; struct wl_list output_list;

@ -1773,6 +1773,11 @@ struct weston_compositor *
weston_compositor_create(struct wl_display *display, weston_compositor_create(struct wl_display *display,
struct weston_log_context *log_ctx, void *user_data); struct weston_log_context *log_ctx, void *user_data);
bool
weston_compositor_add_destroy_listener_once(struct weston_compositor *compositor,
struct wl_listener *listener,
wl_notify_func_t destroy_handler);
enum weston_compositor_backend { enum weston_compositor_backend {
WESTON_BACKEND_DRM, WESTON_BACKEND_DRM,
WESTON_BACKEND_FBDEV, WESTON_BACKEND_FBDEV,

@ -1981,6 +1981,10 @@ wet_module_init(struct weston_compositor *ec,
struct hmi_controller *hmi_ctrl = NULL; struct hmi_controller *hmi_ctrl = NULL;
struct wl_event_loop *loop = NULL; struct wl_event_loop *loop = NULL;
/* ad hoc weston_compositor_add_destroy_listener_once() */
if (wl_signal_get(&ec->destroy_signal, hmi_controller_destroy))
return 0;
hmi_ctrl = hmi_controller_create(ec); hmi_ctrl = hmi_controller_create(ec);
if (hmi_ctrl == NULL) if (hmi_ctrl == NULL)
return -1; return -1;

@ -623,10 +623,14 @@ wet_shell_init(struct weston_compositor *compositor,
if (shell == NULL) if (shell == NULL)
return -1; return -1;
init_ivi_shell(compositor, shell); if (!weston_compositor_add_destroy_listener_once(compositor,
&shell->destroy_listener,
shell_destroy)) {
free(shell);
return 0;
}
shell->destroy_listener.notify = shell_destroy; init_ivi_shell(compositor, shell);
wl_signal_add(&compositor->destroy_signal, &shell->destroy_listener);
shell->wake_listener.notify = wake_handler; shell->wake_listener.notify = wake_handler;
wl_signal_add(&compositor->wake_signal, &shell->wake_listener); wl_signal_add(&compositor->wake_signal, &shell->wake_listener);

@ -7639,6 +7639,41 @@ weston_load_module(const char *name, const char *entrypoint)
return init; return init;
} }
/** Add a compositor destroy listener only once
*
* \param compositor The compositor whose destroy to watch for.
* \param listener The listener struct to initialize.
* \param destroy_handler The callback when compositor is destroyed.
* \return True if listener is added, or false if there already is a listener
* with the given \c destroy_handler.
*
* This function does nothing and returns false if the given callback function
* is already present in the weston_compositor destroy callbacks list.
* Otherwise, this function initializes the given listener with the given
* callback pointer and adds it to the compositor's destroy callbacks list.
*
* This can be used to ensure that plugin initialization is done only once
* in case the same plugin is loaded multiple times. If this function returns
* false, the plugin should be already initialized successfully.
*
* All plugins should register a destroy listener for cleaning up. Note, that
* the plugin destruction order is not guaranteed: plugins that depend on other
* plugins must be able to be torn down in arbitrary order.
*
* \sa weston_compositor_tear_down, weston_compositor_destroy
*/
WL_EXPORT bool
weston_compositor_add_destroy_listener_once(struct weston_compositor *compositor,
struct wl_listener *listener,
wl_notify_func_t destroy_handler)
{
if (wl_signal_get(&compositor->destroy_signal, destroy_handler))
return false;
listener->notify = destroy_handler;
wl_signal_add(&compositor->destroy_signal, listener);
return true;
}
/** Tear down the compositor. /** Tear down the compositor.
* *

@ -797,6 +797,13 @@ weston_module_init(struct weston_compositor *compositor)
if (!pipewire) if (!pipewire)
return -1; return -1;
if (!weston_compositor_add_destroy_listener_once(compositor,
&pipewire->destroy_listener,
weston_pipewire_destroy)) {
free(pipewire);
return 0;
}
pipewire->virtual_output_api = api; pipewire->virtual_output_api = api;
pipewire->compositor = compositor; pipewire->compositor = compositor;
wl_list_init(&pipewire->output_list); wl_list_init(&pipewire->output_list);
@ -821,11 +828,10 @@ weston_module_init(struct weston_compositor *compositor)
"Debug messages from pipewire plugin\n", "Debug messages from pipewire plugin\n",
NULL, NULL, NULL); NULL, NULL, NULL);
pipewire->destroy_listener.notify = weston_pipewire_destroy;
wl_signal_add(&compositor->destroy_signal, &pipewire->destroy_listener);
return 0; return 0;
failed: failed:
wl_list_remove(&pipewire->destroy_listener.link);
free(pipewire); free(pipewire);
return -1; return -1;
} }

@ -913,6 +913,13 @@ weston_module_init(struct weston_compositor *compositor)
if (!remoting) if (!remoting)
return -1; return -1;
if (!weston_compositor_add_destroy_listener_once(compositor,
&remoting->destroy_listener,
weston_remoting_destroy)) {
free(remoting);
return 0;
}
remoting->virtual_output_api = api; remoting->virtual_output_api = api;
remoting->compositor = compositor; remoting->compositor = compositor;
wl_list_init(&remoting->output_list); wl_list_init(&remoting->output_list);
@ -932,11 +939,10 @@ weston_module_init(struct weston_compositor *compositor)
goto failed; goto failed;
} }
remoting->destroy_listener.notify = weston_remoting_destroy;
wl_signal_add(&compositor->destroy_signal, &remoting->destroy_listener);
return 0; return 0;
failed: failed:
wl_list_remove(&remoting->destroy_listener.link);
free(remoting); free(remoting);
return -1; return -1;
} }

@ -181,8 +181,12 @@ wet_shell_init(struct weston_compositor *ec,
if (!dts) if (!dts)
return -1; return -1;
dts->compositor_destroy_listener.notify = shell_destroy; if (!weston_compositor_add_destroy_listener_once(ec,
wl_signal_add(&ec->destroy_signal, &dts->compositor_destroy_listener); &dts->compositor_destroy_listener,
shell_destroy)) {
free(dts);
return 0;
}
weston_layer_init(&dts->layer, ec); weston_layer_init(&dts->layer, ec);
weston_layer_init(&dts->background_layer, ec); weston_layer_init(&dts->background_layer, ec);

@ -46,6 +46,9 @@
struct weston_test { struct weston_test {
struct weston_compositor *compositor; struct weston_compositor *compositor;
/* XXX: missing compositor destroy listener
* https://gitlab.freedesktop.org/wayland/weston/issues/300
*/
struct weston_layer layer; struct weston_layer layer;
struct weston_process process; struct weston_process process;
struct weston_seat seat; struct weston_seat seat;

@ -367,19 +367,24 @@ weston_module_init(struct weston_compositor *compositor)
wxs->wl_display = display; wxs->wl_display = display;
wxs->compositor = compositor; wxs->compositor = compositor;
if (!weston_compositor_add_destroy_listener_once(compositor,
&wxs->destroy_listener,
weston_xserver_destroy)) {
free(wxs);
return 0;
}
if (weston_xwayland_get_api(compositor) != NULL || if (weston_xwayland_get_api(compositor) != NULL ||
weston_xwayland_surface_get_api(compositor) != NULL) { weston_xwayland_surface_get_api(compositor) != NULL) {
weston_log("The xwayland module APIs are already loaded.\n"); weston_log("The xwayland module APIs are already loaded.\n");
free(wxs); goto out_free;
return -1;
} }
ret = weston_plugin_api_register(compositor, WESTON_XWAYLAND_API_NAME, ret = weston_plugin_api_register(compositor, WESTON_XWAYLAND_API_NAME,
&api, sizeof(api)); &api, sizeof(api));
if (ret < 0) { if (ret < 0) {
weston_log("Failed to register the xwayland module API.\n"); weston_log("Failed to register the xwayland module API.\n");
free(wxs); goto out_free;
return -1;
} }
ret = weston_plugin_api_register(compositor, ret = weston_plugin_api_register(compositor,
@ -387,13 +392,9 @@ weston_module_init(struct weston_compositor *compositor)
&surface_api, sizeof(surface_api)); &surface_api, sizeof(surface_api));
if (ret < 0) { if (ret < 0) {
weston_log("Failed to register the xwayland surface API.\n"); weston_log("Failed to register the xwayland surface API.\n");
free(wxs); goto out_free;
return -1;
} }
wxs->destroy_listener.notify = weston_xserver_destroy;
wl_signal_add(&compositor->destroy_signal, &wxs->destroy_listener);
wxs->wm_debug = wxs->wm_debug =
weston_compositor_add_log_scope(wxs->compositor->weston_log_ctx, weston_compositor_add_log_scope(wxs->compositor->weston_log_ctx,
"xwm-wm-x11", "xwm-wm-x11",
@ -401,4 +402,9 @@ weston_module_init(struct weston_compositor *compositor)
NULL, NULL, NULL); NULL, NULL, NULL);
return 0; return 0;
out_free:
wl_list_remove(&wxs->destroy_listener.link);
free(wxs);
return -1;
} }

Loading…
Cancel
Save