Merge "Revert "SocketListener: use poll() instead of select()""
diff --git a/libsysutils/include/sysutils/SocketClient.h b/libsysutils/include/sysutils/SocketClient.h
index c657526..1004f06 100644
--- a/libsysutils/include/sysutils/SocketClient.h
+++ b/libsysutils/include/sysutils/SocketClient.h
@@ -1,6 +1,8 @@
#ifndef _SOCKET_CLIENT_H
#define _SOCKET_CLIENT_H
+#include "List.h"
+
#include <pthread.h>
#include <cutils/atomic.h>
#include <sys/types.h>
@@ -33,7 +35,7 @@
SocketClient(int sock, bool owned, bool useCmdNum);
virtual ~SocketClient();
- int getSocket() const { return mSocket; }
+ int getSocket() { return mSocket; }
pid_t getPid() const { return mPid; }
uid_t getUid() const { return mUid; }
gid_t getGid() const { return mGid; }
@@ -82,4 +84,5 @@
int sendDataLockedv(struct iovec *iov, int iovcnt);
};
+typedef android::sysutils::List<SocketClient *> SocketClientCollection;
#endif
diff --git a/libsysutils/include/sysutils/SocketListener.h b/libsysutils/include/sysutils/SocketListener.h
index 56f2478..bc93b86 100644
--- a/libsysutils/include/sysutils/SocketListener.h
+++ b/libsysutils/include/sysutils/SocketListener.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,8 +18,6 @@
#include <pthread.h>
-#include <unordered_map>
-
#include <sysutils/SocketClient.h>
#include "SocketClientCommand.h"
@@ -27,7 +25,7 @@
bool mListen;
const char *mSocketName;
int mSock;
- std::unordered_map<int, SocketClient*> mClients;
+ SocketClientCollection *mClients;
pthread_mutex_t mClientsLock;
int mCtrlPipe[2];
pthread_t mThread;
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 128a27a..3f8f3db 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,15 +19,13 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <sys/poll.h>
+#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
-#include <vector>
-
#include <cutils/sockets.h>
#include <log/log.h>
#include <sysutils/SocketListener.h>
@@ -54,6 +52,7 @@
mSock = socketFd;
mUseCmdNum = useCmdNum;
pthread_mutex_init(&mClientsLock, NULL);
+ mClients = new SocketClientCollection();
}
SocketListener::~SocketListener() {
@@ -64,9 +63,12 @@
close(mCtrlPipe[0]);
close(mCtrlPipe[1]);
}
- for (auto pair : mClients) {
- pair.second->decRef();
+ SocketClientCollection::iterator it;
+ for (it = mClients->begin(); it != mClients->end();) {
+ (*it)->decRef();
+ it = mClients->erase(it);
}
+ delete mClients;
}
int SocketListener::startListener() {
@@ -93,7 +95,7 @@
SLOGE("Unable to listen on socket (%s)", strerror(errno));
return -1;
} else if (!mListen)
- mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum);
+ mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
if (pipe(mCtrlPipe)) {
SLOGE("pipe failed (%s)", strerror(errno));
@@ -133,10 +135,11 @@
mSock = -1;
}
- for (auto pair : mClients) {
- delete pair.second;
+ SocketClientCollection::iterator it;
+ for (it = mClients->begin(); it != mClients->end();) {
+ delete (*it);
+ it = mClients->erase(it);
}
- mClients.clear();
return 0;
}
@@ -149,30 +152,47 @@
}
void SocketListener::runListener() {
- while (true) {
- std::vector<pollfd> fds;
+
+ SocketClientCollection pendingList;
+
+ while(1) {
+ SocketClientCollection::iterator it;
+ fd_set read_fds;
+ int rc = 0;
+ int max = -1;
+
+ FD_ZERO(&read_fds);
+
+ if (mListen) {
+ max = mSock;
+ FD_SET(mSock, &read_fds);
+ }
+
+ FD_SET(mCtrlPipe[0], &read_fds);
+ if (mCtrlPipe[0] > max)
+ max = mCtrlPipe[0];
pthread_mutex_lock(&mClientsLock);
- fds.reserve(2 + mClients.size());
- fds.push_back({.fd = mCtrlPipe[0], .events = POLLIN});
- if (mListen) fds.push_back({.fd = mSock, .events = POLLIN});
- for (auto pair : mClients) {
+ for (it = mClients->begin(); it != mClients->end(); ++it) {
// NB: calling out to an other object with mClientsLock held (safe)
- const int fd = pair.second->getSocket();
- if (fd != pair.first) SLOGE("fd mismatch: %d != %d", fd, pair.first);
- fds.push_back({.fd = fd, .events = POLLIN});
+ int fd = (*it)->getSocket();
+ FD_SET(fd, &read_fds);
+ if (fd > max) {
+ max = fd;
+ }
}
pthread_mutex_unlock(&mClientsLock);
-
- SLOGV("mListen=%d, mSocketName=%s", mListen, mSocketName);
- int rc = TEMP_FAILURE_RETRY(poll(fds.data(), fds.size(), -1));
- if (rc < 0) {
- SLOGE("poll failed (%s) mListen=%d", strerror(errno), mListen);
+ SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
+ if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
+ if (errno == EINTR)
+ continue;
+ SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
sleep(1);
continue;
- }
+ } else if (!rc)
+ continue;
- if (fds[0].revents & (POLLIN | POLLERR)) {
+ if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
char c = CtrlPipe_Shutdown;
TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
if (c == CtrlPipe_Shutdown) {
@@ -180,7 +200,7 @@
}
continue;
}
- if (mListen && (fds[1].revents & (POLLIN | POLLERR))) {
+ if (mListen && FD_ISSET(mSock, &read_fds)) {
int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
if (c < 0) {
SLOGE("accept failed (%s)", strerror(errno));
@@ -188,33 +208,32 @@
continue;
}
pthread_mutex_lock(&mClientsLock);
- mClients[c] = new SocketClient(c, true, mUseCmdNum);
+ mClients->push_back(new SocketClient(c, true, mUseCmdNum));
pthread_mutex_unlock(&mClientsLock);
}
- // Add all active clients to the pending list first, so we can release
- // the lock before invoking the callbacks.
- std::vector<SocketClient*> pending;
+ /* Add all active clients to the pending list first */
+ pendingList.clear();
pthread_mutex_lock(&mClientsLock);
- const int size = fds.size();
- for (int i = mListen ? 2 : 1; i < size; ++i) {
- const struct pollfd& p = fds[i];
- if (p.events & (POLLIN | POLLERR)) {
- auto it = mClients.find(p.fd);
- if (it == mClients.end()) {
- SLOGE("fd vanished: %d", p.fd);
- continue;
- }
- SocketClient* c = it->second;
- pending.push_back(c);
+ for (it = mClients->begin(); it != mClients->end(); ++it) {
+ SocketClient* c = *it;
+ // NB: calling out to an other object with mClientsLock held (safe)
+ int fd = c->getSocket();
+ if (FD_ISSET(fd, &read_fds)) {
+ pendingList.push_back(c);
c->incRef();
}
}
pthread_mutex_unlock(&mClientsLock);
- for (SocketClient* c : pending) {
- // Process it, if false is returned, remove from the map
- SLOGV("processing fd %d", c->getSocket());
+ /* Process the pending list, since it is owned by the thread,
+ * there is no need to lock it */
+ while (!pendingList.empty()) {
+ /* Pop the first item from the list */
+ it = pendingList.begin();
+ SocketClient* c = *it;
+ pendingList.erase(it);
+ /* Process it, if false is returned, remove from list */
if (!onDataAvailable(c)) {
release(c, false);
}
@@ -227,10 +246,17 @@
bool ret = false;
/* if our sockets are connection-based, remove and destroy it */
if (mListen && c) {
- /* Remove the client from our map */
+ /* Remove the client from our array */
SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
pthread_mutex_lock(&mClientsLock);
- ret = (mClients.erase(c->getSocket()) != 0);
+ SocketClientCollection::iterator it;
+ for (it = mClients->begin(); it != mClients->end(); ++it) {
+ if (*it == c) {
+ mClients->erase(it);
+ ret = true;
+ break;
+ }
+ }
pthread_mutex_unlock(&mClientsLock);
if (ret) {
ret = c->decRef();
@@ -244,19 +270,25 @@
}
void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
- // Add all clients to a separate list first, so we don't have to hold
- // the lock while processing it.
- std::vector<SocketClient*> clients;
+ SocketClientCollection safeList;
+
+ /* Add all active clients to the safe list first */
+ safeList.clear();
pthread_mutex_lock(&mClientsLock);
- clients.reserve(mClients.size());
- for (auto pair : mClients) {
- SocketClient* c = pair.second;
+ SocketClientCollection::iterator i;
+
+ for (i = mClients->begin(); i != mClients->end(); ++i) {
+ SocketClient* c = *i;
c->incRef();
- clients.push_back(c);
+ safeList.push_back(c);
}
pthread_mutex_unlock(&mClientsLock);
- for (SocketClient* c : clients) {
+ while (!safeList.empty()) {
+ /* Pop the first item from the list */
+ i = safeList.begin();
+ SocketClient* c = *i;
+ safeList.erase(i);
// broadcasts are unsolicited and should not include a cmd number
if (c->sendMsg(code, msg, addErrno, false)) {
SLOGW("Error sending broadcast (%s)", strerror(errno));
@@ -266,19 +298,25 @@
}
void SocketListener::runOnEachSocket(SocketClientCommand *command) {
- // Add all clients to a separate list first, so we don't have to hold
- // the lock while processing it.
- std::vector<SocketClient*> clients;
+ SocketClientCollection safeList;
+
+ /* Add all active clients to the safe list first */
+ safeList.clear();
pthread_mutex_lock(&mClientsLock);
- clients.reserve(mClients.size());
- for (auto pair : mClients) {
- SocketClient* c = pair.second;
+ SocketClientCollection::iterator i;
+
+ for (i = mClients->begin(); i != mClients->end(); ++i) {
+ SocketClient* c = *i;
c->incRef();
- clients.push_back(c);
+ safeList.push_back(c);
}
pthread_mutex_unlock(&mClientsLock);
- for (SocketClient* c : clients) {
+ while (!safeList.empty()) {
+ /* Pop the first item from the list */
+ i = safeList.begin();
+ SocketClient* c = *i;
+ safeList.erase(i);
command->runSocketCommand(c);
c->decRef();
}