main: Enable remote outputs later than local (DRM) outputs
[src/agl-compositor.git] / src / systemd-notify.c
1 /*
2  * Copyright (c) 2015 General Electric Company. All rights reserved.
3  * Copyright © 2020 Collabora, Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <errno.h>
30
31 #include <systemd/sd-daemon.h>
32 #include <sys/socket.h>
33 #include <wayland-server.h>
34
35 #include "ivi-compositor.h"
36 #include "shared/helpers.h"
37
38 struct systemd_notifier {
39         int watchdog_time;
40         struct wl_event_source *watchdog_source;
41         struct wl_listener compositor_destroy_listener;
42 };
43
44 static inline bool
45 safe_strtoint(const char *str, int32_t *value)
46 {
47         long ret;
48         char *end;
49
50         assert(str != NULL);
51
52         errno = 0;
53         ret = strtol(str, &end, 10);
54         if (errno != 0) {
55                 return false;
56         } else if (end == str || *end != '\0') {
57                 errno = EINVAL;
58                 return false;
59         }
60
61         if ((long)((int32_t)ret) != ret) {
62                 errno = ERANGE;
63                 return false;
64         }
65
66         *value = (int32_t)ret;
67
68         return true;
69 }
70
71 static int
72 add_systemd_sockets(struct weston_compositor *compositor)
73 {
74         int fd;
75         int cnt_systemd_sockets;
76         int current_fd = 0;
77
78         cnt_systemd_sockets = sd_listen_fds(1);
79
80         if (cnt_systemd_sockets < 0) {
81                 weston_log("sd_listen_fds failed with: %d\n",
82                                 cnt_systemd_sockets);
83                 return -1;
84         }
85
86         /* socket-based activation not used, return silently */
87         if (cnt_systemd_sockets == 0)
88                 return 0;
89
90         while (current_fd < cnt_systemd_sockets) {
91                 fd = SD_LISTEN_FDS_START + current_fd;
92
93                 if (sd_is_socket(fd, AF_UNIX, SOCK_STREAM, 1) <= 0) {
94                         weston_log("invalid socket provided from systemd\n");
95                         return -1;
96                 }
97
98                 if (wl_display_add_socket_fd(compositor->wl_display, fd)) {
99                         weston_log("wl_display_add_socket_fd failed"
100                                         "for systemd provided socket\n");
101                         return -1;
102                 }
103                 current_fd++;
104         }
105
106         weston_log("info: add %d socket(s) provided by systemd\n",
107                         current_fd);
108
109         return current_fd;
110 }
111
112 static int
113 watchdog_handler(void *data)
114 {
115         struct systemd_notifier *notifier = data;
116
117         wl_event_source_timer_update(notifier->watchdog_source,
118                         notifier->watchdog_time);
119
120         sd_notify(0, "WATCHDOG=1");
121
122         return 1;
123 }
124
125 static void
126 weston_compositor_destroy_listener(struct wl_listener *listener, void *data)
127 {
128         struct systemd_notifier *notifier;
129
130         sd_notify(0, "STOPPING=1");
131
132         notifier = container_of(listener, struct systemd_notifier,
133                                 compositor_destroy_listener);
134
135         if (notifier->watchdog_source)
136                 wl_event_source_remove(notifier->watchdog_source);
137
138         wl_list_remove(&notifier->compositor_destroy_listener.link);
139         free(notifier);
140 }
141
142 int
143 ivi_agl_systemd_notify(struct ivi_compositor *ivi)
144 {
145         struct weston_compositor *compositor = ivi->compositor;
146         char *watchdog_time_env;
147         struct wl_event_loop *loop;
148         int32_t watchdog_time_conv;
149
150         struct systemd_notifier *notifier;
151
152         notifier = zalloc(sizeof *notifier);
153         if (notifier == NULL)
154                 return -1;
155
156         notifier->compositor_destroy_listener.notify =
157                 weston_compositor_destroy_listener;
158         wl_signal_add(&compositor->destroy_signal,
159                         &notifier->compositor_destroy_listener);
160
161         if (add_systemd_sockets(compositor) < 0)
162                 return -1;
163
164         weston_log("Sending ready to systemd\n");
165
166         sd_notify(0, "READY=1");
167
168         /* 'WATCHDOG_USEC' is environment variable that is set
169          * by systemd to transfer 'WatchdogSec' watchdog timeout
170          * setting from service file.*/
171         watchdog_time_env = getenv("WATCHDOG_USEC");
172         if (!watchdog_time_env)
173                 return 0;
174
175         if (!safe_strtoint(watchdog_time_env, &watchdog_time_conv))
176                 return 0;
177
178         /* Convert 'WATCHDOG_USEC' to milliseconds and notify
179          * systemd every half of that time.*/
180         watchdog_time_conv /= 1000 * 2;
181         if (watchdog_time_conv <= 0)
182                 return 0;
183
184         notifier->watchdog_time = watchdog_time_conv;
185
186         loop = wl_display_get_event_loop(compositor->wl_display);
187         notifier->watchdog_source =
188                 wl_event_loop_add_timer(loop, watchdog_handler, notifier);
189         wl_event_source_timer_update(notifier->watchdog_source,
190                         notifier->watchdog_time);
191
192         return 0;
193 }