summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernie Innocenti2018-05-23 05:02:52 -0500
committerBernie Innocenti2018-05-25 04:43:12 -0500
commit0ad41cf3f44e5403132f7f620d8199446cb815b4 (patch)
treec9c0c28f5444cd9d97bff3d0fc1a457ad1df712e
parent39cab7cd2538b0f31b3672c71195c47ba3b00de9 (diff)
downloadplatform-system-core-0ad41cf3f44e5403132f7f620d8199446cb815b4.tar.gz
platform-system-core-0ad41cf3f44e5403132f7f620d8199446cb815b4.tar.xz
platform-system-core-0ad41cf3f44e5403132f7f620d8199446cb815b4.zip
SocketListener: use poll() instead of select()
FD_SET is limited to 1024 file descriptors in Linux, which causes processes with too many open files or connections to crash: FORTIFY: FD_ISSET: file descriptor 1024 >= FD_SETSIZE 128 The fix we used elsewhere is replacing select() with poll(), but in the case of SocketListener we additionally need to replace the SocketClient list with a map indexed by fd in order to avoid quadratic behavior on each poll() wakeup. Bug: 79838856 Test: device boots and appears to work normally Change-Id: I19ca4be675e9638104c0e7acf4a4bc62085e8ecd
-rw-r--r--libsysutils/include/sysutils/SocketClient.h5
-rw-r--r--libsysutils/include/sysutils/SocketListener.h6
-rw-r--r--libsysutils/src/SocketListener.cpp164
3 files changed, 68 insertions, 107 deletions
diff --git a/libsysutils/include/sysutils/SocketClient.h b/libsysutils/include/sysutils/SocketClient.h
index 1004f0611..c657526ee 100644
--- a/libsysutils/include/sysutils/SocketClient.h
+++ b/libsysutils/include/sysutils/SocketClient.h
@@ -1,8 +1,6 @@
1#ifndef _SOCKET_CLIENT_H 1#ifndef _SOCKET_CLIENT_H
2#define _SOCKET_CLIENT_H 2#define _SOCKET_CLIENT_H
3 3
4#include "List.h"
5
6#include <pthread.h> 4#include <pthread.h>
7#include <cutils/atomic.h> 5#include <cutils/atomic.h>
8#include <sys/types.h> 6#include <sys/types.h>
@@ -35,7 +33,7 @@ public:
35 SocketClient(int sock, bool owned, bool useCmdNum); 33 SocketClient(int sock, bool owned, bool useCmdNum);
36 virtual ~SocketClient(); 34 virtual ~SocketClient();
37 35
38 int getSocket() { return mSocket; } 36 int getSocket() const { return mSocket; }
39 pid_t getPid() const { return mPid; } 37 pid_t getPid() const { return mPid; }
40 uid_t getUid() const { return mUid; } 38 uid_t getUid() const { return mUid; }
41 gid_t getGid() const { return mGid; } 39 gid_t getGid() const { return mGid; }
@@ -84,5 +82,4 @@ private:
84 int sendDataLockedv(struct iovec *iov, int iovcnt); 82 int sendDataLockedv(struct iovec *iov, int iovcnt);
85}; 83};
86 84
87typedef android::sysutils::List<SocketClient *> SocketClientCollection;
88#endif 85#endif
diff --git a/libsysutils/include/sysutils/SocketListener.h b/libsysutils/include/sysutils/SocketListener.h
index bc93b8635..56f247866 100644
--- a/libsysutils/include/sysutils/SocketListener.h
+++ b/libsysutils/include/sysutils/SocketListener.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2008-2014 The Android Open Source Project 2 * Copyright (C) 2008 The Android Open Source Project
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@
18 18
19#include <pthread.h> 19#include <pthread.h>
20 20
21#include <unordered_map>
22
21#include <sysutils/SocketClient.h> 23#include <sysutils/SocketClient.h>
22#include "SocketClientCommand.h" 24#include "SocketClientCommand.h"
23 25
@@ -25,7 +27,7 @@ class SocketListener {
25 bool mListen; 27 bool mListen;
26 const char *mSocketName; 28 const char *mSocketName;
27 int mSock; 29 int mSock;
28 SocketClientCollection *mClients; 30 std::unordered_map<int, SocketClient*> mClients;
29 pthread_mutex_t mClientsLock; 31 pthread_mutex_t mClientsLock;
30 int mCtrlPipe[2]; 32 int mCtrlPipe[2];
31 pthread_t mThread; 33 pthread_t mThread;
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 3f8f3db8f..128a27a3a 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2008-2014 The Android Open Source Project 2 * Copyright (C) 2008 The Android Open Source Project
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -19,13 +19,15 @@
19#include <errno.h> 19#include <errno.h>
20#include <stdio.h> 20#include <stdio.h>
21#include <stdlib.h> 21#include <stdlib.h>
22#include <sys/select.h> 22#include <sys/poll.h>
23#include <sys/socket.h> 23#include <sys/socket.h>
24#include <sys/time.h> 24#include <sys/time.h>
25#include <sys/types.h> 25#include <sys/types.h>
26#include <sys/un.h> 26#include <sys/un.h>
27#include <unistd.h> 27#include <unistd.h>
28 28
29#include <vector>
30
29#include <cutils/sockets.h> 31#include <cutils/sockets.h>
30#include <log/log.h> 32#include <log/log.h>
31#include <sysutils/SocketListener.h> 33#include <sysutils/SocketListener.h>
@@ -52,7 +54,6 @@ void SocketListener::init(const char *socketName, int socketFd, bool listen, boo
52 mSock = socketFd; 54 mSock = socketFd;
53 mUseCmdNum = useCmdNum; 55 mUseCmdNum = useCmdNum;
54 pthread_mutex_init(&mClientsLock, NULL); 56 pthread_mutex_init(&mClientsLock, NULL);
55 mClients = new SocketClientCollection();
56} 57}
57 58
58SocketListener::~SocketListener() { 59SocketListener::~SocketListener() {
@@ -63,12 +64,9 @@ SocketListener::~SocketListener() {
63 close(mCtrlPipe[0]); 64 close(mCtrlPipe[0]);
64 close(mCtrlPipe[1]); 65 close(mCtrlPipe[1]);
65 } 66 }
66 SocketClientCollection::iterator it; 67 for (auto pair : mClients) {
67 for (it = mClients->begin(); it != mClients->end();) { 68 pair.second->decRef();
68 (*it)->decRef();
69 it = mClients->erase(it);
70 } 69 }
71 delete mClients;
72} 70}
73 71
74int SocketListener::startListener() { 72int SocketListener::startListener() {
@@ -95,7 +93,7 @@ int SocketListener::startListener(int backlog) {
95 SLOGE("Unable to listen on socket (%s)", strerror(errno)); 93 SLOGE("Unable to listen on socket (%s)", strerror(errno));
96 return -1; 94 return -1;
97 } else if (!mListen) 95 } else if (!mListen)
98 mClients->push_back(new SocketClient(mSock, false, mUseCmdNum)); 96 mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum);
99 97
100 if (pipe(mCtrlPipe)) { 98 if (pipe(mCtrlPipe)) {
101 SLOGE("pipe failed (%s)", strerror(errno)); 99 SLOGE("pipe failed (%s)", strerror(errno));
@@ -135,11 +133,10 @@ int SocketListener::stopListener() {
135 mSock = -1; 133 mSock = -1;
136 } 134 }
137 135
138 SocketClientCollection::iterator it; 136 for (auto pair : mClients) {
139 for (it = mClients->begin(); it != mClients->end();) { 137 delete pair.second;
140 delete (*it);
141 it = mClients->erase(it);
142 } 138 }
139 mClients.clear();
143 return 0; 140 return 0;
144} 141}
145 142
@@ -152,47 +149,30 @@ void *SocketListener::threadStart(void *obj) {
152} 149}
153 150
154void SocketListener::runListener() { 151void SocketListener::runListener() {
155 152 while (true) {
156 SocketClientCollection pendingList; 153 std::vector<pollfd> fds;
157
158 while(1) {
159 SocketClientCollection::iterator it;
160 fd_set read_fds;
161 int rc = 0;
162 int max = -1;
163
164 FD_ZERO(&read_fds);
165
166 if (mListen) {
167 max = mSock;
168 FD_SET(mSock, &read_fds);
169 }
170
171 FD_SET(mCtrlPipe[0], &read_fds);
172 if (mCtrlPipe[0] > max)
173 max = mCtrlPipe[0];
174 154
175 pthread_mutex_lock(&mClientsLock); 155 pthread_mutex_lock(&mClientsLock);
176 for (it = mClients->begin(); it != mClients->end(); ++it) { 156 fds.reserve(2 + mClients.size());
157 fds.push_back({.fd = mCtrlPipe[0], .events = POLLIN});
158 if (mListen) fds.push_back({.fd = mSock, .events = POLLIN});
159 for (auto pair : mClients) {
177 // NB: calling out to an other object with mClientsLock held (safe) 160 // NB: calling out to an other object with mClientsLock held (safe)
178 int fd = (*it)->getSocket(); 161 const int fd = pair.second->getSocket();
179 FD_SET(fd, &read_fds); 162 if (fd != pair.first) SLOGE("fd mismatch: %d != %d", fd, pair.first);
180 if (fd > max) { 163 fds.push_back({.fd = fd, .events = POLLIN});
181 max = fd;
182 }
183 } 164 }
184 pthread_mutex_unlock(&mClientsLock); 165 pthread_mutex_unlock(&mClientsLock);
185 SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName); 166
186 if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { 167 SLOGV("mListen=%d, mSocketName=%s", mListen, mSocketName);
187 if (errno == EINTR) 168 int rc = TEMP_FAILURE_RETRY(poll(fds.data(), fds.size(), -1));
188 continue; 169 if (rc < 0) {
189 SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max); 170 SLOGE("poll failed (%s) mListen=%d", strerror(errno), mListen);
190 sleep(1); 171 sleep(1);
191 continue; 172 continue;
192 } else if (!rc) 173 }
193 continue;
194 174
195 if (FD_ISSET(mCtrlPipe[0], &read_fds)) { 175 if (fds[0].revents & (POLLIN | POLLERR)) {
196 char c = CtrlPipe_Shutdown; 176 char c = CtrlPipe_Shutdown;
197 TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1)); 177 TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
198 if (c == CtrlPipe_Shutdown) { 178 if (c == CtrlPipe_Shutdown) {
@@ -200,7 +180,7 @@ void SocketListener::runListener() {
200 } 180 }
201 continue; 181 continue;
202 } 182 }
203 if (mListen && FD_ISSET(mSock, &read_fds)) { 183 if (mListen && (fds[1].revents & (POLLIN | POLLERR))) {
204 int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC)); 184 int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
205 if (c < 0) { 185 if (c < 0) {
206 SLOGE("accept failed (%s)", strerror(errno)); 186 SLOGE("accept failed (%s)", strerror(errno));
@@ -208,32 +188,33 @@ void SocketListener::runListener() {
208 continue; 188 continue;
209 } 189 }
210 pthread_mutex_lock(&mClientsLock); 190 pthread_mutex_lock(&mClientsLock);
211 mClients->push_back(new SocketClient(c, true, mUseCmdNum)); 191 mClients[c] = new SocketClient(c, true, mUseCmdNum);
212 pthread_mutex_unlock(&mClientsLock); 192 pthread_mutex_unlock(&mClientsLock);
213 } 193 }
214 194
215 /* Add all active clients to the pending list first */ 195 // Add all active clients to the pending list first, so we can release
216 pendingList.clear(); 196 // the lock before invoking the callbacks.
197 std::vector<SocketClient*> pending;
217 pthread_mutex_lock(&mClientsLock); 198 pthread_mutex_lock(&mClientsLock);
218 for (it = mClients->begin(); it != mClients->end(); ++it) { 199 const int size = fds.size();
219 SocketClient* c = *it; 200 for (int i = mListen ? 2 : 1; i < size; ++i) {
220 // NB: calling out to an other object with mClientsLock held (safe) 201 const struct pollfd& p = fds[i];
221 int fd = c->getSocket(); 202 if (p.events & (POLLIN | POLLERR)) {
222 if (FD_ISSET(fd, &read_fds)) { 203 auto it = mClients.find(p.fd);
223 pendingList.push_back(c); 204 if (it == mClients.end()) {
205 SLOGE("fd vanished: %d", p.fd);
206 continue;
207 }
208 SocketClient* c = it->second;
209 pending.push_back(c);
224 c->incRef(); 210 c->incRef();
225 } 211 }
226 } 212 }
227 pthread_mutex_unlock(&mClientsLock); 213 pthread_mutex_unlock(&mClientsLock);
228 214
229 /* Process the pending list, since it is owned by the thread, 215 for (SocketClient* c : pending) {
230 * there is no need to lock it */ 216 // Process it, if false is returned, remove from the map
231 while (!pendingList.empty()) { 217 SLOGV("processing fd %d", c->getSocket());
232 /* Pop the first item from the list */
233 it = pendingList.begin();
234 SocketClient* c = *it;
235 pendingList.erase(it);
236 /* Process it, if false is returned, remove from list */
237 if (!onDataAvailable(c)) { 218 if (!onDataAvailable(c)) {
238 release(c, false); 219 release(c, false);
239 } 220 }
@@ -246,17 +227,10 @@ bool SocketListener::release(SocketClient* c, bool wakeup) {
246 bool ret = false; 227 bool ret = false;
247 /* if our sockets are connection-based, remove and destroy it */ 228 /* if our sockets are connection-based, remove and destroy it */
248 if (mListen && c) { 229 if (mListen && c) {
249 /* Remove the client from our array */ 230 /* Remove the client from our map */
250 SLOGV("going to zap %d for %s", c->getSocket(), mSocketName); 231 SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
251 pthread_mutex_lock(&mClientsLock); 232 pthread_mutex_lock(&mClientsLock);
252 SocketClientCollection::iterator it; 233 ret = (mClients.erase(c->getSocket()) != 0);
253 for (it = mClients->begin(); it != mClients->end(); ++it) {
254 if (*it == c) {
255 mClients->erase(it);
256 ret = true;
257 break;
258 }
259 }
260 pthread_mutex_unlock(&mClientsLock); 234 pthread_mutex_unlock(&mClientsLock);
261 if (ret) { 235 if (ret) {
262 ret = c->decRef(); 236 ret = c->decRef();
@@ -270,25 +244,19 @@ bool SocketListener::release(SocketClient* c, bool wakeup) {
270} 244}
271 245
272void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { 246void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
273 SocketClientCollection safeList; 247 // Add all clients to a separate list first, so we don't have to hold
274 248 // the lock while processing it.
275 /* Add all active clients to the safe list first */ 249 std::vector<SocketClient*> clients;
276 safeList.clear();
277 pthread_mutex_lock(&mClientsLock); 250 pthread_mutex_lock(&mClientsLock);
278 SocketClientCollection::iterator i; 251 clients.reserve(mClients.size());
279 252 for (auto pair : mClients) {
280 for (i = mClients->begin(); i != mClients->end(); ++i) { 253 SocketClient* c = pair.second;
281 SocketClient* c = *i;
282 c->incRef(); 254 c->incRef();
283 safeList.push_back(c); 255 clients.push_back(c);
284 } 256 }
285 pthread_mutex_unlock(&mClientsLock); 257 pthread_mutex_unlock(&mClientsLock);
286 258
287 while (!safeList.empty()) { 259 for (SocketClient* c : clients) {
288 /* Pop the first item from the list */
289 i = safeList.begin();
290 SocketClient* c = *i;
291 safeList.erase(i);
292 // broadcasts are unsolicited and should not include a cmd number 260 // broadcasts are unsolicited and should not include a cmd number
293 if (c->sendMsg(code, msg, addErrno, false)) { 261 if (c->sendMsg(code, msg, addErrno, false)) {
294 SLOGW("Error sending broadcast (%s)", strerror(errno)); 262 SLOGW("Error sending broadcast (%s)", strerror(errno));
@@ -298,25 +266,19 @@ void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
298} 266}
299 267
300void SocketListener::runOnEachSocket(SocketClientCommand *command) { 268void SocketListener::runOnEachSocket(SocketClientCommand *command) {
301 SocketClientCollection safeList; 269 // Add all clients to a separate list first, so we don't have to hold
302 270 // the lock while processing it.
303 /* Add all active clients to the safe list first */ 271 std::vector<SocketClient*> clients;
304 safeList.clear();
305 pthread_mutex_lock(&mClientsLock); 272 pthread_mutex_lock(&mClientsLock);
306 SocketClientCollection::iterator i; 273 clients.reserve(mClients.size());
307 274 for (auto pair : mClients) {
308 for (i = mClients->begin(); i != mClients->end(); ++i) { 275 SocketClient* c = pair.second;
309 SocketClient* c = *i;
310 c->incRef(); 276 c->incRef();
311 safeList.push_back(c); 277 clients.push_back(c);
312 } 278 }
313 pthread_mutex_unlock(&mClientsLock); 279 pthread_mutex_unlock(&mClientsLock);
314 280
315 while (!safeList.empty()) { 281 for (SocketClient* c : clients) {
316 /* Pop the first item from the list */
317 i = safeList.begin();
318 SocketClient* c = *i;
319 safeList.erase(i);
320 command->runSocketCommand(c); 282 command->runSocketCommand(c);
321 c->decRef(); 283 c->decRef();
322 } 284 }