Created
November 21, 2016 14:08
-
-
Save johnchen902/043b9974319bf300cfdc40d3eb296472 to your computer and use it in GitHub Desktop.
boost::coroutine2 + ::select = ???
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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