当前位置:网站首页>[Wayland] Weston startup process analysis

[Wayland] Weston startup process analysis

2022-06-12 10:09:00 Lindo

Weston Start process analysis

  • Weston yes Wayland Compositor The implementation of the . Its Server The client runs in the system as an independent process .MakeFile The intermediate compilation result is ,“weston” Executable program of
  • MakeFile.am(weston 2.0.0)
bin_PROGRAMS += weston

weston_LDFLAGS = -export-dynamic
weston_CPPFLAGS = $(AM_CPPFLAGS) -DIN_WESTON 		\
				 -DMODULEDIR='"$(moduledir)"' \
				 -DXSERVER_PATH='"@[email protected]"'
weston_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS)
weston_LDADD = libshared.la [email protected][email protected] \
	$(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) \
	$(DLOPEN_LIBS) $(LIBINPUT_BACKEND_LIBS) \
	$(CLOCK_GETRES_LIBS) \
	-lm

weston_SOURCES = 					\
	compositor/main.c				\
	compositor/weston-screenshooter.c		\
	compositor/text-backend.c			\
	compositor/xwayland.c

Start process analysis

  • flow chart :
     Insert picture description here

  • main function : Entry function . In fact, now weston-2.0.0/compositor/main.c

  • Main content analysis

int main(int argc, char *argv[])
{
    
	// Log Log initialization 
	weston_log_set_handler(vlog, vlog_continue);
	weston_log_file_open(log);
	//  start-up Log
	weston_log("%s\n"
		   STAMP_SPACE "%s\n"
		   STAMP_SPACE "Bug reports to: %s\n"
		   STAMP_SPACE "Build: %s\n",
		   PACKAGE_STRING, PACKAGE_URL, PACKAGE_BUGREPORT,
		   BUILD_ID);

	//  Create a globally unique Display
	display = wl_display_create();
	
	//  Read weston.ini Configuration in file 
	if (load_configuration(&config, noconfig, config_file) < 0)
		goto out_signals;
	//  establish Compositor
	ec = weston_compositor_create(display, &user_data);
	if (ec == NULL) {
    
		weston_log("fatal: failed to create compositor\n");
		goto out;
	}
	//  load backend( The default is drm-backend)
	if (load_backend(ec, backend, &argc, argv, config) < 0) {
    
		weston_log("fatal: failed to create compositor backend\n");
		goto out;
	}

	//  Capture exception Signal
	catch_signals();

	if (fd != -1) {
    
		// ...
		//  Default walk  else if, establish socket
	} else if (weston_create_listening_socket(display, socket_name)) {
    
		goto out;
	}

   //  load shell
	if (wet_load_shell(ec, shell, &argc, argv) < 0)
		goto out;

   //  Wake up the compositor
	weston_compositor_wake(ec);
	// run: Loop monitoring client End request 
	wl_display_run(display);

}
  • It can be seen that the general process is :
  1. initialization Log System
  2. establish Display( Globally unique )
  3. Load profile (ini file )
  4. establish Compositor
  5. load backend
  6. establish socket
  7. load shell
  8. Turn on the cycle

initialization Log System

  • weston-2.0.0/libweston/log.c
//  take vlog As  log_handler
WL_EXPORT void
weston_log_set_handler(log_func_t log, log_func_t cont)
{
    
	log_handler = log;
	log_continue_handler = cont;
}

//  Use log_handler For the output , It's actually used main.c It's from 
// vlog
WL_EXPORT int
weston_vlog(const char *fmt, va_list ap)
{
    
	return log_handler(fmt, ap);
}

//  Used in the code log Output interface 
WL_EXPORT int
weston_log(const char *fmt, ...)
{
    
	int l;
	va_list argp;

	va_start(argp, fmt);
	l = weston_vlog(fmt, argp);
	va_end(argp);

	return l;
}
  • actually ,log System Use vlog and vlog_continue These two functions . The definition of both , stay main.c in .
static FILE *weston_logfile = NULL;
static void
weston_log_file_open(const char *filename)
{
    
	wl_log_set_handler_server(custom_handler);

	if (filename != NULL) {
    
		weston_logfile = fopen(filename, "a");
		if (weston_logfile)
			os_fd_set_cloexec(fileno(weston_logfile));
	}

	if (weston_logfile == NULL)
		weston_logfile = stderr;
	else
		setvbuf(weston_logfile, NULL, _IOLBF, 256);
}

static int
vlog(const char *fmt, va_list ap)
{
    
	int l;

	l = weston_log_timestamp();
	l += vfprintf(weston_logfile, fmt, ap);

	return l;
}

static int
vlog_continue(const char *fmt, va_list argp)
{
    
	return vfprintf(weston_logfile, fmt, argp);
}
  • By default weston_log_file_open function , Parameter is NULL. therefore log The information will be output to stderr in .

establish Global Display

  • wl_display_create:wayland1.13.0/src/wayland-server.c
WL_EXPORT struct wl_display *
wl_display_create(void)
{
    
	struct wl_display *display;
	const char *debug;

	debug = getenv("WAYLAND_DEBUG");
	if (debug && (strstr(debug, "server") || strstr(debug, "1")))
		debug_server = 1;

	display = malloc(sizeof *display);
	if (display == NULL)
		return NULL;
	//  establish Loop
	display->loop = wl_event_loop_create();
	if (display->loop == NULL) {
    
		free(display);
		return NULL;
	}
	// list initialization 
	wl_list_init(&display->global_list);
	wl_list_init(&display->socket_list);
	wl_list_init(&display->client_list);
	wl_list_init(&display->registry_resource_list);
	wl_list_init(&display->protocol_loggers);
	// signal initialization 
	wl_priv_signal_init(&display->destroy_signal);
	wl_priv_signal_init(&display->create_client_signal);

	display->id = 1;
	display->serial = 0;

	display->global_filter = NULL;
	display->global_filter_data = NULL;
	wl_array_init(&display->additional_shm_formats);

	return display;
}
  • wl_event_loop_create:wayland-1.13.0/src/event-loop.c
WL_EXPORT struct wl_event_loop *
wl_event_loop_create(void)
{
    
	struct wl_event_loop *loop;

	loop = malloc(sizeof *loop);
	if (loop == NULL)
		return NULL;
	//  The final call epoll_create
	loop->epoll_fd = wl_os_epoll_create_cloexec();
	if (loop->epoll_fd < 0) {
    
		free(loop);
		return NULL;
	}
	wl_list_init(&loop->check_list);
	wl_list_init(&loop->idle_list);
	wl_list_init(&loop->destroy_list);

	wl_signal_init(&loop->destroy_signal);

	return loop;
}
  • This part is mainly about initialization Display Structure , Use epoll_create Created loop.

Load profile

  • The configuration file :weston Configuration files are provided , The running configuration can be changed dynamically ( Need to restart Server End processes ), For example, what kind of shell、 The type of animation 、backend Type of... Etc .
  • compostior/main.c
static int
load_configuration(struct weston_config **config, int32_t noconfig,
		   const char *config_file)
{
    
    //  The default configuration file is  weston.ini
	const char *file = "weston.ini";
	const char *full_path;

	*config = NULL;

	if (config_file)
		file = config_file;
	
	//  Parse configuration file 
	if (noconfig == 0)
		*config = weston_config_parse(file);

	if (*config) {
    
		full_path = weston_config_get_full_path(*config);

		weston_log("Using config file '%s'\n", full_path);
		setenv(WESTON_CONFIG_FILE_ENV_VAR, full_path, 1);

		return 0;
	}

	if (config_file && noconfig == 0) {
    
		weston_log("fatal: error opening or reading config file"
			   " '%s'.\n", config_file);

		return -1;
	}

	weston_log("Starting with no config file.\n");
	setenv(WESTON_CONFIG_FILE_ENV_VAR, "", 1);

	return 0;
}
  • weston_config_parse The function is responsible for parsing the configuration file . Finally, it will be parsed into a linked list data structure . This function has a large number of lines of code , I won't introduce .
  • Official weston.ini
[core]
#modules=cms-colord.so
#xwayland=true
#shell=desktop-shell.so
#gbm-format=xrgb2101010
#require-input=true

[shell]
background-image=/usr/share/backgrounds/gnome/Aqua.jpg
background-color=0xff002244
background-type=tile
clock-format=minutes
panel-color=0x90ff0000
locking=true
animation=zoom
startup-animation=fade
#binding-modifier=ctrl
#num-workspaces=6
#cursor-theme=whiteglass
#cursor-size=24

#lockscreen-icon=/usr/share/icons/gnome/256x256/actions/lock.png
#lockscreen=/usr/share/backgrounds/gnome/Garden.jpg
#homescreen=/usr/share/backgrounds/gnome/Blinds.jpg
#animation=fade

[launcher]
icon=/usr/share/icons/gnome/24x24/apps/utilities-terminal.png
path=/usr/bin/gnome-terminal

[launcher]
icon=/usr/share/icons/gnome/24x24/apps/utilities-terminal.png
[email protected]@/weston-terminal

[launcher]
icon=/usr/share/icons/hicolor/24x24/apps/google-chrome.png
path=/usr/bin/google-chrome

[launcher]
icon=/usr/share/icons/gnome/24x24/apps/arts.png
[email protected][email protected]/weston-flower

[input-method]
[email protected]@/weston-keyboard

#[output]
#name=LVDS1
#mode=1680x1050
#transform=90
#icc_profile=/usr/share/color/icc/colord/Bluish.icc

#[output]
#name=VGA1
#mode=173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync
#transform=flipped

#[output]
#name=X1
#[email protected]
#transform=flipped-90

#[libinput]
#enable_tap=true

#[touchpad]
#constant_accel_factor = 50
#min_accel_factor = 0.16
#max_accel_factor = 1.0

[screen-share]
[email protected]@/weston --backend=rdp-backend.so --shell=fullscreen-shell.so --no-clients-resize

#[xwayland]
#[email protected]@/Xwayland

establish Compositor

  • weston_compositor_create:libweston/compostior.c
WL_EXPORT struct weston_compositor *
weston_compositor_create(struct wl_display *display, void *user_data)
{
    
	struct weston_compositor *ec;
	struct wl_event_loop *loop;

	ec = zalloc(sizeof *ec);
	if (!ec)
		return NULL;
	// display For the previously created global display
	ec->wl_display = display;
	ec->user_data = user_data;
	//  Initialize a series of signal
	wl_signal_init(&ec->destroy_signal);
	wl_signal_init(&ec->create_surface_signal);
	wl_signal_init(&ec->activate_signal);
	wl_signal_init(&ec->transform_signal);
	wl_signal_init(&ec->kill_signal);
	wl_signal_init(&ec->idle_signal);
	wl_signal_init(&ec->wake_signal);
	wl_signal_init(&ec->show_input_panel_signal);
	wl_signal_init(&ec->hide_input_panel_signal);
	wl_signal_init(&ec->update_input_panel_signal);
	wl_signal_init(&ec->seat_created_signal);
	wl_signal_init(&ec->output_pending_signal);
	wl_signal_init(&ec->output_created_signal);
	wl_signal_init(&ec->output_destroyed_signal);
	wl_signal_init(&ec->output_moved_signal);
	wl_signal_init(&ec->output_resized_signal);
	wl_signal_init(&ec->session_signal);
	ec->session_active = 1;

	ec->output_id_pool = 0;
	ec->repaint_msec = DEFAULT_REPAINT_WINDOW;

	ec->activate_serial = 1;
	//  These steps are key . Again weston There are many such calls in the code .
	// wl_global_create There are four parameters 
	// display、interface、version、bind_func
	//  It can be understood as :Display There is a global object List, Here is the global object List in , Add a new global object . Implementation of the specific interface of the object , Namely wl_compositor_interface.
	if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 4,
			      ec, compositor_bind))
		goto fail;
	//  ditto wl_subcompositor_interface Interface implementation .
	if (!wl_global_create(ec->wl_display, &wl_subcompositor_interface, 1,
			      ec, bind_subcompositor))
		goto fail;
	//  ditto 
	if (!wl_global_create(ec->wl_display, &wp_viewporter_interface, 1,
			      ec, bind_viewporter))
		goto fail;
	//  Same as   On 
	if (!wl_global_create(ec->wl_display, &wp_presentation_interface, 1,
			      ec, bind_presentation))
		goto fail;
	//  I created two golbal object , Corresponding interface by 
	// 1. zwp_relative_pointer_manager_v1_interface
	// 2. zwp_pointer_constraints_v1_interface
	if (weston_input_init(ec) != 0)
		goto fail;
	//  initialization , Several key list: view\plane\layer
	wl_list_init(&ec->view_list);
	wl_list_init(&ec->plane_list);
	wl_list_init(&ec->layer_list);
	wl_list_init(&ec->seat_list);
	wl_list_init(&ec->pending_output_list);
	wl_list_init(&ec->output_list);
	wl_list_init(&ec->key_binding_list);
	wl_list_init(&ec->modifier_binding_list);
	wl_list_init(&ec->button_binding_list);
	wl_list_init(&ec->touch_binding_list);
	wl_list_init(&ec->axis_binding_list);
	wl_list_init(&ec->debug_binding_list);

	wl_list_init(&ec->plugin_api_list);
	//  initialization   First of all plane
	weston_plane_init(&ec->primary_plane, ec, 0, 0);
	weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);

	wl_data_device_manager_init(ec->wl_display);

	wl_display_init_shm(ec->wl_display);

	loop = wl_display_get_event_loop(ec->wl_display);
	ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
	//  initialization layer
	weston_layer_init(&ec->fade_layer, ec);
	weston_layer_init(&ec->cursor_layer, ec);

	weston_layer_set_position(&ec->fade_layer, WESTON_LAYER_POSITION_FADE);
	weston_layer_set_position(&ec->cursor_layer,
				  WESTON_LAYER_POSITION_CURSOR);

	weston_compositor_add_debug_binding(ec, KEY_T,
					    timeline_key_binding_handler, ec);

	return ec;

fail:
	free(ec);
	return NULL;
}
  • Here, several global objects are created , Set the... Corresponding to these global objects interface Realization . And initialized view、layer、plane And so on .

load backend

  • load_backend:compositor/main.c
static int
load_backend(struct weston_compositor *compositor, const char *backend,
	     int *argc, char **argv, struct weston_config *config)
{
    
	if (strstr(backend, "headless-backend.so"))
		return load_headless_backend(compositor, argc, argv, config);
	else if (strstr(backend, "rdp-backend.so"))
		return load_rdp_backend(compositor, argc, argv, config);
	else if (strstr(backend, "fbdev-backend.so"))
		return load_fbdev_backend(compositor, argc, argv, config);
	//  Default walk  drm-backend
	else if (strstr(backend, "drm-backend.so"))
		return load_drm_backend(compositor, argc, argv, config);
	else if (strstr(backend, "x11-backend.so"))
		return load_x11_backend(compositor, argc, argv, config);
	else if (strstr(backend, "wayland-backend.so"))
		return load_wayland_backend(compositor, argc, argv, config);

	weston_log("Error: unknown backend \"%s\"\n", backend);
	return -1;
}
  • load_drm_backend
static int
load_drm_backend(struct weston_compositor *c,
		 int *argc, char **argv, struct weston_config *wc)
{
    
	struct weston_drm_backend_config config = {
    {
     0, }};
	struct weston_config_section *section;
	struct wet_compositor *wet = to_wet_compositor(c);

	//  Go here to create backend
	ret = weston_compositor_load_backend(c, WESTON_BACKEND_DRM,
					     &config.base);

	wet_set_pending_output_handler(c, drm_backend_output_configure);

	free(config.gbm_format);
	free(config.seat_id);

	return ret;
}
  • weston_compositor_load_backend:libweston/compositor.c
WL_EXPORT int
weston_compositor_load_backend(struct weston_compositor *compositor,
			       enum weston_compositor_backend backend,
			       struct weston_backend_config *config_base)
{
    
	int (*backend_init)(struct weston_compositor *c,
			    struct weston_backend_config *config_base);

	if (backend >= ARRAY_LENGTH(backend_map))
		return -1;
	//  adopt dlopen, open drm-backend.so, lookup  weston_backend_init  function 
	backend_init = weston_load_module(backend_map[backend], "weston_backend_init");
	if (!backend_init)
		return -1;
	//  perform weston_backend_init function 
	return backend_init(compositor, config_base);
}
  • weston_backend_init:libweston/compositor-drm.c
WL_EXPORT int
weston_backend_init(struct weston_compositor *compositor,
		    struct weston_backend_config *config_base)
{
    
	struct drm_backend *b;
	struct weston_drm_backend_config config = {
    {
     0, }};

	if (config_base == NULL ||
	    config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
	    config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
    
		weston_log("drm backend config structure is invalid\n");
		return -1;
	}

	config_init_to_defaults(&config);
	memcpy(&config, config_base, config_base->struct_size);
	//  establish  drm backend
	b = drm_backend_create(compositor, &config);
	if (b == NULL)
		return -1;

	return 0;
}
  • drm_backend_create:libweston/compositor-drm.c
static struct drm_backend *
drm_backend_create(struct weston_compositor *compositor,
		   struct weston_drm_backend_config *config)
{
    
	//  Use libdrm Interface , Do some initialization 
	//  establish output object  drmModeGetConnector
}

establish Socket

  • Server Process creation listener socket
  • weston_create_listening_socket:compositor/main.c
static int
weston_create_listening_socket(struct wl_display *display, const char *socket_name)
{
    
	if (socket_name) {
    
		if (wl_display_add_socket(display, socket_name)) {
    
			weston_log("fatal: failed to add socket: %m\n");
			return -1;
		}
	} else {
    
	    //  Default socketname It's empty .
	    //  Create a file called wayland-0 Of socket
		socket_name = wl_display_add_socket_auto(display);
		if (!socket_name) {
    
			weston_log("fatal: failed to add socket: %m\n");
			return -1;
		}
	}

	setenv("WAYLAND_DISPLAY", socket_name, 1);

	return 0;
}

load shell

  • wet_load_shell:compositor/main.c
static int
wet_load_shell(struct weston_compositor *compositor,
	       const char *name, int *argc, char *argv[])
{
    
	int (*shell_init)(struct weston_compositor *ec,
			  int *argc, char *argv[]);
	//  Default :
	//  Use dlopen, open desktop-shell.so, lookup wet_shell_init function 
	shell_init = wet_load_module_entrypoint(name, "wet_shell_init");
	if (!shell_init)
		return -1;
	//  call wet_shell_init
	if (shell_init(compositor, argc, argv) < 0)
		return -1;
	return 0;
}
  • wet_shell_init:deskstop-shell/shell.c
WL_EXPORT int
wet_shell_init(struct weston_compositor *ec,
	       int *argc, char *argv[])
{
    
	//  establish desktop
	shell->desktop = weston_desktop_create(ec, &shell_desktop_api, shell);
	if (!shell->desktop)
		return -1;
	//  Create global objects 
	if (wl_global_create(ec->wl_display,
			     &weston_desktop_shell_interface, 1,
			     shell, bind_desktop_shell) == NULL)
		return -1;

}

Turn on the cycle

  • The cycle here , Refers to the use epoll Mechanism , Interception pair socket( above Server End created socket) Generated read / write events .
WL_EXPORT void
wl_display_run(struct wl_display *display)
{
    
	display->run = 1;

	while (display->run) {
    
		wl_display_flush_clients(display);
		wl_event_loop_dispatch(display->loop, -1);
	}
}
  • wl_event_loop_dispatch:event-loop.c
WL_EXPORT int
wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
{
    
	struct epoll_event ep[32];
	struct wl_event_source *source;
	int i, count, n;

	wl_event_loop_dispatch_idle(loop);

	count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
	if (count < 0)
		return -1;

	for (i = 0; i < count; i++) {
    
		source = ep[i].data.ptr;
		if (source->fd != -1)
			source->interface->dispatch(source, &ep[i]);
	}

	wl_event_loop_process_destroy_list(loop);

	wl_event_loop_dispatch_idle(loop);

	do {
    
		n = post_dispatch_check(loop);
	} while (n > 0);

	return 0;
}
原网站

版权声明
本文为[Lindo]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/03/202203010528238910.html