/* * FdManager.cpp * * Copyright (C) 2008 Matthias Schiffer * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "FdManager.h" #include "ThreadManager.h" #include #include #include #include #include namespace Mad { namespace Net { FdManager FdManager::fdManager; FdManager::FdManager() : running(false) { pipe(interruptPipe); int flags = fcntl(interruptPipe[0], F_GETFL, 0); fcntl(interruptPipe[0], F_SETFL, flags | O_NONBLOCK); flags = fcntl(interruptPipe[1], F_GETFL, 0); fcntl(interruptPipe[1], F_SETFL, flags | O_NONBLOCK); registerFd(interruptPipe[0], sigc::hide(sigc::mem_fun(this, &FdManager::readInterrupt)), POLLIN); } FdManager::~FdManager() { unregisterFd(interruptPipe[0]); close(interruptPipe[0]); close(interruptPipe[1]); } bool FdManager::registerFd(int fd, const sigc::slot &handler, short events) { struct pollfd pollfd = {fd, events, 0}; boost::lock(handlerLock, eventLock); pollfds.insert(std::make_pair(fd, pollfd)); bool ret = handlers.insert(std::make_pair(fd, handler)).second; eventLock.unlock(); handlerLock.unlock(); interrupt(); return ret; } bool FdManager::unregisterFd(int fd) { boost::lock(handlerLock, eventLock); pollfds.erase(fd); bool ret = handlers.erase(fd); eventLock.unlock(); handlerLock.unlock(); interrupt(); return ret; } bool FdManager::setFdEvents(int fd, short events) { boost::unique_lock lock(eventLock); std::map::iterator pollfd = pollfds.find(fd); if(pollfd == pollfds.end()) return false; if(pollfd->second.events != events) { pollfd->second.events = events; interrupt(); } return true; } short FdManager::getFdEvents(int fd) { boost::shared_lock lock(eventLock); std::map::const_iterator pollfd = pollfds.find(fd); if(pollfd == pollfds.end()) return -1; return pollfd->second.events; } void FdManager::readInterrupt() { char buf[20]; while(read(interruptPipe[0], buf, sizeof(buf)) > 0) {} } void FdManager::interrupt() { char buf = 0; write(interruptPipe[1], &buf, sizeof(buf)); } void FdManager::ioThread() { runLock.lock(); running = true; runLock.unlock_and_lock_shared(); while(running) { runLock.unlock_shared(); handlerLock.lock_shared(); eventLock.lock_shared(); readInterrupt(); size_t count = pollfds.size(); struct pollfd *fdarray = new struct pollfd[count]; std::map::iterator pollfd = pollfds.begin(); for(size_t n = 0; n < count; ++n) { fdarray[n] = pollfd->second; ++pollfd; } eventLock.unlock_shared(); handlerLock.unlock_shared(); if(poll(fdarray, count, -1) > 0) { handlerLock.lock_shared(); std::queue > calls; for(size_t n = 0; n < count; ++n) { if(fdarray[n].revents) calls.push(sigc::bind(handlers[fdarray[n].fd], fdarray[n].revents)); } handlerLock.unlock_shared(); while(!calls.empty()) { calls.front()(); calls.pop(); } } delete [] fdarray; runLock.lock_shared(); } runLock.unlock_shared(); } } }