Skip to content

Instantly share code, notes, and snippets.

@johnchen902
Created November 21, 2016 14:08
Show Gist options
  • Save johnchen902/043b9974319bf300cfdc40d3eb296472 to your computer and use it in GitHub Desktop.
Save johnchen902/043b9974319bf300cfdc40d3eb296472 to your computer and use it in GitHub Desktop.
boost::coroutine2 + ::select = ???
#include <stdio.h>
#include <boost/coroutine2/coroutine.hpp>
#include <sys/select.h>
#include <list>
#include <utility>
namespace coselect {
struct tri_fd_set {
fd_set read, write, except;
tri_fd_set () {
FD_ZERO(&read);
FD_ZERO(&write);
FD_ZERO(&except);
}
};
using coro_t = boost::coroutines2::coroutine<tri_fd_set>;
using handle_t = coro_t::push_type;
using pull_handle_t = coro_t::pull_type;
void select(handle_t &handle, tri_fd_set &set) {
handle(set);
struct timeval tv { 0, 0 };
::select(FD_SETSIZE, &set.read, &set.write,
&set.except, &tv);
}
bool operator && (const fd_set &lhs, const fd_set &rhs) {
for(int i = 0; i < FD_SETSIZE; i++)
if(FD_ISSET(i, &lhs) && FD_ISSET(i, &rhs))
return true;
return false;
}
bool operator && (const tri_fd_set &lhs, const tri_fd_set &rhs) {
return (lhs.read && rhs.read) ||
(lhs.write && rhs.write) ||
(lhs.except && rhs.except);
}
fd_set &operator |= (fd_set &lhs, const fd_set &rhs) {
for(int i = 0; i < FD_SETSIZE; i++)
if(FD_ISSET(i, &rhs))
FD_SET(i, &lhs);
return lhs;
}
tri_fd_set &operator |= (tri_fd_set &lhs, const tri_fd_set &rhs) {
lhs.read |= rhs.read;
lhs.write |= rhs.write;
lhs.except |= rhs.except;
return lhs;
}
void select_loop(std::list<pull_handle_t> handles) {
for(auto it = handles.begin(); it != handles.end();)
if(*it)
++it;
else
it = handles.erase(it);
while(!handles.empty()) {
tri_fd_set set;
for(pull_handle_t &handle : handles)
set |= handle.get();
int result = ::select(FD_SETSIZE,
&set.read, &set.write, &set.except, nullptr);
if(result < 0) {
::perror("select");
continue; // XXX what to do
}
for(auto it = handles.begin(); it != handles.end(); )
if((set && it->get()) && !(*it)())
it = handles.erase(it);
else
++it;
}
}
}
int main() {
std::list<coselect::pull_handle_t> handles;
handles.emplace_back(
[](coselect::handle_t &handle) {
while(true) {
{
coselect::tri_fd_set set;
FD_SET(STDIN_FILENO, &set.read);
coselect::select(handle, set);
}
char buf[4096];
ssize_t sz = read(STDIN_FILENO, buf, 4096);
if(sz < 0) {
perror("read");
continue;
}
if(sz == 0)
break;
{
coselect::tri_fd_set set;
FD_SET(STDOUT_FILENO, &set.write);
coselect::select(handle, set);
}
if(write(STDOUT_FILENO, buf, sz) < 0)
perror("write");
}
});
handles.emplace_back([](coselect::handle_t &) {});
// TODO add more handles
coselect::select_loop(std::move(handles));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment