├── README.md ├── example ├── distribute_barrier.cc ├── distribute_lock.cc ├── distribute_sharedlock.cc ├── makefile ├── master_election.cc ├── test.cc └── test_reconnect.cc ├── lib ├── libbase.a └── libnet.a ├── muduo ├── base │ ├── AsyncLogging.cc │ ├── AsyncLogging.h │ ├── Atomic.h │ ├── BlockingQueue.h │ ├── BoundedBlockingQueue.h │ ├── Condition.cc │ ├── Condition.h │ ├── CountDownLatch.cc │ ├── CountDownLatch.h │ ├── CurrentThread.h │ ├── Date.cc │ ├── Date.h │ ├── Exception.cc │ ├── Exception.h │ ├── FileUtil.cc │ ├── FileUtil.h │ ├── GzipFile.h │ ├── LogFile.cc │ ├── LogFile.h │ ├── LogStream.cc │ ├── LogStream.h │ ├── Logging.cc │ ├── Logging.h │ ├── Mutex.h │ ├── ProcessInfo.cc │ ├── ProcessInfo.h │ ├── Singleton.h │ ├── StringPiece.h │ ├── Thread.cc │ ├── Thread.h │ ├── ThreadLocal.h │ ├── ThreadLocalSingleton.h │ ├── ThreadPool.cc │ ├── ThreadPool.h │ ├── TimeZone.cc │ ├── TimeZone.h │ ├── Timestamp.cc │ ├── Timestamp.h │ ├── Types.h │ ├── WeakCallback.h │ ├── copyable.h │ ├── makefile │ └── premake4.lua └── net │ ├── Acceptor.cc │ ├── Acceptor.h │ ├── Boilerplate.cc │ ├── Boilerplate.cc~ │ ├── Boilerplate.h │ ├── Buffer.cc │ ├── Buffer.h │ ├── Callbacks.h │ ├── Channel.cc │ ├── Channel.h │ ├── Connector.cc │ ├── Connector.h │ ├── ConnectorOri.cc │ ├── ConnectorOri.h │ ├── Endian.h │ ├── EventLoop.cc │ ├── EventLoop.h │ ├── EventLoopThread.cc │ ├── EventLoopThread.h │ ├── EventLoopThreadPool.cc │ ├── EventLoopThreadPool.h │ ├── HeartStat.h │ ├── InetAddress.cc │ ├── InetAddress.h │ ├── Poller.cc │ ├── Poller.h │ ├── Socket.cc │ ├── Socket.h │ ├── SocketsOps.cc │ ├── SocketsOps.h │ ├── TcpClient.cc │ ├── TcpClient.h │ ├── TcpConnection.cc │ ├── TcpConnection.h │ ├── TcpServer.cc │ ├── TcpServer.h │ ├── Timer.cc │ ├── Timer.h │ ├── TimerId.h │ ├── TimerQueue.cc │ ├── TimerQueue.h │ ├── UdpClient.cc │ ├── UdpClient.h │ ├── ZlibStream.h │ ├── makefile │ ├── poller │ ├── DefaultPoller.cc │ ├── EPollPoller.cc │ ├── EPollPoller.h │ ├── PollPoller.cc │ └── PollPoller.h │ └── premake4.lua └── src ├── ZkClient.cc ├── ZkClient.h ├── ZkClientManager.cc ├── ZkClientManager.h ├── ZkTimerQueue.cc ├── ZkTimerQueue.h └── makefile /README.md: -------------------------------------------------------------------------------- 1 | # ZkCppClient 2 | 3 | ## ZkCppClient 解决的问题 4 | 5 | ZkCppClient 类似Java客户端ZkClient、Curator,是对ZookeeperLib c api的C++封装,主要解决以下几个问题: 6 | 7 | 1. 支持Watcher的永久注册 8 | Client收到Watcher通知后,会再向Zookeeper注册Watcher。并且,也提供了接口 `取消Watcher的重注册`。 9 | 10 | 2. 支持session重连 11 | 当session超时后,Client会启一个定时器定时重连(默认支持重连)。并且,也提供了接口 `不支持重连`。 12 | 13 | 3. 提供接口,支持递归创建父子结点、递归删除分支结点。 14 | 创建结点的时候 会判断 父结点是否存在,如果不存在,会先创建父结点。 15 | 删除结点的时候 会判断 是否有子结点,如果存在,会先删除子结点。 16 | 17 | 4. 接口友好、错误码归类 18 | 分离了获取数据、注册Watcher的接口,并只对用户提供用得到的参数,对各种错误码做了归类、删减。 19 | 20 | ## 特点 21 | 22 | 1. Client对象利用shared_ptr的形式来对外提供访问。 23 | 由于Client对象 客户端库和用户代码都会访问,它的生命期比较模糊,所以内部、外部都使用boost::shared_ptr来访问Client。 24 | 25 | 2. 借鉴Curator,将Watcher归类成两种:NodeWatcher, ChildWatcher。分离出注册Watcher和获取数据两种接口。 26 | NodeWatcher监听节点的变更(节点删除,节点创建,节点数据变更),ChildWatcher监听子节点的变更(增加、删除子结点),且回调Watcher时会 提供最新的结点值 或 子结点列表。 27 | 28 | 3. 回调函数(Watcher回调、数据回调)采用了boost::function/boost::bind形式,并提供了同步、异步两种接口。 29 | 30 | 4. 抽象出了结点的version,提供指定version的CAS操作。 31 | 在Get结点数据时,会获取到结点的Stat结构,从其中抽取了version,之后在Set,Delete时,可根据指定的version做设置、删除操作。 32 | 33 | 34 | ## 使用方法 35 | 36 | ZkCppClient使用了boost库和muduo库,在编译时需要添加编译选项-DTHREADED,链接zookeeper_mt库。具体的使用方法见examle目录。 37 | 38 | -------------------------------------------------------------------------------- /example/distribute_barrier.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/example/distribute_barrier.cc -------------------------------------------------------------------------------- /example/distribute_lock.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/example/distribute_lock.cc -------------------------------------------------------------------------------- /example/distribute_sharedlock.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/example/distribute_sharedlock.cc -------------------------------------------------------------------------------- /example/makefile: -------------------------------------------------------------------------------- 1 | 2 | LIB_INSTALL_COMM_PATH = ../lib 3 | 4 | INC_COMM_PATH = -I./ -I../ -I/usr/local/include/zookeeper -I../src/ -I/export/newjpush/include -I/export/newjpush/ 5 | 6 | LIB_COMM = -lzookeeper_mt -L$(LIB_INSTALL_COMM_PATH) -lbase -lpthread -lrt -L$(LIB_INSTALL_COMM_PATH) -lnet 7 | 8 | .SUFFIXES: .o .cc 9 | 10 | C_ARGS := -g -O -Wall -fno-common 11 | 12 | cxx = g++ 13 | 14 | CFLAGS = -g -O -Wall $(INC_COMM_PATH) 15 | 16 | BINARY_TEST := test 17 | OI_OBJS_TEST = ../src/ZkTimerQueue.o ../src/ZkClient.o ../src/ZkClientManager.o test.o 18 | 19 | BINARY_RECONN := test_reconn 20 | OI_OBJS_RECONN = ../src/ZkTimerQueue.o ../src/ZkClient.o ../src/ZkClientManager.o test_reconnect.o 21 | 22 | BINARY_ELECTION := master_election 23 | OI_OBJS_ELECTION = ../src/ZkTimerQueue.o ../src/ZkClient.o ../src/ZkClientManager.o master_election.o 24 | 25 | BINARY_LOCK := distribute_lock 26 | OI_OBJS_LOCK = ../src/ZkTimerQueue.o ../src/ZkClient.o ../src/ZkClientManager.o distribute_lock.o 27 | 28 | BINARY_SHAREDLOCK := distribute_sharedlock 29 | OI_OBJS_SHAREDLOCK = ../src/ZkTimerQueue.o ../src/ZkClient.o ../src/ZkClientManager.o distribute_sharedlock.o 30 | 31 | BINARY_BARRIER := distribute_barrier 32 | OI_OBJS_BARRIER = ../src/ZkTimerQueue.o ../src/ZkClient.o ../src/ZkClientManager.o distribute_barrier.o 33 | 34 | all:$(BINARY_TEST) $(BINARY_RECONN) $(BINARY_ELECTION) $(BINARY_LOCK) $(BINARY_SHAREDLOCK) $(BINARY_BARRIER) 35 | 36 | .cc.o: 37 | $(CXX) $(CFLAGS) -c $^ -o ./$@ -DMUDUO_STD_STRING -DUSE_CALL_RECORDER -DTHREADED $(LIB_COMM) 38 | 39 | $(BINARY_TEST):$(OI_OBJS_TEST) 40 | $(CXX) $(C_ARGS) -o $@ $^ $(LIB_COMM) 41 | 42 | $(BINARY_RECONN):$(OI_OBJS_RECONN) 43 | $(CXX) $(C_ARGS) -o $@ $^ $(LIB_COMM) 44 | 45 | $(BINARY_ELECTION):$(OI_OBJS_ELECTION) 46 | $(CXX) $(C_ARGS) -o $@ $^ $(LIB_COMM) 47 | 48 | $(BINARY_LOCK):$(OI_OBJS_LOCK) 49 | $(CXX) $(C_ARGS) -o $@ $^ $(LIB_COMM) 50 | 51 | $(BINARY_SHAREDLOCK):$(OI_OBJS_SHAREDLOCK) 52 | $(CXX) $(C_ARGS) -o $@ $^ $(LIB_COMM) 53 | 54 | $(BINARY_BARRIER):$(OI_OBJS_BARRIER) 55 | $(CXX) $(C_ARGS) -o $@ $^ $(LIB_COMM) 56 | 57 | clean: 58 | rm -f *.o ../src/*.o $(BINARY_TEST) $(BINARY_RECONN) $(BINARY_ELECTION) $(BINARY_LOCK) $(BINARY_SHAREDLOCK) $(BINARY_BARRIER) 59 | -------------------------------------------------------------------------------- /example/master_election.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/example/master_election.cc -------------------------------------------------------------------------------- /example/test_reconnect.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/example/test_reconnect.cc -------------------------------------------------------------------------------- /lib/libbase.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/lib/libbase.a -------------------------------------------------------------------------------- /lib/libnet.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/lib/libnet.a -------------------------------------------------------------------------------- /muduo/base/AsyncLogging.cc: -------------------------------------------------------------------------------- 1 | #include "muduo/base/AsyncLogging.h" 2 | #include "muduo/base/LogFile.h" 3 | #include "muduo/base/Timestamp.h" 4 | #include 5 | 6 | using namespace muduo; 7 | 8 | AsyncLogging::AsyncLogging(const string& basename, 9 | size_t rollSize, 10 | int flushInterval) 11 | : flushInterval_(flushInterval), 12 | running_(false), 13 | basename_(basename), 14 | rollSize_(rollSize), 15 | thread_(boost::bind(&AsyncLogging::threadFunc, this), "Logging"), 16 | latch_(1), 17 | mutex_(), 18 | cond_(mutex_), 19 | currentBuffer_(new Buffer), 20 | nextBuffer_(new Buffer), 21 | buffers_() 22 | { 23 | currentBuffer_->bzero(); 24 | nextBuffer_->bzero(); 25 | buffers_.reserve(16); 26 | } 27 | 28 | void AsyncLogging::append(const char* logline, int len) 29 | { 30 | muduo::MutexLockGuard lock(mutex_); 31 | if (currentBuffer_->avail() > len) 32 | { 33 | currentBuffer_->append(logline, len); 34 | } 35 | else 36 | { 37 | buffers_.push_back(currentBuffer_.release()); 38 | 39 | if (nextBuffer_) 40 | { 41 | currentBuffer_ = boost::ptr_container::move(nextBuffer_); 42 | } 43 | else 44 | { 45 | currentBuffer_.reset(new Buffer); // Rarely happens 46 | } 47 | currentBuffer_->append(logline, len); 48 | cond_.notify(); 49 | } 50 | } 51 | 52 | void AsyncLogging::threadFunc() 53 | { 54 | assert(running_ == true); 55 | latch_.countDown(); 56 | LogFile output(basename_, rollSize_, false); 57 | BufferPtr newBuffer1(new Buffer); 58 | BufferPtr newBuffer2(new Buffer); 59 | newBuffer1->bzero(); 60 | newBuffer2->bzero(); 61 | BufferVector buffersToWrite; 62 | buffersToWrite.reserve(16); 63 | while (running_) 64 | { 65 | assert(newBuffer1 && newBuffer1->length() == 0); 66 | assert(newBuffer2 && newBuffer2->length() == 0); 67 | assert(buffersToWrite.empty()); 68 | 69 | { 70 | muduo::MutexLockGuard lock(mutex_); 71 | if (buffers_.empty()) // unusual usage! 72 | { 73 | cond_.waitForSeconds(flushInterval_); 74 | //std::cout<<"waitForSeconds"< 25) 87 | { 88 | char buf[256]; 89 | snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n", 90 | Timestamp::now().toFormattedString().c_str(), 91 | buffersToWrite.size()-2); 92 | fputs(buf, stderr); 93 | output.append(buf, static_cast(strlen(buf))); 94 | buffersToWrite.erase(buffersToWrite.begin()+2, buffersToWrite.end()); 95 | } 96 | 97 | for (size_t i = 0; i < buffersToWrite.size(); ++i) 98 | { 99 | // FIXME: use unbuffered stdio FILE ? or use ::writev ? 100 | output.append(buffersToWrite[i].data(), buffersToWrite[i].length()); 101 | } 102 | 103 | if (buffersToWrite.size() > 2) 104 | { 105 | // drop non-bzero-ed buffers, avoid trashing 106 | buffersToWrite.resize(2); 107 | } 108 | 109 | if (!newBuffer1) 110 | { 111 | assert(!buffersToWrite.empty()); 112 | newBuffer1 = buffersToWrite.pop_back(); 113 | newBuffer1->reset(); 114 | } 115 | 116 | if (!newBuffer2) 117 | { 118 | assert(!buffersToWrite.empty()); 119 | newBuffer2 = buffersToWrite.pop_back(); 120 | newBuffer2->reset(); 121 | } 122 | 123 | buffersToWrite.clear(); 124 | output.flush(); 125 | } 126 | output.flush(); 127 | } 128 | 129 | -------------------------------------------------------------------------------- /muduo/base/AsyncLogging.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_ASYNCLOGGING_H 2 | #define MUDUO_BASE_ASYNCLOGGING_H 3 | 4 | #include "muduo/base/BlockingQueue.h" 5 | #include "muduo/base/BoundedBlockingQueue.h" 6 | #include "muduo/base/CountDownLatch.h" 7 | #include "muduo/base/Mutex.h" 8 | #include "muduo/base/Thread.h" 9 | #include "muduo/base/LogStream.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace muduo 17 | { 18 | 19 | class AsyncLogging : boost::noncopyable 20 | { 21 | public: 22 | 23 | AsyncLogging(const string& basename, 24 | size_t rollSize, 25 | int flushInterval = 3); 26 | 27 | ~AsyncLogging() 28 | { 29 | if (running_) 30 | { 31 | stop(); 32 | } 33 | } 34 | 35 | void append(const char* logline, int len); 36 | 37 | void start() 38 | { 39 | running_ = true; 40 | thread_.start(); 41 | latch_.wait(); 42 | } 43 | 44 | void stop() 45 | { 46 | running_ = false; 47 | cond_.notify(); 48 | thread_.join(); 49 | } 50 | 51 | private: 52 | 53 | // declare but not define, prevent compiler-synthesized functions 54 | AsyncLogging(const AsyncLogging&); // ptr_container 55 | void operator=(const AsyncLogging&); // ptr_container 56 | 57 | void threadFunc(); 58 | 59 | typedef muduo::detail::FixedBuffer Buffer; 60 | typedef boost::ptr_vector BufferVector; 61 | typedef BufferVector::auto_type BufferPtr; 62 | 63 | const int flushInterval_; 64 | bool running_; 65 | string basename_; 66 | size_t rollSize_; 67 | muduo::Thread thread_; 68 | muduo::CountDownLatch latch_; 69 | muduo::MutexLock mutex_; 70 | muduo::Condition cond_; 71 | BufferPtr currentBuffer_; 72 | BufferPtr nextBuffer_; 73 | BufferVector buffers_; 74 | }; 75 | 76 | } 77 | #endif // MUDUO_BASE_ASYNCLOGGING_H 78 | -------------------------------------------------------------------------------- /muduo/base/Atomic.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_ATOMIC_H 7 | #define MUDUO_BASE_ATOMIC_H 8 | 9 | #include 10 | #include 11 | 12 | namespace muduo 13 | { 14 | 15 | namespace detail 16 | { 17 | template 18 | class AtomicIntegerT : boost::noncopyable 19 | { 20 | public: 21 | AtomicIntegerT() 22 | : value_(0) 23 | { 24 | } 25 | 26 | // uncomment if you need copying and assignment 27 | // 28 | // AtomicIntegerT(const AtomicIntegerT& that) 29 | // : value_(that.get()) 30 | // {} 31 | // 32 | // AtomicIntegerT& operator=(const AtomicIntegerT& that) 33 | // { 34 | // getAndSet(that.get()); 35 | // return *this; 36 | // } 37 | 38 | T get() 39 | { 40 | // in gcc >= 4.7: __atomic_load_n(&value_, __ATOMIC_SEQ_CST) 41 | return __sync_val_compare_and_swap(&value_, 0, 0); 42 | } 43 | 44 | T getAndAdd(T x) 45 | { 46 | // in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST) 47 | return __sync_fetch_and_add(&value_, x); 48 | } 49 | 50 | T addAndGet(T x) 51 | { 52 | return getAndAdd(x) + x; 53 | } 54 | 55 | T incrementAndGet() 56 | { 57 | return addAndGet(1); 58 | } 59 | 60 | T decrementAndGet() 61 | { 62 | return addAndGet(-1); 63 | } 64 | 65 | void add(T x) 66 | { 67 | getAndAdd(x); 68 | } 69 | 70 | void increment() 71 | { 72 | incrementAndGet(); 73 | } 74 | 75 | void decrement() 76 | { 77 | decrementAndGet(); 78 | } 79 | 80 | T getAndSet(T newValue) 81 | { 82 | // in gcc >= 4.7: __atomic_store_n(&value, newValue, __ATOMIC_SEQ_CST) 83 | return __sync_lock_test_and_set(&value_, newValue); 84 | } 85 | 86 | private: 87 | volatile T value_; 88 | }; 89 | } 90 | 91 | typedef detail::AtomicIntegerT AtomicInt32; 92 | typedef detail::AtomicIntegerT AtomicInt64; 93 | } 94 | 95 | #endif // MUDUO_BASE_ATOMIC_H 96 | -------------------------------------------------------------------------------- /muduo/base/BlockingQueue.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_BLOCKINGQUEUE_H 7 | #define MUDUO_BASE_BLOCKINGQUEUE_H 8 | 9 | #include "muduo/base/Condition.h" 10 | #include "muduo/base/Mutex.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace muduo 17 | { 18 | 19 | template 20 | class BlockingQueue : boost::noncopyable 21 | { 22 | public: 23 | BlockingQueue() 24 | : mutex_(), 25 | notEmpty_(mutex_), 26 | queue_() 27 | { 28 | } 29 | 30 | void put(const T& x) 31 | { 32 | MutexLockGuard lock(mutex_); 33 | queue_.push_back(x); 34 | notEmpty_.notify(); // wait morphing saves us 35 | // http://www.domaigne.com/blog/computing/condvars-signal-with-mutex-locked-or-not/ 36 | } 37 | 38 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 39 | void put(T&& x) 40 | { 41 | MutexLockGuard lock(mutex_); 42 | queue_.push_back(std::move(x)); 43 | notEmpty_.notify(); 44 | } 45 | // FIXME: emplace() 46 | #endif 47 | 48 | T take() 49 | { 50 | MutexLockGuard lock(mutex_); 51 | // always use a while-loop, due to spurious wakeup 52 | while (queue_.empty()) 53 | { 54 | notEmpty_.wait(); 55 | } 56 | assert(!queue_.empty()); 57 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 58 | T front(std::move(queue_.front())); 59 | #else 60 | T front(queue_.front()); 61 | #endif 62 | queue_.pop_front(); 63 | return front; 64 | } 65 | 66 | size_t size() const 67 | { 68 | MutexLockGuard lock(mutex_); 69 | return queue_.size(); 70 | } 71 | 72 | private: 73 | mutable MutexLock mutex_; 74 | Condition notEmpty_; 75 | std::deque queue_; 76 | }; 77 | 78 | } 79 | 80 | #endif // MUDUO_BASE_BLOCKINGQUEUE_H 81 | -------------------------------------------------------------------------------- /muduo/base/BoundedBlockingQueue.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H 7 | #define MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H 8 | 9 | #include "muduo/base/Condition.h" 10 | #include "muduo/base/Mutex.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace muduo 17 | { 18 | 19 | template 20 | class BoundedBlockingQueue : boost::noncopyable 21 | { 22 | public: 23 | explicit BoundedBlockingQueue(int maxSize) 24 | : mutex_(), 25 | notEmpty_(mutex_), 26 | notFull_(mutex_), 27 | queue_(maxSize) 28 | { 29 | } 30 | 31 | void put(const T& x) 32 | { 33 | MutexLockGuard lock(mutex_); 34 | while (queue_.full()) 35 | { 36 | notFull_.wait(); 37 | } 38 | assert(!queue_.full()); 39 | queue_.push_back(x); 40 | notEmpty_.notify(); 41 | } 42 | 43 | T take() 44 | { 45 | MutexLockGuard lock(mutex_); 46 | while (queue_.empty()) 47 | { 48 | notEmpty_.wait(); 49 | } 50 | assert(!queue_.empty()); 51 | T front(queue_.front()); 52 | queue_.pop_front(); 53 | notFull_.notify(); 54 | return front; 55 | } 56 | 57 | bool empty() const 58 | { 59 | MutexLockGuard lock(mutex_); 60 | return queue_.empty(); 61 | } 62 | 63 | bool full() const 64 | { 65 | MutexLockGuard lock(mutex_); 66 | return queue_.full(); 67 | } 68 | 69 | size_t size() const 70 | { 71 | MutexLockGuard lock(mutex_); 72 | return queue_.size(); 73 | } 74 | 75 | size_t capacity() const 76 | { 77 | MutexLockGuard lock(mutex_); 78 | return queue_.capacity(); 79 | } 80 | 81 | private: 82 | mutable MutexLock mutex_; 83 | Condition notEmpty_; 84 | Condition notFull_; 85 | boost::circular_buffer queue_; 86 | }; 87 | 88 | } 89 | 90 | #endif // MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H 91 | -------------------------------------------------------------------------------- /muduo/base/Condition.cc: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #include "muduo/base/Condition.h" 7 | 8 | #include 9 | 10 | // returns true if time out, false otherwise. 11 | bool muduo::Condition::waitForSeconds(int seconds) 12 | { 13 | struct timespec abstime; 14 | // FIXME: use CLOCK_MONOTONIC or CLOCK_MONOTONIC_RAW to prevent time rewind. 15 | clock_gettime(CLOCK_REALTIME, &abstime); 16 | abstime.tv_sec += seconds; 17 | MutexLock::UnassignGuard ug(mutex_); 18 | return ETIMEDOUT == pthread_cond_timedwait(&pcond_, mutex_.getPthreadMutex(), &abstime); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /muduo/base/Condition.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_CONDITION_H 7 | #define MUDUO_BASE_CONDITION_H 8 | 9 | #include "muduo/base/Mutex.h" 10 | 11 | #include 12 | #include 13 | 14 | namespace muduo 15 | { 16 | 17 | class Condition : boost::noncopyable 18 | { 19 | public: 20 | explicit Condition(MutexLock& mutex) 21 | : mutex_(mutex) 22 | { 23 | MCHECK(pthread_cond_init(&pcond_, NULL)); 24 | } 25 | 26 | ~Condition() 27 | { 28 | MCHECK(pthread_cond_destroy(&pcond_)); 29 | } 30 | 31 | void wait() 32 | { 33 | MutexLock::UnassignGuard ug(mutex_); 34 | MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex())); 35 | } 36 | 37 | // returns true if time out, false otherwise. 38 | bool waitForSeconds(int seconds); 39 | 40 | void notify() 41 | { 42 | MCHECK(pthread_cond_signal(&pcond_)); 43 | } 44 | 45 | void notifyAll() 46 | { 47 | MCHECK(pthread_cond_broadcast(&pcond_)); 48 | } 49 | 50 | private: 51 | MutexLock& mutex_; 52 | pthread_cond_t pcond_; 53 | }; 54 | 55 | } 56 | #endif // MUDUO_BASE_CONDITION_H 57 | -------------------------------------------------------------------------------- /muduo/base/CountDownLatch.cc: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #include "muduo/base/CountDownLatch.h" 7 | 8 | using namespace muduo; 9 | 10 | CountDownLatch::CountDownLatch(int count) 11 | : mutex_(), 12 | condition_(mutex_), 13 | count_(count) 14 | { 15 | } 16 | 17 | void CountDownLatch::wait() 18 | { 19 | MutexLockGuard lock(mutex_); 20 | while (count_ > 0) { 21 | condition_.wait(); 22 | } 23 | } 24 | 25 | void CountDownLatch::countDown() 26 | { 27 | MutexLockGuard lock(mutex_); 28 | --count_; 29 | if (count_ == 0) { 30 | condition_.notifyAll(); 31 | } 32 | } 33 | 34 | int CountDownLatch::getCount() const 35 | { 36 | MutexLockGuard lock(mutex_); 37 | return count_; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /muduo/base/CountDownLatch.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_COUNTDOWNLATCH_H 7 | #define MUDUO_BASE_COUNTDOWNLATCH_H 8 | 9 | #include "muduo/base/Condition.h" 10 | #include "muduo/base/Mutex.h" 11 | 12 | #include 13 | 14 | namespace muduo 15 | { 16 | 17 | class CountDownLatch : boost::noncopyable 18 | { 19 | public: 20 | 21 | explicit CountDownLatch(int count); 22 | 23 | void wait(); 24 | 25 | void countDown(); 26 | 27 | int getCount() const; 28 | 29 | private: 30 | mutable MutexLock mutex_; 31 | Condition condition_; 32 | int count_; 33 | }; 34 | 35 | } 36 | #endif // MUDUO_BASE_COUNTDOWNLATCH_H 37 | -------------------------------------------------------------------------------- /muduo/base/CurrentThread.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_CURRENTTHREAD_H 7 | #define MUDUO_BASE_CURRENTTHREAD_H 8 | #include 9 | #include 10 | 11 | namespace muduo 12 | { 13 | namespace CurrentThread 14 | { 15 | using std::cin; 16 | using std::cout; 17 | using std::cerr; 18 | using std::endl; 19 | 20 | // internal 21 | extern __thread int t_cachedTid; 22 | extern __thread char t_tidString[32]; 23 | extern __thread int t_tidStringLength; 24 | extern __thread const char* t_threadName; 25 | void cacheTid(); 26 | 27 | inline int tid() 28 | { 29 | if (__builtin_expect(t_cachedTid == 0, 0)) 30 | { 31 | // cout<<"in builtin" <<__FUNCTION__ <<"---"<<__LINE__<<"----"< // snprintf 8 | 9 | namespace muduo 10 | { 11 | namespace detail 12 | { 13 | 14 | char require_32_bit_integer_at_least[sizeof(int) >= sizeof(int32_t) ? 1 : -1]; 15 | 16 | // algorithm and explanation see: 17 | // http://www.faqs.org/faqs/calendars/faq/part2/ 18 | // http://blog.csdn.net/Solstice 19 | 20 | int getJulianDayNumber(int year, int month, int day) 21 | { 22 | (void) require_32_bit_integer_at_least; // no warning please 23 | int a = (14 - month) / 12; 24 | int y = year + 4800 - a; 25 | int m = month + 12 * a - 3; 26 | return day + (153*m + 2) / 5 + y*365 + y/4 - y/100 + y/400 - 32045; 27 | } 28 | 29 | struct Date::YearMonthDay getYearMonthDay(int julianDayNumber) 30 | { 31 | int a = julianDayNumber + 32044; 32 | int b = (4 * a + 3) / 146097; 33 | int c = a - ((b * 146097) / 4); 34 | int d = (4 * c + 3) / 1461; 35 | int e = c - ((1461 * d) / 4); 36 | int m = (5 * e + 2) / 153; 37 | Date::YearMonthDay ymd; 38 | ymd.day = e - ((153 * m + 2) / 5) + 1; 39 | ymd.month = m + 3 - 12 * (m / 10); 40 | ymd.year = b * 100 + d - 4800 + (m / 10); 41 | return ymd; 42 | } 43 | } 44 | const int Date::kJulianDayOf1970_01_01 = detail::getJulianDayNumber(1970, 1, 1); 45 | } 46 | 47 | using namespace muduo; 48 | using namespace muduo::detail; 49 | 50 | Date::Date(int y, int m, int d) 51 | : julianDayNumber_(getJulianDayNumber(y, m, d)) 52 | { 53 | } 54 | 55 | Date::Date(const struct tm& t) 56 | : julianDayNumber_(getJulianDayNumber( 57 | t.tm_year+1900, 58 | t.tm_mon+1, 59 | t.tm_mday)) 60 | { 61 | } 62 | 63 | string Date::toIsoString() const 64 | { 65 | char buf[32]; 66 | YearMonthDay ymd(yearMonthDay()); 67 | snprintf(buf, sizeof buf, "%4d-%02d-%02d", ymd.year, ymd.month, ymd.day); 68 | return buf; 69 | } 70 | 71 | Date::YearMonthDay Date::yearMonthDay() const 72 | { 73 | return getYearMonthDay(julianDayNumber_); 74 | } 75 | 76 | -------------------------------------------------------------------------------- /muduo/base/Date.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_DATE_H 7 | #define MUDUO_BASE_DATE_H 8 | 9 | #include "muduo/base/copyable.h" 10 | #include "muduo/base/Types.h" 11 | 12 | struct tm; 13 | 14 | namespace muduo 15 | { 16 | 17 | /// 18 | /// Date in Gregorian calendar. 19 | /// 20 | /// This class is immutable. 21 | /// It's recommended to pass it by value, since it's passed in register on x64. 22 | /// 23 | class Date : public muduo::copyable 24 | // public boost::less_than_comparable, 25 | // public boost::equality_comparable 26 | { 27 | public: 28 | 29 | struct YearMonthDay 30 | { 31 | int year; // [1900..2500] 32 | int month; // [1..12] 33 | int day; // [1..31] 34 | }; 35 | 36 | static const int kDaysPerWeek = 7; 37 | static const int kJulianDayOf1970_01_01; 38 | 39 | /// 40 | /// Constucts an invalid Date. 41 | /// 42 | Date() 43 | : julianDayNumber_(0) 44 | {} 45 | 46 | /// 47 | /// Constucts a yyyy-mm-dd Date. 48 | /// 49 | /// 1 <= month <= 12 50 | Date(int year, int month, int day); 51 | 52 | /// 53 | /// Constucts a Date from Julian Day Number. 54 | /// 55 | explicit Date(int julianDayNum) 56 | : julianDayNumber_(julianDayNum) 57 | {} 58 | 59 | /// 60 | /// Constucts a Date from struct tm 61 | /// 62 | explicit Date(const struct tm&); 63 | 64 | // default copy/assignment/dtor are Okay 65 | 66 | void swap(Date& that) 67 | { 68 | std::swap(julianDayNumber_, that.julianDayNumber_); 69 | } 70 | 71 | bool valid() const { return julianDayNumber_ > 0; } 72 | 73 | /// 74 | /// Converts to yyyy-mm-dd format. 75 | /// 76 | string toIsoString() const; 77 | 78 | struct YearMonthDay yearMonthDay() const; 79 | 80 | int year() const 81 | { 82 | return yearMonthDay().year; 83 | } 84 | 85 | int month() const 86 | { 87 | return yearMonthDay().month; 88 | } 89 | 90 | int day() const 91 | { 92 | return yearMonthDay().day; 93 | } 94 | 95 | // [0, 1, ..., 6] => [Sunday, Monday, ..., Saturday ] 96 | int weekDay() const 97 | { 98 | return (julianDayNumber_+1) % kDaysPerWeek; 99 | } 100 | 101 | int julianDayNumber() const { return julianDayNumber_; } 102 | 103 | private: 104 | int julianDayNumber_; 105 | }; 106 | 107 | inline bool operator<(Date x, Date y) 108 | { 109 | return x.julianDayNumber() < y.julianDayNumber(); 110 | } 111 | 112 | inline bool operator==(Date x, Date y) 113 | { 114 | return x.julianDayNumber() == y.julianDayNumber(); 115 | } 116 | 117 | } 118 | #endif // MUDUO_BASE_DATE_H 119 | -------------------------------------------------------------------------------- /muduo/base/Exception.cc: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #include "muduo/base/Exception.h" 7 | 8 | //#include 9 | #include 10 | #include 11 | 12 | using namespace muduo; 13 | 14 | Exception::Exception(const char* msg) 15 | : message_(msg) 16 | { 17 | fillStackTrace(); 18 | } 19 | 20 | Exception::Exception(const string& msg) 21 | : message_(msg) 22 | { 23 | fillStackTrace(); 24 | } 25 | 26 | Exception::~Exception() throw () 27 | { 28 | } 29 | 30 | const char* Exception::what() const throw() 31 | { 32 | return message_.c_str(); 33 | } 34 | 35 | const char* Exception::stackTrace() const throw() 36 | { 37 | return stack_.c_str(); 38 | } 39 | 40 | void Exception::fillStackTrace() 41 | { 42 | const int len = 200; 43 | void* buffer[len]; 44 | int nptrs = ::backtrace(buffer, len); 45 | char** strings = ::backtrace_symbols(buffer, nptrs); 46 | if (strings) 47 | { 48 | for (int i = 0; i < nptrs; ++i) 49 | { 50 | // TODO demangle funcion name with abi::__cxa_demangle 51 | stack_.append(strings[i]); 52 | stack_.push_back('\n'); 53 | } 54 | free(strings); 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /muduo/base/Exception.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_EXCEPTION_H 7 | #define MUDUO_BASE_EXCEPTION_H 8 | 9 | #include "muduo/base/Types.h" 10 | #include 11 | 12 | namespace muduo 13 | { 14 | 15 | class Exception : public std::exception 16 | { 17 | public: 18 | explicit Exception(const char* what); 19 | explicit Exception(const string& what); 20 | virtual ~Exception() throw(); 21 | virtual const char* what() const throw(); 22 | const char* stackTrace() const throw(); 23 | 24 | private: 25 | void fillStackTrace(); 26 | 27 | string message_; 28 | string stack_; 29 | }; 30 | 31 | } 32 | 33 | #endif // MUDUO_BASE_EXCEPTION_H 34 | -------------------------------------------------------------------------------- /muduo/base/FileUtil.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include "muduo/base/FileUtil.h" 11 | #include "muduo/base/Logging.h" // strerror_tl 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace muduo; 22 | 23 | FileUtil::AppendFile::AppendFile(StringArg filename) 24 | : fp_(::fopen(filename.c_str(), "ae")), // 'e' for O_CLOEXEC 25 | writtenBytes_(0) 26 | { 27 | assert(fp_); 28 | ::setbuffer(fp_, buffer_, sizeof buffer_); 29 | // posix_fadvise POSIX_FADV_DONTNEED ? 30 | } 31 | 32 | FileUtil::AppendFile::~AppendFile() 33 | { 34 | ::fclose(fp_); 35 | } 36 | 37 | void FileUtil::AppendFile::append(const char* logline, const size_t len) 38 | { 39 | size_t n = write(logline, len); 40 | size_t remain = len - n; 41 | while (remain > 0) 42 | { 43 | size_t x = write(logline + n, remain); 44 | if (x == 0) 45 | { 46 | int err = ferror(fp_); 47 | if (err) 48 | { 49 | fprintf(stderr, "AppendFile::append() failed %s\n", strerror_tl(err)); 50 | } 51 | break; 52 | } 53 | n += x; 54 | remain = len - n; // remain -= x 55 | } 56 | 57 | writtenBytes_ += len; 58 | } 59 | 60 | void FileUtil::AppendFile::flush() 61 | { 62 | ::fflush(fp_); 63 | } 64 | 65 | size_t FileUtil::AppendFile::write(const char* logline, size_t len) 66 | { 67 | // #undef fwrite_unlocked 68 | return ::fwrite_unlocked(logline, 1, len, fp_); 69 | } 70 | 71 | FileUtil::ReadSmallFile::ReadSmallFile(StringArg filename) 72 | : fd_(::open(filename.c_str(), O_RDONLY | O_CLOEXEC)), 73 | err_(0) 74 | { 75 | buf_[0] = '\0'; 76 | if (fd_ < 0) 77 | { 78 | err_ = errno; 79 | } 80 | } 81 | 82 | FileUtil::ReadSmallFile::~ReadSmallFile() 83 | { 84 | if (fd_ >= 0) 85 | { 86 | ::close(fd_); // FIXME: check EINTR 87 | } 88 | } 89 | 90 | // return errno 91 | template 92 | int FileUtil::ReadSmallFile::readToString(int maxSize, 93 | String* content, 94 | int64_t* fileSize, 95 | int64_t* modifyTime, 96 | int64_t* createTime) 97 | { 98 | BOOST_STATIC_ASSERT(sizeof(off_t) == 8); 99 | assert(content != NULL); 100 | int err = err_; 101 | if (fd_ >= 0) 102 | { 103 | content->clear(); 104 | 105 | if (fileSize) 106 | { 107 | struct stat statbuf; 108 | if (::fstat(fd_, &statbuf) == 0) 109 | { 110 | if (S_ISREG(statbuf.st_mode)) 111 | { 112 | *fileSize = statbuf.st_size; 113 | content->reserve(static_cast(std::min(implicit_cast(maxSize), *fileSize))); 114 | } 115 | else if (S_ISDIR(statbuf.st_mode)) 116 | { 117 | err = EISDIR; 118 | } 119 | if (modifyTime) 120 | { 121 | *modifyTime = statbuf.st_mtime; 122 | } 123 | if (createTime) 124 | { 125 | *createTime = statbuf.st_ctime; 126 | } 127 | } 128 | else 129 | { 130 | err = errno; 131 | } 132 | } 133 | 134 | while (content->size() < implicit_cast(maxSize)) 135 | { 136 | size_t toRead = std::min(implicit_cast(maxSize) - content->size(), sizeof(buf_)); 137 | ssize_t n = ::read(fd_, buf_, toRead); 138 | if (n > 0) 139 | { 140 | content->append(buf_, n); 141 | } 142 | else 143 | { 144 | if (n < 0) 145 | { 146 | err = errno; 147 | } 148 | break; 149 | } 150 | } 151 | } 152 | return err; 153 | } 154 | 155 | int FileUtil::ReadSmallFile::readToBuffer(int* size) 156 | { 157 | int err = err_; 158 | if (fd_ >= 0) 159 | { 160 | ssize_t n = ::pread(fd_, buf_, sizeof(buf_)-1, 0); 161 | if (n >= 0) 162 | { 163 | if (size) 164 | { 165 | *size = static_cast(n); 166 | } 167 | buf_[n] = '\0'; 168 | } 169 | else 170 | { 171 | err = errno; 172 | } 173 | } 174 | return err; 175 | } 176 | 177 | template int FileUtil::readFile(StringArg filename, 178 | int maxSize, 179 | string* content, 180 | int64_t*, int64_t*, int64_t*); 181 | 182 | template int FileUtil::ReadSmallFile::readToString( 183 | int maxSize, 184 | string* content, 185 | int64_t*, int64_t*, int64_t*); 186 | 187 | #ifndef MUDUO_STD_STRING 188 | template int FileUtil::readFile(StringArg filename, 189 | int maxSize, 190 | std::string* content, 191 | int64_t*, int64_t*, int64_t*); 192 | 193 | template int FileUtil::ReadSmallFile::readToString( 194 | int maxSize, 195 | std::string* content, 196 | int64_t*, int64_t*, int64_t*); 197 | #endif 198 | 199 | -------------------------------------------------------------------------------- /muduo/base/FileUtil.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_BASE_FILEUTIL_H 12 | #define MUDUO_BASE_FILEUTIL_H 13 | 14 | #include "muduo/base/StringPiece.h" 15 | #include 16 | 17 | namespace muduo 18 | { 19 | 20 | namespace FileUtil 21 | { 22 | 23 | // read small file < 64KB 24 | class ReadSmallFile : boost::noncopyable 25 | { 26 | public: 27 | ReadSmallFile(StringArg filename); 28 | ~ReadSmallFile(); 29 | 30 | // return errno 31 | template 32 | int readToString(int maxSize, 33 | String* content, 34 | int64_t* fileSize, 35 | int64_t* modifyTime, 36 | int64_t* createTime); 37 | 38 | /// Read at maxium kBufferSize into buf_ 39 | // return errno 40 | int readToBuffer(int* size); 41 | 42 | const char* buffer() const { return buf_; } 43 | 44 | static const int kBufferSize = 64*1024; 45 | 46 | private: 47 | int fd_; 48 | int err_; 49 | char buf_[kBufferSize]; 50 | }; 51 | 52 | // read the file content, returns errno if error happens. 53 | template 54 | int readFile(StringArg filename, 55 | int maxSize, 56 | String* content, 57 | int64_t* fileSize = NULL, 58 | int64_t* modifyTime = NULL, 59 | int64_t* createTime = NULL) 60 | { 61 | ReadSmallFile file(filename); 62 | return file.readToString(maxSize, content, fileSize, modifyTime, createTime); 63 | } 64 | 65 | // not thread safe 66 | class AppendFile : boost::noncopyable 67 | { 68 | public: 69 | explicit AppendFile(StringArg filename); 70 | 71 | ~AppendFile(); 72 | 73 | void append(const char* logline, const size_t len); 74 | 75 | void flush(); 76 | 77 | size_t writtenBytes() const { return writtenBytes_; } 78 | 79 | private: 80 | 81 | size_t write(const char* logline, size_t len); 82 | 83 | FILE* fp_; 84 | char buffer_[64*1024]; 85 | size_t writtenBytes_; 86 | }; 87 | } 88 | 89 | } 90 | 91 | #endif // MUDUO_BASE_FILEUTIL_H 92 | 93 | -------------------------------------------------------------------------------- /muduo/base/GzipFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "muduo/base/StringPiece.h" 4 | #include 5 | #include 6 | 7 | namespace muduo 8 | { 9 | 10 | class GzipFile : boost::noncopyable 11 | { 12 | public: 13 | GzipFile(GzipFile&& rhs) 14 | : file_(rhs.file_) 15 | { 16 | rhs.file_ = NULL; 17 | } 18 | 19 | ~GzipFile() 20 | { 21 | if (file_) 22 | { 23 | ::gzclose(file_); 24 | } 25 | } 26 | 27 | GzipFile& operator=(GzipFile&& rhs) 28 | { 29 | swap(rhs); 30 | return *this; 31 | } 32 | 33 | bool valid() const { return file_ != NULL; } 34 | void swap(GzipFile& rhs) { std::swap(file_, rhs.file_); } 35 | #if ZLIB_VERNUM >= 0x1240 36 | bool setBuffer(int size) { return ::gzbuffer(file_, size) == 0; } 37 | #endif 38 | 39 | // return the number of uncompressed bytes actually read, 0 for eof, -1 for error 40 | int read(void* buf, int len) { return ::gzread(file_, buf, len); } 41 | 42 | // return the number of uncompressed bytes actually written 43 | int write(StringPiece buf) { return ::gzwrite(file_, buf.data(), buf.size()); } 44 | 45 | // number of uncompressed bytes 46 | off_t tell() const { return ::gztell(file_); } 47 | 48 | #if ZLIB_VERNUM >= 0x1240 49 | // number of compressed bytes 50 | off_t offset() const { return ::gzoffset(file_); } 51 | #endif 52 | 53 | // int flush(int f) { return ::gzflush(file_, f); } 54 | 55 | static GzipFile openForRead(StringArg filename) 56 | { 57 | return GzipFile(::gzopen(filename.c_str(), "rbe")); 58 | } 59 | 60 | static GzipFile openForAppend(StringArg filename) 61 | { 62 | return GzipFile(::gzopen(filename.c_str(), "abe")); 63 | } 64 | 65 | static GzipFile openForWriteExclusive(StringArg filename) 66 | { 67 | return GzipFile(::gzopen(filename.c_str(), "wbxe")); 68 | } 69 | 70 | static GzipFile openForWriteTruncate(StringArg filename) 71 | { 72 | return GzipFile(::gzopen(filename.c_str(), "wbe")); 73 | } 74 | 75 | private: 76 | explicit GzipFile(gzFile file) 77 | : file_(file) 78 | { 79 | } 80 | 81 | gzFile file_; 82 | }; 83 | 84 | } 85 | -------------------------------------------------------------------------------- /muduo/base/LogFile.cc: -------------------------------------------------------------------------------- 1 | #include "muduo/base/LogFile.h" 2 | 3 | #include "muduo/base/FileUtil.h" 4 | #include "muduo/base/ProcessInfo.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muduo; 11 | 12 | LogFile::LogFile(const string& basename, 13 | size_t rollSize, 14 | bool threadSafe, 15 | int flushInterval, 16 | int checkEveryN) 17 | : basename_(basename), 18 | rollSize_(rollSize), 19 | flushInterval_(flushInterval), 20 | checkEveryN_(checkEveryN), 21 | count_(0), 22 | mutex_(threadSafe ? new MutexLock : NULL), 23 | startOfPeriod_(0), 24 | lastRoll_(0), 25 | lastFlush_(0) 26 | { 27 | assert(basename.find('/') == string::npos); 28 | rollFile(); 29 | } 30 | 31 | LogFile::~LogFile() 32 | { 33 | } 34 | 35 | void LogFile::append(const char* logline, int len) 36 | { 37 | if (mutex_) 38 | { 39 | MutexLockGuard lock(*mutex_); 40 | append_unlocked(logline, len); 41 | } 42 | else 43 | { 44 | append_unlocked(logline, len); 45 | } 46 | } 47 | 48 | void LogFile::flush() 49 | { 50 | if (mutex_) 51 | { 52 | MutexLockGuard lock(*mutex_); 53 | file_->flush(); 54 | } 55 | else 56 | { 57 | file_->flush(); 58 | } 59 | } 60 | 61 | void LogFile::append_unlocked(const char* logline, int len) 62 | { 63 | file_->append(logline, len); 64 | 65 | if (file_->writtenBytes() > rollSize_) 66 | { 67 | rollFile(); 68 | } 69 | else 70 | { 71 | ++count_; 72 | if (count_ >= checkEveryN_) 73 | { 74 | count_ = 0; 75 | time_t now = ::time(NULL); 76 | time_t thisPeriod_ = now / kRollPerSeconds_ * kRollPerSeconds_; 77 | if (thisPeriod_ != startOfPeriod_) 78 | { 79 | rollFile(); 80 | } 81 | else if (now - lastFlush_ > flushInterval_) 82 | { 83 | lastFlush_ = now; 84 | file_->flush(); 85 | } 86 | } 87 | } 88 | } 89 | 90 | bool LogFile::rollFile() 91 | { 92 | time_t now = 0; 93 | string filename = getLogFileName(basename_, &now); 94 | time_t start = now / kRollPerSeconds_ * kRollPerSeconds_; 95 | 96 | if (now > lastRoll_) 97 | { 98 | lastRoll_ = now; 99 | lastFlush_ = now; 100 | startOfPeriod_ = start; 101 | file_.reset(new FileUtil::AppendFile(filename)); 102 | return true; 103 | } 104 | return false; 105 | } 106 | 107 | string LogFile::getLogFileName(const string& basename, time_t* now) 108 | { 109 | string filename; 110 | filename.reserve(basename.size() + 64); 111 | filename = basename; 112 | 113 | char timebuf[32]; 114 | struct tm tm; 115 | *now = time(NULL); 116 | //add by egypt 117 | localtime_r(now, &tm); 118 | //gmtime_r(now, &tm); // FIXME: localtime_r ? 119 | strftime(timebuf, sizeof timebuf, ".%Y%m%d-%H%M%S.", &tm); 120 | filename += timebuf; 121 | 122 | filename += ProcessInfo::hostname(); 123 | 124 | char pidbuf[32]; 125 | snprintf(pidbuf, sizeof pidbuf, ".%d", ProcessInfo::pid()); 126 | filename += pidbuf; 127 | 128 | filename += ".log"; 129 | 130 | return filename; 131 | } 132 | 133 | -------------------------------------------------------------------------------- /muduo/base/LogFile.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_LOGFILE_H 2 | #define MUDUO_BASE_LOGFILE_H 3 | 4 | #include "muduo/base/Mutex.h" 5 | #include "muduo/base/Types.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace muduo 11 | { 12 | 13 | namespace FileUtil 14 | { 15 | class AppendFile; 16 | } 17 | 18 | class LogFile : boost::noncopyable 19 | { 20 | public: 21 | LogFile(const string& basename, 22 | size_t rollSize, 23 | bool threadSafe = true, 24 | int flushInterval = 3, 25 | int checkEveryN = 1024); 26 | ~LogFile(); 27 | 28 | void append(const char* logline, int len); 29 | void flush(); 30 | bool rollFile(); 31 | 32 | private: 33 | void append_unlocked(const char* logline, int len); 34 | 35 | static string getLogFileName(const string& basename, time_t* now); 36 | 37 | const string basename_; 38 | const size_t rollSize_; 39 | const int flushInterval_; 40 | const int checkEveryN_; 41 | 42 | int count_; 43 | 44 | boost::scoped_ptr mutex_; 45 | time_t startOfPeriod_; 46 | time_t lastRoll_; 47 | time_t lastFlush_; 48 | boost::scoped_ptr file_; 49 | 50 | const static int kRollPerSeconds_ = 60*60*24; 51 | }; 52 | 53 | } 54 | #endif // MUDUO_BASE_LOGFILE_H 55 | -------------------------------------------------------------------------------- /muduo/base/LogStream.cc: -------------------------------------------------------------------------------- 1 | #include "muduo/base/LogStream.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace muduo; 12 | using namespace muduo::detail; 13 | 14 | #if defined(__clang__) 15 | #pragma clang diagnostic ignored "-Wtautological-compare" 16 | #else 17 | #pragma GCC diagnostic ignored "-Wtype-limits" 18 | #endif 19 | 20 | namespace muduo 21 | { 22 | namespace detail 23 | { 24 | 25 | const char digits[] = "9876543210123456789"; 26 | const char* zero = digits + 9; 27 | BOOST_STATIC_ASSERT(sizeof(digits) == 20); 28 | 29 | const char digitsHex[] = "0123456789ABCDEF"; 30 | BOOST_STATIC_ASSERT(sizeof digitsHex == 17); 31 | 32 | // Efficient Integer to String Conversions, by Matthew Wilson. 33 | template 34 | size_t convert(char buf[], T value) 35 | { 36 | T i = value; 37 | char* p = buf; 38 | 39 | do 40 | { 41 | int lsd = static_cast(i % 10); 42 | i /= 10; 43 | *p++ = zero[lsd]; 44 | } while (i != 0); 45 | 46 | if (value < 0) 47 | { 48 | *p++ = '-'; 49 | } 50 | *p = '\0'; 51 | std::reverse(buf, p); 52 | 53 | return p - buf; 54 | } 55 | 56 | size_t convertHex(char buf[], uintptr_t value) 57 | { 58 | uintptr_t i = value; 59 | char* p = buf; 60 | 61 | do 62 | { 63 | int lsd = i % 16; 64 | i /= 16; 65 | *p++ = digitsHex[lsd]; 66 | } while (i != 0); 67 | 68 | *p = '\0'; 69 | std::reverse(buf, p); 70 | 71 | return p - buf; 72 | } 73 | 74 | template class FixedBuffer; 75 | template class FixedBuffer; 76 | 77 | } 78 | } 79 | 80 | template 81 | const char* FixedBuffer::debugString() 82 | { 83 | *cur_ = '\0'; 84 | return data_; 85 | } 86 | 87 | template 88 | void FixedBuffer::cookieStart() 89 | { 90 | } 91 | 92 | template 93 | void FixedBuffer::cookieEnd() 94 | { 95 | } 96 | 97 | void LogStream::staticCheck() 98 | { 99 | BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10); 100 | BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10); 101 | BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10); 102 | BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10); 103 | } 104 | 105 | template 106 | void LogStream::formatInteger(T v) 107 | { 108 | if (buffer_.avail() >= kMaxNumericSize) 109 | { 110 | size_t len = convert(buffer_.current(), v); 111 | buffer_.add(len); 112 | } 113 | } 114 | 115 | LogStream& LogStream::operator<<(short v) 116 | { 117 | *this << static_cast(v); 118 | return *this; 119 | } 120 | 121 | LogStream& LogStream::operator<<(unsigned short v) 122 | { 123 | *this << static_cast(v); 124 | return *this; 125 | } 126 | 127 | LogStream& LogStream::operator<<(int v) 128 | { 129 | formatInteger(v); 130 | return *this; 131 | } 132 | 133 | LogStream& LogStream::operator<<(unsigned int v) 134 | { 135 | formatInteger(v); 136 | return *this; 137 | } 138 | 139 | LogStream& LogStream::operator<<(long v) 140 | { 141 | formatInteger(v); 142 | return *this; 143 | } 144 | 145 | LogStream& LogStream::operator<<(unsigned long v) 146 | { 147 | formatInteger(v); 148 | return *this; 149 | } 150 | 151 | LogStream& LogStream::operator<<(long long v) 152 | { 153 | formatInteger(v); 154 | return *this; 155 | } 156 | 157 | LogStream& LogStream::operator<<(unsigned long long v) 158 | { 159 | formatInteger(v); 160 | return *this; 161 | } 162 | 163 | LogStream& LogStream::operator<<(const void* p) 164 | { 165 | uintptr_t v = reinterpret_cast(p); 166 | if (buffer_.avail() >= kMaxNumericSize) 167 | { 168 | char* buf = buffer_.current(); 169 | buf[0] = '0'; 170 | buf[1] = 'x'; 171 | size_t len = convertHex(buf+2, v); 172 | buffer_.add(len+2); 173 | } 174 | return *this; 175 | } 176 | 177 | // FIXME: replace this with Grisu3 by Florian Loitsch. 178 | LogStream& LogStream::operator<<(double v) 179 | { 180 | if (buffer_.avail() >= kMaxNumericSize) 181 | { 182 | int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v); 183 | buffer_.add(len); 184 | } 185 | return *this; 186 | } 187 | 188 | template 189 | Fmt::Fmt(const char* fmt, T val) 190 | { 191 | BOOST_STATIC_ASSERT(boost::is_arithmetic::value == true); 192 | 193 | length_ = snprintf(buf_, sizeof buf_, fmt, val); 194 | assert(static_cast(length_) < sizeof buf_); 195 | } 196 | 197 | // Explicit instantiations 198 | 199 | template Fmt::Fmt(const char* fmt, char); 200 | 201 | template Fmt::Fmt(const char* fmt, short); 202 | template Fmt::Fmt(const char* fmt, unsigned short); 203 | template Fmt::Fmt(const char* fmt, int); 204 | template Fmt::Fmt(const char* fmt, unsigned int); 205 | template Fmt::Fmt(const char* fmt, long); 206 | template Fmt::Fmt(const char* fmt, unsigned long); 207 | template Fmt::Fmt(const char* fmt, long long); 208 | template Fmt::Fmt(const char* fmt, unsigned long long); 209 | 210 | template Fmt::Fmt(const char* fmt, float); 211 | template Fmt::Fmt(const char* fmt, double); 212 | -------------------------------------------------------------------------------- /muduo/base/LogStream.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_LOGSTREAM_H 2 | #define MUDUO_BASE_LOGSTREAM_H 3 | 4 | #include "muduo/base/StringPiece.h" 5 | #include "muduo/base/Types.h" 6 | #include 7 | #include // memcpy 8 | #ifndef MUDUO_STD_STRING 9 | #include 10 | #endif 11 | #include 12 | 13 | namespace muduo 14 | { 15 | 16 | namespace detail 17 | { 18 | 19 | const int kSmallBuffer = 4000; 20 | const int kLargeBuffer = 4000*1000; 21 | 22 | template 23 | class FixedBuffer : boost::noncopyable 24 | { 25 | public: 26 | FixedBuffer() 27 | : cur_(data_) 28 | { 29 | setCookie(cookieStart); 30 | } 31 | 32 | ~FixedBuffer() 33 | { 34 | setCookie(cookieEnd); 35 | } 36 | 37 | void append(const char* /*restrict*/ buf, size_t len) 38 | { 39 | // FIXME: append partially 40 | if (implicit_cast(avail()) > len) 41 | { 42 | memcpy(cur_, buf, len); 43 | cur_ += len; 44 | } 45 | } 46 | 47 | const char* data() const { return data_; } 48 | int length() const { return static_cast(cur_ - data_); } 49 | 50 | // write to data_ directly 51 | char* current() { return cur_; } 52 | int avail() const { return static_cast(end() - cur_); } 53 | void add(size_t len) { cur_ += len; } 54 | 55 | void reset() { cur_ = data_; } 56 | void bzero() { ::bzero(data_, sizeof data_); } 57 | 58 | // for used by GDB 59 | const char* debugString(); 60 | void setCookie(void (*cookie)()) { cookie_ = cookie; } 61 | // for used by unit test 62 | string asString() const { return string(data_, length()); } 63 | 64 | private: 65 | const char* end() const { return data_ + sizeof data_; } 66 | // Must be outline function for cookies. 67 | static void cookieStart(); 68 | static void cookieEnd(); 69 | 70 | void (*cookie_)(); 71 | char data_[SIZE]; 72 | char* cur_; 73 | }; 74 | 75 | } 76 | 77 | class LogStream : boost::noncopyable 78 | { 79 | typedef LogStream self; 80 | public: 81 | typedef detail::FixedBuffer Buffer; 82 | 83 | self& operator<<(bool v) 84 | { 85 | buffer_.append(v ? "1" : "0", 1); 86 | return *this; 87 | } 88 | 89 | self& operator<<(short); 90 | self& operator<<(unsigned short); 91 | self& operator<<(int); 92 | self& operator<<(unsigned int); 93 | self& operator<<(long); 94 | self& operator<<(unsigned long); 95 | self& operator<<(long long); 96 | self& operator<<(unsigned long long); 97 | 98 | self& operator<<(const void*); 99 | 100 | self& operator<<(float v) 101 | { 102 | *this << static_cast(v); 103 | return *this; 104 | } 105 | self& operator<<(double); 106 | // self& operator<<(long double); 107 | 108 | self& operator<<(char v) 109 | { 110 | buffer_.append(&v, 1); 111 | return *this; 112 | } 113 | 114 | // self& operator<<(signed char); 115 | // self& operator<<(unsigned char); 116 | 117 | self& operator<<(const char* str) 118 | { 119 | if (str) 120 | { 121 | buffer_.append(str, strlen(str)); 122 | } 123 | else 124 | { 125 | buffer_.append("(null)", 6); 126 | } 127 | return *this; 128 | } 129 | 130 | self& operator<<(const unsigned char* str) 131 | { 132 | return operator<<(reinterpret_cast(str)); 133 | } 134 | 135 | self& operator<<(const string& v) 136 | { 137 | buffer_.append(v.c_str(), v.size()); 138 | return *this; 139 | } 140 | 141 | #ifndef MUDUO_STD_STRING 142 | self& operator<<(const std::string& v) 143 | { 144 | buffer_.append(v.c_str(), v.size()); 145 | return *this; 146 | } 147 | #endif 148 | 149 | self& operator<<(const StringPiece& v) 150 | { 151 | buffer_.append(v.data(), v.size()); 152 | return *this; 153 | } 154 | 155 | void append(const char* data, int len) { buffer_.append(data, len); } 156 | const Buffer& buffer() const { return buffer_; } 157 | void resetBuffer() { buffer_.reset(); } 158 | 159 | private: 160 | void staticCheck(); 161 | 162 | template 163 | void formatInteger(T); 164 | 165 | Buffer buffer_; 166 | 167 | static const int kMaxNumericSize = 32; 168 | }; 169 | 170 | class Fmt // : boost::noncopyable 171 | { 172 | public: 173 | template 174 | Fmt(const char* fmt, T val); 175 | 176 | const char* data() const { return buf_; } 177 | int length() const { return length_; } 178 | 179 | private: 180 | char buf_[32]; 181 | int length_; 182 | }; 183 | 184 | inline LogStream& operator<<(LogStream& s, const Fmt& fmt) 185 | { 186 | s.append(fmt.data(), fmt.length()); 187 | return s; 188 | } 189 | 190 | } 191 | #endif // MUDUO_BASE_LOGSTREAM_H 192 | 193 | -------------------------------------------------------------------------------- /muduo/base/Logging.cc: -------------------------------------------------------------------------------- 1 | #include "muduo/base/Logging.h" 2 | #include "muduo/base/CurrentThread.h" 3 | #include "muduo/base/Timestamp.h" 4 | #include "muduo/base/TimeZone.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace muduo 13 | { 14 | 15 | /* 16 | class LoggerImpl 17 | { 18 | public: 19 | typedef Logger::LogLevel LogLevel; 20 | LoggerImpl(LogLevel level, int old_errno, const char* file, int line); 21 | void finish(); 22 | 23 | Timestamp time_; 24 | LogStream stream_; 25 | LogLevel level_; 26 | int line_; 27 | const char* fullname_; 28 | const char* basename_; 29 | }; 30 | */ 31 | 32 | __thread char t_errnobuf[512]; 33 | __thread char t_time[32]; 34 | __thread time_t t_lastSecond; 35 | 36 | const char* strerror_tl(int savedErrno) 37 | { 38 | return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf); 39 | } 40 | 41 | Logger::LogLevel initLogLevel() 42 | { 43 | if (::getenv("MUDUO_LOG_TRACE")) 44 | return Logger::TRACE; 45 | else if (::getenv("MUDUO_LOG_DEBUG")) 46 | return Logger::DEBUG; 47 | else 48 | return Logger::INFO; 49 | } 50 | 51 | Logger::LogLevel g_logLevel = initLogLevel(); 52 | 53 | const char* LogLevelName[Logger::NUM_LOG_LEVELS] = 54 | { 55 | "TRACE ", 56 | "DEBUG ", 57 | "INFO ", 58 | "WARN ", 59 | "ERROR ", 60 | "FATAL ", 61 | }; 62 | 63 | // helper class for known string length at compile time 64 | class T 65 | { 66 | public: 67 | T(const char* str, unsigned len) 68 | :str_(str), 69 | len_(len) 70 | { 71 | assert(strlen(str) == len_); 72 | } 73 | 74 | const char* str_; 75 | const unsigned len_; 76 | }; 77 | 78 | inline LogStream& operator<<(LogStream& s, T v) 79 | { 80 | s.append(v.str_, v.len_); 81 | return s; 82 | } 83 | 84 | inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& v) 85 | { 86 | s.append(v.data_, v.size_); 87 | return s; 88 | } 89 | /* 90 | void defaultOutput( AsyncLogging * &,const char* msg, int len) 91 | { 92 | size_t n = fwrite(msg, 1, len, stdout); 93 | //FIXME check n 94 | (void)n; 95 | } 96 | 97 | void defaultFlush(AsyncLogging * ) 98 | { 99 | fflush(stdout); 100 | } 101 | */ 102 | 103 | Logger::AsynOutputFunc g_output; 104 | Logger::AsynFlushFunc g_flush; 105 | //modify by egypt at 2014/9/26 17:09:00 106 | 107 | TimeZone g_logTimeZone(::getenv("MUDUO_TZ_PATH")?::getenv("MUDUO_TZ_PATH"):"/etc/localtime"); 108 | 109 | } 110 | 111 | using namespace muduo; 112 | 113 | Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile& file, int line) 114 | : time_(Timestamp::now()), 115 | stream_(), 116 | level_(level), 117 | line_(line), 118 | basename_(file) 119 | { 120 | formatTime(); 121 | CurrentThread::tid(); 122 | stream_ << T(CurrentThread::tidString(), CurrentThread::tidStringLength()); 123 | stream_ << T(LogLevelName[level], 6); 124 | if (savedErrno != 0) 125 | { 126 | stream_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") "; 127 | } 128 | } 129 | 130 | void Logger::Impl::formatTime() 131 | { 132 | int64_t microSecondsSinceEpoch = time_.microSecondsSinceEpoch(); 133 | time_t seconds = static_cast(microSecondsSinceEpoch / Timestamp::kMicroSecondsPerSecond); 134 | int microseconds = static_cast(microSecondsSinceEpoch % Timestamp::kMicroSecondsPerSecond); 135 | if (seconds != t_lastSecond) 136 | { 137 | t_lastSecond = seconds; 138 | struct tm tm_time; 139 | if (g_logTimeZone.valid()) 140 | { 141 | tm_time = g_logTimeZone.toLocalTime(seconds); 142 | } 143 | else 144 | { 145 | ::gmtime_r(&seconds, &tm_time); // FIXME TimeZone::fromUtcTime 146 | } 147 | 148 | int len = snprintf(t_time, sizeof(t_time), "%4d%02d%02d %02d:%02d:%02d", 149 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 150 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); 151 | assert(len == 17); (void)len; 152 | } 153 | 154 | if (g_logTimeZone.valid()) 155 | { 156 | Fmt us(".%06d ", microseconds); 157 | assert(us.length() == 8); 158 | stream_ << T(t_time, 17) << T(us.data(), 8); 159 | } 160 | else 161 | { 162 | Fmt us(".%06dZ ", microseconds); 163 | assert(us.length() == 9); 164 | stream_ << T(t_time, 17) << T(us.data(), 9); 165 | } 166 | } 167 | 168 | void Logger::Impl::finish() 169 | { 170 | stream_ << " - " << basename_ << ':' << line_ << '\n'; 171 | } 172 | 173 | Logger::Logger(SourceFile file, int line) 174 | : impl_(INFO, 0, file, line) 175 | { 176 | } 177 | 178 | Logger::Logger(SourceFile file, int line, LogLevel level, const char* func) 179 | : impl_(level, 0, file, line) 180 | { 181 | impl_.stream_ << func << ' '; 182 | } 183 | 184 | Logger::Logger(SourceFile file, int line, LogLevel level) 185 | : impl_(level, 0, file, line) 186 | { 187 | } 188 | 189 | Logger::Logger(SourceFile file, int line, bool toAbort) 190 | : impl_(toAbort?FATAL:ERROR, errno, file, line) 191 | { 192 | } 193 | 194 | Logger::~Logger() 195 | { 196 | impl_.finish(); 197 | const LogStream::Buffer& buf(stream().buffer()); 198 | if(g_output) 199 | { 200 | g_output(buf.data(), buf.length()); 201 | } 202 | if (impl_.level_ == FATAL) 203 | { 204 | if(g_flush) 205 | { 206 | g_flush(); 207 | } 208 | abort(); 209 | } 210 | } 211 | 212 | void Logger::setLogLevel(Logger::LogLevel level) 213 | { 214 | g_logLevel = level; 215 | } 216 | 217 | void Logger::setAsynOutput(const AsynOutputFunc &out) 218 | { 219 | g_output = out; 220 | } 221 | 222 | void Logger::setAsynFlush(const AsynFlushFunc &flush) 223 | { 224 | g_flush = flush; 225 | } 226 | 227 | void Logger::setTimeZone(const TimeZone& tz) 228 | { 229 | g_logTimeZone = tz; 230 | } 231 | -------------------------------------------------------------------------------- /muduo/base/Logging.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_LOGGING_H 2 | #define MUDUO_BASE_LOGGING_H 3 | 4 | #include "muduo/base/LogStream.h" 5 | #include "muduo/base/Timestamp.h" 6 | #include 7 | #include 8 | #include 9 | namespace muduo 10 | { 11 | 12 | class TimeZone; 13 | 14 | class Logger 15 | { 16 | public: 17 | enum LogLevel 18 | { 19 | TRACE, 20 | DEBUG, 21 | INFO, 22 | WARN, 23 | ERROR, 24 | FATAL, 25 | NUM_LOG_LEVELS, 26 | }; 27 | 28 | // compile time calculation of basename of source file 29 | class SourceFile 30 | { 31 | public: 32 | template 33 | inline SourceFile(const char (&arr)[N]) 34 | : data_(arr), 35 | size_(N-1) 36 | { 37 | const char* slash = strrchr(data_, '/'); // builtin function 38 | if (slash) 39 | { 40 | data_ = slash + 1; 41 | size_ -= static_cast(data_ - arr); 42 | } 43 | } 44 | 45 | explicit SourceFile(const char* filename) 46 | : data_(filename) 47 | { 48 | const char* slash = strrchr(filename, '/'); 49 | if (slash) 50 | { 51 | data_ = slash + 1; 52 | } 53 | size_ = static_cast(strlen(data_)); 54 | } 55 | 56 | const char* data_; 57 | int size_; 58 | }; 59 | 60 | Logger(SourceFile file, int line); 61 | Logger(SourceFile file, int line, LogLevel level); 62 | Logger(SourceFile file, int line, LogLevel level, const char* func); 63 | Logger(SourceFile file, int line, bool toAbort); 64 | ~Logger(); 65 | 66 | LogStream& stream() { return impl_.stream_; } 67 | 68 | static LogLevel logLevel(); 69 | static void setLogLevel(LogLevel level); 70 | typedef boost::function< void (const char*,int )> AsynOutputFunc; 71 | typedef boost::function< void ()> AsynFlushFunc; 72 | static void setAsynOutput(const AsynOutputFunc &cb); 73 | static void setAsynFlush(const AsynFlushFunc &cb); 74 | static void setTimeZone(const TimeZone& tz); 75 | private: 76 | 77 | class Impl 78 | { 79 | public: 80 | typedef Logger::LogLevel LogLevel; 81 | Impl(LogLevel level, int old_errno, const SourceFile& file, int line); 82 | void formatTime(); 83 | void finish(); 84 | 85 | Timestamp time_; 86 | LogStream stream_; 87 | LogLevel level_; 88 | int line_; 89 | SourceFile basename_; 90 | }; 91 | 92 | Impl impl_; 93 | 94 | }; 95 | 96 | extern Logger::LogLevel g_logLevel; 97 | 98 | inline Logger::LogLevel Logger::logLevel() 99 | { 100 | return g_logLevel; 101 | } 102 | 103 | // 104 | // CAUTION: do not write: 105 | // 106 | // if (good) 107 | // LOG_INFO << "Good news"; 108 | // else 109 | // LOG_WARN << "Bad news"; 110 | // 111 | // this expends to 112 | // 113 | // if (good) 114 | // if (logging_INFO) 115 | // logInfoStream << "Good news"; 116 | // else 117 | // logWarnStream << "Bad news"; 118 | // 119 | #define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \ 120 | muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream() 121 | #define LOG_DEBUG if (muduo::Logger::logLevel() <= muduo::Logger::DEBUG) \ 122 | muduo::Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream() 123 | #define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \ 124 | muduo::Logger(__FILE__, __LINE__).stream() 125 | #define LOG_WARN muduo::Logger(__FILE__, __LINE__, muduo::Logger::WARN).stream() 126 | #define LOG_ERROR muduo::Logger(__FILE__, __LINE__, muduo::Logger::ERROR).stream() 127 | #define LOG_FATAL muduo::Logger(__FILE__, __LINE__, muduo::Logger::FATAL).stream() 128 | #define LOG_SYSERR muduo::Logger(__FILE__, __LINE__, false).stream() 129 | #define LOG_SYSFATAL muduo::Logger(__FILE__, __LINE__, true).stream() 130 | 131 | const char* strerror_tl(int savedErrno); 132 | 133 | // Taken from glog/logging.h 134 | // 135 | // Check that the input is non NULL. This very useful in constructor 136 | // initializer lists. 137 | 138 | #define CHECK_NOTNULL(val) \ 139 | ::muduo::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) 140 | 141 | // A small helper for CHECK_NOTNULL(). 142 | template 143 | T* CheckNotNull(Logger::SourceFile file, int line, const char *names, T* ptr) { 144 | if (ptr == NULL) { 145 | Logger(file, line, Logger::FATAL).stream() << names; 146 | } 147 | return ptr; 148 | } 149 | 150 | } 151 | 152 | #endif // MUDUO_BASE_LOGGING_H 153 | -------------------------------------------------------------------------------- /muduo/base/Mutex.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_MUTEX_H 7 | #define MUDUO_BASE_MUTEX_H 8 | 9 | #include "muduo/base/CurrentThread.h" 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef CHECK_PTHREAD_RETURN_VALUE 15 | 16 | #ifdef NDEBUG 17 | __BEGIN_DECLS 18 | extern void __assert_perror_fail (int errnum, 19 | const char *file, 20 | unsigned int line, 21 | const char *function) 22 | __THROW __attribute__ ((__noreturn__)); 23 | __END_DECLS 24 | #endif 25 | 26 | #define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ 27 | if (__builtin_expect(errnum != 0, 0)) \ 28 | __assert_perror_fail (errnum, __FILE__, __LINE__, __func__);}) 29 | 30 | #else // CHECK_PTHREAD_RETURN_VALUE 31 | 32 | #define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ 33 | assert(errnum == 0); (void) errnum;}) 34 | 35 | #endif // CHECK_PTHREAD_RETURN_VALUE 36 | 37 | namespace muduo 38 | { 39 | 40 | // Use as data member of a class, eg. 41 | // 42 | // class Foo 43 | // { 44 | // public: 45 | // int size() const; 46 | // 47 | // private: 48 | // mutable MutexLock mutex_; 49 | // std::vector data_; // GUARDED BY mutex_ 50 | // }; 51 | class MutexLock : boost::noncopyable 52 | { 53 | public: 54 | MutexLock() 55 | : holder_(0) 56 | { 57 | MCHECK(pthread_mutex_init(&mutex_, NULL)); 58 | } 59 | 60 | ~MutexLock() 61 | { 62 | assert(holder_ == 0); 63 | MCHECK(pthread_mutex_destroy(&mutex_)); 64 | } 65 | 66 | // must be called when locked, i.e. for assertion 67 | bool isLockedByThisThread() const 68 | { 69 | return holder_ == CurrentThread::tid(); 70 | } 71 | 72 | void assertLocked() const 73 | { 74 | assert(isLockedByThisThread()); 75 | } 76 | 77 | // internal usage 78 | 79 | void lock() 80 | { 81 | MCHECK(pthread_mutex_lock(&mutex_)); 82 | assignHolder(); 83 | } 84 | 85 | void unlock() 86 | { 87 | unassignHolder(); 88 | MCHECK(pthread_mutex_unlock(&mutex_)); 89 | } 90 | 91 | pthread_mutex_t* getPthreadMutex() /* non-const */ 92 | { 93 | return &mutex_; 94 | } 95 | 96 | private: 97 | friend class Condition; 98 | 99 | class UnassignGuard : boost::noncopyable 100 | { 101 | public: 102 | UnassignGuard(MutexLock& owner) 103 | : owner_(owner) 104 | { 105 | owner_.unassignHolder(); 106 | } 107 | 108 | ~UnassignGuard() 109 | { 110 | owner_.assignHolder(); 111 | } 112 | 113 | private: 114 | MutexLock& owner_; 115 | }; 116 | 117 | void unassignHolder() 118 | { 119 | holder_ = 0; 120 | } 121 | 122 | void assignHolder() 123 | { 124 | holder_ = CurrentThread::tid(); 125 | } 126 | 127 | pthread_mutex_t mutex_; 128 | pid_t holder_; 129 | }; 130 | 131 | // Use as a stack variable, eg. 132 | // int Foo::size() const 133 | // { 134 | // MutexLockGuard lock(mutex_); 135 | // return data_.size(); 136 | // } 137 | class MutexLockGuard : boost::noncopyable 138 | { 139 | public: 140 | explicit MutexLockGuard(MutexLock& mutex) 141 | : mutex_(mutex) 142 | { 143 | mutex_.lock(); 144 | } 145 | 146 | ~MutexLockGuard() 147 | { 148 | mutex_.unlock(); 149 | } 150 | 151 | private: 152 | 153 | MutexLock& mutex_; 154 | }; 155 | 156 | } 157 | 158 | // Prevent misuse like: 159 | // MutexLockGuard(mutex_); 160 | // A tempory object doesn't hold the lock for long! 161 | #define MutexLockGuard(x) error "Missing guard object name" 162 | 163 | #endif // MUDUO_BASE_MUTEX_H 164 | -------------------------------------------------------------------------------- /muduo/base/ProcessInfo.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include "muduo/base/ProcessInfo.h" 11 | #include "muduo/base/CurrentThread.h" 12 | #include "muduo/base/FileUtil.h" 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include // snprintf 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace muduo 26 | { 27 | namespace detail 28 | { 29 | __thread int t_numOpenedFiles = 0; 30 | int fdDirFilter(const struct dirent* d) 31 | { 32 | if (::isdigit(d->d_name[0])) 33 | { 34 | ++t_numOpenedFiles; 35 | } 36 | return 0; 37 | } 38 | 39 | __thread std::vector* t_pids = NULL; 40 | int taskDirFilter(const struct dirent* d) 41 | { 42 | if (::isdigit(d->d_name[0])) 43 | { 44 | t_pids->push_back(atoi(d->d_name)); 45 | } 46 | return 0; 47 | } 48 | 49 | int scanDir(const char *dirpath, int (*filter)(const struct dirent *)) 50 | { 51 | struct dirent** namelist = NULL; 52 | int result = ::scandir(dirpath, &namelist, filter, alphasort); 53 | assert(namelist == NULL); 54 | return result; 55 | } 56 | 57 | Timestamp g_startTime = Timestamp::now(); 58 | // assume those won't change during the life time of a process. 59 | int g_clockTicks = static_cast(::sysconf(_SC_CLK_TCK)); 60 | int g_pageSize = static_cast(::sysconf(_SC_PAGE_SIZE)); 61 | } 62 | } 63 | 64 | using namespace muduo; 65 | using namespace muduo::detail; 66 | 67 | pid_t ProcessInfo::pid() 68 | { 69 | return ::getpid(); 70 | } 71 | 72 | string ProcessInfo::pidString() 73 | { 74 | char buf[32]; 75 | snprintf(buf, sizeof buf, "%d", pid()); 76 | return buf; 77 | } 78 | 79 | uid_t ProcessInfo::uid() 80 | { 81 | return ::getuid(); 82 | } 83 | 84 | string ProcessInfo::username() 85 | { 86 | struct passwd pwd; 87 | struct passwd* result = NULL; 88 | char buf[8192]; 89 | const char* name = "unknownuser"; 90 | 91 | getpwuid_r(uid(), &pwd, buf, sizeof buf, &result); 92 | if (result) 93 | { 94 | name = pwd.pw_name; 95 | } 96 | return name; 97 | } 98 | 99 | uid_t ProcessInfo::euid() 100 | { 101 | return ::geteuid(); 102 | } 103 | 104 | Timestamp ProcessInfo::startTime() 105 | { 106 | return g_startTime; 107 | } 108 | 109 | int ProcessInfo::clockTicksPerSecond() 110 | { 111 | return g_clockTicks; 112 | } 113 | 114 | int ProcessInfo::pageSize() 115 | { 116 | return g_pageSize; 117 | } 118 | 119 | bool ProcessInfo::isDebugBuild() 120 | { 121 | #ifdef NDEBUG 122 | return false; 123 | #else 124 | return true; 125 | #endif 126 | } 127 | 128 | string ProcessInfo::hostname() 129 | { 130 | // HOST_NAME_MAX 64 131 | // _POSIX_HOST_NAME_MAX 255 132 | char buf[256]; 133 | if (::gethostname(buf, sizeof buf) == 0) 134 | { 135 | buf[sizeof(buf)-1] = '\0'; 136 | return buf; 137 | } 138 | else 139 | { 140 | return "unknownhost"; 141 | } 142 | } 143 | 144 | string ProcessInfo::procname() 145 | { 146 | return procname(procStat()).as_string(); 147 | } 148 | 149 | StringPiece ProcessInfo::procname(const string& stat) 150 | { 151 | StringPiece name; 152 | size_t lp = stat.find('('); 153 | size_t rp = stat.rfind(')'); 154 | if (lp != string::npos && rp != string::npos && lp < rp) 155 | { 156 | name.set(stat.data()+lp+1, static_cast(rp-lp-1)); 157 | } 158 | return name; 159 | } 160 | 161 | string ProcessInfo::procStatus() 162 | { 163 | string result; 164 | FileUtil::readFile("/proc/self/status", 65536, &result); 165 | return result; 166 | } 167 | 168 | string ProcessInfo::procStat() 169 | { 170 | string result; 171 | FileUtil::readFile("/proc/self/stat", 65536, &result); 172 | return result; 173 | } 174 | 175 | string ProcessInfo::threadStat() 176 | { 177 | char buf[64]; 178 | snprintf(buf, sizeof buf, "/proc/self/task/%d/stat", CurrentThread::tid()); 179 | string result; 180 | FileUtil::readFile(buf, 65536, &result); 181 | return result; 182 | } 183 | 184 | string ProcessInfo::exePath() 185 | { 186 | string result; 187 | char buf[1024]; 188 | ssize_t n = ::readlink("/proc/self/exe", buf, sizeof buf); 189 | if (n > 0) 190 | { 191 | result.assign(buf, n); 192 | } 193 | return result; 194 | } 195 | 196 | int ProcessInfo::openedFiles() 197 | { 198 | t_numOpenedFiles = 0; 199 | scanDir("/proc/self/fd", fdDirFilter); 200 | return t_numOpenedFiles; 201 | } 202 | 203 | int ProcessInfo::maxOpenFiles() 204 | { 205 | struct rlimit rl; 206 | if (::getrlimit(RLIMIT_NOFILE, &rl)) 207 | { 208 | return openedFiles(); 209 | } 210 | else 211 | { 212 | return static_cast(rl.rlim_cur); 213 | } 214 | } 215 | 216 | ProcessInfo::CpuTime ProcessInfo::cpuTime() 217 | { 218 | ProcessInfo::CpuTime t; 219 | struct tms tms; 220 | if (::times(&tms) >= 0) 221 | { 222 | const double hz = static_cast(clockTicksPerSecond()); 223 | t.userSeconds = static_cast(tms.tms_utime) / hz; 224 | t.systemSeconds = static_cast(tms.tms_stime) / hz; 225 | } 226 | return t; 227 | } 228 | 229 | int ProcessInfo::numThreads() 230 | { 231 | int result = 0; 232 | string status = procStatus(); 233 | size_t pos = status.find("Threads:"); 234 | if (pos != string::npos) 235 | { 236 | result = ::atoi(status.c_str() + pos + 8); 237 | } 238 | return result; 239 | } 240 | 241 | std::vector ProcessInfo::threads() 242 | { 243 | std::vector result; 244 | t_pids = &result; 245 | scanDir("/proc/self/task", taskDirFilter); 246 | t_pids = NULL; 247 | std::sort(result.begin(), result.end()); 248 | return result; 249 | } 250 | 251 | -------------------------------------------------------------------------------- /muduo/base/ProcessInfo.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_BASE_PROCESSINFO_H 12 | #define MUDUO_BASE_PROCESSINFO_H 13 | 14 | #include "muduo/base/StringPiece.h" 15 | #include "muduo/base/Types.h" 16 | #include "muduo/base/Timestamp.h" 17 | #include 18 | 19 | namespace muduo 20 | { 21 | 22 | namespace ProcessInfo 23 | { 24 | pid_t pid(); 25 | string pidString(); 26 | uid_t uid(); 27 | string username(); 28 | uid_t euid(); 29 | Timestamp startTime(); 30 | int clockTicksPerSecond(); 31 | int pageSize(); 32 | bool isDebugBuild(); // constexpr 33 | 34 | string hostname(); 35 | string procname(); 36 | StringPiece procname(const string& stat); 37 | 38 | /// read /proc/self/status 39 | string procStatus(); 40 | 41 | /// read /proc/self/stat 42 | string procStat(); 43 | 44 | /// read /proc/self/task/tid/stat 45 | string threadStat(); 46 | 47 | /// readlink /proc/self/exe 48 | string exePath(); 49 | 50 | int openedFiles(); 51 | int maxOpenFiles(); 52 | 53 | struct CpuTime 54 | { 55 | double userSeconds; 56 | double systemSeconds; 57 | 58 | CpuTime() : userSeconds(0.0), systemSeconds(0.0) { } 59 | }; 60 | CpuTime cpuTime(); 61 | 62 | int numThreads(); 63 | std::vector threads(); 64 | } 65 | 66 | } 67 | 68 | #endif // MUDUO_BASE_PROCESSINFO_H 69 | -------------------------------------------------------------------------------- /muduo/base/Singleton.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_SINGLETON_H 7 | #define MUDUO_BASE_SINGLETON_H 8 | 9 | #include 10 | #include 11 | #include // atexit 12 | 13 | namespace muduo 14 | { 15 | 16 | namespace detail 17 | { 18 | // This doesn't detect inherited member functions! 19 | // http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions 20 | template 21 | struct has_no_destroy 22 | { 23 | template static char test(typeof(&C::no_destroy)); // or decltype in C++11 24 | template static int32_t test(...); 25 | const static bool value = sizeof(test(0)) == 1; 26 | }; 27 | } 28 | 29 | template 30 | class Singleton : boost::noncopyable 31 | { 32 | public: 33 | static T& instance() 34 | { 35 | pthread_once(&ponce_, &Singleton::init); 36 | return *value_; 37 | } 38 | 39 | private: 40 | Singleton(); 41 | ~Singleton(); 42 | 43 | static void init() 44 | { 45 | value_ = new T(); 46 | if (!detail::has_no_destroy::value) 47 | { 48 | ::atexit(destroy); 49 | } 50 | } 51 | 52 | static void destroy() 53 | { 54 | typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; 55 | T_must_be_complete_type dummy; (void) dummy; 56 | 57 | delete value_; 58 | } 59 | 60 | private: 61 | static pthread_once_t ponce_; 62 | static T* value_; 63 | }; 64 | 65 | template 66 | pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT; 67 | 68 | template 69 | T* Singleton::value_ = NULL; 70 | 71 | } 72 | #endif 73 | 74 | -------------------------------------------------------------------------------- /muduo/base/Thread.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_THREAD_H 7 | #define MUDUO_BASE_THREAD_H 8 | 9 | #include "muduo/base/Atomic.h" 10 | #include "muduo/base/Types.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace muduo 18 | { 19 | 20 | class Thread : boost::noncopyable 21 | { 22 | public: 23 | typedef boost::function ThreadFunc; 24 | 25 | explicit Thread(const ThreadFunc&, const string& name = string()); 26 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 27 | explicit Thread(ThreadFunc&&, const string& name = string()); 28 | #endif 29 | ~Thread(); 30 | 31 | void start(); 32 | int join(); // return pthread_join() 33 | 34 | bool started() const { return started_; } 35 | // pthread_t pthreadId() const { return pthreadId_; } 36 | pid_t tid() const { return *tid_; } 37 | const string& name() const { return name_; } 38 | 39 | static int numCreated() { return numCreated_.get(); } 40 | 41 | private: 42 | void setDefaultName(); 43 | 44 | bool started_; 45 | bool joined_; 46 | pthread_t pthreadId_; 47 | boost::shared_ptr tid_; 48 | ThreadFunc func_; 49 | string name_; 50 | 51 | static AtomicInt32 numCreated_; 52 | }; 53 | 54 | } 55 | #endif 56 | -------------------------------------------------------------------------------- /muduo/base/ThreadLocal.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_THREADLOCAL_H 7 | #define MUDUO_BASE_THREADLOCAL_H 8 | 9 | #include 10 | #include 11 | 12 | namespace muduo 13 | { 14 | 15 | template 16 | class ThreadLocal : boost::noncopyable 17 | { 18 | public: 19 | ThreadLocal() 20 | { 21 | pthread_key_create(&pkey_, &ThreadLocal::destructor); 22 | } 23 | 24 | ~ThreadLocal() 25 | { 26 | pthread_key_delete(pkey_); 27 | } 28 | 29 | T& value() 30 | { 31 | T* perThreadValue = static_cast(pthread_getspecific(pkey_)); 32 | if (!perThreadValue) 33 | { 34 | T* newObj = new T(); 35 | pthread_setspecific(pkey_, newObj); 36 | perThreadValue = newObj; 37 | } 38 | return *perThreadValue; 39 | } 40 | 41 | private: 42 | 43 | static void destructor(void *x) 44 | { 45 | T* obj = static_cast(x); 46 | typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; 47 | T_must_be_complete_type dummy; (void) dummy; 48 | delete obj; 49 | } 50 | 51 | private: 52 | pthread_key_t pkey_; 53 | }; 54 | 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /muduo/base/ThreadLocalSingleton.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_THREADLOCALSINGLETON_H 7 | #define MUDUO_BASE_THREADLOCALSINGLETON_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace muduo 14 | { 15 | 16 | template 17 | class ThreadLocalSingleton : boost::noncopyable 18 | { 19 | public: 20 | 21 | static T& instance() 22 | { 23 | if (!t_value_) 24 | { 25 | t_value_ = new T(); 26 | deleter_.set(t_value_); 27 | } 28 | return *t_value_; 29 | } 30 | 31 | static T* pointer() 32 | { 33 | return t_value_; 34 | } 35 | 36 | private: 37 | ThreadLocalSingleton(); 38 | ~ThreadLocalSingleton(); 39 | 40 | static void destructor(void* obj) 41 | { 42 | assert(obj == t_value_); 43 | typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; 44 | T_must_be_complete_type dummy; (void) dummy; 45 | delete t_value_; 46 | t_value_ = 0; 47 | } 48 | 49 | class Deleter 50 | { 51 | public: 52 | Deleter() 53 | { 54 | pthread_key_create(&pkey_, &ThreadLocalSingleton::destructor); 55 | } 56 | 57 | ~Deleter() 58 | { 59 | pthread_key_delete(pkey_); 60 | } 61 | 62 | void set(T* newObj) 63 | { 64 | assert(pthread_getspecific(pkey_) == NULL); 65 | pthread_setspecific(pkey_, newObj); 66 | } 67 | 68 | pthread_key_t pkey_; 69 | }; 70 | 71 | static __thread T* t_value_; 72 | static Deleter deleter_; 73 | }; 74 | 75 | template 76 | __thread T* ThreadLocalSingleton::t_value_ = 0; 77 | 78 | template 79 | typename ThreadLocalSingleton::Deleter ThreadLocalSingleton::deleter_; 80 | 81 | } 82 | #endif 83 | -------------------------------------------------------------------------------- /muduo/base/ThreadPool.cc: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #include "muduo/base/ThreadPool.h" 7 | 8 | #include "muduo/base/Exception.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace muduo; 15 | 16 | ThreadPool::ThreadPool(const string& name) 17 | : mutex_(), 18 | notEmpty_(mutex_), 19 | notFull_(mutex_), 20 | name_(name), 21 | maxQueueSize_(0), 22 | running_(false) 23 | { 24 | } 25 | 26 | ThreadPool::~ThreadPool() 27 | { 28 | if (running_) 29 | { 30 | stop(); 31 | } 32 | } 33 | 34 | void ThreadPool::start(int numThreads) 35 | { 36 | assert(threads_.empty()); 37 | running_ = true; 38 | threads_.reserve(numThreads); 39 | for (int i = 0; i < numThreads; ++i) 40 | { 41 | char id[32]; 42 | snprintf(id, sizeof id, "%d", i+1); 43 | threads_.push_back(new muduo::Thread( 44 | boost::bind(&ThreadPool::runInThread, this), name_+id)); 45 | threads_[i].start(); 46 | } 47 | if (numThreads == 0 && threadInitCallback_) 48 | { 49 | threadInitCallback_(); 50 | } 51 | } 52 | 53 | void ThreadPool::stop() 54 | { 55 | { 56 | MutexLockGuard lock(mutex_); 57 | running_ = false; 58 | notEmpty_.notifyAll(); 59 | } 60 | for_each(threads_.begin(), 61 | threads_.end(), 62 | boost::bind(&muduo::Thread::join, _1)); 63 | } 64 | 65 | void ThreadPool::run(const Task& task) 66 | { 67 | if (threads_.empty()) 68 | { 69 | task(); 70 | } 71 | else 72 | { 73 | MutexLockGuard lock(mutex_); 74 | while (isFull()) 75 | { 76 | notFull_.wait(); 77 | } 78 | assert(!isFull()); 79 | 80 | queue_.push_back(task); 81 | notEmpty_.notify(); 82 | } 83 | } 84 | 85 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 86 | void ThreadPool::run(Task&& task) 87 | { 88 | if (threads_.empty()) 89 | { 90 | task(); 91 | } 92 | else 93 | { 94 | MutexLockGuard lock(mutex_); 95 | while (isFull()) 96 | { 97 | notFull_.wait(); 98 | } 99 | assert(!isFull()); 100 | 101 | queue_.push_back(std::move(task)); 102 | notEmpty_.notify(); 103 | } 104 | } 105 | #endif 106 | 107 | ThreadPool::Task ThreadPool::take() 108 | { 109 | MutexLockGuard lock(mutex_); 110 | // always use a while-loop, due to spurious wakeup 111 | while (queue_.empty() && running_) 112 | { 113 | notEmpty_.wait(); 114 | } 115 | Task task; 116 | if (!queue_.empty()) 117 | { 118 | task = queue_.front(); 119 | queue_.pop_front(); 120 | if (maxQueueSize_ > 0) 121 | { 122 | notFull_.notify(); 123 | } 124 | } 125 | return task; 126 | } 127 | 128 | bool ThreadPool::isFull() const 129 | { 130 | mutex_.assertLocked(); 131 | return maxQueueSize_ > 0 && queue_.size() >= maxQueueSize_; 132 | } 133 | 134 | void ThreadPool::runInThread() 135 | { 136 | try 137 | { 138 | if (threadInitCallback_) 139 | { 140 | threadInitCallback_(); 141 | } 142 | while (running_) 143 | { 144 | Task task(take()); 145 | if (task) 146 | { 147 | task(); 148 | } 149 | } 150 | } 151 | catch (const Exception& ex) 152 | { 153 | fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); 154 | fprintf(stderr, "reason: %s\n", ex.what()); 155 | fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); 156 | abort(); 157 | } 158 | catch (const std::exception& ex) 159 | { 160 | fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); 161 | fprintf(stderr, "reason: %s\n", ex.what()); 162 | abort(); 163 | } 164 | catch (...) 165 | { 166 | fprintf(stderr, "unknown exception caught in ThreadPool %s\n", name_.c_str()); 167 | throw; // rethrow 168 | } 169 | } 170 | 171 | -------------------------------------------------------------------------------- /muduo/base/ThreadPool.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_THREADPOOL_H 7 | #define MUDUO_BASE_THREADPOOL_H 8 | 9 | #include "muduo/base/Condition.h" 10 | #include "muduo/base/Mutex.h" 11 | #include "muduo/base/Thread.h" 12 | #include "muduo/base/Types.h" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | namespace muduo 21 | { 22 | 23 | class ThreadPool : boost::noncopyable 24 | { 25 | public: 26 | typedef boost::function Task; 27 | 28 | explicit ThreadPool(const string& name = string("ThreadPool")); 29 | ~ThreadPool(); 30 | 31 | // Must be called before start(). 32 | void setMaxQueueSize(int maxSize) { maxQueueSize_ = maxSize; } 33 | void setThreadInitCallback(const Task& cb) 34 | { threadInitCallback_ = cb; } 35 | 36 | void start(int numThreads); 37 | void stop(); 38 | 39 | // Could block if maxQueueSize > 0 40 | void run(const Task& f); 41 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 42 | void run(Task&& f); 43 | #endif 44 | 45 | private: 46 | bool isFull() const; 47 | void runInThread(); 48 | Task take(); 49 | 50 | MutexLock mutex_; 51 | Condition notEmpty_; 52 | Condition notFull_; 53 | string name_; 54 | Task threadInitCallback_; 55 | boost::ptr_vector threads_; 56 | std::deque queue_; 57 | size_t maxQueueSize_; 58 | bool running_; 59 | }; 60 | 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /muduo/base/TimeZone.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_TIMEZONE_H 7 | #define MUDUO_BASE_TIMEZONE_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace muduo 14 | { 15 | 16 | // TimeZone for 1970~2030 17 | class TimeZone : public muduo::copyable 18 | { 19 | public: 20 | explicit TimeZone(const char* zonefile); 21 | TimeZone(int eastOfUtc, const char* tzname); // a fixed timezone 22 | TimeZone() {} // an invalid timezone 23 | 24 | // default copy ctor/assignment/dtor are Okay. 25 | 26 | bool valid() const 27 | { 28 | // 'explicit operator bool() const' in C++11 29 | return static_cast(data_); 30 | } 31 | 32 | struct tm toLocalTime(time_t secondsSinceEpoch) const; 33 | time_t fromLocalTime(const struct tm&) const; 34 | 35 | // gmtime(3) 36 | static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false); 37 | // timegm(3) 38 | static time_t fromUtcTime(const struct tm&); 39 | // year in [1900..2500], month in [1..12], day in [1..31] 40 | static time_t fromUtcTime(int year, int month, int day, 41 | int hour, int minute, int seconds); 42 | 43 | struct Data; 44 | 45 | private: 46 | 47 | boost::shared_ptr data_; 48 | }; 49 | 50 | } 51 | #endif // MUDUO_BASE_TIMEZONE_H 52 | -------------------------------------------------------------------------------- /muduo/base/Timestamp.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #ifndef __STDC_FORMAT_MACROS 7 | #define __STDC_FORMAT_MACROS 8 | #endif 9 | 10 | #include 11 | 12 | #include 13 | 14 | using namespace muduo; 15 | 16 | BOOST_STATIC_ASSERT(sizeof(Timestamp) == sizeof(int64_t)); 17 | 18 | string Timestamp::toString() const 19 | { 20 | char buf[32] = {0}; 21 | int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond; 22 | int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond; 23 | snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds); 24 | return buf; 25 | } 26 | 27 | string Timestamp::toFormattedString(bool showMicroseconds) const 28 | { 29 | char buf[32] = {0}; 30 | time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); 31 | struct tm tm_time; 32 | gmtime_r(&seconds, &tm_time); 33 | 34 | if (showMicroseconds) 35 | { 36 | int microseconds = static_cast(microSecondsSinceEpoch_ % kMicroSecondsPerSecond); 37 | snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d", 38 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 39 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, 40 | microseconds); 41 | } 42 | else 43 | { 44 | snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d", 45 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 46 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); 47 | } 48 | return buf; 49 | } 50 | 51 | Timestamp Timestamp::now() 52 | { 53 | struct timeval tv; 54 | gettimeofday(&tv, NULL); 55 | int64_t seconds = tv.tv_sec; 56 | return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec); 57 | } 58 | 59 | -------------------------------------------------------------------------------- /muduo/base/Timestamp.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_TIMESTAMP_H 2 | #define MUDUO_BASE_TIMESTAMP_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace muduo 10 | { 11 | 12 | /// 13 | /// Time stamp in UTC, in microseconds resolution. 14 | /// 15 | /// This class is immutable. 16 | /// It's recommended to pass it by value, since it's passed in register on x64. 17 | /// 18 | class Timestamp : public muduo::copyable, 19 | public boost::less_than_comparable 20 | { 21 | public: 22 | /// 23 | /// Constucts an invalid Timestamp. 24 | /// 25 | Timestamp() 26 | : microSecondsSinceEpoch_(0) 27 | { 28 | } 29 | 30 | /// 31 | /// Constucts a Timestamp at specific time 32 | /// 33 | /// @param microSecondsSinceEpoch 34 | explicit Timestamp(int64_t microSecondsSinceEpochArg) 35 | : microSecondsSinceEpoch_(microSecondsSinceEpochArg) 36 | { 37 | } 38 | 39 | void swap(Timestamp& that) 40 | { 41 | std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_); 42 | } 43 | 44 | // default copy/assignment/dtor are Okay 45 | 46 | string toString() const; 47 | string toFormattedString(bool showMicroseconds = true) const; 48 | 49 | bool valid() const { return microSecondsSinceEpoch_ > 0; } 50 | 51 | // for internal usage. 52 | int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; } 53 | time_t secondsSinceEpoch() const 54 | { return static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); } 55 | 56 | /// 57 | /// Get time of now. 58 | /// 59 | static Timestamp now(); 60 | static Timestamp invalid() 61 | { 62 | return Timestamp(); 63 | } 64 | 65 | static Timestamp fromUnixTime(time_t t) 66 | { 67 | return fromUnixTime(t, 0); 68 | } 69 | 70 | static Timestamp fromUnixTime(time_t t, int microseconds) 71 | { 72 | return Timestamp(static_cast(t) * kMicroSecondsPerSecond + microseconds); 73 | } 74 | 75 | static const int kMicroSecondsPerSecond = 1000 * 1000; 76 | 77 | private: 78 | int64_t microSecondsSinceEpoch_; 79 | }; 80 | 81 | inline bool operator<(Timestamp lhs, Timestamp rhs) 82 | { 83 | return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch(); 84 | } 85 | 86 | inline bool operator==(Timestamp lhs, Timestamp rhs) 87 | { 88 | return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch(); 89 | } 90 | 91 | /// 92 | /// Gets time difference of two timestamps, result in seconds. 93 | /// 94 | /// @param high, low 95 | /// @return (high-low) in seconds 96 | /// @c double has 52-bit precision, enough for one-microsecond 97 | /// resolution for next 100 years. 98 | inline double timeDifference(Timestamp high, Timestamp low) 99 | { 100 | int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch(); 101 | return static_cast(diff) / Timestamp::kMicroSecondsPerSecond; 102 | } 103 | 104 | /// 105 | /// Add @c seconds to given timestamp. 106 | /// 107 | /// @return timestamp+seconds as Timestamp 108 | /// 109 | inline Timestamp addTime(Timestamp timestamp, double seconds) 110 | { 111 | int64_t delta = static_cast(seconds * Timestamp::kMicroSecondsPerSecond); 112 | return Timestamp(timestamp.microSecondsSinceEpoch() + delta); 113 | } 114 | 115 | } 116 | #endif // MUDUO_BASE_TIMESTAMP_H 117 | -------------------------------------------------------------------------------- /muduo/base/Types.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_TYPES_H 2 | #define MUDUO_BASE_TYPES_H 3 | 4 | #include 5 | #ifdef MUDUO_STD_STRING 6 | #include 7 | #else // !MUDUO_STD_STRING 8 | #include 9 | #include 10 | #endif 11 | 12 | #ifndef NDEBUG 13 | #include 14 | #endif 15 | 16 | /// 17 | /// The most common stuffs. 18 | /// 19 | namespace muduo 20 | { 21 | 22 | #ifdef MUDUO_STD_STRING 23 | using std::string; 24 | #else // !MUDUO_STD_STRING 25 | typedef __gnu_cxx::__sso_string string; 26 | #endif 27 | 28 | // Taken from google-protobuf stubs/common.h 29 | // 30 | // Protocol Buffers - Google's data interchange format 31 | // Copyright 2008 Google Inc. All rights reserved. 32 | // http://code.google.com/p/protobuf/ 33 | // 34 | // Redistribution and use in source and binary forms, with or without 35 | // modification, are permitted provided that the following conditions are 36 | // met: 37 | // 38 | // * Redistributions of source code must retain the above copyright 39 | // notice, this list of conditions and the following disclaimer. 40 | // * Redistributions in binary form must reproduce the above 41 | // copyright notice, this list of conditions and the following disclaimer 42 | // in the documentation and/or other materials provided with the 43 | // distribution. 44 | // * Neither the name of Google Inc. nor the names of its 45 | // contributors may be used to endorse or promote products derived from 46 | // this software without specific prior written permission. 47 | // 48 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 49 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 50 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 51 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 52 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 53 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 54 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 55 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 56 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 57 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 58 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 | 60 | // Author: kenton@google.com (Kenton Varda) and others 61 | // 62 | // Contains basic types and utilities used by the rest of the library. 63 | 64 | // 65 | // Use implicit_cast as a safe version of static_cast or const_cast 66 | // for upcasting in the type hierarchy (i.e. casting a pointer to Foo 67 | // to a pointer to SuperclassOfFoo or casting a pointer to Foo to 68 | // a const pointer to Foo). 69 | // When you use implicit_cast, the compiler checks that the cast is safe. 70 | // Such explicit implicit_casts are necessary in surprisingly many 71 | // situations where C++ demands an exact type match instead of an 72 | // argument type convertable to a target type. 73 | // 74 | // The From type can be inferred, so the preferred syntax for using 75 | // implicit_cast is the same as for static_cast etc.: 76 | // 77 | // implicit_cast(expr) 78 | // 79 | // implicit_cast would have been part of the C++ standard library, 80 | // but the proposal was submitted too late. It will probably make 81 | // its way into the language in the future. 82 | template 83 | inline To implicit_cast(From const &f) { 84 | return f; 85 | } 86 | 87 | // When you upcast (that is, cast a pointer from type Foo to type 88 | // SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts 89 | // always succeed. When you downcast (that is, cast a pointer from 90 | // type Foo to type SubclassOfFoo), static_cast<> isn't safe, because 91 | // how do you know the pointer is really of type SubclassOfFoo? It 92 | // could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, 93 | // when you downcast, you should use this macro. In debug mode, we 94 | // use dynamic_cast<> to double-check the downcast is legal (we die 95 | // if it's not). In normal mode, we do the efficient static_cast<> 96 | // instead. Thus, it's important to test in debug mode to make sure 97 | // the cast is legal! 98 | // This is the only place in the code we should use dynamic_cast<>. 99 | // In particular, you SHOULDN'T be using dynamic_cast<> in order to 100 | // do RTTI (eg code like this: 101 | // if (dynamic_cast(foo)) HandleASubclass1Object(foo); 102 | // if (dynamic_cast(foo)) HandleASubclass2Object(foo); 103 | // You should design the code some other way not to need this. 104 | 105 | template // use like this: down_cast(foo); 106 | inline To down_cast(From* f) { // so we only accept pointers 107 | // Ensures that To is a sub-type of From *. This test is here only 108 | // for compile-time type checking, and has no overhead in an 109 | // optimized build at run-time, as it will be optimized away 110 | // completely. 111 | if (false) { 112 | implicit_cast(0); 113 | } 114 | 115 | #if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) 116 | assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! 117 | #endif 118 | return static_cast(f); 119 | } 120 | 121 | } 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /muduo/base/WeakCallback.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | // 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #ifndef MUDUO_BASE_WEAKCALLBACK_H 10 | #define MUDUO_BASE_WEAKCALLBACK_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace muduo 17 | { 18 | 19 | // A barely usable WeakCallback 20 | 21 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 22 | 23 | // FIXME: support std::shared_ptr as well, maybe using template template parameters 24 | 25 | template 26 | class WeakCallback 27 | { 28 | public: 29 | 30 | WeakCallback(const boost::weak_ptr& object, 31 | const std::function& function) 32 | : object_(object), function_(function) 33 | { 34 | } 35 | 36 | // Default dtor, copy ctor and assignment are okay 37 | 38 | void operator()(ARGS&&... args) const 39 | { 40 | boost::shared_ptr ptr(object_.lock()); 41 | if (ptr) 42 | { 43 | function_(ptr.get(), std::forward(args)...); 44 | } 45 | // else 46 | // { 47 | // LOG_TRACE << "expired"; 48 | // } 49 | } 50 | 51 | private: 52 | 53 | boost::weak_ptr object_; 54 | std::function function_; 55 | }; 56 | 57 | template 58 | WeakCallback makeWeakCallback(const boost::shared_ptr& object, 59 | void (CLASS::*function)(ARGS...)) 60 | { 61 | return WeakCallback(object, function); 62 | } 63 | 64 | template 65 | WeakCallback makeWeakCallback(const boost::shared_ptr& object, 66 | void (CLASS::*function)(ARGS...) const) 67 | { 68 | return WeakCallback(object, function); 69 | } 70 | 71 | #else // __GXX_EXPERIMENTAL_CXX0X__ 72 | 73 | // the C++98/03 version doesn't support arguments. 74 | 75 | template 76 | class WeakCallback 77 | { 78 | public: 79 | 80 | WeakCallback(const boost::weak_ptr& object, 81 | const boost::function& function) 82 | : object_(object), function_(function) 83 | { 84 | } 85 | 86 | // Default dtor, copy ctor and assignment are okay 87 | 88 | void operator()() const 89 | { 90 | boost::shared_ptr ptr(object_.lock()); 91 | if (ptr) 92 | { 93 | function_(ptr.get()); 94 | } 95 | // else 96 | // { 97 | // LOG_TRACE << "expired"; 98 | // } 99 | } 100 | 101 | private: 102 | 103 | boost::weak_ptr object_; 104 | boost::function function_; 105 | }; 106 | 107 | template 108 | WeakCallback makeWeakCallback(const boost::shared_ptr& object, 109 | void (CLASS::*function)()) 110 | { 111 | return WeakCallback(object, function); 112 | } 113 | 114 | template 115 | WeakCallback makeWeakCallback(const boost::shared_ptr& object, 116 | void (CLASS::*function)() const) 117 | { 118 | return WeakCallback(object, function); 119 | } 120 | 121 | #endif // __GXX_EXPERIMENTAL_CXX0X__ 122 | } 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /muduo/base/copyable.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_COPYABLE_H 2 | #define MUDUO_BASE_COPYABLE_H 3 | 4 | namespace muduo 5 | { 6 | 7 | /// A tag class emphasises the objects are copyable. 8 | /// The empty base class optimization applies. 9 | /// Any derived class of copyable should be a value type. 10 | class copyable 11 | { 12 | }; 13 | 14 | }; 15 | 16 | #endif // MUDUO_BASE_COPYABLE_H 17 | -------------------------------------------------------------------------------- /muduo/base/makefile: -------------------------------------------------------------------------------- 1 | 2 | LIB_INSTALL_COMM_PATH = ../../lib 3 | 4 | LIB_BOOST_COMM_PATH := /export/newjpush/lib 5 | LIB_BOOST_COMM := -L$(LIB_BOOST_COMM_PATH) -Wl,-Bstatic -lboost_thread -Wl,-Bdynamic -lm -lc -Wl,-Bstatic -lboost_system -Wl,-Bdynamic -lm -lc 6 | 7 | .SUFFIXES: .o .cc 8 | 9 | cxx = g++ 10 | 11 | CFLAGS = -g -Wall -I../../ -I/export/newjpush/include -I/export/newjpush/ 12 | 13 | OI_OBJS = AsyncLogging.o Condition.o CountDownLatch.o Date.o Exception.o \ 14 | FileUtil.o LogFile.o Logging.o LogStream.o \ 15 | ProcessInfo.o Thread.o ThreadPool.o Timestamp.o TimeZone.o 16 | 17 | OUTPUT := libbase.a 18 | 19 | all:$(OUTPUT) 20 | 21 | .cc.o: 22 | $(CXX) $(CFLAGS) -c $^ -o $@ -DMUDUO_STD_STRING $(LIB_BOOST_COMM) 23 | 24 | libbase.a:$(OI_OBJS) 25 | ar -rs $@ $^ 26 | 27 | install: 28 | cp -f -R $(OUTPUT) $(LIB_INSTALL_COMM_PATH)/ 29 | 30 | clean: 31 | rm -f *.o *.a 32 | -------------------------------------------------------------------------------- /muduo/base/premake4.lua: -------------------------------------------------------------------------------- 1 | project "base" 2 | kind "StaticLib" 3 | language "C++" 4 | links{'pthread', 'rt'} 5 | targetdir(libdir) 6 | targetname('muduo_base') 7 | headersdir('muduo/base') 8 | headers('*.h') 9 | files { 10 | 'AsyncLogging.cc', 11 | 'Condition.cc', 12 | 'CountDownLatch.cc', 13 | 'Date.cc', 14 | 'Exception.cc', 15 | 'FileUtil.cc', 16 | 'LogFile.cc', 17 | 'Logging.cc', 18 | 'LogStream.cc', 19 | 'ProcessInfo.cc', 20 | 'Timestamp.cc', 21 | 'TimeZone.cc', 22 | 'Thread.cc', 23 | 'ThreadPool.cc', 24 | } 25 | -------------------------------------------------------------------------------- /muduo/net/Acceptor.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | //#include 21 | //#include 22 | 23 | using namespace muduo; 24 | using namespace muduo::net; 25 | 26 | Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport) 27 | : loop_(loop), 28 | acceptSocket_(sockets::createNonblockingOrDie()), 29 | acceptChannel_(loop, acceptSocket_.fd()), 30 | listenning_(false), 31 | idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) 32 | { 33 | assert(idleFd_ >= 0); 34 | acceptSocket_.setReuseAddr(true); 35 | acceptSocket_.setReusePort(reuseport); 36 | acceptSocket_.bindAddress(listenAddr); 37 | acceptChannel_.setReadCallback( 38 | boost::bind(&Acceptor::handleRead, this)); 39 | } 40 | 41 | Acceptor::~Acceptor() 42 | { 43 | acceptChannel_.disableAll(); 44 | acceptChannel_.remove(); 45 | ::close(idleFd_); 46 | } 47 | 48 | void Acceptor::listen() 49 | { 50 | loop_->assertInLoopThread(); 51 | listenning_ = true; 52 | acceptSocket_.listen(); 53 | acceptChannel_.enableReading(); 54 | } 55 | 56 | void Acceptor::handleRead() 57 | { 58 | loop_->assertInLoopThread(); 59 | InetAddress peerAddr; 60 | //FIXME loop until no more 61 | int connfd = acceptSocket_.accept(&peerAddr); 62 | if (connfd >= 0) 63 | { 64 | // string hostport = peerAddr.toIpPort(); 65 | // LOG_TRACE << "Accepts of " << hostport; 66 | if (newConnectionCallback_) 67 | { 68 | newConnectionCallback_(connfd, peerAddr); 69 | } 70 | else 71 | { 72 | sockets::close(connfd); 73 | } 74 | } 75 | else 76 | { 77 | LOG_SYSERR << "in Acceptor::handleRead"; 78 | // Read the section named "The special problem of 79 | // accept()ing when you can't" in libev's doc. 80 | // By Marc Lehmann, author of livev. 81 | if (errno == EMFILE) 82 | { 83 | ::close(idleFd_); 84 | idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL); 85 | ::close(idleFd_); 86 | idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC); 87 | } 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /muduo/net/Acceptor.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_ACCEPTOR_H 12 | #define MUDUO_NET_ACCEPTOR_H 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | 25 | class EventLoop; 26 | class InetAddress; 27 | 28 | /// 29 | /// Acceptor of incoming TCP connections. 30 | /// 31 | class Acceptor : boost::noncopyable 32 | { 33 | public: 34 | typedef boost::function NewConnectionCallback; 36 | 37 | Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport); 38 | ~Acceptor(); 39 | 40 | void setNewConnectionCallback(const NewConnectionCallback& cb) 41 | { newConnectionCallback_ = cb; } 42 | 43 | bool listenning() const { return listenning_; } 44 | void listen(); 45 | 46 | private: 47 | void handleRead(); 48 | 49 | EventLoop* loop_; 50 | Socket acceptSocket_; 51 | Channel acceptChannel_; 52 | NewConnectionCallback newConnectionCallback_; 53 | bool listenning_; 54 | int idleFd_; 55 | }; 56 | 57 | } 58 | } 59 | 60 | #endif // MUDUO_NET_ACCEPTOR_H 61 | -------------------------------------------------------------------------------- /muduo/net/Boilerplate.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include 11 | 12 | using namespace muduo; 13 | using namespace muduo::net; 14 | 15 | 16 | -------------------------------------------------------------------------------- /muduo/net/Boilerplate.cc~: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include 11 | 12 | using namespace muduo; 13 | using namespace muduo::net; 14 | 15 | 16 | -------------------------------------------------------------------------------- /muduo/net/Boilerplate.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | // This is an internal header file, you should not include this. 11 | 12 | #ifndef MUDUO_NET_BOILERPLATE_H 13 | #define MUDUO_NET_BOILERPLATE_H 14 | 15 | #include 16 | 17 | namespace muduo 18 | { 19 | namespace net 20 | { 21 | 22 | class BoilerPlate : boost::noncopyable 23 | { 24 | public: 25 | 26 | private: 27 | }; 28 | 29 | } 30 | } 31 | 32 | #endif // MUDUO_NET_BOILERPLATE_H 33 | -------------------------------------------------------------------------------- /muduo/net/Buffer.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | using namespace muduo; 18 | using namespace muduo::net; 19 | 20 | const char Buffer::kCRLF[] = "\r\n"; 21 | 22 | const size_t Buffer::kCheapPrepend; 23 | const size_t Buffer::kInitialSize; 24 | 25 | ssize_t Buffer::readFd(int fd, int* savedErrno) 26 | { 27 | // saved an ioctl()/FIONREAD call to tell how much to read 28 | char extrabuf[65536]; 29 | struct iovec vec[2]; 30 | const size_t writable = writableBytes(); 31 | vec[0].iov_base = begin()+writerIndex_; 32 | vec[0].iov_len = writable; 33 | vec[1].iov_base = extrabuf; 34 | vec[1].iov_len = sizeof extrabuf; 35 | // when there is enough space in this buffer, don't read into extrabuf. 36 | // when extrabuf is used, we read 128k-1 bytes at most. 37 | const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1; 38 | const ssize_t n = sockets::readv(fd, vec, iovcnt); 39 | if (n < 0) 40 | { 41 | *savedErrno = errno; 42 | } 43 | else if (implicit_cast(n) <= writable) 44 | { 45 | writerIndex_ += n; 46 | } 47 | else 48 | { 49 | writerIndex_ = buffer_.size(); 50 | append(extrabuf, n - writable); 51 | } 52 | // if (n == writable + sizeof extrabuf) 53 | // { 54 | // goto line_30; 55 | // } 56 | return n; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /muduo/net/Callbacks.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_CALLBACKS_H 12 | #define MUDUO_NET_CALLBACKS_H 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | namespace muduo 20 | { 21 | 22 | // Adapted from google-protobuf stubs/common.h 23 | // see License in muduo/base/Types.h 24 | template 25 | inline ::boost::shared_ptr down_pointer_cast(const ::boost::shared_ptr& f) 26 | { 27 | if (false) 28 | { 29 | implicit_cast(0); 30 | } 31 | 32 | #ifndef NDEBUG 33 | assert(f == NULL || dynamic_cast(get_pointer(f)) != NULL); 34 | #endif 35 | return ::boost::static_pointer_cast(f); 36 | } 37 | 38 | namespace net 39 | { 40 | 41 | // All client visible callbacks go here. 42 | 43 | class Buffer; 44 | class TcpConnection; 45 | typedef boost::shared_ptr TcpConnectionPtr; 46 | typedef boost::function TimerCallback; 47 | typedef boost::function ConnectionCallback; 48 | typedef boost::function CloseCallback; 49 | typedef boost::function WriteCompleteCallback; 50 | typedef boost::function HighWaterMarkCallback; 51 | 52 | // the data has been read to (buf, len) 53 | typedef boost::function MessageCallback; 56 | 57 | void defaultConnectionCallback(const TcpConnectionPtr& conn); 58 | void defaultMessageCallback(const TcpConnectionPtr& conn, 59 | Buffer* buffer, 60 | Timestamp receiveTime); 61 | 62 | } 63 | } 64 | 65 | #endif // MUDUO_NET_CALLBACKS_H 66 | -------------------------------------------------------------------------------- /muduo/net/Channel.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | using namespace muduo; 18 | using namespace muduo::net; 19 | 20 | const int Channel::kNoneEvent = 0; 21 | const int Channel::kReadEvent = POLLIN | POLLPRI; 22 | const int Channel::kWriteEvent = POLLOUT; 23 | 24 | Channel::Channel(EventLoop* loop, int fd__) 25 | : loop_(loop), 26 | fd_(fd__), 27 | events_(0), 28 | revents_(0), 29 | index_(-1), 30 | logHup_(true), 31 | tied_(false), 32 | eventHandling_(false), 33 | addedToLoop_(false) 34 | { 35 | } 36 | 37 | Channel::~Channel() 38 | { 39 | assert(!eventHandling_); 40 | assert(!addedToLoop_); 41 | if (loop_->isInLoopThread()) 42 | { 43 | assert(!loop_->hasChannel(this)); 44 | } 45 | } 46 | 47 | void Channel::tie(const boost::shared_ptr& obj) 48 | { 49 | tie_ = obj; 50 | tied_ = true; 51 | } 52 | 53 | void Channel::update() 54 | { 55 | addedToLoop_ = true; 56 | loop_->updateChannel(this); 57 | } 58 | 59 | void Channel::remove() 60 | { 61 | assert(isNoneEvent()); 62 | addedToLoop_ = false; 63 | loop_->removeChannel(this); 64 | } 65 | 66 | void Channel::handleEvent(Timestamp receiveTime) 67 | { 68 | boost::shared_ptr guard; 69 | if (tied_) 70 | { 71 | guard = tie_.lock(); 72 | if (guard) 73 | { 74 | handleEventWithGuard(receiveTime); 75 | } 76 | } 77 | else 78 | { 79 | handleEventWithGuard(receiveTime); 80 | } 81 | } 82 | 83 | void Channel::handleEventWithGuard(Timestamp receiveTime) 84 | { 85 | eventHandling_ = true; 86 | LOG_TRACE << reventsToString(); 87 | if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) 88 | { 89 | if (logHup_) 90 | { 91 | LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP"; 92 | } 93 | if (closeCallback_) closeCallback_(); 94 | } 95 | 96 | if (revents_ & POLLNVAL) 97 | { 98 | LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL"; 99 | } 100 | 101 | if (revents_ & (POLLERR | POLLNVAL)) 102 | { 103 | if (errorCallback_) errorCallback_(); 104 | } 105 | if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) 106 | { 107 | if (readCallback_) readCallback_(receiveTime); 108 | } 109 | if (revents_ & POLLOUT) 110 | { 111 | if (writeCallback_) writeCallback_(); 112 | } 113 | eventHandling_ = false; 114 | } 115 | 116 | string Channel::reventsToString() const 117 | { 118 | return eventsToString(fd_, revents_); 119 | } 120 | 121 | string Channel::eventsToString() const 122 | { 123 | return eventsToString(fd_, events_); 124 | } 125 | 126 | string Channel::eventsToString(int fd, int ev) 127 | { 128 | std::ostringstream oss; 129 | oss << fd << ": "; 130 | if (ev & POLLIN) 131 | oss << "IN "; 132 | if (ev & POLLPRI) 133 | oss << "PRI "; 134 | if (ev & POLLOUT) 135 | oss << "OUT "; 136 | if (ev & POLLHUP) 137 | oss << "HUP "; 138 | if (ev & POLLRDHUP) 139 | oss << "RDHUP "; 140 | if (ev & POLLERR) 141 | oss << "ERR "; 142 | if (ev & POLLNVAL) 143 | oss << "NVAL "; 144 | 145 | return oss.str().c_str(); 146 | } 147 | -------------------------------------------------------------------------------- /muduo/net/Channel.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_CHANNEL_H 12 | #define MUDUO_NET_CHANNEL_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | namespace muduo 22 | { 23 | namespace net 24 | { 25 | 26 | class EventLoop; 27 | 28 | /// 29 | /// A selectable I/O channel. 30 | /// 31 | /// This class doesn't own the file descriptor. 32 | /// The file descriptor could be a socket, 33 | /// an eventfd, a timerfd, or a signalfd 34 | class Channel : boost::noncopyable 35 | { 36 | public: 37 | typedef boost::function EventCallback; 38 | typedef boost::function ReadEventCallback; 39 | 40 | Channel(EventLoop* loop, int fd); 41 | ~Channel(); 42 | 43 | void handleEvent(Timestamp receiveTime); 44 | void setReadCallback(const ReadEventCallback& cb) 45 | { readCallback_ = cb; } 46 | void setWriteCallback(const EventCallback& cb) 47 | { writeCallback_ = cb; } 48 | void setCloseCallback(const EventCallback& cb) 49 | { closeCallback_ = cb; } 50 | void setErrorCallback(const EventCallback& cb) 51 | { errorCallback_ = cb; } 52 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 53 | void setReadCallback(ReadEventCallback&& cb) 54 | { readCallback_ = std::move(cb); } 55 | void setWriteCallback(EventCallback&& cb) 56 | { writeCallback_ = std::move(cb); } 57 | void setCloseCallback(EventCallback&& cb) 58 | { closeCallback_ = std::move(cb); } 59 | void setErrorCallback(EventCallback&& cb) 60 | { errorCallback_ = std::move(cb); } 61 | #endif 62 | 63 | /// Tie this channel to the owner object managed by shared_ptr, 64 | /// prevent the owner object being destroyed in handleEvent. 65 | void tie(const boost::shared_ptr&); 66 | 67 | int fd() const { return fd_; } 68 | int events() const { return events_; } 69 | void set_revents(int revt) { revents_ = revt; } // used by pollers 70 | // int revents() const { return revents_; } 71 | bool isNoneEvent() const { return events_ == kNoneEvent; } 72 | 73 | void enableReading() { events_ |= kReadEvent; update(); } 74 | void disableReading() { events_ &= ~kReadEvent; update(); } 75 | void enableWriting() { events_ |= kWriteEvent; update(); } 76 | void disableWriting() { events_ &= ~kWriteEvent; update(); } 77 | void disableAll() { events_ = kNoneEvent; update(); } 78 | bool isWriting() const { return events_ & kWriteEvent; } 79 | 80 | // for Poller 81 | int index() { return index_; } 82 | void set_index(int idx) { index_ = idx; } 83 | 84 | // for debug 85 | string reventsToString() const; 86 | string eventsToString() const; 87 | 88 | void doNotLogHup() { logHup_ = false; } 89 | 90 | EventLoop* ownerLoop() { return loop_; } 91 | void remove(); 92 | 93 | private: 94 | static string eventsToString(int fd, int ev); 95 | 96 | void update(); 97 | void handleEventWithGuard(Timestamp receiveTime); 98 | 99 | static const int kNoneEvent; 100 | static const int kReadEvent; 101 | static const int kWriteEvent; 102 | 103 | EventLoop* loop_; 104 | const int fd_; 105 | int events_; 106 | int revents_; // it's the received event types of epoll or poll 107 | int index_; // used by Poller. 108 | bool logHup_; 109 | 110 | boost::weak_ptr tie_; 111 | bool tied_; 112 | bool eventHandling_; 113 | bool addedToLoop_; 114 | ReadEventCallback readCallback_; 115 | EventCallback writeCallback_; 116 | EventCallback closeCallback_; 117 | EventCallback errorCallback_; 118 | }; 119 | 120 | } 121 | } 122 | #endif // MUDUO_NET_CHANNEL_H 123 | -------------------------------------------------------------------------------- /muduo/net/Connector.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | 21 | using namespace muduo; 22 | using namespace muduo::net; 23 | 24 | const int Connector::kMaxRetryDelayMs; 25 | 26 | Connector::Connector(EventLoop* loop, const InetAddress& serverAddr) 27 | : loop_(loop), 28 | serverAddr_(serverAddr), 29 | connect_(false), 30 | state_(kDisconnected), 31 | retryDelayMs_(kInitRetryDelayMs) 32 | { 33 | LOG_DEBUG << "ctor[" << this << "]"; 34 | } 35 | 36 | Connector::~Connector() 37 | { 38 | LOG_DEBUG << "dtor[" << this << "]"; 39 | assert(!channel_); 40 | } 41 | 42 | void Connector::start() 43 | { 44 | connect_ = true; 45 | loop_->runInLoop(boost::bind(&Connector::startInLoop, this)); // FIXME: unsafe 46 | } 47 | 48 | void Connector::startInLoop() 49 | { 50 | loop_->assertInLoopThread(); 51 | assert(state_ == kDisconnected); 52 | if (connect_) 53 | { 54 | connect(); 55 | } 56 | else 57 | { 58 | LOG_DEBUG << "do not connect"; 59 | } 60 | } 61 | 62 | void Connector::stop() 63 | { 64 | connect_ = false; 65 | loop_->queueInLoop(boost::bind(&Connector::stopInLoop, this)); // FIXME: unsafe 66 | // FIXME: cancel timer 67 | } 68 | 69 | void Connector::stopInLoop() 70 | { 71 | loop_->assertInLoopThread(); 72 | if (state_ == kConnecting) 73 | { 74 | setState(kDisconnected); 75 | int sockfd = removeAndResetChannel(); 76 | retry(sockfd); 77 | } 78 | } 79 | 80 | void Connector::connect() 81 | { 82 | int sockfd = sockets::createNonblockingOrDie(); 83 | int ret = sockets::connect(sockfd, serverAddr_.getSockAddrInet()); 84 | int savedErrno = (ret == 0) ? 0 : errno; 85 | switch (savedErrno) 86 | { 87 | case 0: 88 | case EINPROGRESS: 89 | case EINTR: 90 | case EISCONN: 91 | connecting(sockfd); 92 | break; 93 | 94 | case EAGAIN: 95 | case EADDRINUSE: 96 | case EADDRNOTAVAIL: 97 | case ECONNREFUSED: 98 | case ENETUNREACH: 99 | retry(sockfd); 100 | break; 101 | 102 | case EACCES: 103 | case EPERM: 104 | case EAFNOSUPPORT: 105 | case EALREADY: 106 | case EBADF: 107 | case EFAULT: 108 | case ENOTSOCK: 109 | LOG_SYSERR << "connect error in Connector::startInLoop " << savedErrno; 110 | sockets::close(sockfd); 111 | break; 112 | 113 | default: 114 | LOG_SYSERR << "Unexpected error in Connector::startInLoop " << savedErrno; 115 | sockets::close(sockfd); 116 | // connectErrorCallback_(); 117 | break; 118 | } 119 | } 120 | 121 | void Connector::restart() 122 | { 123 | loop_->assertInLoopThread(); 124 | setState(kDisconnected); 125 | retryDelayMs_ = kInitRetryDelayMs; 126 | connect_ = true; 127 | startInLoop(); 128 | } 129 | 130 | void Connector::connecting(int sockfd) 131 | { 132 | setState(kConnecting); 133 | assert(!channel_); 134 | channel_.reset(new Channel(loop_, sockfd)); 135 | channel_->setWriteCallback( 136 | boost::bind(&Connector::handleWrite, this)); // FIXME: unsafe 137 | channel_->setErrorCallback( 138 | boost::bind(&Connector::handleError, this)); // FIXME: unsafe 139 | 140 | // channel_->tie(shared_from_this()); is not working, 141 | // as channel_ is not managed by shared_ptr 142 | channel_->enableWriting(); 143 | } 144 | 145 | int Connector::removeAndResetChannel() 146 | { 147 | channel_->disableAll(); 148 | channel_->remove(); 149 | int sockfd = channel_->fd(); 150 | // Can't reset channel_ here, because we are inside Channel::handleEvent 151 | loop_->queueInLoop(boost::bind(&Connector::resetChannel, this)); // FIXME: unsafe 152 | return sockfd; 153 | } 154 | 155 | void Connector::resetChannel() 156 | { 157 | channel_.reset(); 158 | } 159 | 160 | void Connector::handleWrite() 161 | { 162 | LOG_TRACE << "Connector::handleWrite " << state_; 163 | 164 | if (state_ == kConnecting) 165 | { 166 | int sockfd = removeAndResetChannel(); 167 | int err = sockets::getSocketError(sockfd); 168 | if (err) 169 | { 170 | LOG_WARN << "Connector::handleWrite - SO_ERROR = " 171 | << err << " " << strerror_tl(err); 172 | retry(sockfd); 173 | } 174 | else if (sockets::isSelfConnect(sockfd)) 175 | { 176 | LOG_WARN << "Connector::handleWrite - Self connect"; 177 | retry(sockfd); 178 | } 179 | else 180 | { 181 | setState(kConnected); 182 | if (connect_) 183 | { 184 | newConnectionCallback_(sockfd); 185 | } 186 | else 187 | { 188 | sockets::close(sockfd); 189 | } 190 | } 191 | } 192 | else 193 | { 194 | // what happened? 195 | assert(state_ == kDisconnected); 196 | } 197 | } 198 | 199 | void Connector::handleError() 200 | { 201 | LOG_ERROR << "Connector::handleError state=" << state_; 202 | if (state_ == kConnecting) 203 | { 204 | int sockfd = removeAndResetChannel(); 205 | int err = sockets::getSocketError(sockfd); 206 | LOG_TRACE << "SO_ERROR = " << err << " " << strerror_tl(err); 207 | retry(sockfd); 208 | } 209 | } 210 | 211 | void Connector::retry(int sockfd) 212 | { 213 | sockets::close(sockfd); 214 | setState(kDisconnected); 215 | if (connect_) 216 | { 217 | LOG_INFO << "Connector::retry - Retry connecting to " << serverAddr_.toIpPort() 218 | << " in " << retryDelayMs_ << " milliseconds. "; 219 | loop_->runAfter(retryDelayMs_/1000.0, 220 | boost::bind(&Connector::startInLoop, shared_from_this())); 221 | retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs); 222 | } 223 | else 224 | { 225 | LOG_DEBUG << "do not connect"; 226 | } 227 | } 228 | 229 | -------------------------------------------------------------------------------- /muduo/net/Connector.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_CONNECTOR_H 12 | #define MUDUO_NET_CONNECTOR_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace muduo 22 | { 23 | namespace net 24 | { 25 | 26 | class Channel; 27 | class EventLoop; 28 | 29 | class Connector : boost::noncopyable, 30 | public boost::enable_shared_from_this 31 | { 32 | public: 33 | typedef boost::function NewConnectionCallback; 34 | 35 | Connector(EventLoop* loop, const InetAddress& serverAddr); 36 | ~Connector(); 37 | 38 | void setNewConnectionCallback(const NewConnectionCallback& cb) 39 | { newConnectionCallback_ = cb; } 40 | 41 | void start(); // can be called in any thread 42 | void restart(); // must be called in loop thread 43 | void stop(); // can be called in any thread 44 | 45 | const InetAddress& serverAddress() const { return serverAddr_; } 46 | 47 | private: 48 | enum States { kDisconnected, kConnecting, kConnected }; 49 | static const int kMaxRetryDelayMs = 30*1000; 50 | static const int kInitRetryDelayMs = 500; 51 | 52 | void setState(States s) { state_ = s; } 53 | void startInLoop(); 54 | void stopInLoop(); 55 | void connect(); 56 | void connecting(int sockfd); 57 | void handleWrite(); 58 | void handleError(); 59 | void retry(int sockfd); 60 | int removeAndResetChannel(); 61 | void resetChannel(); 62 | 63 | EventLoop* loop_; 64 | InetAddress serverAddr_; 65 | bool connect_; // atomic 66 | States state_; // FIXME: use atomic variable 67 | boost::scoped_ptr channel_; 68 | NewConnectionCallback newConnectionCallback_; 69 | int retryDelayMs_; 70 | }; 71 | 72 | } 73 | } 74 | 75 | #endif // MUDUO_NET_CONNECTOR_H 76 | -------------------------------------------------------------------------------- /muduo/net/ConnectorOri.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_CONNECTOR_ORI_H 12 | #define MUDUO_NET_CONNECTOR_ORI_H 13 | 14 | #include "muduo/net/InetAddress.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace muduo 22 | { 23 | namespace net 24 | { 25 | 26 | class Channel; 27 | class EventLoop; 28 | 29 | class ConnectorOri : boost::noncopyable, 30 | public boost::enable_shared_from_this 31 | { 32 | public: 33 | typedef boost::function NewConnectionCallback; 34 | //add by egypt 35 | ConnectorOri(EventLoop* loop, const InetAddress& serverddr, const string& name = "", bool isBindAddr = false); 36 | ~ConnectorOri(); 37 | 38 | void setNewConnectionCallback(const NewConnectionCallback& cb) 39 | { newConnectionCallback_ = cb; } 40 | 41 | void start(); // can be called in any thread 42 | void restart(); // must be called in loop thread 43 | void stop(); // can be called in any thread 44 | 45 | const InetAddress& serverAddress() const { return serverAddr_; } 46 | //add by egypt 47 | const string& clientName() const { return clientName_; } 48 | //add by egypt 49 | int& getConnName() { return connName_; } 50 | void setConnName(const int& connName){ connName_ = connName; } 51 | // add by egypt 52 | bool connectState_; 53 | // add by egypt 54 | bool retryState_; 55 | 56 | void setBindAddr(const InetAddress& addr) 57 | { 58 | isbindLocalAddr_ = true; 59 | bindLocalAddr_ = addr; 60 | }; 61 | 62 | //bzh add 2015.8.20 63 | bool isConnected() {return state_== kConnected;}; 64 | private: 65 | enum States { kDisconnected, kConnecting, kConnected }; 66 | static const int kMaxRetryDelayMs = 30*1000; 67 | static const int kInitRetryDelayMs = 500; 68 | 69 | void setState(States s) { state_ = s; } 70 | void startInLoop(); 71 | void stopInLoop(); 72 | void connect(); 73 | void connecting(int sockfd); 74 | void handleWrite(); 75 | void handleError(); 76 | void retry(int sockfd); 77 | int removeAndResetChannel(); 78 | void resetChannel(); 79 | 80 | EventLoop* loop_; 81 | InetAddress serverAddr_; 82 | 83 | //bzh add 2015.6.30 start 84 | bool isbindLocalAddr_; 85 | InetAddress bindLocalAddr_; 86 | //bzh add 2015.6.30 end 87 | 88 | bool connect_; // atomic 89 | States state_; // FIXME: use atomic variable 90 | boost::scoped_ptr channel_; 91 | NewConnectionCallback newConnectionCallback_; 92 | int retryDelayMs_; 93 | //add by egypt 94 | const string clientName_; 95 | //add by egypt 96 | int connName_; 97 | }; 98 | 99 | } 100 | } 101 | 102 | #endif // MUDUO_NET_CONNECTOR_H 103 | -------------------------------------------------------------------------------- /muduo/net/Endian.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_ENDIAN_H 12 | #define MUDUO_NET_ENDIAN_H 13 | 14 | #include 15 | #include 16 | 17 | namespace muduo 18 | { 19 | namespace net 20 | { 21 | namespace sockets 22 | { 23 | 24 | // the inline assembler code makes type blur, 25 | // so we disable warnings for a while. 26 | #if defined(__clang__) || __GNUC_MINOR__ >= 6 27 | #pragma GCC diagnostic push 28 | #endif 29 | #pragma GCC diagnostic ignored "-Wconversion" 30 | #pragma GCC diagnostic ignored "-Wold-style-cast" 31 | inline uint64_t hostToNetwork64(uint64_t host64) 32 | { 33 | return htobe64(host64); 34 | } 35 | 36 | inline uint32_t hostToNetwork32(uint32_t host32) 37 | { 38 | return htobe32(host32); 39 | } 40 | 41 | inline uint16_t hostToNetwork16(uint16_t host16) 42 | { 43 | return htobe16(host16); 44 | } 45 | 46 | inline uint64_t networkToHost64(uint64_t net64) 47 | { 48 | return be64toh(net64); 49 | } 50 | 51 | inline uint32_t networkToHost32(uint32_t net32) 52 | { 53 | return be32toh(net32); 54 | } 55 | 56 | inline uint16_t networkToHost16(uint16_t net16) 57 | { 58 | return be16toh(net16); 59 | } 60 | #if defined(__clang__) || __GNUC_MINOR__ >= 6 61 | #pragma GCC diagnostic pop 62 | #else 63 | #pragma GCC diagnostic warning "-Wconversion" 64 | #pragma GCC diagnostic warning "-Wold-style-cast" 65 | #endif 66 | 67 | 68 | } 69 | } 70 | } 71 | 72 | #endif // MUDUO_NET_ENDIAN_H 73 | -------------------------------------------------------------------------------- /muduo/net/EventLoop.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_EVENTLOOP_H 12 | #define MUDUO_NET_EVENTLOOP_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace muduo 28 | { 29 | namespace net 30 | { 31 | 32 | class Channel; 33 | class Poller; 34 | class TimerQueue; 35 | 36 | /// 37 | /// Reactor, at most one per thread. 38 | /// 39 | /// This is an interface class, so don't expose too much details. 40 | class EventLoop : boost::noncopyable 41 | { 42 | public: 43 | typedef boost::function Functor; 44 | 45 | EventLoop(); 46 | ~EventLoop(); // force out-line dtor, for scoped_ptr members. 47 | 48 | /// 49 | /// Loops forever. 50 | /// 51 | /// Must be called in the same thread as creation of the object. 52 | /// 53 | void loop(); 54 | 55 | /// Quits loop. 56 | /// 57 | /// This is not 100% thread safe, if you call through a raw pointer, 58 | /// better to call through shared_ptr for 100% safety. 59 | void quit(); 60 | 61 | /// 62 | /// Time when poll returns, usually means data arrival. 63 | /// 64 | Timestamp pollReturnTime() const { return pollReturnTime_; } 65 | 66 | int64_t iteration() const { return iteration_; } 67 | 68 | /// Runs callback immediately in the loop thread. 69 | /// It wakes up the loop, and run the cb. 70 | /// If in the same loop thread, cb is run within the function. 71 | /// Safe to call from other threads. 72 | void runInLoop(const Functor& cb); 73 | /// Queues callback in the loop thread. 74 | /// Runs after finish pooling. 75 | /// Safe to call from other threads. 76 | void queueInLoop(const Functor& cb); 77 | 78 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 79 | void runInLoop(Functor&& cb); 80 | void queueInLoop(Functor&& cb); 81 | #endif 82 | 83 | // timers 84 | 85 | /// 86 | /// Runs callback at 'time'. 87 | /// Safe to call from other threads. 88 | /// 89 | TimerId runAt(const Timestamp& time, const TimerCallback& cb); 90 | /// 91 | /// Runs callback after @c delay seconds. 92 | /// Safe to call from other threads. 93 | /// 94 | TimerId runAfter(double delay, const TimerCallback& cb); 95 | /// 96 | /// Runs callback every @c interval seconds. 97 | /// Safe to call from other threads. 98 | /// 99 | TimerId runEvery(double interval, const TimerCallback& cb); 100 | /// 101 | /// Cancels the timer. 102 | /// Safe to call from other threads. 103 | /// 104 | void cancel(TimerId timerId); 105 | 106 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 107 | TimerId runAt(const Timestamp& time, TimerCallback&& cb); 108 | TimerId runAfter(double delay, TimerCallback&& cb); 109 | TimerId runEvery(double interval, TimerCallback&& cb); 110 | #endif 111 | 112 | // internal usage 113 | void wakeup(); 114 | void updateChannel(Channel* channel); 115 | void removeChannel(Channel* channel); 116 | bool hasChannel(Channel* channel); 117 | 118 | // pid_t threadId() const { return threadId_; } 119 | void assertInLoopThread() 120 | { 121 | if (!isInLoopThread()) 122 | { 123 | abortNotInLoopThread(); 124 | } 125 | } 126 | bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); } 127 | // bool callingPendingFunctors() const { return callingPendingFunctors_; } 128 | bool eventHandling() const { return eventHandling_; } 129 | 130 | void setContext(const boost::any& context) 131 | { context_ = context; } 132 | 133 | const boost::any& getContext() const 134 | { return context_; } 135 | 136 | boost::any* getMutableContext() 137 | { return &context_; } 138 | 139 | static EventLoop* getEventLoopOfCurrentThread(); 140 | 141 | private: 142 | void abortNotInLoopThread(); 143 | void handleRead(); // waked up 144 | void doPendingFunctors(); 145 | 146 | void printActiveChannels() const; // DEBUG 147 | 148 | typedef std::vector ChannelList; 149 | 150 | bool looping_; /* atomic */ 151 | bool quit_; /* atomic and shared between threads, okay on x86, I guess. */ 152 | bool eventHandling_; /* atomic */ 153 | bool callingPendingFunctors_; /* atomic */ 154 | int64_t iteration_; 155 | const pid_t threadId_; 156 | Timestamp pollReturnTime_; 157 | boost::scoped_ptr poller_; 158 | boost::scoped_ptr timerQueue_; 159 | int wakeupFd_; 160 | // unlike in TimerQueue, which is an internal class, 161 | // we don't expose Channel to client. 162 | boost::scoped_ptr wakeupChannel_; 163 | boost::any context_; 164 | 165 | // scratch variables 166 | ChannelList activeChannels_; 167 | Channel* currentActiveChannel_; 168 | 169 | MutexLock mutex_; 170 | std::vector pendingFunctors_; // @GuardedBy mutex_ 171 | }; 172 | 173 | } 174 | } 175 | #endif // MUDUO_NET_EVENTLOOP_H 176 | -------------------------------------------------------------------------------- /muduo/net/EventLoopThread.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | using namespace muduo; 16 | using namespace muduo::net; 17 | 18 | 19 | EventLoopThread::EventLoopThread(const ThreadInitCallback& cb, 20 | const string& name) 21 | : loop_(NULL), 22 | exiting_(false), 23 | thread_(boost::bind(&EventLoopThread::threadFunc, this), name), 24 | mutex_(), 25 | cond_(mutex_), 26 | callback_(cb) 27 | { 28 | } 29 | 30 | EventLoopThread::~EventLoopThread() 31 | { 32 | exiting_ = true; 33 | if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_. 34 | { 35 | // still a tiny chance to call destructed object, if threadFunc exits just now. 36 | // but when EventLoopThread destructs, usually programming is exiting anyway. 37 | loop_->quit(); 38 | thread_.join(); 39 | } 40 | } 41 | 42 | EventLoop* EventLoopThread::startLoop() 43 | { 44 | assert(!thread_.started()); 45 | thread_.start(); 46 | 47 | { 48 | MutexLockGuard lock(mutex_); 49 | while (loop_ == NULL) 50 | { 51 | cond_.wait(); 52 | } 53 | } 54 | 55 | return loop_; 56 | } 57 | 58 | void EventLoopThread::threadFunc() 59 | { 60 | EventLoop loop; 61 | 62 | if (callback_) 63 | { 64 | callback_(&loop); 65 | } 66 | 67 | { 68 | MutexLockGuard lock(mutex_); 69 | loop_ = &loop; 70 | cond_.notify(); 71 | } 72 | 73 | loop.loop(); 74 | //assert(exiting_); 75 | loop_ = NULL; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /muduo/net/EventLoopThread.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_EVENTLOOPTHREAD_H 12 | #define MUDUO_NET_EVENTLOOPTHREAD_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | 25 | class EventLoop; 26 | 27 | class EventLoopThread : boost::noncopyable 28 | { 29 | public: 30 | typedef boost::function ThreadInitCallback; 31 | 32 | EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(), 33 | const string& name = string()); 34 | ~EventLoopThread(); 35 | EventLoop* startLoop(); 36 | 37 | private: 38 | void threadFunc(); 39 | 40 | EventLoop* loop_; 41 | bool exiting_; 42 | Thread thread_; 43 | MutexLock mutex_; 44 | Condition cond_; 45 | ThreadInitCallback callback_; 46 | }; 47 | 48 | } 49 | } 50 | 51 | #endif // MUDUO_NET_EVENTLOOPTHREAD_H 52 | 53 | -------------------------------------------------------------------------------- /muduo/net/EventLoopThreadPool.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | using namespace muduo; 19 | using namespace muduo::net; 20 | 21 | 22 | EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg) 23 | : baseLoop_(baseLoop), 24 | name_(nameArg), 25 | started_(false), 26 | numThreads_(0), 27 | next_(0) 28 | { 29 | } 30 | 31 | EventLoopThreadPool::~EventLoopThreadPool() 32 | { 33 | // Don't delete loop, it's stack variable 34 | } 35 | 36 | void EventLoopThreadPool::start(const ThreadInitCallback& cb) 37 | { 38 | assert(!started_); 39 | baseLoop_->assertInLoopThread(); 40 | 41 | started_ = true; 42 | 43 | for (int i = 0; i < numThreads_; ++i) 44 | { 45 | char buf[name_.size() + 32]; 46 | snprintf(buf, sizeof buf, "%s%d", name_.c_str(), i); 47 | EventLoopThread* t = new EventLoopThread(cb, buf); 48 | threads_.push_back(t); 49 | loops_.push_back(t->startLoop()); 50 | } 51 | if (numThreads_ == 0 && cb) 52 | { 53 | cb(baseLoop_); 54 | } 55 | } 56 | 57 | EventLoop* EventLoopThreadPool::getNextLoop() 58 | { 59 | baseLoop_->assertInLoopThread(); 60 | assert(started_); 61 | EventLoop* loop = baseLoop_; 62 | 63 | if (!loops_.empty()) 64 | { 65 | // round-robin 66 | loop = loops_[next_]; 67 | ++next_; 68 | if (implicit_cast(next_) >= loops_.size()) 69 | { 70 | next_ = 0; 71 | } 72 | } 73 | return loop; 74 | } 75 | 76 | EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode) 77 | { 78 | baseLoop_->assertInLoopThread(); 79 | EventLoop* loop = baseLoop_; 80 | 81 | if (!loops_.empty()) 82 | { 83 | loop = loops_[hashCode % loops_.size()]; 84 | } 85 | return loop; 86 | } 87 | 88 | std::vector EventLoopThreadPool::getAllLoops() 89 | { 90 | baseLoop_->assertInLoopThread(); 91 | assert(started_); 92 | if (loops_.empty()) 93 | { 94 | return std::vector(1, baseLoop_); 95 | } 96 | else 97 | { 98 | return loops_; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /muduo/net/EventLoopThreadPool.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_EVENTLOOPTHREADPOOL_H 12 | #define MUDUO_NET_EVENTLOOPTHREADPOOL_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace muduo 22 | { 23 | 24 | namespace net 25 | { 26 | 27 | class EventLoop; 28 | class EventLoopThread; 29 | 30 | class EventLoopThreadPool : boost::noncopyable 31 | { 32 | public: 33 | typedef boost::function ThreadInitCallback; 34 | 35 | EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg); 36 | ~EventLoopThreadPool(); 37 | void setThreadNum(int numThreads) { numThreads_ = numThreads; } 38 | void start(const ThreadInitCallback& cb = ThreadInitCallback()); 39 | 40 | // valid after calling start() 41 | /// round-robin 42 | EventLoop* getNextLoop(); 43 | 44 | /// with the same hash code, it will always return the same EventLoop 45 | EventLoop* getLoopForHash(size_t hashCode); 46 | 47 | std::vector getAllLoops(); 48 | 49 | bool started() const 50 | { return started_; } 51 | 52 | const string& name() const 53 | { return name_; } 54 | 55 | private: 56 | 57 | EventLoop* baseLoop_; 58 | string name_; 59 | bool started_; 60 | int numThreads_; 61 | int next_; 62 | boost::ptr_vector threads_; 63 | std::vector loops_; 64 | }; 65 | 66 | } 67 | } 68 | 69 | #endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H 70 | -------------------------------------------------------------------------------- /muduo/net/HeartStat.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/muduo/net/HeartStat.h -------------------------------------------------------------------------------- /muduo/net/InetAddress.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include // bzero 17 | #include 18 | 19 | #include 20 | 21 | // INADDR_ANY use (type)value casting. 22 | #pragma GCC diagnostic ignored "-Wold-style-cast" 23 | static const in_addr_t kInaddrAny = INADDR_ANY; 24 | static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK; 25 | #pragma GCC diagnostic error "-Wold-style-cast" 26 | 27 | // /* Structure describing an Internet socket address. */ 28 | // struct sockaddr_in { 29 | // sa_family_t sin_family; /* address family: AF_INET */ 30 | // uint16_t sin_port; /* port in network byte order */ 31 | // struct in_addr sin_addr; /* internet address */ 32 | // }; 33 | 34 | // /* Internet address. */ 35 | // typedef uint32_t in_addr_t; 36 | // struct in_addr { 37 | // in_addr_t s_addr; /* address in network byte order */ 38 | // }; 39 | 40 | using namespace muduo; 41 | using namespace muduo::net; 42 | 43 | BOOST_STATIC_ASSERT(sizeof(InetAddress) == sizeof(struct sockaddr_in)); 44 | 45 | InetAddress::InetAddress(uint16_t port, bool loopbackOnly) 46 | { 47 | bzero(&addr_, sizeof addr_); 48 | addr_.sin_family = AF_INET; 49 | in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; 50 | addr_.sin_addr.s_addr = sockets::hostToNetwork32(ip); 51 | addr_.sin_port = sockets::hostToNetwork16(port); 52 | } 53 | 54 | InetAddress::InetAddress(StringArg ip, uint16_t port) 55 | { 56 | bzero(&addr_, sizeof addr_); 57 | sockets::fromIpPort(ip.c_str(), port, &addr_); 58 | } 59 | 60 | string InetAddress::toIpPort() const 61 | { 62 | char buf[32]; 63 | sockets::toIpPort(buf, sizeof buf, addr_); 64 | return buf; 65 | } 66 | 67 | string InetAddress::toIp() const 68 | { 69 | char buf[32]; 70 | sockets::toIp(buf, sizeof buf, addr_); 71 | return buf; 72 | } 73 | 74 | uint16_t InetAddress::toPort() const 75 | { 76 | return sockets::networkToHost16(addr_.sin_port); 77 | } 78 | 79 | static __thread char t_resolveBuffer[64 * 1024]; 80 | 81 | bool InetAddress::resolve(StringArg hostname, InetAddress* out) 82 | { 83 | assert(out != NULL); 84 | struct hostent hent; 85 | struct hostent* he = NULL; 86 | int herrno = 0; 87 | bzero(&hent, sizeof(hent)); 88 | 89 | int ret = gethostbyname_r(hostname.c_str(), &hent, t_resolveBuffer, sizeof t_resolveBuffer, &he, &herrno); 90 | if (ret == 0 && he != NULL) 91 | { 92 | assert(he->h_addrtype == AF_INET && he->h_length == sizeof(uint32_t)); 93 | out->addr_.sin_addr = *reinterpret_cast(he->h_addr); 94 | return true; 95 | } 96 | else 97 | { 98 | if (ret) 99 | { 100 | LOG_SYSERR << "InetAddress::resolve"; 101 | } 102 | return false; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /muduo/net/InetAddress.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_INETADDRESS_H 12 | #define MUDUO_NET_INETADDRESS_H 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | namespace muduo 20 | { 21 | namespace net 22 | { 23 | 24 | /// 25 | /// Wrapper of sockaddr_in. 26 | /// 27 | /// This is an POD interface class. 28 | class InetAddress : public muduo::copyable 29 | { 30 | public: 31 | /// Constructs an endpoint with given port number. 32 | /// Mostly used in TcpServer listening. 33 | explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false); 34 | 35 | /// Constructs an endpoint with given ip and port. 36 | /// @c ip should be "1.2.3.4" 37 | InetAddress(StringArg ip, uint16_t port); 38 | 39 | /// Constructs an endpoint with given struct @c sockaddr_in 40 | /// Mostly used when accepting new connections 41 | InetAddress(const struct sockaddr_in& addr) 42 | : addr_(addr) 43 | { } 44 | 45 | string toIp() const; 46 | string toIpPort() const; 47 | uint16_t toPort() const; 48 | 49 | // default copy/assignment are Okay 50 | 51 | const struct sockaddr_in& getSockAddrInet() const { return addr_; } 52 | void setSockAddrInet(const struct sockaddr_in& addr) { addr_ = addr; } 53 | 54 | uint32_t ipNetEndian() const { return addr_.sin_addr.s_addr; } 55 | uint16_t portNetEndian() const { return addr_.sin_port; } 56 | 57 | // resolve hostname to IP address, not changing port or sin_family 58 | // return true on success. 59 | // thread safe 60 | static bool resolve(StringArg hostname, InetAddress* result); 61 | // static std::vector resolveAll(const char* hostname, uint16_t port = 0); 62 | 63 | private: 64 | struct sockaddr_in addr_; 65 | }; 66 | 67 | } 68 | } 69 | 70 | #endif // MUDUO_NET_INETADDRESS_H 71 | -------------------------------------------------------------------------------- /muduo/net/Poller.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | 11 | #include 12 | 13 | using namespace muduo; 14 | using namespace muduo::net; 15 | 16 | Poller::Poller(EventLoop* loop) 17 | : ownerLoop_(loop) 18 | { 19 | } 20 | 21 | Poller::~Poller() 22 | { 23 | } 24 | 25 | bool Poller::hasChannel(Channel* channel) const 26 | { 27 | assertInLoopThread(); 28 | ChannelMap::const_iterator it = channels_.find(channel->fd()); 29 | return it != channels_.end() && it->second == channel; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /muduo/net/Poller.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_POLLER_H 12 | #define MUDUO_NET_POLLER_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | namespace muduo 22 | { 23 | namespace net 24 | { 25 | 26 | class Channel; 27 | 28 | /// 29 | /// Base class for IO Multiplexing 30 | /// 31 | /// This class doesn't own the Channel objects. 32 | class Poller : boost::noncopyable 33 | { 34 | public: 35 | typedef std::vector ChannelList; 36 | 37 | Poller(EventLoop* loop); 38 | virtual ~Poller(); 39 | 40 | /// Polls the I/O events. 41 | /// Must be called in the loop thread. 42 | virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0; 43 | 44 | /// Changes the interested I/O events. 45 | /// Must be called in the loop thread. 46 | virtual void updateChannel(Channel* channel) = 0; 47 | 48 | /// Remove the channel, when it destructs. 49 | /// Must be called in the loop thread. 50 | virtual void removeChannel(Channel* channel) = 0; 51 | 52 | virtual bool hasChannel(Channel* channel) const; 53 | 54 | static Poller* newDefaultPoller(EventLoop* loop); 55 | 56 | void assertInLoopThread() const 57 | { 58 | ownerLoop_->assertInLoopThread(); 59 | } 60 | 61 | protected: 62 | typedef std::map ChannelMap; 63 | ChannelMap channels_; 64 | 65 | private: 66 | EventLoop* ownerLoop_; 67 | }; 68 | 69 | } 70 | } 71 | #endif // MUDUO_NET_POLLER_H 72 | -------------------------------------------------------------------------------- /muduo/net/Socket.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include // bzero 18 | #include // snprintf 19 | 20 | using namespace muduo; 21 | using namespace muduo::net; 22 | 23 | Socket::~Socket() 24 | { 25 | sockets::close(sockfd_); 26 | } 27 | 28 | bool Socket::getTcpInfo(struct tcp_info* tcpi) const 29 | { 30 | socklen_t len = sizeof(*tcpi); 31 | bzero(tcpi, len); 32 | return ::getsockopt(sockfd_, SOL_TCP, TCP_INFO, tcpi, &len) == 0; 33 | } 34 | 35 | bool Socket::getTcpInfoString(char* buf, int len) const 36 | { 37 | struct tcp_info tcpi; 38 | bool ok = getTcpInfo(&tcpi); 39 | if (ok) 40 | { 41 | snprintf(buf, len, "unrecovered=%u " 42 | "rto=%u ato=%u snd_mss=%u rcv_mss=%u " 43 | "lost=%u retrans=%u rtt=%u rttvar=%u " 44 | "sshthresh=%u cwnd=%u total_retrans=%u", 45 | tcpi.tcpi_retransmits, // Number of unrecovered [RTO] timeouts 46 | tcpi.tcpi_rto, // Retransmit timeout in usec 47 | tcpi.tcpi_ato, // Predicted tick of soft clock in usec 48 | tcpi.tcpi_snd_mss, 49 | tcpi.tcpi_rcv_mss, 50 | tcpi.tcpi_lost, // Lost packets 51 | tcpi.tcpi_retrans, // Retransmitted packets out 52 | tcpi.tcpi_rtt, // Smoothed round trip time in usec 53 | tcpi.tcpi_rttvar, // Medium deviation 54 | tcpi.tcpi_snd_ssthresh, 55 | tcpi.tcpi_snd_cwnd, 56 | tcpi.tcpi_total_retrans); // Total retransmits for entire connection 57 | } 58 | return ok; 59 | } 60 | 61 | void Socket::bindAddress(const InetAddress& addr) 62 | { 63 | sockets::bindOrDie(sockfd_, addr.getSockAddrInet()); 64 | } 65 | 66 | void Socket::listen() 67 | { 68 | sockets::listenOrDie(sockfd_); 69 | } 70 | 71 | int Socket::accept(InetAddress* peeraddr) 72 | { 73 | struct sockaddr_in addr; 74 | bzero(&addr, sizeof addr); 75 | int connfd = sockets::accept(sockfd_, &addr); 76 | if (connfd >= 0) 77 | { 78 | peeraddr->setSockAddrInet(addr); 79 | } 80 | return connfd; 81 | } 82 | 83 | void Socket::shutdownWrite() 84 | { 85 | sockets::shutdownWrite(sockfd_); 86 | } 87 | 88 | void Socket::setTcpNoDelay(bool on) 89 | { 90 | int optval = on ? 1 : 0; 91 | ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, 92 | &optval, static_cast(sizeof optval)); 93 | // FIXME CHECK 94 | } 95 | 96 | void Socket::setReuseAddr(bool on) 97 | { 98 | int optval = on ? 1 : 0; 99 | ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, 100 | &optval, static_cast(sizeof optval)); 101 | // FIXME CHECK 102 | } 103 | 104 | void Socket::setReusePort(bool on) 105 | { 106 | #ifdef SO_REUSEPORT 107 | int optval = on ? 1 : 0; 108 | int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, 109 | &optval, static_cast(sizeof optval)); 110 | if (ret < 0 && on) 111 | { 112 | LOG_SYSERR << "SO_REUSEPORT failed."; 113 | } 114 | #else 115 | if (on) 116 | { 117 | LOG_ERROR << "SO_REUSEPORT is not supported."; 118 | } 119 | #endif 120 | } 121 | 122 | void Socket::setKeepAlive(bool on) 123 | { 124 | int optval = on ? 1 : 0; 125 | ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, 126 | &optval, static_cast(sizeof optval)); 127 | // FIXME CHECK 128 | } 129 | 130 | -------------------------------------------------------------------------------- /muduo/net/Socket.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_SOCKET_H 12 | #define MUDUO_NET_SOCKET_H 13 | 14 | #include 15 | 16 | // struct tcp_info is in 17 | struct tcp_info; 18 | 19 | namespace muduo 20 | { 21 | /// 22 | /// TCP networking. 23 | /// 24 | namespace net 25 | { 26 | 27 | class InetAddress; 28 | 29 | /// 30 | /// Wrapper of socket file descriptor. 31 | /// 32 | /// It closes the sockfd when desctructs. 33 | /// It's thread safe, all operations are delagated to OS. 34 | class Socket : boost::noncopyable 35 | { 36 | public: 37 | explicit Socket(int sockfd) 38 | : sockfd_(sockfd) 39 | { } 40 | 41 | // Socket(Socket&&) // move constructor in C++11 42 | ~Socket(); 43 | 44 | int fd() const { return sockfd_; } 45 | // return true if success. 46 | bool getTcpInfo(struct tcp_info*) const; 47 | bool getTcpInfoString(char* buf, int len) const; 48 | 49 | /// abort if address in use 50 | void bindAddress(const InetAddress& localaddr); 51 | /// abort if address in use 52 | void listen(); 53 | 54 | /// On success, returns a non-negative integer that is 55 | /// a descriptor for the accepted socket, which has been 56 | /// set to non-blocking and close-on-exec. *peeraddr is assigned. 57 | /// On error, -1 is returned, and *peeraddr is untouched. 58 | int accept(InetAddress* peeraddr); 59 | 60 | void shutdownWrite(); 61 | 62 | /// 63 | /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). 64 | /// 65 | void setTcpNoDelay(bool on); 66 | 67 | /// 68 | /// Enable/disable SO_REUSEADDR 69 | /// 70 | void setReuseAddr(bool on); 71 | 72 | /// 73 | /// Enable/disable SO_REUSEPORT 74 | /// 75 | void setReusePort(bool on); 76 | 77 | /// 78 | /// Enable/disable SO_KEEPALIVE 79 | /// 80 | void setKeepAlive(bool on); 81 | 82 | private: 83 | const int sockfd_; 84 | }; 85 | 86 | } 87 | } 88 | #endif // MUDUO_NET_SOCKET_H 89 | -------------------------------------------------------------------------------- /muduo/net/SocketsOps.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_SOCKETSOPS_H 12 | #define MUDUO_NET_SOCKETSOPS_H 13 | 14 | #include 15 | 16 | namespace muduo 17 | { 18 | namespace net 19 | { 20 | namespace sockets 21 | { 22 | 23 | /// 24 | /// Creates a non-blocking socket file descriptor, 25 | /// abort if any error. 26 | int createNonblockingOrDie(); 27 | 28 | int connect(int sockfd, const struct sockaddr_in& addr); 29 | void bindOrDie(int sockfd, const struct sockaddr_in& addr); 30 | void listenOrDie(int sockfd); 31 | int accept(int sockfd, struct sockaddr_in* addr); 32 | ssize_t read(int sockfd, void *buf, size_t count); 33 | ssize_t readv(int sockfd, const struct iovec *iov, int iovcnt); 34 | ssize_t write(int sockfd, const void *buf, size_t count); 35 | void close(int sockfd); 36 | void shutdownWrite(int sockfd); 37 | 38 | void toIpPort(char* buf, size_t size, 39 | const struct sockaddr_in& addr); 40 | void toIp(char* buf, size_t size, 41 | const struct sockaddr_in& addr); 42 | void fromIpPort(const char* ip, uint16_t port, 43 | struct sockaddr_in* addr); 44 | 45 | int getSocketError(int sockfd); 46 | 47 | const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr); 48 | struct sockaddr* sockaddr_cast(struct sockaddr_in* addr); 49 | const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr); 50 | struct sockaddr_in* sockaddr_in_cast(struct sockaddr* addr); 51 | 52 | struct sockaddr_in getLocalAddr(int sockfd); 53 | struct sockaddr_in getPeerAddr(int sockfd); 54 | bool isSelfConnect(int sockfd); 55 | 56 | } 57 | } 58 | } 59 | 60 | #endif // MUDUO_NET_SOCKETSOPS_H 61 | -------------------------------------------------------------------------------- /muduo/net/TcpClient.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include // snprintf 20 | 21 | using namespace muduo; 22 | using namespace muduo::net; 23 | 24 | // TcpClient::TcpClient(EventLoop* loop) 25 | // : loop_(loop) 26 | // { 27 | // } 28 | 29 | // TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port) 30 | // : loop_(CHECK_NOTNULL(loop)), 31 | // serverAddr_(host, port) 32 | // { 33 | // } 34 | 35 | namespace muduo 36 | { 37 | namespace net 38 | { 39 | namespace detail 40 | { 41 | 42 | void removeConnection(EventLoop* loop, const TcpConnectionPtr& conn) 43 | { 44 | loop->queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn)); 45 | } 46 | 47 | void removeConnector(const ConnectorPtr& connector) 48 | { 49 | //connector-> 50 | } 51 | 52 | } 53 | } 54 | } 55 | 56 | TcpClient::TcpClient(EventLoop* loop, 57 | const InetAddress& serverAddr, 58 | const string& nameArg) 59 | : loop_(CHECK_NOTNULL(loop)), 60 | connector_(new Connector(loop, serverAddr)), 61 | name_(nameArg), 62 | connectionCallback_(defaultConnectionCallback), 63 | messageCallback_(defaultMessageCallback), 64 | retry_(false), 65 | connect_(true), 66 | nextConnId_(1) 67 | { 68 | connector_->setNewConnectionCallback( 69 | boost::bind(&TcpClient::newConnection, this, _1)); 70 | // FIXME setConnectFailedCallback 71 | LOG_INFO << "TcpClient::TcpClient[" << name_ 72 | << "] - connector " << get_pointer(connector_); 73 | } 74 | 75 | TcpClient::~TcpClient() 76 | { 77 | LOG_INFO << "TcpClient::~TcpClient[" << name_ 78 | << "] - connector " << get_pointer(connector_); 79 | TcpConnectionPtr conn; 80 | bool unique = false; 81 | { 82 | MutexLockGuard lock(mutex_); 83 | unique = connection_.unique(); 84 | conn = connection_; 85 | } 86 | if (conn) 87 | { 88 | assert(loop_ == conn->getLoop()); 89 | // FIXME: not 100% safe, if we are in different thread 90 | CloseCallback cb = boost::bind(&detail::removeConnection, loop_, _1); 91 | loop_->runInLoop( 92 | boost::bind(&TcpConnection::setCloseCallback, conn, cb)); 93 | if (unique) 94 | { 95 | conn->forceClose(); 96 | } 97 | } 98 | else 99 | { 100 | connector_->stop(); 101 | // FIXME: HACK 102 | loop_->runAfter(1, boost::bind(&detail::removeConnector, connector_)); 103 | } 104 | } 105 | 106 | void TcpClient::connect() 107 | { 108 | // FIXME: check state 109 | LOG_INFO << "TcpClient::connect[" << name_ << "] - connecting to " 110 | << connector_->serverAddress().toIpPort(); 111 | connect_ = true; 112 | connector_->start(); 113 | } 114 | 115 | void TcpClient::disconnect() 116 | { 117 | connect_ = false; 118 | 119 | { 120 | MutexLockGuard lock(mutex_); 121 | if (connection_) 122 | { 123 | connection_->shutdown(); 124 | } 125 | } 126 | } 127 | 128 | void TcpClient::stop() 129 | { 130 | connect_ = false; 131 | connector_->stop(); 132 | } 133 | 134 | void TcpClient::newConnection(int sockfd) 135 | { 136 | loop_->assertInLoopThread(); 137 | InetAddress peerAddr(sockets::getPeerAddr(sockfd)); 138 | char buf[32]; 139 | snprintf(buf, sizeof buf, ":%s#%d", peerAddr.toIpPort().c_str(), nextConnId_); 140 | ++nextConnId_; 141 | string connName = name_ + buf; 142 | 143 | InetAddress localAddr(sockets::getLocalAddr(sockfd)); 144 | // FIXME poll with zero timeout to double confirm the new connection 145 | // FIXME use make_shared if necessary 146 | TcpConnectionPtr conn(new TcpConnection(loop_, 147 | connName, 148 | sockfd, 149 | localAddr, 150 | peerAddr)); 151 | 152 | conn->setConnectionCallback(connectionCallback_); 153 | conn->setMessageCallback(messageCallback_); 154 | conn->setWriteCompleteCallback(writeCompleteCallback_); 155 | conn->setCloseCallback( 156 | boost::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe 157 | { 158 | MutexLockGuard lock(mutex_); 159 | connection_ = conn; 160 | } 161 | conn->connectEstablished(); 162 | } 163 | 164 | void TcpClient::removeConnection(const TcpConnectionPtr& conn) 165 | { 166 | loop_->assertInLoopThread(); 167 | assert(loop_ == conn->getLoop()); 168 | 169 | { 170 | MutexLockGuard lock(mutex_); 171 | assert(connection_ == conn); 172 | connection_.reset(); 173 | } 174 | 175 | loop_->queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn)); 176 | if (retry_ && connect_) 177 | { 178 | LOG_INFO << "TcpClient::connect[" << name_ << "] - Reconnecting to " 179 | << connector_->serverAddress().toIpPort(); 180 | connector_->restart(); 181 | } 182 | } 183 | 184 | -------------------------------------------------------------------------------- /muduo/net/TcpClient.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_TCPCLIENT_H 12 | #define MUDUO_NET_TCPCLIENT_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | namespace muduo 20 | { 21 | namespace net 22 | { 23 | 24 | class Connector; 25 | typedef boost::shared_ptr ConnectorPtr; 26 | 27 | class TcpClient : boost::noncopyable 28 | { 29 | public: 30 | // TcpClient(EventLoop* loop); 31 | // TcpClient(EventLoop* loop, const string& host, uint16_t port); 32 | TcpClient(EventLoop* loop, 33 | const InetAddress& serverAddr, 34 | const string& nameArg); 35 | ~TcpClient(); // force out-line dtor, for scoped_ptr members. 36 | 37 | void connect(); 38 | void disconnect(); 39 | void stop(); 40 | 41 | TcpConnectionPtr connection() const 42 | { 43 | MutexLockGuard lock(mutex_); 44 | return connection_; 45 | } 46 | 47 | EventLoop* getLoop() const { return loop_; } 48 | bool retry() const; 49 | void enableRetry() { retry_ = true; } 50 | 51 | const string& name() const 52 | { return name_; } 53 | 54 | /// Set connection callback. 55 | /// Not thread safe. 56 | void setConnectionCallback(const ConnectionCallback& cb) 57 | { connectionCallback_ = cb; } 58 | 59 | /// Set message callback. 60 | /// Not thread safe. 61 | void setMessageCallback(const MessageCallback& cb) 62 | { messageCallback_ = cb; } 63 | 64 | /// Set write complete callback. 65 | /// Not thread safe. 66 | void setWriteCompleteCallback(const WriteCompleteCallback& cb) 67 | { writeCompleteCallback_ = cb; } 68 | 69 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 70 | void setConnectionCallback(ConnectionCallback&& cb) 71 | { connectionCallback_ = std::move(cb); } 72 | void setMessageCallback(MessageCallback&& cb) 73 | { messageCallback_ = std::move(cb); } 74 | void setWriteCompleteCallback(WriteCompleteCallback&& cb) 75 | { writeCompleteCallback_ = std::move(cb); } 76 | #endif 77 | 78 | private: 79 | /// Not thread safe, but in loop 80 | void newConnection(int sockfd); 81 | /// Not thread safe, but in loop 82 | void removeConnection(const TcpConnectionPtr& conn); 83 | 84 | EventLoop* loop_; 85 | ConnectorPtr connector_; // avoid revealing Connector 86 | const string name_; 87 | ConnectionCallback connectionCallback_; 88 | MessageCallback messageCallback_; 89 | WriteCompleteCallback writeCompleteCallback_; 90 | bool retry_; // atomic 91 | bool connect_; // atomic 92 | // always in loop thread 93 | int nextConnId_; 94 | mutable MutexLock mutex_; 95 | TcpConnectionPtr connection_; // @GuardedBy mutex_ 96 | }; 97 | 98 | } 99 | } 100 | 101 | #endif // MUDUO_NET_TCPCLIENT_H 102 | -------------------------------------------------------------------------------- /muduo/net/TcpConnection.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_TCPCONNECTION_H 12 | #define MUDUO_NET_TCPCONNECTION_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | // struct tcp_info is in 27 | struct tcp_info; 28 | 29 | namespace muduo 30 | { 31 | namespace net 32 | { 33 | 34 | class Channel; 35 | class EventLoop; 36 | class Socket; 37 | 38 | /// 39 | /// TCP connection, for both client and server usage. 40 | /// 41 | /// This is an interface class, so don't expose too much details. 42 | class TcpConnection : boost::noncopyable, 43 | public boost::enable_shared_from_this 44 | { 45 | public: 46 | /// Constructs a TcpConnection with a connected sockfd 47 | /// 48 | /// User should not create this object. 49 | TcpConnection(EventLoop* loop, 50 | const string& name, 51 | int sockfd, 52 | const InetAddress& localAddr, 53 | const InetAddress& peerAddr); 54 | ~TcpConnection(); 55 | 56 | EventLoop* getLoop() const { return loop_; } 57 | const string& name() const { return name_; } 58 | const InetAddress& localAddress() const { return localAddr_; } 59 | const InetAddress& peerAddress() const { return peerAddr_; } 60 | bool connected() const { return state_ == kConnected; } 61 | bool disconnected() const { return state_ == kDisconnected; } 62 | // return true if success. 63 | bool getTcpInfo(struct tcp_info*) const; 64 | string getTcpInfoString() const; 65 | 66 | // void send(string&& message); // C++11 67 | void send(const void* message, int len); 68 | void send(const StringPiece& message); 69 | // void send(Buffer&& message); // C++11 70 | void send(Buffer* message); // this one will swap data 71 | void shutdown(); // NOT thread safe, no simultaneous calling 72 | // void shutdownAndForceCloseAfter(double seconds); // NOT thread safe, no simultaneous calling 73 | void forceClose(); 74 | void forceCloseWithDelay(double seconds); 75 | void setTcpNoDelay(bool on); 76 | 77 | void setContext(const boost::any& context) 78 | { context_ = context; } 79 | 80 | const boost::any& getContext() const 81 | { return context_; } 82 | 83 | boost::any* getMutableContext() 84 | { return &context_; } 85 | 86 | void setConnectionCallback(const ConnectionCallback& cb) 87 | { connectionCallback_ = cb; } 88 | 89 | void setMessageCallback(const MessageCallback& cb) 90 | { messageCallback_ = cb; } 91 | 92 | void setWriteCompleteCallback(const WriteCompleteCallback& cb) 93 | { writeCompleteCallback_ = cb; } 94 | 95 | void setHighWaterMarkCallback(const HighWaterMarkCallback& cb, size_t highWaterMark) 96 | { highWaterMarkCallback_ = cb; highWaterMark_ = highWaterMark; } 97 | 98 | /// Advanced interface 99 | Buffer* inputBuffer() 100 | { return &inputBuffer_; } 101 | 102 | Buffer* outputBuffer() 103 | { return &outputBuffer_; } 104 | 105 | /// Internal use only. 106 | void setCloseCallback(const CloseCallback& cb) 107 | { closeCallback_ = cb; } 108 | 109 | // called when TcpServer accepts a new connection 110 | void connectEstablished(); // should be called only once 111 | // called when TcpServer has removed me from its map 112 | void connectDestroyed(); // should be called only once 113 | 114 | private: 115 | enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting }; 116 | void handleRead(Timestamp receiveTime); 117 | void handleWrite(); 118 | void handleClose(); 119 | void handleError(); 120 | // void sendInLoop(string&& message); 121 | void sendInLoop(const StringPiece& message); 122 | void sendInLoop(const void* message, size_t len); 123 | void shutdownInLoop(); 124 | // void shutdownAndForceCloseInLoop(double seconds); 125 | void forceCloseInLoop(); 126 | void setState(StateE s) { state_ = s; } 127 | const char* stateToString() const; 128 | 129 | EventLoop* loop_; 130 | const string name_; 131 | StateE state_; // FIXME: use atomic variable 132 | // we don't expose those classes to client. 133 | boost::scoped_ptr socket_; 134 | boost::scoped_ptr channel_; 135 | const InetAddress localAddr_; 136 | const InetAddress peerAddr_; 137 | ConnectionCallback connectionCallback_; 138 | MessageCallback messageCallback_; 139 | WriteCompleteCallback writeCompleteCallback_; 140 | HighWaterMarkCallback highWaterMarkCallback_; 141 | CloseCallback closeCallback_; 142 | size_t highWaterMark_; 143 | Buffer inputBuffer_; 144 | Buffer outputBuffer_; // FIXME: use list as output buffer. 145 | boost::any context_; 146 | // FIXME: creationTime_, lastReceiveTime_ 147 | // bytesReceived_, bytesSent_ 148 | }; 149 | 150 | typedef boost::shared_ptr TcpConnectionPtr; 151 | 152 | } 153 | } 154 | 155 | #endif // MUDUO_NET_TCPCONNECTION_H 156 | -------------------------------------------------------------------------------- /muduo/net/TcpServer.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include // snprintf 20 | 21 | using namespace muduo; 22 | using namespace muduo::net; 23 | 24 | TcpServer::TcpServer(EventLoop* loop, 25 | const InetAddress& listenAddr, 26 | const string& nameArg, 27 | Option option) 28 | : loop_(CHECK_NOTNULL(loop)), 29 | hostport_(listenAddr.toIpPort()), 30 | name_(nameArg), 31 | acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)), 32 | threadPool_(new EventLoopThreadPool(loop, name_)), 33 | connectionCallback_(defaultConnectionCallback), 34 | messageCallback_(defaultMessageCallback), 35 | nextConnId_(1) 36 | { 37 | acceptor_->setNewConnectionCallback( 38 | boost::bind(&TcpServer::newConnection, this, _1, _2)); 39 | } 40 | 41 | TcpServer::~TcpServer() 42 | { 43 | loop_->assertInLoopThread(); 44 | LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing"; 45 | 46 | for (ConnectionMap::iterator it(connections_.begin()); 47 | it != connections_.end(); ++it) 48 | { 49 | TcpConnectionPtr conn = it->second; 50 | it->second.reset(); 51 | conn->getLoop()->runInLoop( 52 | boost::bind(&TcpConnection::connectDestroyed, conn)); 53 | conn.reset(); 54 | } 55 | } 56 | 57 | void TcpServer::setThreadNum(int numThreads) 58 | { 59 | assert(0 <= numThreads); 60 | threadPool_->setThreadNum(numThreads); 61 | } 62 | 63 | void TcpServer::start() 64 | { 65 | if (started_.getAndSet(1) == 0) 66 | { 67 | threadPool_->start(threadInitCallback_); 68 | 69 | assert(!acceptor_->listenning()); 70 | loop_->runInLoop( 71 | boost::bind(&Acceptor::listen, get_pointer(acceptor_))); 72 | } 73 | } 74 | 75 | void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) 76 | { 77 | loop_->assertInLoopThread(); 78 | EventLoop* ioLoop = threadPool_->getNextLoop(); 79 | char buf[32]; 80 | snprintf(buf, sizeof buf, ":%s#%d", hostport_.c_str(), nextConnId_); 81 | ++nextConnId_; 82 | string connName = name_ + buf; 83 | 84 | LOG_INFO << "TcpServer::newConnection [" << name_ 85 | << "] - new connection [" << connName 86 | << "] from " << peerAddr.toIpPort(); 87 | InetAddress localAddr(sockets::getLocalAddr(sockfd)); 88 | // FIXME poll with zero timeout to double confirm the new connection 89 | // FIXME use make_shared if necessary 90 | TcpConnectionPtr conn(new TcpConnection(ioLoop, 91 | connName, 92 | sockfd, 93 | localAddr, 94 | peerAddr)); 95 | connections_[connName] = conn; 96 | conn->setConnectionCallback(connectionCallback_); 97 | conn->setMessageCallback(messageCallback_); 98 | conn->setWriteCompleteCallback(writeCompleteCallback_); 99 | conn->setCloseCallback( 100 | boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe 101 | ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn)); 102 | } 103 | 104 | void TcpServer::removeConnection(const TcpConnectionPtr& conn) 105 | { 106 | // FIXME: unsafe 107 | loop_->runInLoop(boost::bind(&TcpServer::removeConnectionInLoop, this, conn)); 108 | } 109 | 110 | void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) 111 | { 112 | loop_->assertInLoopThread(); 113 | LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_ 114 | << "] - connection " << conn->name(); 115 | size_t n = connections_.erase(conn->name()); 116 | (void)n; 117 | assert(n == 1); 118 | EventLoop* ioLoop = conn->getLoop(); 119 | ioLoop->queueInLoop( 120 | boost::bind(&TcpConnection::connectDestroyed, conn)); 121 | } 122 | 123 | -------------------------------------------------------------------------------- /muduo/net/TcpServer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_TCPSERVER_H 12 | #define MUDUO_NET_TCPSERVER_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace muduo 24 | { 25 | namespace net 26 | { 27 | 28 | class Acceptor; 29 | class EventLoop; 30 | class EventLoopThreadPool; 31 | 32 | /// 33 | /// TCP server, supports single-threaded and thread-pool models. 34 | /// 35 | /// This is an interface class, so don't expose too much details. 36 | class TcpServer : boost::noncopyable 37 | { 38 | public: 39 | typedef boost::function ThreadInitCallback; 40 | enum Option 41 | { 42 | kNoReusePort, 43 | kReusePort, 44 | }; 45 | 46 | //TcpServer(EventLoop* loop, const InetAddress& listenAddr); 47 | TcpServer(EventLoop* loop, 48 | const InetAddress& listenAddr, 49 | const string& nameArg, 50 | Option option = kNoReusePort); 51 | ~TcpServer(); // force out-line dtor, for scoped_ptr members. 52 | 53 | const string& hostport() const { return hostport_; } 54 | const string& name() const { return name_; } 55 | EventLoop* getLoop() const { return loop_; } 56 | 57 | /// Set the number of threads for handling input. 58 | /// 59 | /// Always accepts new connection in loop's thread. 60 | /// Must be called before @c start 61 | /// @param numThreads 62 | /// - 0 means all I/O in loop's thread, no thread will created. 63 | /// this is the default value. 64 | /// - 1 means all I/O in another thread. 65 | /// - N means a thread pool with N threads, new connections 66 | /// are assigned on a round-robin basis. 67 | void setThreadNum(int numThreads); 68 | void setThreadInitCallback(const ThreadInitCallback& cb) 69 | { threadInitCallback_ = cb; } 70 | /// valid after calling start() 71 | boost::shared_ptr threadPool() 72 | { return threadPool_; } 73 | 74 | /// Starts the server if it's not listenning. 75 | /// 76 | /// It's harmless to call it multiple times. 77 | /// Thread safe. 78 | void start(); 79 | 80 | /// Set connection callback. 81 | /// Not thread safe. 82 | void setConnectionCallback(const ConnectionCallback& cb) 83 | { connectionCallback_ = cb; } 84 | 85 | /// Set message callback. 86 | /// Not thread safe. 87 | void setMessageCallback(const MessageCallback& cb) 88 | { messageCallback_ = cb; } 89 | 90 | /// Set write complete callback. 91 | /// Not thread safe. 92 | void setWriteCompleteCallback(const WriteCompleteCallback& cb) 93 | { writeCompleteCallback_ = cb; } 94 | 95 | private: 96 | /// Not thread safe, but in loop 97 | void newConnection(int sockfd, const InetAddress& peerAddr); 98 | /// Thread safe. 99 | void removeConnection(const TcpConnectionPtr& conn); 100 | /// Not thread safe, but in loop 101 | void removeConnectionInLoop(const TcpConnectionPtr& conn); 102 | 103 | typedef std::map ConnectionMap; 104 | 105 | EventLoop* loop_; // the acceptor loop 106 | const string hostport_; 107 | const string name_; 108 | boost::scoped_ptr acceptor_; // avoid revealing Acceptor 109 | boost::shared_ptr threadPool_; 110 | ConnectionCallback connectionCallback_; 111 | MessageCallback messageCallback_; 112 | WriteCompleteCallback writeCompleteCallback_; 113 | ThreadInitCallback threadInitCallback_; 114 | AtomicInt32 started_; 115 | // always in loop thread 116 | int nextConnId_; 117 | ConnectionMap connections_; 118 | }; 119 | 120 | } 121 | } 122 | 123 | #endif // MUDUO_NET_TCPSERVER_H 124 | -------------------------------------------------------------------------------- /muduo/net/Timer.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | 11 | using namespace muduo; 12 | using namespace muduo::net; 13 | 14 | AtomicInt64 Timer::s_numCreated_; 15 | 16 | void Timer::restart(Timestamp now) 17 | { 18 | if (repeat_) 19 | { 20 | expiration_ = addTime(now, interval_); 21 | } 22 | else 23 | { 24 | expiration_ = Timestamp::invalid(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /muduo/net/Timer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_TIMER_H 12 | #define MUDUO_NET_TIMER_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | /// 25 | /// Internal class for timer event. 26 | /// 27 | class Timer : boost::noncopyable 28 | { 29 | public: 30 | Timer(const TimerCallback& cb, Timestamp when, double interval) 31 | : callback_(cb), 32 | expiration_(when), 33 | interval_(interval), 34 | repeat_(interval > 0.0), 35 | sequence_(s_numCreated_.incrementAndGet()) 36 | { } 37 | 38 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 39 | Timer(TimerCallback&& cb, Timestamp when, double interval) 40 | : callback_(std::move(cb)), 41 | expiration_(when), 42 | interval_(interval), 43 | repeat_(interval > 0.0), 44 | sequence_(s_numCreated_.incrementAndGet()) 45 | { } 46 | #endif 47 | 48 | void run() const 49 | { 50 | callback_(); 51 | } 52 | 53 | Timestamp expiration() const { return expiration_; } 54 | bool repeat() const { return repeat_; } 55 | int64_t sequence() const { return sequence_; } 56 | 57 | void restart(Timestamp now); 58 | 59 | static int64_t numCreated() { return s_numCreated_.get(); } 60 | 61 | private: 62 | const TimerCallback callback_; 63 | Timestamp expiration_; 64 | const double interval_; 65 | const bool repeat_; 66 | const int64_t sequence_; 67 | 68 | static AtomicInt64 s_numCreated_; 69 | }; 70 | } 71 | } 72 | #endif // MUDUO_NET_TIMER_H 73 | -------------------------------------------------------------------------------- /muduo/net/TimerId.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_TIMERID_H 12 | #define MUDUO_NET_TIMERID_H 13 | 14 | #include 15 | 16 | namespace muduo 17 | { 18 | namespace net 19 | { 20 | 21 | class Timer; 22 | 23 | /// 24 | /// An opaque identifier, for canceling Timer. 25 | /// 26 | class TimerId : public muduo::copyable 27 | { 28 | public: 29 | TimerId() 30 | : timer_(NULL), 31 | sequence_(0) 32 | { 33 | } 34 | 35 | TimerId(Timer* timer, int64_t seq) 36 | : timer_(timer), 37 | sequence_(seq) 38 | { 39 | } 40 | 41 | // default copy-ctor, dtor and assignment are okay 42 | 43 | friend class TimerQueue; 44 | 45 | int64_t getSeq() {return sequence_;}; //bzh add 46 | Timer* getTimer() {return timer_;}; //bzh add 47 | private: 48 | Timer* timer_; 49 | int64_t sequence_; 50 | }; 51 | 52 | } 53 | } 54 | 55 | #endif // MUDUO_NET_TIMERID_H 56 | -------------------------------------------------------------------------------- /muduo/net/TimerQueue.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_TIMERQUEUE_H 12 | #define MUDUO_NET_TIMERQUEUE_H 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace muduo 25 | { 26 | namespace net 27 | { 28 | 29 | class EventLoop; 30 | class Timer; 31 | class TimerId; 32 | 33 | /// 34 | /// A best efforts timer queue. 35 | /// No guarantee that the callback will be on time. 36 | /// 37 | class TimerQueue : boost::noncopyable 38 | { 39 | public: 40 | TimerQueue(EventLoop* loop); 41 | ~TimerQueue(); 42 | 43 | /// 44 | /// Schedules the callback to be run at given time, 45 | /// repeats if @c interval > 0.0. 46 | /// 47 | /// Must be thread safe. Usually be called from other threads. 48 | TimerId addTimer(const TimerCallback& cb, 49 | Timestamp when, 50 | double interval); 51 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 52 | TimerId addTimer(TimerCallback&& cb, 53 | Timestamp when, 54 | double interval); 55 | #endif 56 | 57 | void cancel(TimerId timerId); 58 | 59 | private: 60 | 61 | // FIXME: use unique_ptr instead of raw pointers. 62 | typedef std::pair Entry; 63 | typedef std::set TimerList; 64 | typedef std::pair ActiveTimer; 65 | typedef std::set ActiveTimerSet; 66 | 67 | void addTimerInLoop(Timer* timer); 68 | void cancelInLoop(TimerId timerId); 69 | // called when timerfd alarms 70 | void handleRead(); 71 | // move out all expired timers 72 | std::vector getExpired(Timestamp now); 73 | void reset(const std::vector& expired, Timestamp now); 74 | 75 | bool insert(Timer* timer); 76 | 77 | EventLoop* loop_; 78 | const int timerfd_; 79 | Channel timerfdChannel_; 80 | // Timer list sorted by expiration 81 | TimerList timers_; 82 | 83 | // for cancel() 84 | ActiveTimerSet activeTimers_; 85 | bool callingExpiredTimers_; /* atomic */ 86 | ActiveTimerSet cancelingTimers_; 87 | }; 88 | 89 | } 90 | } 91 | #endif // MUDUO_NET_TIMERQUEUE_H 92 | -------------------------------------------------------------------------------- /muduo/net/UdpClient.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | //#include 9 | 10 | using namespace muduo; 11 | using namespace muduo::net; 12 | 13 | pthread_key_t UdpClient::threadKey_; 14 | pthread_once_t UdpClient::threadOnce_ = PTHREAD_ONCE_INIT; 15 | 16 | UdpClient::UdpClient() 17 | : sndBufSize_ (-1) 18 | {} 19 | 20 | void UdpClient::createThreadData() 21 | { 22 | if(pthread_key_create(&threadKey_, &UdpClient::releaseThreadData) != 0) 23 | { 24 | LOG_ERROR << "create thread key failed, errmsg=" << strerror_tl(errno); 25 | } 26 | } 27 | 28 | void UdpClient::releaseThreadData(void *data) 29 | { 30 | if(NULL != data) 31 | { 32 | delete (ThreadData*)data; 33 | } 34 | } 35 | 36 | void UdpClient::send(const char *buf, int size) 37 | { 38 | ThreadData *threadData = getThreadData(); 39 | if(NULL == threadData) 40 | { 41 | LOG_ERROR << "get thread data failed."; 42 | return; 43 | } 44 | // sockfd may be closed due to an io fault 45 | if(threadData->sockfd < 0) 46 | { 47 | threadData->sockfd = createSocket(); 48 | if(threadData->sockfd < 0) 49 | { 50 | return; 51 | } 52 | } 53 | // choose an address 54 | if(threadData->addrList.empty()) 55 | { 56 | LOG_WARN << "addr list is empty."; 57 | return; 58 | } 59 | InetAddress & addr = threadData->addrList[threadData->curAddrIndex]; 60 | threadData->curAddrIndex = (threadData->curAddrIndex+1)%threadData->addrList.size(); 61 | const struct sockaddr_in &sin = addr.getSockAddrInet(); 62 | // send data 63 | if(sendto(threadData->sockfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) != size) 64 | { 65 | close(threadData->sockfd); 66 | // open a new socket and retry 67 | threadData->sockfd = createSocket(); 68 | if(threadData->sockfd < 0) 69 | { 70 | return; 71 | } 72 | // retry 73 | if(sendto(threadData->sockfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) != size) 74 | { 75 | LOG_ERROR << "sendto failed, errmsg=" << strerror_tl(errno); 76 | close(threadData->sockfd); 77 | threadData->sockfd = -1; 78 | } 79 | } 80 | } 81 | 82 | void UdpClient::setSndBufSize(int size) 83 | { 84 | sndBufSize_ = size; 85 | } 86 | 87 | int UdpClient::createSocket() 88 | { 89 | int fd = socket(AF_INET, SOCK_DGRAM, 0); 90 | if(fd < 0) 91 | { 92 | LOG_ERROR << "create socket failed, errmsg=" << strerror_tl(errno); 93 | return -1; 94 | } 95 | int sndBufSize = sndBufSize_ ; 96 | if(sndBufSize != -1) 97 | { 98 | if(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndBufSize, sizeof(sndBufSize)) != 0) 99 | { 100 | LOG_WARN << "set send buf size failed, size=" << sndBufSize_ << ", errmsg=" << strerror_tl(errno); 101 | } 102 | else 103 | { 104 | sndBufSize = 0; 105 | socklen_t len = sizeof(sndBufSize); 106 | if(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndBufSize, &len) == 0 && sndBufSize < sndBufSize_) 107 | { 108 | LOG_WARN << "set send buf size failed, actual size is " << sndBufSize; 109 | } 110 | } 111 | } 112 | 113 | return fd; 114 | } 115 | 116 | UdpClient::ThreadData *UdpClient::getThreadData() 117 | { 118 | // create thread specific key 119 | if(pthread_once(&threadOnce_, &UdpClient::createThreadData) != 0) 120 | { 121 | LOG_ERROR << "pthread_once failed, " << strerror_tl(errno); 122 | return NULL; 123 | } 124 | // get thread specific data 125 | ThreadData *threadData = (ThreadData *)pthread_getspecific(threadKey_); 126 | if(NULL == threadData) 127 | { 128 | // create thread specific data 129 | threadData = new ThreadData; 130 | assert(threadData); 131 | { 132 | muduo::MutexLockGuard lk(mutex_); 133 | threadData->addrList = addrList_; 134 | } 135 | threadData->curAddrIndex = 0; 136 | threadData->sockfd = -1; 137 | if(pthread_setspecific(threadKey_, threadData) != 0) 138 | { 139 | LOG_ERROR << "set thread specific data failed, errmsg=" << strerror_tl(errno); 140 | delete threadData; 141 | return NULL; 142 | } 143 | } 144 | return threadData; 145 | } 146 | 147 | // run in child thread 148 | void UdpClient::resetThreadData(const NetAddrList &addrList) 149 | { 150 | // get thread specific data 151 | ThreadData *threadData = (ThreadData *)pthread_getspecific(threadKey_); 152 | if(NULL != threadData) 153 | { 154 | threadData->addrList = addrList; 155 | threadData->curAddrIndex = 0; 156 | } 157 | } 158 | 159 | // run in main thread 160 | void UdpClient::resetAddrList(const NetAddrList &addrList) 161 | { 162 | muduo::MutexLockGuard lk(mutex_); 163 | addrList_ = addrList; 164 | } -------------------------------------------------------------------------------- /muduo/net/UdpClient.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_NET_UDPCLIENT_H 2 | #define MUDUO_NET_UDPCLIENT_H 3 | //#include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | //#include 10 | //#include 11 | //#include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #define MAX_SERVER_PORT 20 18 | 19 | namespace muduo 20 | { 21 | namespace net 22 | { 23 | 24 | class UdpClient 25 | { 26 | public: 27 | typedef std::vector NetAddrList; 28 | UdpClient(); 29 | // run in main thread 30 | void resetAddrList(const NetAddrList &addrList); 31 | // run in child thread 32 | void resetThreadData(const NetAddrList &addrList); 33 | void send(const char *buf, int size); 34 | void setSndBufSize(int size); 35 | // 36 | private: 37 | struct ThreadData 38 | { 39 | NetAddrList addrList; 40 | int sockfd; 41 | int curAddrIndex; 42 | }; 43 | // thread specific data and method 44 | static void createThreadData(); 45 | static void releaseThreadData(void *data); 46 | static pthread_key_t threadKey_; 47 | static pthread_once_t threadOnce_; 48 | // 49 | ThreadData *getThreadData(); 50 | int createSocket(); 51 | // 52 | NetAddrList addrList_; 53 | muduo::MutexLock mutex_; 54 | // 55 | volatile int sndBufSize_; 56 | }; 57 | 58 | } 59 | } 60 | #endif -------------------------------------------------------------------------------- /muduo/net/ZlibStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #pragma GCC diagnostic ignored "-Wold-style-cast" 6 | #include 7 | 8 | namespace muduo 9 | { 10 | namespace net 11 | { 12 | 13 | // input is zlib compressed data, output uncompressed data 14 | // FIXME: finish this 15 | class ZlibInputStream : boost::noncopyable 16 | { 17 | public: 18 | explicit ZlibInputStream(Buffer* output) 19 | : output_(output), 20 | zerror_(Z_OK) 21 | { 22 | bzero(&zstream_, sizeof zstream_); 23 | zerror_ = inflateInit(&zstream_); 24 | } 25 | 26 | ~ZlibInputStream() 27 | { 28 | finish(); 29 | } 30 | 31 | bool write(StringPiece buf); 32 | bool write(Buffer* input); 33 | bool finish(); 34 | // inflateEnd(&zstream_); 35 | 36 | private: 37 | int decompress(int flush); 38 | 39 | Buffer* output_; 40 | z_stream zstream_; 41 | int zerror_; 42 | }; 43 | 44 | // input is uncompressed data, output zlib compressed data 45 | class ZlibOutputStream : boost::noncopyable 46 | { 47 | public: 48 | explicit ZlibOutputStream(Buffer* output) 49 | : output_(output), 50 | zerror_(Z_OK), 51 | bufferSize_(1024) 52 | { 53 | bzero(&zstream_, sizeof zstream_); 54 | zerror_ = deflateInit(&zstream_, Z_DEFAULT_COMPRESSION); 55 | } 56 | 57 | ~ZlibOutputStream() 58 | { 59 | finish(); 60 | } 61 | 62 | // Return last error message or NULL if no error. 63 | const char* zlibErrorMessage() const { return zstream_.msg; } 64 | 65 | int zlibErrorCode() const { return zerror_; } 66 | int64_t inputBytes() const { return zstream_.total_in; } 67 | int64_t outputBytes() const { return zstream_.total_out; } 68 | int internalOutputBufferSize() const { return bufferSize_; } 69 | 70 | bool write(StringPiece buf) 71 | { 72 | if (zerror_ != Z_OK) 73 | return false; 74 | 75 | assert(zstream_.next_in == NULL && zstream_.avail_in == 0); 76 | void* in = const_cast(buf.data()); 77 | zstream_.next_in = static_cast(in); 78 | zstream_.avail_in = buf.size(); 79 | while (zstream_.avail_in > 0 && zerror_ == Z_OK) 80 | { 81 | zerror_ = compress(Z_NO_FLUSH); 82 | } 83 | if (zstream_.avail_in == 0) 84 | { 85 | assert(static_cast(zstream_.next_in) == buf.end()); 86 | zstream_.next_in = NULL; 87 | } 88 | return zerror_ == Z_OK; 89 | } 90 | 91 | // compress input as much as possible, not guarantee consuming all data. 92 | bool write(Buffer* input) 93 | { 94 | if (zerror_ != Z_OK) 95 | return false; 96 | 97 | void* in = const_cast(input->peek()); 98 | zstream_.next_in = static_cast(in); 99 | zstream_.avail_in = static_cast(input->readableBytes()); 100 | if (zstream_.avail_in > 0 && zerror_ == Z_OK) 101 | { 102 | zerror_ = compress(Z_NO_FLUSH); 103 | } 104 | input->retrieve(input->readableBytes() - zstream_.avail_in); 105 | return zerror_ == Z_OK; 106 | } 107 | 108 | bool finish() 109 | { 110 | if (zerror_ != Z_OK) 111 | return false; 112 | 113 | while (zerror_ == Z_OK) 114 | { 115 | zerror_ = compress(Z_FINISH); 116 | } 117 | zerror_ = deflateEnd(&zstream_); 118 | bool ok = zerror_ == Z_OK; 119 | zerror_ = Z_STREAM_END; 120 | return ok; 121 | } 122 | 123 | private: 124 | int compress(int flush) 125 | { 126 | output_->ensureWritableBytes(bufferSize_); 127 | zstream_.next_out = reinterpret_cast(output_->beginWrite()); 128 | zstream_.avail_out = static_cast(output_->writableBytes()); 129 | int error = ::deflate(&zstream_, flush); 130 | output_->hasWritten(output_->writableBytes() - zstream_.avail_out); 131 | if (output_->writableBytes() == 0 && bufferSize_ < 65536) 132 | { 133 | bufferSize_ *= 2; 134 | } 135 | return error; 136 | } 137 | 138 | Buffer* output_; 139 | z_stream zstream_; 140 | int zerror_; 141 | int bufferSize_; 142 | }; 143 | 144 | } 145 | } 146 | 147 | -------------------------------------------------------------------------------- /muduo/net/makefile: -------------------------------------------------------------------------------- 1 | 2 | LIB_INSTALL_COMM_PATH = ../../lib 3 | 4 | INC_COMM_PATH = -I../../ -I../../ -I/export/newjpush/include -I/export/newjpush/ 5 | 6 | LIB_BOOST_COMM_PATH := /export/newjpush/lib 7 | LIB_BOOST_COMM := -L$(LIB_BOOST_COMM_PATH) -Wl,-Bstatic -lboost_thread -Wl,-Bdynamic -lm -lc -Wl,-Bstatic -lboost_system -Wl,-Bdynamic -lm -lc 8 | 9 | .SUFFIXES: .o .cc 10 | 11 | cxx = g++ 12 | 13 | CFLAGS = -g -Wall $(INC_COMM_PATH) 14 | 15 | OI_OBJS = Acceptor.o Boilerplate.o Buffer.o \ 16 | Channel.o Connector.o ConnectorOri.o EventLoop.o EventLoopThread.o \ 17 | EventLoopThreadPool.o InetAddress.o Poller.o Socket.o \ 18 | SocketsOps.o TcpConnection.o TcpServer.o TcpClient.o \ 19 | Timer.o TimerQueue.o ./poller/DefaultPoller.o ./poller/EPollPoller.o \ 20 | ./poller/PollPoller.o UdpClient.o 21 | 22 | OUTPUT := libnet.a 23 | 24 | all:$(OUTPUT) 25 | 26 | .cc.o: 27 | $(CXX) $(CFLAGS) -c $^ -o ./$@ -DMUDUO_STD_STRING 28 | 29 | libnet.a:$(OI_OBJS) 30 | ar -rs $@ $^ 31 | 32 | install: 33 | cp -R -f $(OUTPUT) $(LIB_INSTALL_COMM_PATH)/ 34 | 35 | clean: 36 | rm -f *.o *.a ./poller/*.o 37 | -------------------------------------------------------------------------------- /muduo/net/poller/DefaultPoller.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | using namespace muduo::net; 16 | 17 | Poller* Poller::newDefaultPoller(EventLoop* loop) 18 | { 19 | if (::getenv("MUDUO_USE_POLL")) 20 | { 21 | return new PollPoller(loop); 22 | } 23 | else 24 | { 25 | return new EPollPoller(loop); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /muduo/net/poller/EPollPoller.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_POLLER_EPOLLPOLLER_H 12 | #define MUDUO_NET_POLLER_EPOLLPOLLER_H 13 | 14 | #include 15 | 16 | #include 17 | 18 | struct epoll_event; 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | 25 | /// 26 | /// IO Multiplexing with epoll(4). 27 | /// 28 | class EPollPoller : public Poller 29 | { 30 | public: 31 | EPollPoller(EventLoop* loop); 32 | virtual ~EPollPoller(); 33 | 34 | virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels); 35 | virtual void updateChannel(Channel* channel); 36 | virtual void removeChannel(Channel* channel); 37 | 38 | private: 39 | static const int kInitEventListSize = 16; 40 | 41 | static const char* operationToString(int op); 42 | 43 | void fillActiveChannels(int numEvents, 44 | ChannelList* activeChannels) const; 45 | void update(int operation, Channel* channel); 46 | 47 | typedef std::vector EventList; 48 | 49 | int epollfd_; 50 | EventList events_; 51 | }; 52 | 53 | } 54 | } 55 | #endif // MUDUO_NET_POLLER_EPOLLPOLLER_H 56 | -------------------------------------------------------------------------------- /muduo/net/poller/PollPoller.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace muduo; 20 | using namespace muduo::net; 21 | 22 | PollPoller::PollPoller(EventLoop* loop) 23 | : Poller(loop) 24 | { 25 | } 26 | 27 | PollPoller::~PollPoller() 28 | { 29 | } 30 | 31 | Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels) 32 | { 33 | // XXX pollfds_ shouldn't change 34 | int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); 35 | int savedErrno = errno; 36 | Timestamp now(Timestamp::now()); 37 | if (numEvents > 0) 38 | { 39 | LOG_TRACE << numEvents << " events happended"; 40 | fillActiveChannels(numEvents, activeChannels); 41 | } 42 | else if (numEvents == 0) 43 | { 44 | LOG_TRACE << " nothing happended"; 45 | } 46 | else 47 | { 48 | if (savedErrno != EINTR) 49 | { 50 | errno = savedErrno; 51 | LOG_SYSERR << "PollPoller::poll()"; 52 | } 53 | } 54 | return now; 55 | } 56 | 57 | void PollPoller::fillActiveChannels(int numEvents, 58 | ChannelList* activeChannels) const 59 | { 60 | for (PollFdList::const_iterator pfd = pollfds_.begin(); 61 | pfd != pollfds_.end() && numEvents > 0; ++pfd) 62 | { 63 | if (pfd->revents > 0) 64 | { 65 | --numEvents; 66 | ChannelMap::const_iterator ch = channels_.find(pfd->fd); 67 | assert(ch != channels_.end()); 68 | Channel* channel = ch->second; 69 | assert(channel->fd() == pfd->fd); 70 | channel->set_revents(pfd->revents); 71 | // pfd->revents = 0; 72 | activeChannels->push_back(channel); 73 | } 74 | } 75 | } 76 | 77 | void PollPoller::updateChannel(Channel* channel) 78 | { 79 | Poller::assertInLoopThread(); 80 | LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); 81 | if (channel->index() < 0) 82 | { 83 | // a new one, add to pollfds_ 84 | assert(channels_.find(channel->fd()) == channels_.end()); 85 | struct pollfd pfd; 86 | pfd.fd = channel->fd(); 87 | pfd.events = static_cast(channel->events()); 88 | pfd.revents = 0; 89 | pollfds_.push_back(pfd); 90 | int idx = static_cast(pollfds_.size())-1; 91 | channel->set_index(idx); 92 | channels_[pfd.fd] = channel; 93 | } 94 | else 95 | { 96 | // update existing one 97 | assert(channels_.find(channel->fd()) != channels_.end()); 98 | assert(channels_[channel->fd()] == channel); 99 | int idx = channel->index(); 100 | assert(0 <= idx && idx < static_cast(pollfds_.size())); 101 | struct pollfd& pfd = pollfds_[idx]; 102 | assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); 103 | pfd.events = static_cast(channel->events()); 104 | pfd.revents = 0; 105 | if (channel->isNoneEvent()) 106 | { 107 | // ignore this pollfd 108 | pfd.fd = -channel->fd()-1; 109 | } 110 | } 111 | } 112 | 113 | void PollPoller::removeChannel(Channel* channel) 114 | { 115 | Poller::assertInLoopThread(); 116 | LOG_TRACE << "fd = " << channel->fd(); 117 | assert(channels_.find(channel->fd()) != channels_.end()); 118 | assert(channels_[channel->fd()] == channel); 119 | assert(channel->isNoneEvent()); 120 | int idx = channel->index(); 121 | assert(0 <= idx && idx < static_cast(pollfds_.size())); 122 | const struct pollfd& pfd = pollfds_[idx]; (void)pfd; 123 | assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events()); 124 | size_t n = channels_.erase(channel->fd()); 125 | assert(n == 1); (void)n; 126 | if (implicit_cast(idx) == pollfds_.size()-1) 127 | { 128 | pollfds_.pop_back(); 129 | } 130 | else 131 | { 132 | int channelAtEnd = pollfds_.back().fd; 133 | iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); 134 | if (channelAtEnd < 0) 135 | { 136 | channelAtEnd = -channelAtEnd-1; 137 | } 138 | channels_[channelAtEnd]->set_index(idx); 139 | pollfds_.pop_back(); 140 | } 141 | } 142 | 143 | -------------------------------------------------------------------------------- /muduo/net/poller/PollPoller.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_POLLER_POLLPOLLER_H 12 | #define MUDUO_NET_POLLER_POLLPOLLER_H 13 | 14 | #include 15 | 16 | #include 17 | 18 | struct pollfd; 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | 25 | /// 26 | /// IO Multiplexing with poll(2). 27 | /// 28 | class PollPoller : public Poller 29 | { 30 | public: 31 | 32 | PollPoller(EventLoop* loop); 33 | virtual ~PollPoller(); 34 | 35 | virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels); 36 | virtual void updateChannel(Channel* channel); 37 | virtual void removeChannel(Channel* channel); 38 | 39 | private: 40 | void fillActiveChannels(int numEvents, 41 | ChannelList* activeChannels) const; 42 | 43 | typedef std::vector PollFdList; 44 | PollFdList pollfds_; 45 | }; 46 | 47 | } 48 | } 49 | #endif // MUDUO_NET_POLLER_POLLPOLLER_H 50 | -------------------------------------------------------------------------------- /muduo/net/premake4.lua: -------------------------------------------------------------------------------- 1 | project "net" 2 | kind "StaticLib" 3 | language "C++" 4 | links('base') 5 | targetdir(libdir) 6 | targetname('muduo_net') 7 | includedirs('../..') 8 | headersdir('muduo/net') 9 | headers { 10 | 'Buffer.h', 11 | 'Callbacks.h', 12 | 'Channel.h', 13 | 'Endian.h', 14 | 'EventLoop.h', 15 | 'EventLoopThread.h', 16 | 'EventLoopThreadPool.h', 17 | 'InetAddress.h', 18 | 'TcpClient.h', 19 | 'TcpConnection.h', 20 | 'TcpServer.h', 21 | 'TimerId.h', 22 | } 23 | 24 | files { 25 | 'Acceptor.cc', 26 | 'Buffer.cc', 27 | 'Channel.cc', 28 | 'Connector.cc', 29 | 'EventLoop.cc', 30 | 'EventLoopThread.cc', 31 | 'EventLoopThreadPool.cc', 32 | 'InetAddress.cc', 33 | 'Poller.cc', 34 | 'poller/DefaultPoller.cc', 35 | 'poller/EPollPoller.cc', 36 | 'poller/PollPoller.cc', 37 | 'Socket.cc', 38 | 'SocketsOps.cc', 39 | 'TcpClient.cc', 40 | 'TcpConnection.cc', 41 | 'TcpServer.cc', 42 | 'Timer.cc', 43 | 'TimerQueue.cc', 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/ZkClient.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/src/ZkClient.cc -------------------------------------------------------------------------------- /src/ZkClient.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/src/ZkClient.h -------------------------------------------------------------------------------- /src/ZkClientManager.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/src/ZkClientManager.cc -------------------------------------------------------------------------------- /src/ZkClientManager.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/src/ZkClientManager.h -------------------------------------------------------------------------------- /src/ZkTimerQueue.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baozh/zookeeper_cpp_client/db7990bb880b7eac94eb02735aae4a6cdbf2880f/src/ZkTimerQueue.cc -------------------------------------------------------------------------------- /src/ZkTimerQueue.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef __ZK_TIMERQUEUE_H 12 | #define __ZK_TIMERQUEUE_H 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include "muduo/base/Mutex.h" 20 | #include "muduo/base/Timestamp.h" 21 | #include "muduo/net/Callbacks.h" 22 | 23 | #include "muduo/net/Timer.h" 24 | #include "muduo/net/TimerId.h" 25 | 26 | #include "ZkClient.h" 27 | 28 | 29 | 30 | class ZkNetClient; 31 | 32 | namespace ZkCppClient 33 | { 34 | 35 | class ZkTimerQueue 36 | { 37 | public: 38 | ZkTimerQueue(int thread_id, int epoll_fd/*, SslClientThreadManager *manager*/); 39 | ~ZkTimerQueue(); 40 | 41 | /// 42 | /// Schedules the callback to be run at given time, 43 | /// repeats if @c interval > 0.0. 44 | /// 45 | /// Must be thread safe. Usually be called from other threads. 46 | muduo::net::TimerId addTimer(const muduo::net::TimerCallback& cb, 47 | muduo::Timestamp when, 48 | double interval); 49 | 50 | void cancel(muduo::net::TimerId timerId); 51 | int getTimerFd() {return timerfd_;}; 52 | 53 | private: 54 | 55 | typedef std::pair Entry; 56 | typedef std::set TimerList; 57 | typedef std::pair ActiveTimer; 58 | typedef std::set ActiveTimerSet; 59 | 60 | void addTimerInLoop(muduo::net::Timer* timer); 61 | void cancelInLoop(muduo::net::TimerId timerId); 62 | 63 | void handleRead(); 64 | 65 | std::vector getExpired(muduo::Timestamp now); 66 | 67 | void reset(const std::vector& expired, muduo::Timestamp now); 68 | 69 | bool insert(muduo::net::Timer* timer); 70 | 71 | //EventLoop* loop_; 72 | int threadId_; 73 | const int timerfd_; 74 | ZkNetClient* pTimerClient_; 75 | int epollfd_; 76 | 77 | //Channel timerfdChannel_; 78 | // Timer list sorted by expiration 79 | TimerList timers_; 80 | 81 | // for cancel() 82 | ActiveTimerSet activeTimers_; 83 | bool callingExpiredTimers_; /* atomic */ 84 | ActiveTimerSet cancelingTimers_; 85 | }; 86 | 87 | } 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | 2 | LIB_INSTALL_COMM_PATH = ../lib 3 | 4 | INC_COMM_PATH = -I./ -I../ -I/usr/local/include/zookeeper -I/export/newjpush/include -I/export/newjpush/ 5 | 6 | LIB_BOOST_COMM_PATH := /export/newjpush/lib 7 | LIB_BOOST_COMM := -L$(LIB_BOOST_COMM_PATH) -Wl,-Bstatic -lboost_thread -Wl,-Bdynamic -lm -lc -Wl,-Bstatic -lboost_system -Wl,-Bdynamic -lm -lc 8 | 9 | LIB_COMM = -lzookeeper_mt -L$(LIB_INSTALL_COMM_PATH) -lbase -lpthread -lrt -L$(LIB_INSTALL_COMM_PATH) -lnet -lboost_thread -lboost_system $(LIB_BOOST_COMM) 10 | 11 | .SUFFIXES: .o .cc 12 | 13 | cxx = g++ 14 | 15 | CFLAGS = -g -O -Wall $(INC_COMM_PATH) 16 | 17 | OI_OBJS = ZkClient.o ZkClientManager.o ZkTimerQueue.o 18 | 19 | OUTPUT := libzkcpp.a 20 | 21 | all:$(OUTPUT) 22 | 23 | .cc.o: 24 | $(CXX) $(CFLAGS) -c $^ -o ./$@ -DMUDUO_STD_STRING -DUSE_CALL_RECORDER -DTHREADED $(LIB_COMM) 25 | 26 | mvHead: 27 | cp -R -f $(HEADERS) $(INC_INSTALL_COMM_PATH)/ 28 | 29 | $(OUTPUT):$(OI_OBJS) 30 | ar -rs $@ $^ 31 | 32 | install: 33 | cp -R -f $(OUTPUT) $(LIB_INSTALL_COMM_PATH)/ 34 | 35 | clean: 36 | rm -f *.o *.a 37 | --------------------------------------------------------------------------------