summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-devtools/pseudo/files/0001-Use-epoll-API-on-Linux.patch292
-rw-r--r--meta/recipes-devtools/pseudo/pseudo_1.8.2.bb1
2 files changed, 293 insertions, 0 deletions
diff --git a/meta/recipes-devtools/pseudo/files/0001-Use-epoll-API-on-Linux.patch b/meta/recipes-devtools/pseudo/files/0001-Use-epoll-API-on-Linux.patch
new file mode 100644
index 0000000000..42557b17a7
--- /dev/null
+++ b/meta/recipes-devtools/pseudo/files/0001-Use-epoll-API-on-Linux.patch
@@ -0,0 +1,292 @@
1From 9e407e0be01695e7b927f5820ade87ee9602c248 Mon Sep 17 00:00:00 2001
2From: Alexander Kanavin <alex.kanavin@gmail.com>
3Date: Fri, 15 Sep 2017 17:00:14 +0300
4Subject: [PATCH] Use epoll API on Linux
5
6Also a couple of other modifications due to epoll having
7a different approach to how the working set of fds is defined
8and used:
91) open_client() returns an index into the array of clients
102) close_client() has a protection against being called twice
11with the same client (which would mess up the active_clients
12counter)
13
14Upstream-Status: Submitted [Seebs CC'd by email]
15Signed-off-by: Alexander Kanavin <alex.kanavin@gmail.com>
16
17---
18 enums/exit_status.in | 3 +
19 pseudo_server.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++-
20 2 files changed, 190 insertions(+), 2 deletions(-)
21
22diff --git a/enums/exit_status.in b/enums/exit_status.in
23index 6be44d3..88f94cd 100644
24--- a/enums/exit_status.in
25+++ b/enums/exit_status.in
26@@ -18,3 +18,6 @@ listen_fd, "server loop had no valid listen fd"
27 pseudo_loaded, "server couldn't get out of pseudo environment"
28 pseudo_prefix, "couldn't get valid pseudo prefix"
29 pseudo_invocation, "invalid server command arguments"
30+epoll_create, "epoll_create() failed"
31+epoll_ctl, "epoll_ctl() failed"
32+
33diff --git a/pseudo_server.c b/pseudo_server.c
34index ff16efd..14d34de 100644
35--- a/pseudo_server.c
36+++ b/pseudo_server.c
37@@ -40,6 +40,12 @@
38 #include "pseudo_client.h"
39 #include "pseudo_db.h"
40
41+// This has to come after pseudo includes, as that's where PSEUDO_PORT defines are
42+#ifdef PSEUDO_PORT_LINUX
43+#include <sys/epoll.h>
44+#endif
45+
46+
47 static int listen_fd = -1;
48
49 typedef struct {
50@@ -59,6 +65,7 @@ static int active_clients = 0, highest_client = 0, max_clients = 0;
51
52 #define LOOP_DELAY 2
53 #define DEFAULT_PSEUDO_SERVER_TIMEOUT 30
54+#define EPOLL_MAX_EVENTS 10
55 int pseudo_server_timeout = DEFAULT_PSEUDO_SERVER_TIMEOUT;
56 static int die_peacefully = 0;
57 static int die_forcefully = 0;
58@@ -80,6 +87,9 @@ quit_now(int signal) {
59 static int messages = 0, responses = 0;
60 static struct timeval message_time = { .tv_sec = 0 };
61
62+#ifdef PSEUDO_PORT_LINUX
63+static void pseudo_server_loop_epoll(void);
64+#endif
65 static void pseudo_server_loop(void);
66
67 /* helper function to make a directory, just like mkdir -p.
68@@ -369,12 +379,16 @@ pseudo_server_start(int daemonize) {
69 kill(ppid, SIGUSR1);
70 }
71 }
72+#ifdef PSEUDO_PORT_LINUX
73+ pseudo_server_loop_epoll();
74+#else
75 pseudo_server_loop();
76+#endif
77 return 0;
78 }
79
80 /* mess with internal tables as needed */
81-static void
82+static unsigned int
83 open_client(int fd) {
84 pseudo_client_t *new_clients;
85 int i;
86@@ -390,7 +404,7 @@ open_client(int fd) {
87 ++active_clients;
88 if (i > highest_client)
89 highest_client = i;
90- return;
91+ return i;
92 }
93 }
94
95@@ -414,9 +428,11 @@ open_client(int fd) {
96
97 max_clients += 16;
98 ++active_clients;
99+ return max_clients - 16;
100 } else {
101 pseudo_diag("error allocating new client, fd %d\n", fd);
102 close(fd);
103+ return 0;
104 }
105 }
106
107@@ -433,6 +449,10 @@ close_client(int client) {
108 client, highest_client);
109 return;
110 }
111+ if (clients[client].fd == -1) {
112+ pseudo_debug(PDBGF_SERVER, "client %d already closed\n", client);
113+ return;
114+ }
115 close(clients[client].fd);
116 clients[client].fd = -1;
117 free(clients[client].tag);
118@@ -566,6 +586,171 @@ serve_client(int i) {
119 }
120 }
121
122+#ifdef PSEUDO_PORT_LINUX
123+static void pseudo_server_loop_epoll(void)
124+{
125+ struct sockaddr_un client;
126+ socklen_t len;
127+ int i;
128+ int rc;
129+ int fd;
130+ int timeout;
131+ struct epoll_event ev, events[EPOLL_MAX_EVENTS];
132+ int loop_timeout = pseudo_server_timeout;
133+
134+ clients = malloc(16 * sizeof(*clients));
135+
136+ clients[0].fd = listen_fd;
137+ clients[0].pid = getpid();
138+
139+ for (i = 1; i < 16; ++i) {
140+ clients[i].fd = -1;
141+ clients[i].pid = 0;
142+ clients[i].tag = NULL;
143+ clients[i].program = NULL;
144+ }
145+
146+ active_clients = 1;
147+ max_clients = 16;
148+ highest_client = 0;
149+
150+ pseudo_debug(PDBGF_SERVER, "server loop started.\n");
151+ if (listen_fd < 0) {
152+ pseudo_diag("got into loop with no valid listen fd.\n");
153+ exit(PSEUDO_EXIT_LISTEN_FD);
154+ }
155+
156+ timeout = LOOP_DELAY * 1000;
157+
158+ int epollfd = epoll_create1(0);
159+ if (epollfd == -1) {
160+ pseudo_diag("epoll_create1() failed.\n");
161+ exit(PSEUDO_EXIT_EPOLL_CREATE);
162+ }
163+ ev.events = EPOLLIN;
164+ ev.data.u64 = 0;
165+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, clients[0].fd, &ev) == -1) {
166+ pseudo_diag("epoll_ctl() failed with listening socket.\n");
167+ exit(PSEUDO_EXIT_EPOLL_CTL);
168+ }
169+
170+ pdb_log_msg(SEVERITY_INFO, NULL, NULL, NULL, "server started (pid %d)", getpid());
171+
172+ for (;;) {
173+ rc = epoll_wait(epollfd, events, EPOLL_MAX_EVENTS, timeout);
174+ if (rc == 0 || (rc == -1 && errno == EINTR)) {
175+ /* If there's no clients, start timing out. If there
176+ * are active clients, never time out.
177+ */
178+ if (active_clients == 1) {
179+ loop_timeout -= LOOP_DELAY;
180+ /* maybe flush database to disk */
181+ pdb_maybe_backup();
182+ if (loop_timeout <= 0) {
183+ pseudo_debug(PDBGF_SERVER, "no more clients, got bored.\n");
184+ die_peacefully = 1;
185+ } else {
186+ /* display this if not exiting */
187+ pseudo_debug(PDBGF_SERVER | PDBGF_BENCHMARK, "%d messages handled in %.4f seconds, %d responses\n",
188+ messages,
189+ (double) message_time.tv_sec +
190+ (double) message_time.tv_usec / 1000000.0,
191+ responses);
192+ }
193+ }
194+ } else if (rc > 0) {
195+ loop_timeout = pseudo_server_timeout;
196+ for (i = 0; i < rc; ++i) {
197+ if (clients[events[i].data.u64].fd == listen_fd) {
198+ if (!die_forcefully) {
199+ len = sizeof(client);
200+ if ((fd = accept(listen_fd, (struct sockaddr *) &client, &len)) != -1) {
201+ /* Don't allow clients to end up on fd 2, because glibc's
202+ * malloc debug uses that fd unconditionally.
203+ */
204+ if (fd == 2) {
205+ int newfd = fcntl(fd, F_DUPFD, 3);
206+ close(fd);
207+ fd = newfd;
208+ }
209+ pseudo_debug(PDBGF_SERVER, "new client fd %d\n", fd);
210+ /* A new client implicitly cancels any
211+ * previous shutdown request, or a
212+ * shutdown for lack of clients.
213+ */
214+ pseudo_server_timeout = DEFAULT_PSEUDO_SERVER_TIMEOUT;
215+ die_peacefully = 0;
216+
217+ ev.events = EPOLLIN;
218+ ev.data.u64 = open_client(fd);
219+ if (ev.data.u64 != 0 && epoll_ctl(epollfd, EPOLL_CTL_ADD, clients[ev.data.u64].fd, &ev) == -1) {
220+ pseudo_diag("epoll_ctl() failed with accepted socket.\n");
221+ exit(PSEUDO_EXIT_EPOLL_CTL);
222+ }
223+ } else if (errno == EMFILE) {
224+ pseudo_debug(PDBGF_SERVER, "Hit max open files, dropping a client.\n");
225+ /* In theory there is a potential race here where if we close a client,
226+ it may have sent us a fastop message which we don't act upon.
227+ If we don't close a filehandle we'll loop indefinitely thought.
228+ Only close one per loop iteration in the interests of caution */
229+ for (int j = 1; j <= highest_client; ++j) {
230+ if (clients[j].fd != -1) {
231+ close_client(j);
232+ break;
233+ }
234+ }
235+ }
236+ }
237+ } else {
238+ struct timeval tv1, tv2;
239+ int rc;
240+ gettimeofday(&tv1, NULL);
241+ rc = serve_client(events[i].data.u64);
242+ gettimeofday(&tv2, NULL);
243+ ++messages;
244+ if (rc == 0)
245+ ++responses;
246+ message_time.tv_sec += (tv2.tv_sec - tv1.tv_sec);
247+ message_time.tv_usec += (tv2.tv_usec - tv1.tv_usec);
248+ if (message_time.tv_usec < 0) {
249+ message_time.tv_usec += 1000000;
250+ --message_time.tv_sec;
251+ } else while (message_time.tv_usec > 1000000) {
252+ message_time.tv_usec -= 1000000;
253+ ++message_time.tv_sec;
254+ }
255+ }
256+ if (die_forcefully)
257+ break;
258+ }
259+ pseudo_debug(PDBGF_SERVER, "server loop complete [%d clients left]\n", active_clients);
260+ } else {
261+ pseudo_diag("epoll_wait failed: %s\n", strerror(errno));
262+ break;
263+ }
264+ if (die_peacefully || die_forcefully) {
265+ pseudo_debug(PDBGF_SERVER, "quitting.\n");
266+ pseudo_debug(PDBGF_SERVER | PDBGF_BENCHMARK, "server %d exiting: handled %d messages in %.4f seconds\n",
267+ getpid(), messages,
268+ (double) message_time.tv_sec +
269+ (double) message_time.tv_usec / 1000000.0);
270+ pdb_log_msg(SEVERITY_INFO, NULL, NULL, NULL, "server %d exiting: handled %d messages in %.4f seconds",
271+ getpid(), messages,
272+ (double) message_time.tv_sec +
273+ (double) message_time.tv_usec / 1000000.0);
274+ /* and at this point, we'll start refusing connections */
275+ close(clients[0].fd);
276+ /* This is a good place to insert a delay for
277+ * debugging race conditions during startup. */
278+ /* usleep(300000); */
279+ exit(0);
280+ }
281+ }
282+
283+}
284+
285+#endif
286+
287 /* get clients, handle messages, shut down.
288 * This doesn't actually do any work, it just calls a ton of things which
289 * do work.
290--
2912.14.1
292
diff --git a/meta/recipes-devtools/pseudo/pseudo_1.8.2.bb b/meta/recipes-devtools/pseudo/pseudo_1.8.2.bb
index 9bcd031892..81853e95c4 100644
--- a/meta/recipes-devtools/pseudo/pseudo_1.8.2.bb
+++ b/meta/recipes-devtools/pseudo/pseudo_1.8.2.bb
@@ -8,6 +8,7 @@ SRC_URI = "http://downloads.yoctoproject.org/releases/pseudo/${BPN}-${PV}.tar.bz
8 file://efe0be279901006f939cd357ccee47b651c786da.patch \ 8 file://efe0be279901006f939cd357ccee47b651c786da.patch \
9 file://b6b68db896f9963558334aff7fca61adde4ec10f.patch \ 9 file://b6b68db896f9963558334aff7fca61adde4ec10f.patch \
10 file://toomanyfiles.patch \ 10 file://toomanyfiles.patch \
11 file://0001-Use-epoll-API-on-Linux.patch \
11 " 12 "
12 13
13SRC_URI[md5sum] = "7d41e72188fbea1f696c399c1a435675" 14SRC_URI[md5sum] = "7d41e72188fbea1f696c399c1a435675"