/* * 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) { gl_rwlock_init(handlerLock); gl_rwlock_init(eventLock); gl_rwlock_init(runLock); 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]); gl_rwlock_destroy(runLock); gl_rwlock_destroy(eventLock); gl_rwlock_destroy(handlerLock); } bool FdManager::registerFd(int fd, const sigc::slot &handler, short events) { struct pollfd pollfd = {fd, events, 0}; gl_rwlock_wrlock(handlerLock); gl_rwlock_wrlock(eventLock); pollfds.insert(std::make_pair(fd, pollfd)); bool ret = handlers.insert(std::make_pair(fd, handler)).second; gl_rwlock_unlock(eventLock); gl_rwlock_unlock(handlerLock); interrupt(); return ret; } bool FdManager::unregisterFd(int fd) { gl_rwlock_wrlock(handlerLock); gl_rwlock_wrlock(eventLock); pollfds.erase(fd); bool ret = handlers.erase(fd); gl_rwlock_unlock(eventLock); gl_rwlock_unlock(handlerLock); interrupt(); return ret; } bool FdManager::setFdEvents(int fd, short events) { gl_rwlock_wrlock(eventLock); std::map::iterator pollfd = pollfds.find(fd); if(pollfd == pollfds.end()) { gl_rwlock_unlock(eventLock); return false; } if(pollfd->second.events != events) { pollfd->second.events = events; interrupt(); } gl_rwlock_unlock(eventLock); return true; } short FdManager::getFdEvents(int fd) { gl_rwlock_rdlock(eventLock); std::map::const_iterator pollfd = pollfds.find(fd); if(pollfd == pollfds.end()) return -1; short ret = pollfd->second.events; gl_rwlock_unlock(eventLock); return ret; } 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() { gl_rwlock_wrlock(runLock); running = true; gl_rwlock_unlock(runLock); gl_rwlock_rdlock(runLock); while(running) { gl_rwlock_unlock(runLock); gl_rwlock_rdlock(handlerLock); gl_rwlock_rdlock(eventLock); 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; } gl_rwlock_unlock(eventLock); gl_rwlock_unlock(handlerLock); if(poll(fdarray, count, -1) > 0) { gl_rwlock_rdlock(handlerLock); 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)); } gl_rwlock_unlock(handlerLock); while(!calls.empty()) { calls.front()(); calls.pop(); } } delete [] fdarray; gl_rwlock_rdlock(runLock); } gl_rwlock_unlock(runLock); } } }