Skip to content

Commit

Permalink
common: Adding Select class
Browse files Browse the repository at this point in the history
The Select class implements ::select (2) API with multiple tables or
file-descriptor.

Usage:
  Select cs;
  cs.addSelectable(&netlink);
  cs.addSelectable(&consumerTable);

  while (true)
  {
    Selectable *object;
    int tempfd;
    if (s.select(&object, &tempfd) != Select::OBJECT)
      break;

    // Check if object is consumerTable or netlink
  }

Signed-off-by: Elad Raz <[email protected]>
  • Loading branch information
eladraz authored and Shuotian Cheng committed Mar 7, 2016
1 parent 347ba0a commit ebb7957
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 1 deletion.
3 changes: 2 additions & 1 deletion common/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ libswsscommon_la_SOURCES = \
dbconnector.cpp \
table.cpp \
json.cpp \
producertable.cpp
producertable.cpp \
select.cpp

libswsscommon_la_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON)
libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON)
Expand Down
81 changes: 81 additions & 0 deletions common/select.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "common/selectable.h"
#include "common/select.h"
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>

using namespace std;

namespace swss {

void Select::addSelectable(Selectable *c)
{
m_objects.push_back(c);
}

void Select::addFd(int fd)
{
m_fds.push_back(fd);
}

int Select::select(Selectable **c, int *fd, unsigned int timeout)
{
struct timeval t = {0, (suseconds_t)(timeout)*1000};
struct timeval *pTimeout = NULL;
fd_set fs;
int err;

FD_ZERO(&fs);
*c = NULL;
*fd = 0;
if (timeout != std::numeric_limits<unsigned int>::max())
pTimeout = &t;

/* Checking caching from reader */
for (Selectable *i : m_objects)
{
err = i->readCache();
if (err == Selectable::ERROR)
return Select::ERROR;
else if (err == Selectable::DATA) {
*c = i;
return Select::OBJECT;
}
/* else, timeout = no data */

i->addFd(&fs);
}

for (int fd : m_fds)
{
FD_SET(fd, &fs);
}

err = ::select(FD_SETSIZE, &fs, NULL, NULL, pTimeout);
if (err < 0)
return Select::ERROR;
if (err == 0)
return Select::TIMEOUT;

/* Check other consumer-table */
for (Selectable *i : m_objects)
if (i->isMe(&fs))
{
i->readMe();
*c = i;
return Select::OBJECT;
}

/* Check other FDs */
for (int f : m_fds)
if (FD_ISSET(f, &fs))
{
*fd = f;
return Select::FD;
}

/* Shouldn't reach here */
return Select::ERROR;
}

};
44 changes: 44 additions & 0 deletions common/select.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef __CONSUMERSELECT__
#define __CONSUMERSELECT__

#include <string>
#include <vector>
#include <limits>
#include <hiredis/hiredis.h>
#include "common/selectable.h"

namespace swss {

class Select
{
public:
/* Add object for select */
void addSelectable(Selectable *c);

/* Add file-descriptor for select */
void addFd(int fd);

/*
* Wait until data will arrived, returns the object on which select()
* was signaled.
*/
enum {
OBJECT = 0,
FD = 1,
ERROR = 2,
TIMEOUT = 3
};
int select(Selectable **c, int *fd,
unsigned int timeout = std::numeric_limits<unsigned int>::max());

private:
/* Create a new redisContext, SELECT DB and SUBSRIBE */
void subsribe();

std::vector<Selectable * > m_objects;
std::vector<int> m_fds;
};

}

#endif

0 comments on commit ebb7957

Please sign in to comment.