├── Define.h ├── README.md ├── IAcceptorCallback.h ├── IChannelCallback.h ├── main.cc ├── Thread.h ├── IRun.h ├── IMuduoUser.h ├── Task.h ├── Declear.h ├── Epoll.h ├── Buffer.h ├── Task.cc ├── CurrentThread.h ├── ThreadPool.h ├── Thread.cc ├── Acceptor.h ├── Timestamp.h ├── Buffer.cc ├── ThreadPool.cc ├── TcpServer.h ├── EchoServer.h ├── Channel.h ├── Condition.h ├── TcpServer.cc ├── BlockingQueue.h ├── Timer.h ├── Mutex.h ├── TcpConnection.h ├── EventLoop.h ├── Makefile ├── TimerQueue.h ├── Channel.cc ├── EchoServer.cc ├── Epoll.cc ├── Timestamp.cc ├── Acceptor.cc ├── EventLoop.cc ├── TcpConnection.cc └── TimerQueue.cc /Define.h: -------------------------------------------------------------------------------- 1 | #ifndef DEFINE_H 2 | #define DEFINE_H 3 | 4 | #define MAX_LINE 100 5 | #define MAX_EVENTS 500 6 | #define MAX_LISTENFD 5 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### mini-muduo 2 | 3 | ### version:1.0 4 | 5 | ### 说明 6 | >1.基于reactor+ThreadPoll模型的多线程并发服务器,参考了陈硕的muduo网络库和网上的一些代码,后面有时间把它做成WebServer 7 | 2.实现了简单的接受、发送缓存区 8 | 3.加入了Timer定时器 9 | -------------------------------------------------------------------------------- /IAcceptorCallback.h: -------------------------------------------------------------------------------- 1 | #ifndef IACCEPTORCALLBACK_H 2 | #define IACCEPTORCALLBACK_H 3 | 4 | class IAcceptorCallback 5 | { 6 | public: 7 | virtual void newConnection(int sockfd) = 0; 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /IChannelCallback.h: -------------------------------------------------------------------------------- 1 | #ifndef ICHANNELCALLBACK_H 2 | #define ICHANNELCALLBACK_H 3 | 4 | class IChannelCallback 5 | { 6 | public: 7 | virtual void handleRead() = 0; 8 | virtual void handleWrite() = 0; 9 | }; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /main.cc: -------------------------------------------------------------------------------- 1 | #include "TcpServer.h" 2 | #include "EventLoop.h" 3 | #include "EchoServer.h" 4 | 5 | int main(int args, char** argv) 6 | { 7 | EventLoop loop; 8 | EchoServer echoserver(&loop); 9 | echoserver.start(); 10 | loop.loop(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /Thread.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_H 2 | #define THREAD_H 3 | 4 | #include "Declear.h" 5 | #include "Task.h" 6 | 7 | class Thread 8 | { 9 | public: 10 | Thread(Task& task); 11 | void start(); 12 | pid_t gettid(); 13 | private: 14 | Task _task; 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /IRun.h: -------------------------------------------------------------------------------- 1 | #ifndef IRUN_H 2 | #define IRUN_H 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | class IRun0 9 | { 10 | public: 11 | virtual void run0() = 0; 12 | }; 13 | 14 | class IRun2 15 | { 16 | public: 17 | virtual void run2(const string& str, void* param) = 0; 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /IMuduoUser.h: -------------------------------------------------------------------------------- 1 | #ifndef IMUDUOUSER_H 2 | #define IMUDUOUSER_H 3 | 4 | #include "Declear.h" 5 | #include 6 | using namespace std; 7 | 8 | class IMuduoUser 9 | { 10 | public: 11 | virtual void onConnection(TcpConnection* pCon) = 0; 12 | virtual void onMessage(TcpConnection* pCon, Buffer* pBuf) = 0; 13 | virtual void onWriteComplate(TcpConnection* pCon) = 0; 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /Task.h: -------------------------------------------------------------------------------- 1 | #ifndef TASK_H 2 | #define TASK_H 3 | 4 | #include "Declear.h" 5 | #include 6 | 7 | class Task 8 | { 9 | public: 10 | Task(IRun0* func); 11 | Task(IRun2* func, const std::string& str, void* param); 12 | void doTask(); 13 | private: 14 | IRun0* _func0; 15 | IRun2* _func2; 16 | std::string _str; 17 | void* _param; 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /Declear.h: -------------------------------------------------------------------------------- 1 | #ifndef DECLEAR_H 2 | #define DECLEAR_H 3 | 4 | class IChannelCallback; 5 | class IAcceptorCallback; 6 | class Channel; 7 | class Acceptor; 8 | class TcpConnection; 9 | class EventLoop; 10 | class Epoll; 11 | class IMuduoUser; 12 | class Buffer; 13 | class TimerQueue; 14 | class Timestamp; 15 | class IRun0; 16 | class IRun2; 17 | class Timer; 18 | class Task; 19 | class Thread; 20 | class ThreadPool; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /Epoll.h: -------------------------------------------------------------------------------- 1 | #ifndef EPOLL_H 2 | #define EPOLL_H 3 | 4 | #include 5 | 6 | #include "Declear.h" 7 | #include "Define.h" 8 | 9 | #include 10 | using namespace std; 11 | 12 | class Epoll 13 | { 14 | public: 15 | Epoll(); 16 | ~Epoll(); 17 | void poll(vector* pChannels); 18 | void update(Channel* pChannel); 19 | private: 20 | int _epollfd; 21 | struct epoll_event _events[MAX_EVENTS]; 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /Buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef BUFFER_H 2 | #define BUFFER_H 3 | 4 | #include 5 | using namespace std; 6 | 7 | class Buffer 8 | { 9 | public: 10 | Buffer(); 11 | ~Buffer(); 12 | const char* peek(); 13 | int readableBytes(); 14 | void retrieve(int len); 15 | void append(const string& buf); 16 | string retrieveAllAsString(); 17 | string retrieveAsString(size_t len); 18 | private: 19 | string _buf; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /Task.cc: -------------------------------------------------------------------------------- 1 | #include "Task.h" 2 | 3 | #include "IRun.h" 4 | 5 | Task::Task(IRun0* func) 6 | :_func0(func) 7 | ,_func2(NULL) 8 | ,_param(NULL) 9 | { 10 | 11 | } 12 | 13 | Task::Task(IRun2* func, const string& str, void* param) 14 | :_func0(NULL) 15 | ,_func2(func) 16 | ,_str(str) 17 | ,_param(param) 18 | { 19 | 20 | } 21 | 22 | void Task::doTask() 23 | { 24 | if(_func0) { 25 | _func0->run0(); 26 | } else { 27 | _func2->run2(_str, _param); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /CurrentThread.h: -------------------------------------------------------------------------------- 1 | #ifndef CURRENTTHREAD_H 2 | #define CURRENTTHREAD_H 3 | 4 | #include 5 | #include 6 | 7 | namespace CurrentThread 8 | { 9 | extern __thread int t_cachedTid; 10 | inline void cacheTid() 11 | { 12 | t_cachedTid = static_cast(::syscall(SYS_gettid)); 13 | } 14 | inline int tid() 15 | { 16 | if(t_cachedTid == 0) 17 | { 18 | cacheTid(); 19 | } 20 | return t_cachedTid; 21 | } 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /ThreadPool.h: -------------------------------------------------------------------------------- 1 | #ifndef THREADPOOL_H 2 | #define THREADPOOL_H 3 | 4 | #include "Declear.h" 5 | #include "BlockingQueue.h" 6 | #include "Task.h" 7 | #include "IRun.h" 8 | 9 | #include 10 | using namespace std; 11 | 12 | class ThreadPool : public IRun0 13 | { 14 | public: 15 | ThreadPool(); 16 | void start(int numThreads); 17 | void addTask(Task& task); 18 | virtual void run0(); 19 | private: 20 | void runInThread(); 21 | BlockingQueue _tasks; 22 | vector _threads; 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /Thread.cc: -------------------------------------------------------------------------------- 1 | #include "Thread.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace CurrentThread 8 | { 9 | __thread int t_cachedTid = 0; 10 | } 11 | 12 | void* globalRun(void* arg) 13 | { 14 | ((Task*)arg)->doTask(); 15 | return 0; 16 | } 17 | 18 | Thread::Thread(Task& task) 19 | :_task(task) 20 | { } 21 | 22 | void Thread::start() 23 | { 24 | pthread_t t; 25 | ::pthread_create(&t, NULL, globalRun, &_task); 26 | } 27 | 28 | pid_t Thread::gettid() 29 | { 30 | return static_cast(::syscall(SYS_gettid)); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Acceptor.h: -------------------------------------------------------------------------------- 1 | #ifndef ACCEPTOR_H 2 | #define ACCEPTOR_H 3 | 4 | #include "Declear.h" 5 | #include "Define.h" 6 | #include "IChannelCallback.h" 7 | 8 | class Acceptor : public IChannelCallback 9 | { 10 | public: 11 | Acceptor(EventLoop* pLoop); 12 | ~Acceptor(); 13 | 14 | void start(); 15 | void setCallback(IAcceptorCallback* pCallback); 16 | virtual void handleRead(); 17 | virtual void handleWrite(); 18 | private: 19 | int createAndListen(); 20 | int _listenfd; 21 | Channel* _pSocketAChannel; 22 | IAcceptorCallback* _pCallback; 23 | EventLoop* _pLoop; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /Timestamp.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMESTAMP_H 2 | #define TIMESTAMP_H 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | class Timestamp 9 | { 10 | public: 11 | Timestamp(double microSeconds = 0.0); 12 | ~Timestamp(); 13 | bool valid(); 14 | int64_t microSecondsSinceEpoch(); 15 | string toString() const; 16 | 17 | static Timestamp now(); 18 | static Timestamp nowAfter(double seconds); 19 | static double nowMicroSeconds(); 20 | static const int kMicroSecondsPerSecond = 1000 * 1000; 21 | private: 22 | int64_t _microSecondsSinceEpoch; 23 | }; 24 | bool operator <(Timestamp l, Timestamp r); 25 | bool operator ==(Timestamp l, Timestamp r); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /Buffer.cc: -------------------------------------------------------------------------------- 1 | #include "Buffer.h" 2 | 3 | Buffer::Buffer() 4 | {} 5 | 6 | Buffer::~Buffer() 7 | {} 8 | 9 | const char* Buffer::peek() 10 | { 11 | return _buf.c_str(); 12 | } 13 | 14 | int Buffer::readableBytes() 15 | { 16 | return static_cast(_buf.size()); 17 | } 18 | 19 | void Buffer::retrieve(int len) 20 | { 21 | _buf = _buf.substr(len, _buf.size()); 22 | } 23 | 24 | void Buffer::append(const string& data) 25 | { 26 | _buf.append(data); 27 | } 28 | 29 | string Buffer::retrieveAllAsString() 30 | { 31 | return retrieveAsString(readableBytes()); 32 | } 33 | 34 | string Buffer::retrieveAsString(size_t len) 35 | { 36 | string result(peek(), len); 37 | retrieve(len); 38 | return result; 39 | } 40 | -------------------------------------------------------------------------------- /ThreadPool.cc: -------------------------------------------------------------------------------- 1 | #include "ThreadPool.h" 2 | #include "Thread.h" 3 | 4 | ThreadPool::ThreadPool() { } 5 | 6 | void ThreadPool::start(int numThreads) 7 | { 8 | _threads.reserve(numThreads); 9 | for(int i = 0 ; i < numThreads; i++) 10 | { 11 | Task task(this); 12 | Thread* p = new Thread(task); 13 | _threads.push_back(p); 14 | p->start(); 15 | } 16 | } 17 | 18 | //virtual for Thread 19 | void ThreadPool::addTask(Task& task) 20 | { 21 | _tasks.put(task); 22 | } 23 | 24 | //virtual for Thread class 25 | void ThreadPool::run0() 26 | { 27 | runInThread(); 28 | } 29 | 30 | void ThreadPool::runInThread() 31 | { 32 | while(true) 33 | { 34 | _tasks.take().doTask(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /TcpServer.h: -------------------------------------------------------------------------------- 1 | #ifndef TCPSERVER_H 2 | #define TCPSERVER_H 3 | 4 | #include 5 | 6 | #include "Declear.h" 7 | #include "Define.h" 8 | #include "IAcceptorCallback.h" 9 | #include "IMuduoUser.h" 10 | 11 | #include 12 | using namespace std; 13 | 14 | class TcpServer : public IAcceptorCallback 15 | { 16 | public: 17 | TcpServer(EventLoop* pLoop); 18 | ~TcpServer(); 19 | void start(); 20 | void setCallback(IMuduoUser* pUser); 21 | virtual void newConnection(int sockfd); 22 | private: 23 | struct epoll_event _events[MAX_EVENTS]; 24 | map _connections; 25 | Acceptor* _pAcceptor; 26 | EventLoop* _pLoop; 27 | IMuduoUser* _pUser; 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /EchoServer.h: -------------------------------------------------------------------------------- 1 | #ifndef ECHOSERVER_H 2 | #define ECHOSERVER_H 3 | 4 | #include "IMuduoUser.h" 5 | #include "IRun.h" 6 | #include "TcpServer.h" 7 | #include "ThreadPool.h" 8 | 9 | class EchoServer : public IMuduoUser 10 | , public IRun2 11 | { 12 | public: 13 | EchoServer(EventLoop* pLoop); 14 | ~EchoServer(); 15 | void start(); 16 | virtual void onConnection(TcpConnection* pCon); 17 | virtual void onMessage(TcpConnection* pCon, Buffer* pBuf); 18 | virtual void onWriteComplate(TcpConnection* pCon); 19 | 20 | virtual void run2(const string& str, void* tcp); 21 | private: 22 | int fib(int n); 23 | EventLoop* _pLoop; 24 | TcpServer _pServer; 25 | ThreadPool _threadpool; 26 | int _timer; 27 | int _index; 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /Channel.h: -------------------------------------------------------------------------------- 1 | //author voidccc 2 | #ifndef CHANNEL_H 3 | #define CHANNEL_H 4 | 5 | #include "Declear.h" 6 | 7 | class Channel 8 | { 9 | public: 10 | Channel(EventLoop* pLoop, int sockfd); 11 | ~Channel(); 12 | void setCallback(IChannelCallback* pCallback); 13 | void handleEvent(); 14 | void setRevents(int revent); 15 | void setIndex(int index); 16 | void enableReading(); 17 | void enableWriting(); 18 | void disableWriting(); 19 | bool isWriting(); 20 | int getEvents(); 21 | int getfd(); 22 | int getIndex(); 23 | private: 24 | void update(); 25 | int _sockfd; 26 | int _events; 27 | int _revents; 28 | int _index; 29 | IChannelCallback* _pCallback; 30 | EventLoop* _pLoop; 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Condition.h: -------------------------------------------------------------------------------- 1 | #ifndef CONDITION_H 2 | #define CONDITION_H 3 | 4 | #include 5 | #include "Mutex.h" 6 | 7 | class Condition 8 | { 9 | public: 10 | Condition(MutexLock& mutex) 11 | :_mutex(mutex) 12 | { 13 | pthread_cond_init(&_condid, NULL); 14 | } 15 | ~Condition() 16 | { 17 | pthread_cond_destroy(&_condid); 18 | } 19 | void wait() 20 | { 21 | pthread_cond_wait(&_condid, _mutex.getPthreadMutex()); 22 | } 23 | void notify() 24 | { 25 | pthread_cond_signal(&_condid); 26 | } 27 | void notifyAll() 28 | { 29 | pthread_cond_broadcast(&_condid); 30 | } 31 | private: 32 | MutexLock& _mutex; 33 | pthread_cond_t _condid; 34 | }; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /TcpServer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "TcpServer.h" 4 | #include "Channel.h" 5 | #include "Acceptor.h" 6 | #include "TcpConnection.h" 7 | 8 | #include 9 | 10 | TcpServer::TcpServer(EventLoop* pLoop) 11 | :_pAcceptor(NULL) 12 | ,_pLoop(pLoop) 13 | ,_pUser(NULL) 14 | { 15 | } 16 | 17 | TcpServer::~TcpServer() 18 | { 19 | } 20 | 21 | void TcpServer::start() 22 | { 23 | _pAcceptor = new Acceptor(_pLoop); // Memory Leak !!! 24 | _pAcceptor->setCallback(this); 25 | _pAcceptor->start(); 26 | } 27 | 28 | void TcpServer::newConnection(int sockfd) 29 | { 30 | TcpConnection* tcp = new TcpConnection(sockfd, _pLoop); // Memory Leak !!! 31 | _connections[sockfd] = tcp; 32 | tcp->setUser(_pUser); 33 | tcp->connectEstablished(); 34 | } 35 | 36 | void TcpServer::setCallback(IMuduoUser* user) 37 | { 38 | _pUser = user; 39 | } 40 | -------------------------------------------------------------------------------- /BlockingQueue.h: -------------------------------------------------------------------------------- 1 | #ifndef BLOCKINGQUEUE_H 2 | #define BLOCKINGQUEUE_H 3 | 4 | #include 5 | #include "Condition.h" 6 | #include "Mutex.h" 7 | 8 | using namespace std; 9 | 10 | template 11 | class BlockingQueue 12 | { 13 | public: 14 | BlockingQueue() 15 | :_cond(_mutex) 16 | {} 17 | void put(const T& one) 18 | { 19 | MutexLockGuard lock(_mutex); 20 | _queue.push_back(one); 21 | _cond.notify(); 22 | } 23 | 24 | T take() 25 | { 26 | MutexLockGuard lock(_mutex); 27 | while(_queue.empty()) 28 | { 29 | _cond.wait(); 30 | } 31 | T front(_queue.front()); 32 | _queue.pop_front(); 33 | return front; 34 | } 35 | private: 36 | deque _queue; 37 | MutexLock _mutex; 38 | Condition _cond; 39 | }; 40 | #endif 41 | -------------------------------------------------------------------------------- /Timer.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_H 2 | #define TIMER_H 3 | 4 | #include "Declear.h" 5 | 6 | #include "IRun.h" 7 | 8 | class Timer 9 | { 10 | public: 11 | Timer(Timestamp stamp, IRun0* pRun, double interval) 12 | :_stamp(stamp) 13 | ,_id(stamp) 14 | ,_pRun0(pRun) 15 | ,_interval(interval) 16 | {} 17 | Timestamp getStamp() 18 | { 19 | return _stamp; 20 | } 21 | Timestamp getId() 22 | { 23 | return _id; 24 | } 25 | void timeout() 26 | { 27 | _pRun0->run0(); 28 | } 29 | 30 | bool isRepeat() 31 | { 32 | return _interval > 0.0; 33 | } 34 | 35 | void moveToNext() 36 | { 37 | _stamp = Timestamp::nowAfter(_interval); 38 | } 39 | private: 40 | Timestamp _stamp; 41 | Timestamp _id; 42 | IRun0* _pRun0; 43 | double _interval;//seconds 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /Mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef MUTEX_H 2 | #define MUTEX_H 3 | 4 | #include 5 | 6 | class MutexLock 7 | { 8 | public: 9 | MutexLock() 10 | { 11 | pthread_mutex_init(&_mutexid, NULL); 12 | } 13 | ~MutexLock() 14 | { 15 | pthread_mutex_destroy(&_mutexid); 16 | } 17 | void lock() 18 | { 19 | pthread_mutex_lock(&_mutexid); 20 | } 21 | void unlock() 22 | { 23 | pthread_mutex_unlock(&_mutexid); 24 | } 25 | 26 | pthread_mutex_t* getPthreadMutex() 27 | { 28 | return &_mutexid; 29 | } 30 | private: 31 | pthread_mutex_t _mutexid; 32 | }; 33 | 34 | class MutexLockGuard 35 | { 36 | public: 37 | MutexLockGuard(MutexLock& mutex) 38 | :_mutex(mutex) 39 | { 40 | _mutex.lock(); 41 | } 42 | ~MutexLockGuard() 43 | { 44 | _mutex.unlock(); 45 | } 46 | private: 47 | MutexLock& _mutex; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /TcpConnection.h: -------------------------------------------------------------------------------- 1 | #ifndef TCPCONNECTION_H 2 | #define TCPCONNECTION_H 3 | 4 | #include "Declear.h" 5 | #include "IChannelCallback.h" 6 | #include "Buffer.h" 7 | #include "IRun.h" 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | class TcpConnection : public IChannelCallback 13 | , public IRun0 14 | , public IRun2 15 | { 16 | public: 17 | TcpConnection(int sockfd, EventLoop* pLoop); 18 | ~TcpConnection(); 19 | void send(const string& message); 20 | void sendInLoop(const string& message); 21 | void connectEstablished(); 22 | void setUser(IMuduoUser* pUser); 23 | 24 | void setCallback(IAcceptorCallback* pCallback); 25 | virtual void handleRead(); 26 | virtual void handleWrite(); 27 | virtual void run0(); 28 | virtual void run2(const string& message, void* param); 29 | private: 30 | int _sockfd; 31 | Channel* _pSocketChannel; 32 | EventLoop* _pLoop; 33 | IMuduoUser* _pUser; 34 | Buffer _inBuf; 35 | Buffer _outBuf; 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /EventLoop.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENTLOOP_H 2 | #define EVENTLOOP_H 3 | 4 | #include "Declear.h" 5 | #include "IChannelCallback.h" 6 | #include "Task.h" 7 | #include "Mutex.h" 8 | 9 | #include 10 | using namespace std; 11 | 12 | class EventLoop : public IChannelCallback 13 | { 14 | public: 15 | EventLoop(); 16 | ~EventLoop(); 17 | void loop(); 18 | void update(Channel* pChannel); 19 | void queueInLoop(Task& task); 20 | void runInLoop(Task& task); 21 | int runAt(Timestamp when, IRun0* pRun); 22 | int runAfter(double delay, IRun0* pRun); 23 | int runEvery(double interval, IRun0* pRun); 24 | void cancelTimer(int timerfd); 25 | bool isInLoopThread(); 26 | 27 | virtual void handleRead(); 28 | virtual void handleWrite(); 29 | private: 30 | void wakeup(); 31 | int createEventfd(); 32 | void doPendingFunctors(); 33 | bool _quit; 34 | bool _callingPendingFunctors; 35 | Epoll* _pPoller; 36 | int _eventfd; 37 | const pid_t _threadId; 38 | Channel* _pEventfdChannel; 39 | MutexLock _mutex; 40 | vector _pendingFunctors; 41 | TimerQueue* _pTimerQueue; 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ##################################### 2 | # Copyright (c) 1997 George Foot (george.foot@merton.ox.ac.uk) 3 | # # All rights reserved. 4 | # ###################################### 5 | # #目标(可执行文档)名称,库(譬如stdcx,iostr,mysql等),头文件路径 6 | DESTINATION := mini-muduo 7 | LIBS := pthread 8 | INCLUDES := . 9 | 10 | 11 | RM := rm -f 12 | #C,CC或CPP文件的后缀 13 | PS=cc 14 | # GNU Make的隐含变量定义 15 | CC=g++ 16 | CPPFLAGS = -g -Wall -O3 -march=native 17 | CPPFLAGS += $(addprefix -I,$(INCLUDES)) 18 | CPPFLAGS += -MMD 19 | 20 | #以下部分无需修改 21 | SOURCE := $(wildcard *.$(PS)) 22 | OBJS := $(patsubst %.$(PS),%.o,$(SOURCE)) 23 | DEPS := $(patsubst %.o,%.d,$(OBJS)) 24 | MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS)) 25 | MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.$(PS),$(MISSING_DEPS))) 26 | 27 | .PHONY : all deps objs clean rebuild 28 | 29 | all : $(DESTINATION) 30 | 31 | deps : $(DEPS) 32 | $(CC) -MM -MMD $(SOURCE) 33 | 34 | 35 | objs : $(OBJS) 36 | 37 | clean : 38 | @$(RM) *.o 39 | @$(RM) *.d 40 | @$(RM) $(DESTINATION) 41 | 42 | rebuild: clean all 43 | 44 | ifneq ($(MISSING_DEPS),) 45 | $(MISSING_DEPS) : 46 | @$(RM) $(patsubst %.d,%.o,$@) 47 | endif 48 | 49 | -include $(DEPS) 50 | 51 | $(DESTINATION) : $(OBJS) 52 | $(CC) -o $(DESTINATION) $(OBJS) $(addprefix -l,$(LIBS)) 53 | #结束 54 | -------------------------------------------------------------------------------- /TimerQueue.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMERQUEUE_H 2 | #define TIMERQUEUE_H 3 | 4 | #include "Declear.h" 5 | #include "IChannelCallback.h" 6 | #include "IRun.h" 7 | #include "Timestamp.h" 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | class TimerQueue : public IChannelCallback 14 | , public IRun2 15 | { 16 | public: 17 | 18 | TimerQueue(EventLoop* pLoop); 19 | ~TimerQueue(); 20 | void doAddTimer(Timer* timer); 21 | void doCancelTimer(Timer* timer); 22 | long addTimer(IRun0* pRun, 23 | Timestamp when, 24 | double interval); 25 | void cancelTimer(long timerId); 26 | 27 | virtual void run2(const string& str, void* timer); 28 | 29 | virtual void handleRead(); 30 | virtual void handleWrite(); 31 | 32 | private: 33 | typedef std::pair Entry; 34 | typedef std::set TimerList; 35 | 36 | int createTimerfd(); 37 | vector getExpired(Timestamp now); 38 | void readTimerfd(int timerfd, Timestamp now); 39 | void reset(const vector& expired, Timestamp now); 40 | void resetTimerfd(int timerfd, Timestamp stamp); 41 | bool insert(Timer* pItem); 42 | struct timespec howMuchTimeFromNow(Timestamp when); 43 | 44 | int _timerfd; 45 | TimerList _pTimers; 46 | EventLoop* _pLoop; 47 | Channel* _pTimerfdChannel; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /Channel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Channel.h" 4 | #include "IChannelCallback.h" 5 | #include "EventLoop.h" 6 | 7 | #include 8 | using namespace std; 9 | 10 | Channel::Channel(EventLoop* pLoop, int sockfd) 11 | :_sockfd(sockfd) 12 | ,_events(0) 13 | ,_revents(0) 14 | ,_index(-1) 15 | ,_pCallback(NULL) 16 | ,_pLoop(pLoop) 17 | { 18 | } 19 | 20 | void Channel::setCallback(IChannelCallback* pCallback) 21 | { 22 | _pCallback = pCallback; 23 | } 24 | 25 | void Channel::setRevents(int revents) 26 | { 27 | _revents = revents; 28 | } 29 | 30 | void Channel::setIndex(int index) 31 | { 32 | _index = index; 33 | } 34 | 35 | void Channel::handleEvent() 36 | { 37 | if(_revents & EPOLLIN) 38 | { 39 | _pCallback->handleRead(); 40 | } 41 | if(_revents & EPOLLOUT) 42 | { 43 | _pCallback->handleWrite(); 44 | } 45 | } 46 | 47 | void Channel::enableReading() 48 | { 49 | _events |= EPOLLIN; 50 | update(); 51 | } 52 | 53 | void Channel::enableWriting() 54 | { 55 | _events |= EPOLLOUT; 56 | update(); 57 | } 58 | 59 | void Channel::disableWriting() 60 | { 61 | _events &= ~EPOLLOUT; 62 | update(); 63 | } 64 | 65 | bool Channel::isWriting() 66 | { 67 | return _events & EPOLLOUT; 68 | } 69 | 70 | void Channel::update() 71 | { 72 | _pLoop->update(this); 73 | } 74 | 75 | int Channel::getEvents() 76 | { 77 | return _events; 78 | } 79 | 80 | int Channel::getfd() 81 | { 82 | return _sockfd; 83 | } 84 | 85 | int Channel::getIndex() 86 | { 87 | return _index; 88 | } 89 | -------------------------------------------------------------------------------- /EchoServer.cc: -------------------------------------------------------------------------------- 1 | //author voidccc 2 | 3 | #include "EchoServer.h" 4 | #include "TcpConnection.h" 5 | #include "EventLoop.h" 6 | #include "CurrentThread.h" 7 | #include "Task.h" 8 | 9 | #include 10 | 11 | #define MESSAGE_LENGTH 8 12 | 13 | EchoServer::EchoServer(EventLoop* pLoop) 14 | :_pLoop(pLoop) 15 | ,_pServer(pLoop) 16 | ,_timer(-1) 17 | ,_index(0) 18 | { 19 | _pServer.setCallback(this); 20 | } 21 | 22 | EchoServer::~EchoServer() 23 | {} 24 | 25 | void EchoServer::start() 26 | { 27 | _pServer.start(); 28 | _threadpool.start(3); 29 | } 30 | 31 | void EchoServer::onConnection(TcpConnection* pCon) 32 | { 33 | cout << "onConnection" << endl; 34 | } 35 | 36 | void EchoServer::onMessage(TcpConnection* pCon, Buffer* pBuf) 37 | { 38 | while(pBuf->readableBytes() > MESSAGE_LENGTH) 39 | { 40 | string message = pBuf->retrieveAsString(MESSAGE_LENGTH); 41 | Task task(this, message, pCon); 42 | _threadpool.addTask(task); 43 | } 44 | } 45 | 46 | void EchoServer::onWriteComplate(TcpConnection* pCon) 47 | { 48 | cout << "onWriteComplate" << endl; 49 | } 50 | 51 | //run in different therad 52 | void EchoServer::run2(const string& str, void* tcp) 53 | { 54 | //IO blocking task or CPU busy task 55 | cout << "fib(30) = " << fib(30) << " tid = " << CurrentThread::tid() << endl; 56 | ((TcpConnection*)tcp)->send(str + "\n"); 57 | } 58 | 59 | //fib is short for Fibonacci, fib is a CPU busy method 60 | int EchoServer::fib(int n) 61 | { 62 | return (n == 1 || n == 2) ? 1 : (fib(n-1) + fib(n-2)); 63 | } 64 | -------------------------------------------------------------------------------- /Epoll.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Epoll.h" 4 | #include "Channel.h" 5 | #include "Define.h" 6 | 7 | #include 8 | using namespace std; 9 | 10 | const int kNew = -1; 11 | const int kAdded = 1; 12 | 13 | Epoll::Epoll() 14 | { 15 | _epollfd = ::epoll_create(1); 16 | if (_epollfd <= 0) 17 | cout << "epoll_create error, errno:" << _epollfd << endl; 18 | } 19 | 20 | Epoll::~Epoll() 21 | {} 22 | 23 | void Epoll::poll(vector* pChannels) 24 | { 25 | int fds = ::epoll_wait(_epollfd, _events, MAX_EVENTS, -1); 26 | if(fds == -1) 27 | { 28 | cout << "epoll_wait error, errno:" << errno << endl; 29 | return; 30 | } 31 | for(int i = 0; i < fds; i++) 32 | { 33 | Channel* pChannel = static_cast(_events[i].data.ptr); 34 | pChannel->setRevents(_events[i].events); 35 | pChannels->push_back(pChannel); 36 | } 37 | } 38 | 39 | void Epoll::update(Channel* pChannel) 40 | { 41 | int index = pChannel->getIndex(); 42 | if(index == kNew) 43 | { 44 | struct epoll_event ev; 45 | ev.data.ptr = pChannel; 46 | ev.events = pChannel->getEvents(); 47 | int fd = pChannel->getfd(); 48 | pChannel->setIndex(kAdded); 49 | ::epoll_ctl(_epollfd, EPOLL_CTL_ADD, fd, &ev); 50 | } 51 | else 52 | { 53 | struct epoll_event ev; 54 | ev.data.ptr = pChannel; 55 | ev.events = pChannel->getEvents(); 56 | int fd = pChannel->getfd(); 57 | ::epoll_ctl(_epollfd, EPOLL_CTL_MOD, fd, &ev); 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Timestamp.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define __STDC_FORMAT_MACROS 4 | #include 5 | #undef __STDC_FORMAT_MACROS 6 | 7 | #include "Timestamp.h" 8 | 9 | #include 10 | 11 | Timestamp::Timestamp(double microSeconds) 12 | :_microSecondsSinceEpoch(microSeconds) 13 | {} 14 | 15 | Timestamp::~Timestamp() 16 | {} 17 | 18 | bool Timestamp::valid() 19 | { 20 | return _microSecondsSinceEpoch > 0; 21 | } 22 | 23 | int64_t Timestamp::microSecondsSinceEpoch() 24 | { 25 | return _microSecondsSinceEpoch; 26 | } 27 | 28 | string Timestamp::toString() const 29 | { 30 | char buf[32] = {0}; 31 | int64_t seconds = _microSecondsSinceEpoch / kMicroSecondsPerSecond; 32 | int64_t microseconds = _microSecondsSinceEpoch % kMicroSecondsPerSecond; 33 | snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds); 34 | return buf; 35 | } 36 | 37 | Timestamp Timestamp::now() 38 | { 39 | return Timestamp(Timestamp::nowMicroSeconds()); 40 | } 41 | 42 | Timestamp Timestamp::nowAfter(double seconds) 43 | { 44 | return Timestamp(Timestamp::nowMicroSeconds() + kMicroSecondsPerSecond * seconds); 45 | } 46 | 47 | double Timestamp::nowMicroSeconds() 48 | { 49 | struct timeval tv; 50 | gettimeofday(&tv, NULL); 51 | int64_t seconds = tv.tv_sec; 52 | return seconds * kMicroSecondsPerSecond + tv.tv_usec; 53 | } 54 | 55 | bool operator<(Timestamp l, Timestamp r) 56 | { 57 | return l.microSecondsSinceEpoch() < r.microSecondsSinceEpoch(); 58 | } 59 | 60 | bool operator==(Timestamp l, Timestamp r) 61 | { 62 | cout << "operator ==" << endl; 63 | return l.microSecondsSinceEpoch() == r.microSecondsSinceEpoch(); 64 | } 65 | 66 | -------------------------------------------------------------------------------- /Acceptor.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "Acceptor.h" 6 | #include "Channel.h" 7 | #include "IAcceptorCallback.h" 8 | #include "EventLoop.h" 9 | 10 | #include 11 | using namespace std; 12 | 13 | Acceptor::Acceptor(EventLoop* pLoop) 14 | :_listenfd(-1) 15 | ,_pSocketAChannel(NULL) 16 | ,_pCallback(NULL) 17 | ,_pLoop(pLoop) 18 | {} 19 | 20 | Acceptor::~Acceptor() 21 | {} 22 | 23 | void Acceptor::start() 24 | { 25 | _listenfd = createAndListen(); 26 | _pSocketAChannel = new Channel(_pLoop, _listenfd); // Memory Leak !!! 27 | _pSocketAChannel->setCallback(this); 28 | _pSocketAChannel->enableReading(); 29 | } 30 | 31 | int Acceptor::createAndListen() 32 | { 33 | int on = 1; 34 | _listenfd = socket(AF_INET, SOCK_STREAM, 0); 35 | struct sockaddr_in servaddr; 36 | fcntl(_listenfd, F_SETFL, O_NONBLOCK); //no-block io 37 | setsockopt(_listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 38 | servaddr.sin_family = AF_INET; 39 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 40 | servaddr.sin_port = htons(11111); 41 | 42 | if(-1 == bind(_listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))) 43 | { 44 | cout << "bind error, errno:" << errno << endl; 45 | } 46 | 47 | if(-1 == listen(_listenfd, MAX_LISTENFD)) 48 | { 49 | cout << "listen error, errno:" << errno << endl; 50 | } 51 | return _listenfd; 52 | } 53 | 54 | void Acceptor::handleRead() 55 | { 56 | int connfd; 57 | struct sockaddr_in cliaddr; 58 | socklen_t clilen = sizeof(struct sockaddr_in); 59 | connfd = accept(_listenfd, (sockaddr*)&cliaddr, (socklen_t*)&clilen); 60 | if(connfd > 0) 61 | { 62 | cout << "new connection from " 63 | << "[" << inet_ntoa(cliaddr.sin_addr) 64 | << ":" << ntohs(cliaddr.sin_port) << "]" 65 | << " new socket fd:" << connfd 66 | << endl; 67 | } 68 | else 69 | { 70 | cout << "accept error, connfd:" << connfd 71 | << " errno:" << errno << endl; 72 | } 73 | fcntl(connfd, F_SETFL, O_NONBLOCK); //no-block io 74 | 75 | _pCallback->newConnection(connfd); 76 | } 77 | 78 | void Acceptor::handleWrite() 79 | { 80 | 81 | } 82 | 83 | void Acceptor::setCallback(IAcceptorCallback* pCallback) 84 | { 85 | _pCallback = pCallback; 86 | } 87 | -------------------------------------------------------------------------------- /EventLoop.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "EventLoop.h" 4 | #include "Channel.h" 5 | #include "Epoll.h" 6 | #include "TimerQueue.h" 7 | #include "Timestamp.h" 8 | #include "Task.h" 9 | #include "CurrentThread.h" 10 | 11 | #include 12 | using namespace std; 13 | 14 | EventLoop::EventLoop() 15 | :_quit(false) 16 | ,_callingPendingFunctors(false) 17 | ,_pPoller(new Epoll()) // Memory Leak !!! 18 | ,_threadId(CurrentThread::tid()) 19 | ,_pTimerQueue(new TimerQueue(this)) // Memory Leak!!! 20 | { 21 | _eventfd = createEventfd(); 22 | _pEventfdChannel = new Channel(this, _eventfd); // Memory Leak !!! 23 | _pEventfdChannel->setCallback(this); 24 | _pEventfdChannel->enableReading(); 25 | } 26 | 27 | EventLoop::~EventLoop() 28 | {} 29 | 30 | void EventLoop::loop() 31 | { 32 | while(!_quit) 33 | { 34 | vector channels; 35 | _pPoller->poll(&channels); 36 | 37 | vector::iterator it; 38 | for(it = channels.begin(); it != channels.end(); ++it) 39 | { 40 | (*it)->handleEvent(); 41 | } 42 | 43 | doPendingFunctors(); 44 | } 45 | } 46 | 47 | void EventLoop::update(Channel* pChannel) 48 | { 49 | _pPoller->update(pChannel); 50 | } 51 | 52 | void EventLoop::queueInLoop(Task& task) 53 | { 54 | { 55 | MutexLockGuard guard(_mutex); 56 | _pendingFunctors.push_back(task); 57 | } 58 | 59 | if(!isInLoopThread() || _callingPendingFunctors) 60 | { 61 | wakeup(); 62 | } 63 | } 64 | 65 | void EventLoop::runInLoop(Task& task) 66 | { 67 | if(isInLoopThread()) 68 | { 69 | task.doTask(); 70 | } 71 | else 72 | { 73 | queueInLoop(task); 74 | } 75 | } 76 | 77 | void EventLoop::wakeup() 78 | { 79 | uint64_t one = 1; 80 | ssize_t n = ::write(_eventfd, &one, sizeof one); 81 | if (n != sizeof one) 82 | { 83 | cout << "EventLoop::wakeup() writes " << n << " bytes instead of 8" << endl; 84 | } 85 | } 86 | 87 | int EventLoop::createEventfd() 88 | { 89 | int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 90 | if (evtfd < 0) 91 | { 92 | cout << "Failed in eventfd" << endl; 93 | } 94 | return evtfd; 95 | } 96 | 97 | void EventLoop::handleRead() 98 | { 99 | uint64_t one = 1; 100 | ssize_t n = ::read(_eventfd, &one, sizeof one); 101 | if (n != sizeof one) 102 | { 103 | cout << "EventEventLoop::handleRead() reads " << n << " bytes instead of 8" << endl; 104 | } 105 | } 106 | 107 | void EventLoop::handleWrite() 108 | {} 109 | 110 | void EventLoop::doPendingFunctors() 111 | { 112 | vector tempRuns; 113 | _callingPendingFunctors = true; 114 | { 115 | MutexLockGuard guard(_mutex); 116 | tempRuns.swap(_pendingFunctors); 117 | } 118 | vector::iterator it; 119 | for(it = tempRuns.begin(); it != tempRuns.end(); ++it) 120 | { 121 | it->doTask(); 122 | } 123 | _callingPendingFunctors = false; 124 | } 125 | int EventLoop::runAt(Timestamp when, IRun0* pRun) 126 | { 127 | return _pTimerQueue->addTimer(pRun, when, 0.0); 128 | } 129 | 130 | int EventLoop::runAfter(double delay, IRun0* pRun) 131 | { 132 | return _pTimerQueue->addTimer(pRun, Timestamp::nowAfter(delay), 0.0); 133 | } 134 | 135 | int EventLoop::runEvery(double interval, IRun0* pRun) 136 | { 137 | return _pTimerQueue->addTimer(pRun, Timestamp::nowAfter(interval), interval); 138 | } 139 | 140 | void EventLoop::cancelTimer(int timerId) 141 | { 142 | _pTimerQueue->cancelTimer(timerId); 143 | } 144 | 145 | bool EventLoop::isInLoopThread() 146 | { 147 | return _threadId == CurrentThread::tid(); 148 | } 149 | -------------------------------------------------------------------------------- /TcpConnection.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "TcpConnection.h" 7 | #include "Channel.h" 8 | #include "EventLoop.h" 9 | #include "Define.h" 10 | #include "IMuduoUser.h" 11 | #include "Task.h" 12 | 13 | #include //for bzero 14 | #include 15 | using namespace std; 16 | 17 | TcpConnection::TcpConnection(int sockfd, EventLoop* pLoop) 18 | :_sockfd(sockfd) 19 | ,_pLoop(pLoop) 20 | ,_pUser(NULL) 21 | { 22 | _pSocketChannel = new Channel(_pLoop, _sockfd); // Memory Leak !!! 23 | _pSocketChannel->setCallback(this); 24 | _pSocketChannel->enableReading(); 25 | } 26 | 27 | TcpConnection::~TcpConnection() 28 | {} 29 | 30 | void TcpConnection::handleRead() 31 | { 32 | int sockfd = _pSocketChannel->getfd(); 33 | int readlength; 34 | char line[MAX_LINE]; 35 | if(sockfd < 0) 36 | { 37 | cout << "EPOLLIN sockfd < 0 error " << endl; 38 | return; 39 | } 40 | bzero(line, MAX_LINE); 41 | if((readlength = read(sockfd, line, MAX_LINE)) < 0) 42 | { 43 | if(errno == ECONNRESET) 44 | { 45 | cout << "ECONNREST closed socket fd:" << sockfd << endl; 46 | close(sockfd); 47 | } 48 | } 49 | else if(readlength == 0) 50 | { 51 | cout << "read 0 closed socket fd:" << sockfd << endl; 52 | close(sockfd); 53 | } 54 | else 55 | { 56 | string linestr(line, readlength); 57 | _inBuf.append(linestr); 58 | _pUser->onMessage(this, &_inBuf); 59 | } 60 | } 61 | 62 | void TcpConnection::handleWrite() 63 | { 64 | int sockfd = _pSocketChannel->getfd(); 65 | if(_pSocketChannel->isWriting()) 66 | { 67 | int n = ::write(sockfd, _outBuf.peek(), _outBuf.readableBytes()); 68 | if( n > 0) 69 | { 70 | cout << "write " << n << " bytes data again" << endl; 71 | _outBuf.retrieve(n); 72 | if(_outBuf.readableBytes() == 0) 73 | { 74 | _pSocketChannel->disableWriting(); //remove EPOLLOUT 75 | Task task(this); 76 | _pLoop->queueInLoop(task); //invoke onWriteComplate 77 | } 78 | } 79 | } 80 | } 81 | 82 | void TcpConnection::send(const string& message) 83 | { 84 | if(_pLoop->isInLoopThread()) 85 | { 86 | sendInLoop(message); 87 | } 88 | else 89 | { 90 | Task task(this, message, this); 91 | _pLoop->runInLoop(task); 92 | } 93 | } 94 | 95 | void TcpConnection::sendInLoop(const string& message) 96 | { 97 | int n = 0; 98 | if(_outBuf.readableBytes() == 0) 99 | { 100 | n = ::write(_sockfd, message.c_str(), message.size()); 101 | if(n < 0) 102 | cout << "write error" << endl; 103 | if(n == static_cast(message.size())) 104 | { 105 | Task task(this); 106 | _pLoop->queueInLoop(task); //invoke onWriteComplate 107 | } 108 | } 109 | 110 | if( n < static_cast(message.size())) 111 | { 112 | _outBuf.append(message.substr(n, message.size())); 113 | if(!_pSocketChannel->isWriting()) 114 | { 115 | _pSocketChannel->enableWriting(); //add EPOLLOUT 116 | } 117 | } 118 | } 119 | 120 | void TcpConnection::connectEstablished() 121 | { 122 | if(_pUser) 123 | _pUser->onConnection(this); 124 | } 125 | 126 | void TcpConnection::setUser(IMuduoUser* user) 127 | { 128 | _pUser = user; 129 | } 130 | 131 | void TcpConnection::run0() 132 | { 133 | _pUser->onWriteComplate(this); 134 | } 135 | 136 | void TcpConnection::run2(const string& message, void* param) 137 | { 138 | sendInLoop(message); 139 | } 140 | -------------------------------------------------------------------------------- /TimerQueue.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "TimerQueue.h" 7 | #include "Channel.h" 8 | #include "EventLoop.h" 9 | #include "Timestamp.h" 10 | #include "Timer.h" 11 | #include "Task.h" 12 | 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | 18 | #define UINTPTR_MAX 0xffffffff 19 | 20 | TimerQueue::TimerQueue(EventLoop *pLoop) 21 | :_timerfd(createTimerfd()) 22 | ,_pLoop(pLoop) 23 | ,_pTimerfdChannel(new Channel(_pLoop, _timerfd)) // Memory Leak !!! 24 | { 25 | _pTimerfdChannel->setCallback(this); 26 | _pTimerfdChannel->enableReading(); 27 | } 28 | 29 | TimerQueue::~TimerQueue() 30 | { 31 | ::close(_timerfd); 32 | } 33 | 34 | void TimerQueue::run2(const string& str, void* timer) 35 | { 36 | if(str == "addtimer") 37 | { 38 | doAddTimer((Timer*)timer); 39 | } 40 | else if(str == "canceltimer") 41 | { 42 | doCancelTimer((Timer*)timer); 43 | } 44 | else { } 45 | } 46 | 47 | void TimerQueue::doAddTimer(Timer* pTimer) 48 | { 49 | bool earliestChanged = insert(pTimer); 50 | if(earliestChanged) 51 | { 52 | resetTimerfd(_timerfd, pTimer->getStamp()); 53 | } 54 | } 55 | 56 | void TimerQueue::doCancelTimer(Timer* pTimer) 57 | { 58 | Entry e(pTimer->getId(), pTimer); 59 | TimerList::iterator it; 60 | for(it = _pTimers.begin(); it != _pTimers.end(); ++it) 61 | { 62 | if(it->second == pTimer) 63 | { 64 | _pTimers.erase(it); 65 | break; 66 | } 67 | } 68 | } 69 | 70 | /////////////////////////////////////// 71 | /// Add a timer to the system 72 | /// @param pRun: callback interface 73 | /// @param when: time 74 | /// @param interval: 75 | /// 0 = happen only once, no repeat 76 | /// n = happen after the first time every n seconds 77 | /// @return the process unique id of the timer 78 | long TimerQueue::addTimer(IRun0* pRun, Timestamp when, double interval) 79 | { 80 | Timer* pAddTimer = new Timer(when, pRun, interval); //Memory Leak !!! 81 | string str("addTimer"); 82 | Task task(this, str, pAddTimer); 83 | _pLoop->queueInLoop(task); 84 | return (long)(pAddTimer); 85 | } 86 | 87 | void TimerQueue::cancelTimer(long timerId) 88 | { 89 | Timer* pCancel = (Timer*)(timerId); 90 | string str("canceltimer"); 91 | Task task(this, str, pCancel); 92 | _pLoop->queueInLoop(task); 93 | } 94 | 95 | void TimerQueue::handleRead() 96 | { 97 | Timestamp now(Timestamp::now()); 98 | readTimerfd(_timerfd, now); 99 | 100 | vector expired = getExpired(now); 101 | vector::iterator it; 102 | for(it = expired.begin(); it != expired.end(); ++it) 103 | { 104 | it->second->timeout(); 105 | } 106 | reset(expired, now); 107 | } 108 | 109 | void TimerQueue::handleWrite() 110 | {} 111 | 112 | int TimerQueue::createTimerfd() 113 | { 114 | int timerfd = ::timerfd_create(CLOCK_MONOTONIC, 115 | TFD_NONBLOCK | TFD_CLOEXEC); 116 | if(timerfd < 0) 117 | { 118 | cout << "failed in timerfd_create" << endl; 119 | } 120 | return timerfd; 121 | } 122 | 123 | std::vector TimerQueue::getExpired(Timestamp now) 124 | { 125 | std::vector expired; 126 | Entry sentry(now, reinterpret_cast(UINTPTR_MAX)); 127 | TimerList::iterator end = _pTimers.lower_bound(sentry); 128 | copy(_pTimers.begin(), end, back_inserter(expired)); 129 | _pTimers.erase(_pTimers.begin(), end); 130 | return expired; 131 | } 132 | 133 | void TimerQueue::readTimerfd(int timerfd, Timestamp now) 134 | { 135 | uint64_t howmany; 136 | ssize_t n = ::read(timerfd, &howmany, sizeof(howmany)); 137 | if (n != sizeof(howmany)) 138 | { 139 | cout << "Timer::readTimerfd() error " << endl; 140 | } 141 | } 142 | 143 | void TimerQueue::reset(const vector& expired, Timestamp now) 144 | { 145 | vector::const_iterator it; 146 | for(it = expired.begin(); it != expired.end(); ++it) 147 | { 148 | if(it->second->isRepeat()) 149 | { 150 | it->second->moveToNext(); 151 | insert(it->second); 152 | } 153 | } 154 | 155 | Timestamp nextExpire; 156 | if(!_pTimers.empty()) 157 | { 158 | nextExpire = _pTimers.begin()->second->getStamp(); 159 | } 160 | if(nextExpire.valid()) 161 | { 162 | resetTimerfd(_timerfd, nextExpire); 163 | } 164 | } 165 | 166 | void TimerQueue::resetTimerfd(int timerfd, Timestamp stamp) 167 | { 168 | struct itimerspec newValue; 169 | struct itimerspec oldValue; 170 | bzero(&newValue, sizeof(newValue)); 171 | bzero(&oldValue, sizeof(oldValue)); 172 | newValue.it_value = howMuchTimeFromNow(stamp); 173 | int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); 174 | if(ret) 175 | { 176 | cout << "timerfd_settime error" << endl; 177 | } 178 | } 179 | 180 | bool TimerQueue::insert(Timer* pTimer) 181 | { 182 | bool earliestChanged = false; 183 | Timestamp when = pTimer->getStamp(); 184 | TimerList::iterator it = _pTimers.begin(); 185 | if(it == _pTimers.end() || when < it->first) 186 | { 187 | earliestChanged = true; 188 | } 189 | pair result 190 | = _pTimers.insert(Entry(when, pTimer)); 191 | if(!(result.second)) 192 | { 193 | cout << "_pTimers.insert() error " << endl; 194 | } 195 | 196 | return earliestChanged; 197 | } 198 | 199 | struct timespec TimerQueue::howMuchTimeFromNow(Timestamp when) 200 | { 201 | int64_t microseconds = when.microSecondsSinceEpoch() 202 | - Timestamp::now().microSecondsSinceEpoch(); 203 | if (microseconds < 100) 204 | { 205 | microseconds = 100; 206 | } 207 | struct timespec ts; 208 | ts.tv_sec = static_cast( 209 | microseconds / Timestamp::kMicroSecondsPerSecond); 210 | ts.tv_nsec = static_cast( 211 | (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); 212 | return ts; 213 | } 214 | --------------------------------------------------------------------------------