libsysutils: SocketListener export release

* Foreground thread (legacy) closes connection by
  reporting false return value for onDataAvailable.
* Background thread can choose instead to close the
  connection asynchronously by calling release, must
  return true for the onDataAvailable method.

Change-Id: I70ab37d5c22b02804aa3b4dfb26cc9b75291f8b6
This commit is contained in:
Mark Salyzyn 2014-01-08 12:44:23 -08:00
parent a6e965578e
commit d7ad4e409e
2 changed files with 53 additions and 26 deletions

View File

@ -44,10 +44,13 @@ public:
void runOnEachSocket(SocketClientCommand *command);
bool release(SocketClient *c) { return release(c, true); }
protected:
virtual bool onDataAvailable(SocketClient *c) = 0;
private:
bool release(SocketClient *c, bool wakeup);
static void *threadStart(void *obj);
void runListener();
void init(const char *socketName, int socketFd, bool listen, bool useCmdNum);

View File

@ -29,6 +29,9 @@
#include <sysutils/SocketListener.h>
#include <sysutils/SocketClient.h>
#define CtrlPipe_Shutdown 0
#define CtrlPipe_Wakeup 1
SocketListener::SocketListener(const char *socketName, bool listen) {
init(socketName, -1, listen, false);
}
@ -101,7 +104,7 @@ int SocketListener::startListener() {
}
int SocketListener::stopListener() {
char c = 0;
char c = CtrlPipe_Shutdown;
int rc;
rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
@ -143,7 +146,7 @@ void *SocketListener::threadStart(void *obj) {
void SocketListener::runListener() {
SocketClientCollection *pendingList = new SocketClientCollection();
SocketClientCollection pendingList;
while(1) {
SocketClientCollection::iterator it;
@ -167,8 +170,9 @@ void SocketListener::runListener() {
// NB: calling out to an other object with mClientsLock held (safe)
int fd = (*it)->getSocket();
FD_SET(fd, &read_fds);
if (fd > max)
if (fd > max) {
max = fd;
}
}
pthread_mutex_unlock(&mClientsLock);
SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
@ -181,8 +185,14 @@ void SocketListener::runListener() {
} else if (!rc)
continue;
if (FD_ISSET(mCtrlPipe[0], &read_fds))
break;
if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
char c = CtrlPipe_Shutdown;
TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
if (c == CtrlPipe_Shutdown) {
break;
}
continue;
}
if (mListen && FD_ISSET(mSock, &read_fds)) {
struct sockaddr addr;
socklen_t alen;
@ -204,14 +214,14 @@ void SocketListener::runListener() {
}
/* Add all active clients to the pending list first */
pendingList->clear();
pendingList.clear();
pthread_mutex_lock(&mClientsLock);
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);
pendingList.push_back(c);
c->incRef();
}
}
@ -219,31 +229,45 @@ void SocketListener::runListener() {
/* Process the pending list, since it is owned by the thread,
* there is no need to lock it */
while (!pendingList->empty()) {
while (!pendingList.empty()) {
/* Pop the first item from the list */
it = pendingList->begin();
it = pendingList.begin();
SocketClient* c = *it;
pendingList->erase(it);
/* Process it, if false is returned and our sockets are
* connection-based, remove and destroy it */
if (!onDataAvailable(c) && mListen) {
/* Remove the client from our array */
SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
if (*it == c) {
mClients->erase(it);
break;
}
}
pthread_mutex_unlock(&mClientsLock);
/* Remove our reference to the client */
c->decRef();
pendingList.erase(it);
/* Process it, if false is returned, remove from list */
if (!onDataAvailable(c)) {
release(c, false);
}
c->decRef();
}
}
delete pendingList;
}
bool SocketListener::release(SocketClient* c, bool wakeup) {
bool ret = false;
/* if our sockets are connection-based, remove and destroy it */
if (mListen && c) {
/* Remove the client from our array */
SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
pthread_mutex_lock(&mClientsLock);
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();
if (wakeup) {
char b = CtrlPipe_Wakeup;
TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &b, 1));
}
}
}
return ret;
}
void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {