├── CMakeLists.txt ├── CMakeLists2.txt ├── README.md └── muduo ├── base ├── Atomic.h ├── CMakeLists.txt ├── CString.h ├── ChronoTimestamp.cpp ├── ChronoTimestamp.h ├── Singleton.h ├── String.cpp ├── String.h ├── StringPiece.h ├── Thread.cpp ├── Thread.h ├── Types.h ├── copyable.h ├── gtest-all.cpp ├── gtest.h ├── noncopyable.h └── tests │ ├── Atomic_unittest.cpp │ ├── CMakeLists.txt │ ├── CString_test.cpp │ ├── ChronoTimestamp_test.cpp │ ├── ChronoTimestamp_test_benchmark.cpp │ ├── Mutex_test.cc │ ├── Singleton_test.cpp │ ├── String_test.cpp │ ├── Timestamp_unittest.cc │ └── thread_test.cpp ├── log ├── AsyncLogging.cpp ├── AsyncLogging.h ├── BlockingQueue.h ├── BoundedBlockingQueue.h ├── CMakeLists.txt ├── FileUtil.cpp ├── FileUtil.h ├── LogFile.cpp ├── LogFile.h ├── LogStream.cpp ├── LogStream.h ├── Logging.cpp ├── Logging.h ├── ProcessInfo.cpp ├── ProcessInfo.h ├── SimpeCircularBuffer.cpp └── tests │ ├── AsyncLogging_test.cpp │ ├── BlockingQueue_bench.cpp │ ├── BlockingQueue_test.cpp │ ├── BlockingQueue_test2.cpp │ ├── BoundedBlockingQueue_test.cpp │ ├── CMakeLists.txt │ ├── FileUtil_test.cpp │ ├── LogFile_test.cpp │ ├── LogStream_bench.cpp │ ├── LogStream_test.cpp │ ├── Logging_test.cpp │ └── ProcessInfo_test.cpp ├── net ├── Acceptor.cpp ├── Acceptor.h ├── CMakeLists.txt ├── Callbacks.cpp ├── Callbacks.h ├── Channel.cpp ├── Channel.h ├── Endian.h ├── EventLoop.cpp ├── EventLoop.h ├── GzipFile.h ├── How to implement multithread safe singleton in C++11 without using .txt ├── InetAddress.cpp ├── InetAddress.h ├── Poller.cpp ├── Poller.h ├── Sockets.cpp ├── Sockets.h ├── SocketsOps.cc ├── SocketsOps.h ├── inner class .cpp ├── move_vector_size.cpp ├── note-.txt ├── poller │ ├── CMakeLists.txt │ ├── DefaultPoller.cpp │ ├── PollPoller.cpp │ └── PollPoller.h ├── tests │ ├── CMakeLists.txt │ ├── EventLoop_test_simple0.cpp │ ├── EventLoop_test_simple1.cpp │ ├── EventLoop_test_simple2.cpp │ └── GzipFile_test.cpp └── tiny_boost_any.cpp └── timer ├── CMakeLists.txt ├── Timer.cpp ├── Timer.h ├── TimerId.h ├── TimerQueue.cpp ├── TimerQueue.h └── tests ├── CMakeLists.txt └── Timer_test.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(muduo_in_cpp14 C CXX ) 3 | 4 | set(CMAKE_BUILD_TYPE "Debug") 5 | #set(CMAKE_BUILD_TYPE "Release") 6 | #[[set(CMAKE_CXX_COMPILER "g++")]] 7 | set(CMAKE_C_COMPILER "/usr/bin/clang") 8 | set(CMAKE_CXX_COMPILER "clang++") 9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread ") 10 | 11 | enable_testing() 12 | include_directories ("${PROJECT_SOURCE_DIR}/") 13 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/) 14 | set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/) 15 | 16 | add_subdirectory(muduo/base) 17 | add_subdirectory(muduo/log) 18 | add_subdirectory(muduo/net) 19 | add_subdirectory(muduo/timer) 20 | include_directories(${PROJECT_SOURCE_DIR}) 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /CMakeLists2.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(tmuduo) 3 | 4 | set(CMAKE_BUILD_TYPE "Debug") 5 | 6 | ADD_DEFINITIONS(-DDMUDUO_LOG_TRACE) 7 | 8 | #[[ 9 | set(CMAKE_BUILD_TYPE "Release") 10 | set(CMAKE_CXX_COMPILER "g++") 11 | 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -o3 ")]] 13 | 14 | #set(CMAKE_CXX_COMPILER "g++") 15 | set(CMAKE_C_COMPILER "/usr/bin/clang") 16 | set(CMAKE_CXX_COMPILER "clang++") 17 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -o1 -pg")#gprof 18 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -g -libc++ -libc++abi") 19 | 20 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -g -stdlib=libc++ -lc++abi") 21 | 22 | 23 | 24 | 25 | add_executable(thread_test thread_test.cpp) 26 | 27 | add_executable(move_vector_size move_vector_size.cpp) 28 | 29 | 30 | 31 | 32 | add_executable(String String_test.cpp String.cpp gtest-all.cpp) 33 | add_executable(CString_test CString_test.cpp) 34 | 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 对C++高性能网络库muduo 的重构,使用c++11/14。 2 | 3 | [muduo简介](https://github.com/chenshuo/muduo) 4 | 5 | 本库与muduo的区别: 6 | 7 | 1),完全使用C++11/14 8 | 2),使用移动语义和完美转发等C++新特性提高程序性能。 9 | 3),使用C++ 内置的原子库\ 代替编译器特有的原子操作。 10 | 4),使用C++ 内置的多线程库\ 代替pthread族函数。 11 | 5),使用C++ 内置的时间库\ 代替旧的C语言式的time族函数。 12 | 6),去除boost依赖。完全使用C++开发。 13 | 7),更完备的test测试功能,几乎覆盖每一个.cpp文件。 14 | 15 | 16 | 开发尚未完成... -------------------------------------------------------------------------------- /muduo/base/Atomic.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TMUDUO_ATOMIC_H 3 | #define TMUDUO_ATOMIC_H 4 | 5 | #include 6 | #include 7 | 8 | /************************************************* 9 | c++11标准库提供了多种原子类操作。 10 | 使用std的原子整数操作和bool型操作。 11 | *************************************************/ 12 | namespace muduo 13 | { 14 | 15 | using AtomicInt32= std::atomic_int_fast32_t; 16 | using AtomicInt64= std::atomic_int_fast64_t; 17 | using Atomic_bool= std::atomic_bool; 18 | 19 | 20 | } 21 | 22 | #endif // TMUDUO_ATOMIC_H 23 | -------------------------------------------------------------------------------- /muduo/base/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(base_SRE 2 | ChronoTimestamp.cpp 3 | 4 | ) 5 | add_library(muduo_base ${base_SRE}) 6 | add_library(gtest gtest-all.cpp) 7 | target_link_libraries(muduo_base pthread) 8 | 9 | install(TARGETS muduo_base DESTINATION lib) 10 | 11 | file(GLOB HEADERS "*.h") 12 | install(FILES ${HEADERS} DESTINATION include/muduo/base) 13 | if(NOT CMAKE_BUILD_NO_EXAMPLES) 14 | add_subdirectory(tests) 15 | endif() -------------------------------------------------------------------------------- /muduo/base/CString.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TMUDUO_CSTRING_H 3 | #define TMUDUO_CSTRING_H 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | class CString 10 | { 11 | 12 | public: 13 | CString() : data_(new char[1]) 14 | { 15 | *data_ = '\0'; 16 | }; 17 | 18 | CString(const char *rhs) 19 | { 20 | data_ = new char[strlen(rhs) + 1];//why +1? 21 | strcpy(data_, rhs); 22 | } 23 | 24 | CString(const char *rhs, size_t len) 25 | { 26 | data_ = new char[len + 1]; 27 | strncpy(data_, rhs, len); 28 | } 29 | 30 | CString(const CString &rhs) 31 | { 32 | // delete[]data_; 33 | data_ = new char[rhs.len() + 1]; 34 | strcpy(data_, rhs.data_); 35 | } 36 | 37 | CString(CString &&rhs) 38 | { 39 | // swap(rhs.data_); 40 | data_ = rhs.data_; 41 | rhs.data_ = nullptr; 42 | } 43 | 44 | CString &operator=(const char *rhs) 45 | { 46 | delete[]data_; 47 | data_ = new char[strlen(rhs) + 1]; 48 | printf("==\n"); 49 | if (data_ == rhs) 50 | return *this; 51 | strcpy(data_, rhs); 52 | return *this; 53 | } 54 | 55 | /*有memory leak,用valgrind查了以后证明的确有,在复制一个String对象的时候, 56 | * 假如接收的String本身data_不为空,你的String(const char *str, std::size_t len)函数会直接把data_ 57 | * 指向了新allocate的memory而没有释放之前allocate的memory。*/ 58 | 59 | CString &operator=(CString rhs)//不用证同测试,why? 60 | { 61 | swap(rhs); 62 | // delete[]rhs.data_;// 63 | // rhs.data_ = nullptr; 64 | return *this; 65 | } 66 | 67 | CString &operator=(CString &&rhs) noexcept 68 | { 69 | // swap(data_,rhs.data_); 70 | data_ = rhs.data_; 71 | rhs.data_ = nullptr; 72 | return *this; 73 | } 74 | 75 | bool operator==(const char *rhs) const 76 | { 77 | return strcmp(data_, rhs) == 0; 78 | } 79 | 80 | bool operator==(CString &rhs) const 81 | { 82 | return strcmp(data_, rhs.data_) == 0; 83 | } 84 | 85 | char *c_str() //const 86 | { 87 | return data_; 88 | } 89 | 90 | const size_t len() const 91 | { 92 | return strlen(data_); 93 | } 94 | 95 | ~CString() noexcept 96 | { 97 | delete[] data_; 98 | } 99 | 100 | void swap(CString &rhs) noexcept 101 | { 102 | std::swap(data_, rhs.data_); 103 | } 104 | 105 | private: 106 | char *data_; 107 | }; 108 | 109 | #endif //TMUDUO_CSTRING_H 110 | 111 | //delegating constructor 委托构造函数 -------------------------------------------------------------------------------- /muduo/base/ChronoTimestamp.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace muduo; 8 | //static_assert(sizeof(ChronoTimestamp) == sizeof(int64_t), "ChronoTimestamp == int64_t "); 9 | 10 | 11 | 12 | string ChronoTimestamp::toString() const 13 | { 14 | char buf[32] = {0}; 15 | 16 | int64_t us=microSecondsSinceEpoch_.count(); 17 | int64_t seconds = us / kMicroSecondsPerSecond; 18 | int64_t microseconds = us % kMicroSecondsPerSecond; 19 | snprintf(buf, sizeof(buf) - 1, "%ld.%06ld", seconds, microseconds); 20 | return buf; 21 | } 22 | 23 | string ChronoTimestamp::toFormattedString(bool showMicroseconds) const 24 | { 25 | char buf[32]={0}; 26 | time_t seconds = static_cast(microSecondsSinceEpoch_.count()/kMicroSecondsPerSecond); 27 | struct tm tm_time; 28 | gmtime_r(&seconds, &tm_time); 29 | 30 | if (showMicroseconds) 31 | { 32 | int microseconds = static_cast(microSecondsSinceEpoch_.count() % kMicroSecondsPerSecond); 33 | snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d", 34 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 35 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, 36 | microseconds); 37 | } 38 | else 39 | { 40 | snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d", 41 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 42 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); 43 | } 44 | return buf; 45 | } 46 | -------------------------------------------------------------------------------- /muduo/base/ChronoTimestamp.h: -------------------------------------------------------------------------------- 1 | #ifndef TMUDUO_CHRONOTIMESTAMP_H 2 | #define TMUDUO_CHRONOTIMESTAMP_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace muduo 9 | { 10 | 11 | class ChronoTimestamp : public muduo::copyable 12 | { 13 | public: 14 | ChronoTimestamp() : microSecondsSinceEpoch_(0) 15 | { 16 | } 17 | 18 | explicit ChronoTimestamp(std::chrono::microseconds us) 19 | { 20 | microSecondsSinceEpoch_ = us; 21 | } 22 | 23 | bool valid() const 24 | { return microSecondsSinceEpoch_ > std::chrono::microseconds(0); } 25 | 26 | void swap(ChronoTimestamp &that) 27 | { 28 | std::swap(microSecondsSinceEpoch_,that.microSecondsSinceEpoch_); 29 | } 30 | 31 | 32 | std::string toString() const; 33 | 34 | std::string toFormattedString(bool showMicroseconds=true) const; 35 | 36 | std::chrono::microseconds microSecondsSinceEpoch() 37 | { 38 | return microSecondsSinceEpoch_; 39 | } 40 | static ChronoTimestamp now() 41 | { 42 | std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); 43 | //auto us = std::chrono::duration_cast(now.time_since_epoch()).count();//微秒数,int64_t 44 | std::chrono::microseconds nowin_us=std::chrono::duration_cast(now.time_since_epoch()); 45 | return ChronoTimestamp(nowin_us); 46 | }; 47 | 48 | 49 | static ChronoTimestamp invalid() 50 | { 51 | return ChronoTimestamp(); 52 | } 53 | 54 | static const int kMicroSecondsPerSecond = 1000 * 1000; 55 | private: 56 | std::chrono::microseconds microSecondsSinceEpoch_; 57 | }; 58 | 59 | 60 | 61 | inline bool operator<(ChronoTimestamp lhs,ChronoTimestamp rhs) 62 | { 63 | return lhs.microSecondsSinceEpoch().count()(diff)/ChronoTimestamp::kMicroSecondsPerSecond; 76 | } 77 | inline ChronoTimestamp addTime(ChronoTimestamp timestamp, double seconds) 78 | { 79 | int64_t delta= static_cast(seconds*ChronoTimestamp::kMicroSecondsPerSecond); 80 | return ChronoTimestamp(std::chrono::microseconds((timestamp.microSecondsSinceEpoch().count()+delta))); 81 | } 82 | } 83 | 84 | 85 | #endif //TMUDUO_CHRONOTIMESTAMP_H 86 | //成员变量microSecondsSinceEpoch_表示到1970-01-01 00:00:00 UTC的微秒数。 -------------------------------------------------------------------------------- /muduo/base/Singleton.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TMUDUO_SINGLETON_H 3 | #define TMUDUO_SINGLETON_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace muduo 11 | { 12 | namespace detail 13 | { 14 | template 15 | struct has_no_destory 16 | { 17 | template 18 | static char test(decltype(&C::no_destory())); 19 | 20 | template 21 | static int64_t test(...); 22 | 23 | const static bool value = sizeof(test(0)) == 1; 24 | }; 25 | std::mutex mu; 26 | } 27 | 28 | 29 | template 30 | std::once_flag flag; 31 | 32 | 33 | template 34 | class Signleton : noncopyable 35 | { 36 | public: 37 | static T &instance() 38 | { 39 | // std::call_once(flag, &Signleton::init); 40 | 41 | if(value_== nullptr) 42 | init(); 43 | assert(value_ != nullptr); 44 | return *value_; 45 | } 46 | 47 | 48 | private: 49 | //static std::once_flag flag; 50 | static T *value_; 51 | //static initializations are thread safe now in C++11 52 | //C++11 made it so static initialization is thread-safe, so a lot of the more complicated recipes aren't needed. 53 | 54 | static void init() 55 | { 56 | 57 | std::lock_guard< std::mutex> lock(detail::mu); 58 | if (value_ != nullptr) 59 | return; 60 | value_ = new T(); 61 | if (!detail::has_no_destory::value) 62 | ::atexit(destroy); 63 | } 64 | 65 | static void destroy() 66 | { 67 | typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; 68 | T_must_be_complete_type dummy; 69 | (void) dummy; 70 | delete value_; 71 | value_ = nullptr; 72 | } 73 | 74 | private: 75 | Signleton(); 76 | 77 | ~Signleton(); 78 | }; 79 | 80 | template 81 | T *Signleton::value_ = nullptr; 82 | 83 | 84 | }; 85 | 86 | 87 | #endif //TMUDUO_SINGLETON_H 88 | -------------------------------------------------------------------------------- /muduo/base/String.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include "String.h" 5 | 6 | using namespace std; 7 | 8 | String::String() : 9 | len_(0), str_ptr_(make_unique>()) 10 | { 11 | } 12 | 13 | String::String(const char *chars) : String() 14 | { 15 | str_ptr_->clear(); 16 | for (int i = 0; (chars + i) != nullptr && *(chars + i) != '\0'; ++i) 17 | { 18 | 19 | str_ptr_->push_back(*(chars + i)); 20 | } 21 | } 22 | 23 | String::String(const char *chars, size_t len) : String() 24 | { 25 | str_ptr_->clear(); 26 | for (int i = 0; i < len; ++i) 27 | { 28 | str_ptr_->push_back(*(chars + i)); 29 | } 30 | } 31 | 32 | String::String(String &rhs) : String() 33 | { 34 | str_ptr_->clear();/* 35 | for (auto it = rhs.str_ptr_->begin(); it != rhs.str_ptr_->end(); ++it) 36 | str_ptr_->push_back(*it);*/ 37 | (*str_ptr_)=(*rhs.str_ptr_); 38 | } 39 | 40 | String::String(String &&rhs) : String() 41 | { 42 | 43 | str_ptr_ = std::move(rhs.str_ptr_); 44 | rhs.str_ptr_= nullptr; 45 | } 46 | 47 | String &String::operator=(String &rhs) 48 | { 49 | str_ptr_->clear();/* 50 | for (auto it = rhs.str_ptr_->begin(); it != rhs.str_ptr_->end(); ++it) 51 | str_ptr_->push_back(*it);*/ 52 | (*str_ptr_) = (*rhs.str_ptr_); 53 | return *this; 54 | } 55 | 56 | String &String::operator=(String &&rhs) 57 | { 58 | // swap(str_ptr_,rhs.str_ptr_); 59 | str_ptr_ = std::move(rhs.str_ptr_); 60 | rhs.str_ptr_= nullptr; 61 | return *this; 62 | } 63 | 64 | String &String::operator=(const char *chars) 65 | { 66 | str_ptr_->clear(); 67 | for (int i = 0; (chars+i)!= nullptr && *(chars+i)!='\0'; ++i) 68 | { 69 | str_ptr_->push_back(*(chars+i)); 70 | } 71 | return *this; 72 | } 73 | 74 | bool String::operator==(const char *chars) const 75 | { 76 | for (int i = 0; i < str_ptr_->size(); ++i) 77 | { 78 | if (*(chars + i) != (*str_ptr_)[i]) 79 | return false; 80 | } 81 | return true; 82 | } 83 | 84 | bool String::operator==(const String &rhs) const 85 | { 86 | return (*str_ptr_) == (*rhs.str_ptr_); 87 | } 88 | 89 | String::~String() 90 | { 91 | 92 | } -------------------------------------------------------------------------------- /muduo/base/String.h: -------------------------------------------------------------------------------- 1 | 2 | //http://coolshell.cn/articles/10478.html 3 | 4 | #ifndef TMUDUO_STRING_H 5 | #define TMUDUO_STRING_H 6 | 7 | #include 8 | #include 9 | 10 | class String 11 | { 12 | public: 13 | String(); 14 | 15 | String( const char * chars); 16 | 17 | 18 | String(const char * chars, size_t len); 19 | String(String &rhs); 20 | 21 | String(String &&rhs); 22 | 23 | String &operator=(String& rhs); 24 | String&operator=(String&& rhs); 25 | String&operator=(const char* chars); 26 | bool operator==(const char * chars) const; 27 | bool operator==(const String & rhs) const; 28 | 29 | char * c_str() 30 | { 31 | return &(*str_ptr_)[0]; 32 | } 33 | ~String(); 34 | 35 | private: 36 | size_t len_ = 0; 37 | std::unique_ptr > str_ptr_= nullptr; 38 | 39 | }; 40 | 41 | #endif //TMUDUO_STRING_H 42 | -------------------------------------------------------------------------------- /muduo/base/StringPiece.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_STRINGPIECE_H 4 | #define TMUDUO_STRINGPIECE_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace muduo 12 | { 13 | class StringArg 14 | { 15 | public: 16 | StringArg(const char *str) : str_(str) 17 | {} 18 | 19 | StringArg(const string &str) : str_(str.c_str()) 20 | {} 21 | 22 | const char *c_str() const 23 | { 24 | return str_; 25 | } 26 | 27 | private: 28 | const char *str_; 29 | }; 30 | 31 | class StringPiece 32 | { 33 | 34 | public: 35 | StringPiece() : ptr_(nullptr), length_(0) 36 | {} 37 | 38 | StringPiece(const char *str) : ptr_(str), length_(static_cast(strlen(ptr_))) 39 | {} 40 | 41 | StringPiece(const unsigned char *str) : 42 | ptr_(reinterpret_cast(str)), 43 | length_(static_cast(strlen(ptr_))) 44 | {} 45 | 46 | StringPiece(const string &str) : 47 | ptr_(str.data()), length_(static_cast(str.size())) 48 | {} 49 | 50 | StringPiece(const char *offset, int len) : ptr_(offset), length_(len) 51 | {} 52 | 53 | const char *data() const 54 | { return ptr_; } 55 | 56 | int size() const 57 | { return length_; } 58 | 59 | bool empty() 60 | { return length_ == 0; } 61 | 62 | const char *const begin() 63 | { return ptr_; } 64 | 65 | const char *const end() 66 | { return ptr_ + length_; } 67 | 68 | void clear() 69 | { 70 | ptr_ = nullptr; 71 | length_ = 0; 72 | } 73 | 74 | void set(const char *buffer, int len) 75 | { 76 | ptr_ = buffer; 77 | length_ = len; 78 | } 79 | 80 | void set(const void *buffer, int len) 81 | { 82 | ptr_ = reinterpret_cast(buffer); 83 | length_ = len; 84 | } 85 | 86 | char operator[](int i) const 87 | { return ptr_[i]; } 88 | 89 | void remove_prefix(int n) 90 | { 91 | ptr_ += n; 92 | length_ -= n; 93 | } 94 | 95 | void remove_suffix(int n) 96 | { 97 | length_ -= n; 98 | } 99 | 100 | bool operator==(const StringPiece &x) const 101 | { 102 | return ((length_ == x.length_) && memcmp(ptr_, x.ptr_, length_)); 103 | } 104 | 105 | bool operator!=(const StringPiece &x) const 106 | { return !(*this == x); } 107 | 108 | 109 | #define STRINGPIECE_BINARY_PREDICATE(cmp, auxcmp) \ 110 | bool operator cmp (const StringPiece& x)const{ \ 111 | int r=memcmp(ptr_,x.ptr_,length_=, >); 121 | 122 | STRINGPIECE_BINARY_PREDICATE(>, >); 123 | #undef STRINGPIECE_BINARY_PREDICATE 124 | 125 | int compare(const StringPiece &x) const 126 | { 127 | int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); 128 | if (r == 0) 129 | { 130 | if (length_ < x.length_) 131 | r = -1; 132 | else if (length_ > x.length_) 133 | r = +1; 134 | } 135 | return r; 136 | } 137 | 138 | string as_string() const 139 | { 140 | return string(data(),size()); 141 | } 142 | 143 | void CopyToString(string* target)const 144 | { 145 | target->assign(ptr_,length_); 146 | } 147 | 148 | bool starts_with(const StringPiece& x)const 149 | { 150 | return ((length_>=x.length_)&&(memcmp(ptr_,x.ptr_,x.length_)==0)); 151 | } 152 | 153 | private: 154 | const char *ptr_; 155 | int length_; 156 | 157 | }; 158 | } 159 | 160 | std::ostream& operator<<(std::ostream& o,const muduo::StringPiece& piece); 161 | 162 | #endif //TMUDUO_STRINGPIECE_H 163 | -------------------------------------------------------------------------------- /muduo/base/Thread.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | namespace muduo 5 | { 6 | namespace CurrentThread 7 | { 8 | thread_local int t_cachedTid = 0; 9 | thread_local char t_tidString[32]; 10 | thread_local const char *t_threadName = "unknown"; 11 | static_assert(std::is_same::value, "pid_t should be int"); 12 | } 13 | 14 | namespace detail 15 | { 16 | pid_t gettid() 17 | { return static_cast(::syscall(SYS_gettid)); } 18 | 19 | void afterFork() 20 | { 21 | CurrentThread::t_cachedTid = 0; 22 | CurrentThread::t_threadName = "main"; 23 | CurrentThread::tid(); 24 | } 25 | 26 | class ThreadNameInitializer 27 | { 28 | public: 29 | ThreadNameInitializer() 30 | { 31 | CurrentThread::t_threadName = "main"; 32 | CurrentThread::tid(); 33 | pthread_atfork(NULL, NULL, &afterFork); 34 | } 35 | }; 36 | 37 | ThreadNameInitializer init; 38 | 39 | class ThreadData 40 | { 41 | typedef muduo::Thread::Threadfunc ThreadFunc; 42 | ThreadFunc func_; 43 | std::string name_; 44 | std::weak_ptr wkTid_; 45 | 46 | ThreadData(const ThreadFunc &func, 47 | const std::string &name, 48 | const std::shared_ptr &tid) 49 | : func_(func), 50 | name_(name), 51 | wkTid_(tid) 52 | {} 53 | 54 | 55 | }; 56 | } 57 | 58 | AtomicInt32 Thread::numCreated_; 59 | Thread::Thread(const Threadfunc &, const std::string &name) 60 | { 61 | 62 | } 63 | } -------------------------------------------------------------------------------- /muduo/base/Thread.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_THREAD_H 4 | #define TMUDUO_THREAD_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | namespace muduo 13 | { 14 | class Thread:noncopyable 15 | { 16 | public: 17 | typedef std::functionThreadfunc; 18 | explicit Thread(const Threadfunc& ,const std::string& name=std::string()); 19 | explicit Thread(Threadfunc&& ,const std::string& name=std::string()); 20 | ~Thread(); 21 | 22 | static int numCreated(){return numCreated_;} 23 | private: 24 | void setDefaultName(); 25 | bool joined_; 26 | bool started; 27 | std::string name_; 28 | static AtomicInt32 numCreated_; 29 | 30 | }; 31 | } 32 | #endif //TMUDUO_THREAD_H 33 | -------------------------------------------------------------------------------- /muduo/base/Types.h: -------------------------------------------------------------------------------- 1 | #ifndef TMUDUO_TYPES_H 2 | #define TMUDUO_TYPES_H 3 | #include 4 | #include 5 | 6 | #ifndef NDEBUG 7 | #include 8 | #endif 9 | 10 | #include 11 | 12 | 13 | namespace muduo 14 | { 15 | 16 | using std::string; 17 | 18 | 19 | // 20 | // Use implicit_cast as a safe version of static_cast or const_cast 21 | // for upcasting in the type hierarchy (i.e. casting a pointer to Foo 22 | // to a pointer to SuperclassOfFoo or casting a pointer to Foo to 23 | // a const pointer to Foo). 24 | // When you use implicit_cast, the compiler checks that the cast is safe. 25 | // Such explicit implicit_casts are necessary in surprisingly many 26 | // situations where C++ demands an exact type match instead of an 27 | // argument type convertable to a target type. 28 | // 29 | // The From type can be inferred, so the preferred syntax for using 30 | // implicit_cast is the same as for static_cast etc.: 31 | // 32 | // implicit_cast(expr) 33 | // 34 | // implicit_cast would have been part of the C++ standard library, 35 | // but the proposal was submitted too late. It will probably make 36 | // its way into the language in the future. 37 | template 38 | inline To implicit_cast(From const &f) 39 | { 40 | return f; 41 | } 42 | 43 | // When you upcast (that is, cast a pointer from type Foo to type 44 | // SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts 45 | // always succeed. When you downcast (that is, cast a pointer from 46 | // type Foo to type SubclassOfFoo), static_cast<> isn't safe, because 47 | // how do you know the pointer is really of type SubclassOfFoo? It 48 | // could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, 49 | // when you downcast, you should use this macro. In debug mode, we 50 | // use dynamic_cast<> to double-check the downcast is legal (we die 51 | // if it's not). In normal mode, we do the efficient static_cast<> 52 | // instead. Thus, it's important to test in debug mode to make sure 53 | // the cast is legal! 54 | // This is the only place in the code we should use dynamic_cast<>. 55 | // In particular, you SHOULDN'T be using dynamic_cast<> in order to 56 | // do RTTI (eg code like this: 57 | // if (dynamic_cast(foo)) HandleASubclass1Object(foo); 58 | // if (dynamic_cast(foo)) HandleASubclass2Object(foo); 59 | // You should design the code some other way not to need this. 60 | 61 | template // use like this: down_cast(foo); 62 | inline To down_cast(From* f) // so we only accept pointers 63 | { 64 | // Ensures that To is a sub-type of From *. This test is here only 65 | // for compile-time type checking, and has no overhead in an 66 | // optimized build at run-time, as it will be optimized away 67 | // completely. 68 | if (false) 69 | { 70 | implicit_cast(0); 71 | } 72 | 73 | #if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) 74 | assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! 75 | #endif 76 | return static_cast(f); 77 | } 78 | 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /muduo/base/copyable.h: -------------------------------------------------------------------------------- 1 | #ifndef TMUDUO_COPYABLE_H 2 | #define TMUDUO_COPYABLE_H 3 | 4 | namespace muduo 5 | { 6 | 7 | 8 | class copyable 9 | { 10 | protected: 11 | copyable() = default; 12 | ~copyable() = default; 13 | }; 14 | 15 | }; 16 | 17 | #endif // TMUDUO_COPYABLE_H 18 | -------------------------------------------------------------------------------- /muduo/base/noncopyable.h: -------------------------------------------------------------------------------- 1 | #ifndef TMUDUO_NONCOPYABLE_H 2 | #define TMUDUO_NONCOPYABLE_H 3 | 4 | namespace muduo 5 | { 6 | 7 | class noncopyable 8 | { 9 | protected: 10 | noncopyable() = default; 11 | ~noncopyable() = default; 12 | 13 | private: 14 | noncopyable(const noncopyable&) = delete; 15 | void operator=(const noncopyable&) = delete; 16 | }; 17 | 18 | } 19 | 20 | #endif // TMUDUO_NONCOPYABLE_H 21 | -------------------------------------------------------------------------------- /muduo/base/tests/Atomic_unittest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int knum = 1000000; 8 | int kthread = 100; 9 | 10 | 11 | void addnum(muduo::AtomicInt64 &a, int &b) {//noncopyable 12 | for (int i = 0; i < knum; ++i) { 13 | ++a; 14 | std::this_thread::yield(); 15 | ++b; 16 | } 17 | std::cout << "thread_id " << std::this_thread::get_id() << " done\n"; 18 | } 19 | 20 | 21 | 22 | int main() { 23 | 24 | muduo::AtomicInt64 a(0); 25 | int b = 0; 26 | assert(a.load() == 0); 27 | assert(a.fetch_add(1) == 0); 28 | assert(a.load() == 1); 29 | a.fetch_sub(1); 30 | 31 | 32 | std::vector threads; 33 | 34 | for (int i = 0; i < kthread; ++i) { 35 | threads.push_back(std::thread(addnum, std::ref(a), std::ref(b))); 36 | } 37 | 38 | for (auto &it :threads) 39 | it.join(); 40 | 41 | assert(a == knum * kthread); 42 | assert(b != knum * kthread); 43 | std::cout << __FILE__ << " , " << __LINE__ << (": test ok : a=") << a << ",b=" << b << std::endl; 44 | 45 | } 46 | 47 | //clang++ Atomic_unittest.cc -std=c++11 -I../../../ -pthread 48 | -------------------------------------------------------------------------------- /muduo/base/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(Atomic_unittest Atomic_unittest.cpp) 2 | target_link_libraries(Atomic_unittest muduo_base) 3 | 4 | #add_executable(ChronoTimestamp_test ChronoTimestamp_test.cpp ChronoTimestamp.cpp) 5 | #add_test(NAME Atomic_unittest COMMAND Atomic_unittest) 6 | 7 | add_executable(ChronoTimestamp_test ChronoTimestamp_test.cpp ) 8 | target_link_libraries(ChronoTimestamp_test muduo_base) 9 | 10 | add_executable(ChronoTimestamp_test_benchmark ChronoTimestamp_test_benchmark.cpp ) 11 | target_link_libraries(ChronoTimestamp_test_benchmark muduo_base) 12 | 13 | add_executable(Singleton_test Singleton_test.cpp) 14 | target_link_libraries(Singleton_test muduo_base) 15 | 16 | -------------------------------------------------------------------------------- /muduo/base/tests/CString_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | /*int main() 8 | { 9 | CString s1; 10 | s1=std::move("123"); 11 | return 0; 12 | }*/ 13 | //#define CString std::string 14 | 15 | void foo(CString x) 16 | { 17 | } 18 | 19 | void bar(const CString& x) 20 | { 21 | } 22 | 23 | CString baz() 24 | { 25 | CString ret("world"); 26 | return ret; 27 | } 28 | 29 | int main() 30 | { 31 | CString s0; 32 | CString s1("hello"); 33 | CString s2(s0); 34 | CString s3 = s1; 35 | s2 = s1; 36 | 37 | foo(s1); 38 | bar(s1); 39 | foo("temporary"); 40 | bar("temporary"); 41 | CString s4 = baz(); 42 | 43 | std::vector svec; 44 | svec.push_back(s0); 45 | svec.push_back(s1); 46 | svec.push_back(baz()); 47 | svec.push_back("good job"); 48 | } -------------------------------------------------------------------------------- /muduo/base/tests/ChronoTimestamp_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace muduo; 7 | using namespace std; 8 | void passByConstReference(const ChronoTimestamp& x) 9 | { 10 | printf("%s\n", x.toString().c_str()); 11 | } 12 | 13 | void passByValue(ChronoTimestamp x) 14 | { 15 | printf("%s\n", x.toString().c_str()); 16 | } 17 | 18 | 19 | void benchmark() 20 | { 21 | const int kNumber = 1000*1000; 22 | 23 | std::vector stamps; 24 | stamps.reserve(kNumber); 25 | for (int i = 0; i < kNumber; ++i) 26 | { 27 | stamps.push_back(ChronoTimestamp::now()); 28 | } 29 | printf("%s\n", stamps.front().toString().c_str()); 30 | printf("%s\n", stamps.back().toString().c_str()); 31 | printf("%f\n", timeDifference(stamps.back(), stamps.front())); 32 | 33 | int increments[100] = { 0 }; 34 | int64_t start = stamps.front().microSecondsSinceEpoch().count(); 35 | for (int i = 1; i < kNumber; ++i) 36 | { 37 | int64_t next = stamps[i].microSecondsSinceEpoch().count(); 38 | int64_t inc = next - start; 39 | start = next; 40 | if (inc < 0) 41 | { 42 | printf("reverse!\n"); 43 | } 44 | else if (inc < 100) 45 | { 46 | ++increments[inc]; 47 | } 48 | else 49 | { 50 | printf("big gap %d\n", static_cast(inc)); 51 | } 52 | } 53 | 54 | for (int i = 0; i < 100; ++i) 55 | { 56 | printf("%2d: %d\n", i, increments[i]); 57 | } 58 | } 59 | int main() 60 | { 61 | ChronoTimestamp t; 62 | t=t.now(); 63 | cout< 4 | #include 5 | 6 | using namespace muduo; 7 | using namespace std; 8 | 9 | const int kNumber = 1000 * 1000 * 100;//*5 10 | 11 | void benchmark() 12 | { 13 | for (int i = 1; i < kNumber; ++i) 14 | { 15 | ChronoTimestamp t; 16 | t = t.now(); 17 | t.toFormattedString(); 18 | } 19 | 20 | } 21 | 22 | int main() 23 | { 24 | ChronoTimestamp t; 25 | t = t.now(); 26 | cout << t.toFormattedString() << endl; 27 | 28 | benchmark(); 29 | ChronoTimestamp t2 = t.now(); 30 | cout << t2.toFormattedString() << endl; 31 | cout << kNumber<<" total use " << timeDifference(t2, t) << " s \n"; 32 | return 0; 33 | } 34 | 35 | /* 36 | kNumber=5M 37 | 38 | 20170527 15:22:27.477461 39 | 20170527 15:22:29.719607 40 | 5000000 total use 2.24215 s 41 | */ 42 | 43 | /* 44 | kNumber=100M 45 | 46 | ChronoTimestamp 47 | 20170526 14:56:30.711533 48 | 20170526 14:57:14.411524 49 | 100000000 total use 43.7 s 50 | 51 | 52 | Timestamp 53 | 20170526 14:55:27.177002 54 | 20170526 14:56:10.686032 55 | 100000000 total use 43.509 s 56 | */ -------------------------------------------------------------------------------- /muduo/base/tests/Mutex_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace muduo; 9 | using namespace std; 10 | using namespace std; 11 | std::mutex g_mutex; 12 | vector g_vec; 13 | const int kCount = 10 * 1000 * 1000;//10M 14 | 15 | void threadFunc() { 16 | for (int i = 0; i < kCount; ++i) { 17 | lock_guard< mutex> lock(g_mutex); 18 | g_vec.push_back(i); 19 | } 20 | } 21 | 22 | int foo() __attribute__ ((noinline));///fun函数不能作为inline函数优化 23 | 24 | int g_count = 0; 25 | 26 | int foo() { 27 | lock_guard< mutex> lock(g_mutex); 28 | 29 | 30 | ++g_count; 31 | return 0; 32 | } 33 | 34 | int main() { 35 | foo(); 36 | if (g_count != 1) { 37 | printf("MCHECK calls twice.\n"); 38 | abort(); 39 | } 40 | 41 | const int kMaxThreads = 8; 42 | g_vec.reserve(kMaxThreads * kCount); 43 | 44 | ChronoTimestamp start(ChronoTimestamp::now()); 45 | for (int i = 0; i < kCount; ++i) { 46 | g_vec.push_back(i); 47 | } 48 | 49 | printf("single thread without lock %f\n", timeDifference(ChronoTimestamp::now(), start)); 50 | 51 | start = ChronoTimestamp::now(); 52 | printf(" now -start= %f\n", timeDifference(ChronoTimestamp::now(), start)); 53 | 54 | threadFunc(); 55 | printf("single thread with lock %f\n", timeDifference(ChronoTimestamp::now(), start)); 56 | 57 | for (int nthreads = 1; nthreads < kMaxThreads; ++nthreads) { 58 | std::vector> threads; 59 | g_vec.clear(); 60 | start = ChronoTimestamp::now(); 61 | for (int i = 0; i < nthreads; ++i) { 62 | threads.emplace_back(new thread(&threadFunc)); 63 | //threads.back()->start(); 64 | } 65 | for (int i = 0; i < nthreads; ++i) { 66 | threads[i]->join(); 67 | } 68 | printf("%d thread(s) with lock %f\n", nthreads, timeDifference(ChronoTimestamp::now(), start)); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /muduo/base/tests/Singleton_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class Test : muduo::noncopyable 12 | { 13 | public: 14 | Test() 15 | { 16 | printf("tid=%zu, Test() %p \n", std::hash()(std::this_thread::get_id()), this); 17 | } 18 | 19 | ~Test() 20 | { 21 | printf("tid=%zu,~Test()%p %s \n", std::hash()(std::this_thread::get_id()), this, name_.c_str()); 22 | } 23 | 24 | const std::string &name()const {return name_;} 25 | 26 | void setname(const std::string& n){name_=n;} 27 | 28 | private: 29 | std::string name_; 30 | }; 31 | 32 | class TestNoDestroy:muduo::noncopyable 33 | { 34 | public: 35 | void no_destroy(); 36 | 37 | TestNoDestroy() 38 | { 39 | printf("tid=%zu ,constructing TestNoDestroy() %p \n", std::hash()(std::this_thread::get_id()),this); 40 | } 41 | 42 | ~TestNoDestroy() 43 | { 44 | printf("tid=%zu, destructing ~TestNoDestroy() %p \n", std::hash()(std::this_thread::get_id()),this); 45 | } 46 | 47 | }; 48 | 49 | void threadFunc(int i) 50 | { 51 | std::mutex mu; 52 | std::lock_guard< std::mutex> lock(mu); 53 | printf("tid=%zu ,%p ,name=%s\n", 54 | std::hash()(std::this_thread::get_id()), 55 | &muduo::Signleton::instance(), 56 | muduo::Signleton::instance().name().c_str()); 57 | 58 | std::this_thread::yield(); 59 | std::string s=std::to_string(i); 60 | muduo::Signleton::instance().setname(s); 61 | 62 | } 63 | int main() 64 | { 65 | muduo::Signleton::instance().setname("only one -1"); 66 | 67 | printf("tid=%zu ,%p name=%s \n", 68 | std::hash()(std::this_thread::get_id()), 69 | &muduo::Signleton::instance(), 70 | muduo::Signleton::instance().name().c_str()); 71 | 72 | std::vector> vthreads; 73 | for (int i = 0; i < 100; ++i) 74 | { 75 | vthreads.emplace_back(new std::thread(threadFunc,i)); 76 | } 77 | 78 | for(auto & t:vthreads) 79 | t->join(); 80 | 81 | printf("\n\n"); 82 | 83 | 84 | printf("tid=%zu ,%p name=%s ----\n", 85 | std::hash()(std::this_thread::get_id()), 86 | &muduo::Signleton::instance(), 87 | muduo::Signleton::instance().name().c_str()); 88 | 89 | 90 | 91 | printf("with valgrind: %zd-byte memory leak .\n",sizeof(TestNoDestroy)); 92 | muduo::Signleton::instance(); 93 | 94 | 95 | } -------------------------------------------------------------------------------- /muduo/base/tests/String_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | 10 | #include "gtest.h" 11 | 12 | GTEST_API_ int main(int argc, char **argv) 13 | { 14 | std::cout << "Running main() from gtest_main.cc\n"; 15 | 16 | testing::InitGoogleTest(&argc, argv); 17 | 18 | String s("123"); 19 | 20 | // printf("%s--\n",s.c_str()); 21 | // cout << (s == "123") << endl; 22 | 23 | return RUN_ALL_TESTS(); 24 | } 25 | 26 | 27 | TEST(String_test, chars) 28 | { 29 | String s("123"); 30 | EXPECT_EQ(s, "123"); 31 | String s2(s); 32 | EXPECT_EQ(s, s2); 33 | EXPECT_EQ(s2, "123"); 34 | s2 = "321"; 35 | EXPECT_EQ(s2, "321"); 36 | String s3 = "321"; 37 | EXPECT_EQ(s3, s2); 38 | 39 | s3 = "123"; 40 | String s4 = "321"; 41 | swap(s3, s4); 42 | EXPECT_EQ(s3, "321"); 43 | EXPECT_EQ(s4, "123"); 44 | } -------------------------------------------------------------------------------- /muduo/base/tests/Timestamp_unittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using muduo::Timestamp; 6 | 7 | void passByConstReference(const Timestamp& x) 8 | { 9 | printf("%s\n", x.toString().c_str()); 10 | } 11 | 12 | void passByValue(Timestamp x) 13 | { 14 | printf("%s\n", x.toString().c_str()); 15 | } 16 | 17 | void benchmark() 18 | { 19 | const int kNumber = 1000*1000; 20 | 21 | std::vector stamps; 22 | stamps.reserve(kNumber); 23 | for (int i = 0; i < kNumber; ++i) 24 | { 25 | stamps.push_back(Timestamp::now()); 26 | } 27 | printf("%s\n", stamps.front().toString().c_str()); 28 | printf("%s\n", stamps.back().toString().c_str()); 29 | printf("%f\n", timeDifference(stamps.back(), stamps.front())); 30 | 31 | int increments[100] = { 0 }; 32 | int64_t start = stamps.front().microSecondsSinceEpoch(); 33 | for (int i = 1; i < kNumber; ++i) 34 | { 35 | int64_t next = stamps[i].microSecondsSinceEpoch(); 36 | int64_t inc = next - start; 37 | start = next; 38 | if (inc < 0) 39 | { 40 | printf("reverse!\n"); 41 | } 42 | else if (inc < 100) 43 | { 44 | ++increments[inc]; 45 | } 46 | else 47 | { 48 | printf("big gap %d\n", static_cast(inc)); 49 | } 50 | } 51 | 52 | for (int i = 0; i < 100; ++i) 53 | { 54 | printf("%2d: %d\n", i, increments[i]); 55 | } 56 | } 57 | 58 | int main() 59 | { 60 | Timestamp now(Timestamp::now()); 61 | printf("%s\n", now.toString().c_str()); 62 | passByValue(now); 63 | passByConstReference(now); 64 | benchmark(); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /muduo/base/tests/thread_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | void mysleep(int seconds) 11 | { 12 | timespec t = {seconds, 0}; 13 | nanosleep(&t, NULL); 14 | } 15 | 16 | void threadFunc() 17 | { 18 | std::cout << "tid=" << std::this_thread::get_id() << endl; 19 | } 20 | 21 | void threadFunc2(int x) 22 | { 23 | std::cout << "tid= " << std::this_thread::get_id() << " ,x=" << x << endl; 24 | } 25 | int i=0; 26 | void threadFunc3() 27 | { 28 | std::cout << "tid=" << std::this_thread::get_id()<<" i="<> vthreads; 76 | 77 | 78 | for (int j = 0; j < 10; ++j) 79 | { 80 | vthreads.emplace_back(new thread(threadFunc3)); 81 | 82 | } 83 | 84 | sleep(1); 85 | t1.join(); 86 | t2.join(); 87 | t3.join(); 88 | t4.join(); 89 | 90 | for(auto & it:vthreads) 91 | it->join(); 92 | cout << "done all\n"; 93 | } -------------------------------------------------------------------------------- /muduo/log/AsyncLogging.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace muduo; 10 | using namespace std; 11 | 12 | AsyncLogging::AsyncLogging(const std::string &basename, size_t rollSize, int flushInterval) 13 | : flushInterval_(flushInterval), 14 | running_(false), 15 | basename_(basename), 16 | rollSize_(rollSize), 17 | currentBuffer_(new Buffer), 18 | nextBuffer_(new Buffer) 19 | { 20 | 21 | currentBuffer_->bzero(); 22 | nextBuffer_->bzero(); 23 | buffers_.reserve(16); 24 | } 25 | 26 | /************************************************* 27 | 发送方(前端)将日志追加到(后端)中;使用多个缓冲区避免磁盘IO阻塞.前端生成一个日志时,调用appen(), 28 | 如果当前缓冲剩余空间足够大,则直接写入.不唤醒后端线程 29 | 否则先将已满缓冲移入后端,再交换当前缓冲与预备缓冲.并唤醒后端线程写入磁盘. 30 | 31 | 当前端写入太快,导致2块缓冲已经用完时,则分配一块新的缓冲作为当前缓冲. 32 | *************************************************/ 33 | void AsyncLogging::append(const char *logline, int len) 34 | { 35 | std::lock_guard g(mutex_); 36 | if (currentBuffer_->avail() > len) 37 | currentBuffer_->append(logline, len); 38 | else 39 | { 40 | buffers_.push_back(std::move(currentBuffer_)); 41 | if (nextBuffer_) 42 | currentBuffer_ = std::move(nextBuffer_); 43 | else//when it happen ? 44 | currentBuffer_.reset(new Buffer);//Rarely happens 45 | 46 | currentBuffer_->append(logline, len); 47 | cv_.notify_one(); 48 | } 49 | } 50 | 51 | /************************************************* 52 | 1.前端负责往A填充日志消息,后端负责将B的消息写入磁盘文件.A写满之后,交换AB. 53 | 2.后端将前述A的数据写入磁盘,前端往B填充日志消息. 54 | 3.往复循环 55 | 用2个buffer的好处是在添加日志的时候不必等待磁盘io,而是直接往内存缓冲区写入,同时避免每条日志触发唤醒后端(写入磁盘IO). 56 | 前端不是将一条条日志分别发送给后端,而是多条日志整合成一个大的buffer传送给后端,减少线程唤醒的次数与开销. 57 | 另,为避免长时间未写入磁盘,即使bufferA未满,也每3秒执行一次交换(swap A B),使得能及时写入磁盘. 58 | 59 | *************************************************/ 60 | 61 | 62 | /************************************************* 63 | threadFunc()内含后端接收方. 64 | 具体实现:分配2块缓冲区,目的是在临界区内与前端缓冲交换指针(swap),高效传递日志. 65 | 临界区内等待条件触发:1,超时,2,前端写满一个或者多个缓冲. 66 | 67 | 当条件满足时,将当前缓冲移入后端,并立刻将空闲缓冲移为当前缓冲,临界区后面的代码可以安全的访问后端:将日志数据写入磁盘. 68 | 临界区内最后用newBuffer2替换newBuffer2目的在于前端始终有一个预备缓冲可调用. 69 | 70 | 运行时分析: 71 | 1.前端写入速度低,3s超时后才将后端唤醒,此时执行swap操作.然后写入磁盘. 72 | 2.前端写入速度适中,超时前已经写满当前缓冲,于是唤醒后端写入磁盘 73 | 3.前端短时间写入较快,超时前append已经写满2个缓冲,于是append重新分配一个缓冲, 74 | 4.前端写入非常快,log可能无法正常写入磁盘,于是丢弃消息. 75 | *************************************************/ 76 | void AsyncLogging::threadFunc() 77 | { 78 | assert(running_ == true); 79 | LogFile output(basename_, rollSize_, false); 80 | BufferPtr newBuffer1(new Buffer); 81 | BufferPtr newBuffer2(new Buffer); 82 | newBuffer1->bzero(); 83 | newBuffer2->bzero(); 84 | BufferVector bufferToWrite;//B 85 | bufferToWrite.reserve(16); 86 | while (running_) 87 | { 88 | assert(newBuffer1 && newBuffer1->length() == 0); 89 | assert(newBuffer2 && newBuffer2->length() == 0); 90 | assert(bufferToWrite.empty()); 91 | 92 | { 93 | std::unique_lock g(mutex_); 94 | std::chrono::seconds time_it(flushInterval_); 95 | if (buffers_.empty()) 96 | cv_.wait_for(g,time_it); 97 | 98 | buffers_.push_back(std::move(currentBuffer_));//input to A 99 | currentBuffer_ = std::move(newBuffer1); 100 | bufferToWrite.swap(buffers_);//AB交换 101 | if (!nextBuffer_) 102 | nextBuffer_ = std::move(newBuffer2); 103 | } 104 | 105 | assert(!bufferToWrite.empty()); 106 | 107 | if (bufferToWrite.size() > 25)//目的:解决消息堆积问题.生产者速度高于消费者,前端存在过多消息则需要丢弃,否则可能导致内存暴涨 108 | { 109 | char buf[256]; 110 | snprintf(buf, sizeof(buf), "Drop log messages at %s,%zd larger buffers\n", 111 | ChronoTimestamp::now().toFormattedString().c_str(), bufferToWrite.size() - 2); 112 | fputs(buf, stderr); 113 | output.append(buf, static_cast(strlen(buf))); 114 | bufferToWrite.erase(bufferToWrite.begin() + 2, bufferToWrite.end()); 115 | } 116 | for (int i = 0; i < bufferToWrite.size(); ++i)//写入磁盘io 117 | { 118 | output.append(bufferToWrite[i]->data(), bufferToWrite[i]->length()); 119 | } 120 | if (bufferToWrite.size() > 2) 121 | bufferToWrite.resize(2); 122 | 123 | if (!newBuffer1) 124 | { 125 | assert(!bufferToWrite.empty()); 126 | newBuffer1 = std::move(bufferToWrite.back()); 127 | bufferToWrite.pop_back();//why this? 128 | newBuffer1->reset(); 129 | } 130 | 131 | if (!newBuffer2) 132 | { 133 | assert(!bufferToWrite.empty()); 134 | newBuffer2 = std::move(bufferToWrite.back()); 135 | bufferToWrite.pop_back(); 136 | newBuffer2.reset(); 137 | } 138 | 139 | bufferToWrite.clear(); 140 | output.flush(); 141 | } 142 | output.flush(); 143 | } -------------------------------------------------------------------------------- /muduo/log/AsyncLogging.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_ASYNCLOGGING_H 4 | #define TMUDUO_ASYNCLOGGING_H 5 | 6 | #include 7 | #include 8 | //#include 9 | //#include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace muduo 16 | { 17 | class AsyncLogging : noncopyable 18 | { 19 | public: 20 | AsyncLogging(const std::string &basename, size_t rollSize, int flushInterval = 3); 21 | 22 | ~AsyncLogging() 23 | { 24 | if (running_) 25 | stop(); 26 | } 27 | 28 | void append(const char *logline, int len); 29 | 30 | void start() 31 | { 32 | running_ = true; 33 | thread_ptr.reset(new std::thread(&AsyncLogging::threadFunc, this)); 34 | 35 | 36 | } 37 | 38 | void stop() 39 | { 40 | running_ = false; 41 | thread_ptr->join(); 42 | 43 | } 44 | 45 | private: 46 | void threadFunc(); 47 | 48 | typedef muduo::detail::FixedBuffer Buffer; 49 | typedef std::vector> BufferVector; 50 | typedef BufferVector::value_type BufferPtr; 51 | 52 | const int flushInterval_; 53 | std::string basename_; 54 | size_t rollSize_; 55 | std::mutex mutex_; 56 | std::condition_variable cv_; 57 | 58 | /************************************************* 59 | 前后端各2块缓冲区. 60 | *************************************************/ 61 | BufferPtr currentBuffer_;//当前缓冲(前端) 62 | BufferPtr nextBuffer_;//预备缓冲(前端) 63 | BufferVector buffers_;//待写入文件的缓冲,(后端).A 64 | Atomic_bool running_{false}; 65 | std::unique_ptr thread_ptr; 66 | 67 | }; 68 | } 69 | #endif //TMUDUO_ASYNCLOGGING_H 70 | -------------------------------------------------------------------------------- /muduo/log/BlockingQueue.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_BLOCKINGQUEUE_H 4 | #define TMUDUO_BLOCKINGQUEUE_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | namespace muduo 13 | { 14 | template 15 | class BlockingQueue : noncopyable//无界队列. 16 | { 17 | public: 18 | BlockingQueue() 19 | { 20 | } 21 | 22 | void put(const T &x) 23 | { 24 | std::lock_guard g(mutex_); 25 | queue_.push_back(x); 26 | cv.notify_one(); 27 | } 28 | 29 | void put(T &&x) 30 | { 31 | std::lock_guard g(mutex_); 32 | queue_.push_back(std::move(x)); 33 | cv.notify_one(); 34 | } 35 | 36 | T take() 37 | { 38 | 39 | std::unique_lock g(mutex_); 40 | while (queue_.empty()) 41 | { 42 | // cv.wait(g,std::bind(&BlockingQueue::notEmpty,this)); 43 | cv.wait(g,[&]{return !queue_.empty();}); 44 | } 45 | 46 | assert(!queue_.empty()); 47 | T front(std::move(queue_.front())); 48 | queue_.pop_front(); 49 | return front; 50 | } 51 | 52 | size_t size() 53 | { 54 | std::lock_guard g(mutex_); 55 | return queue_.size(); 56 | } 57 | 58 | 59 | 60 | private: 61 | 62 | /* bool notEmpty() 63 | { 64 | //std::lock_guard g(mutex_);//不能再加锁了.否则造成死锁. 65 | return !queue_.empty(); 66 | }*/ 67 | std::mutex mutex_; 68 | std::condition_variable cv; 69 | std::deque queue_; 70 | }; 71 | } 72 | #endif //TMUDUO_BLOCKINGQUEUE_H 73 | -------------------------------------------------------------------------------- /muduo/log/BoundedBlockingQueue.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_BOUNDEDBLOCKINGQUEUE_H 4 | #define TMUDUO_BOUNDEDBLOCKINGQUEUE_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace muduo 13 | { 14 | template 15 | class BoundedBlockingQueue : noncopyable 16 | { 17 | public: 18 | BoundedBlockingQueue(int maxSize) : maxSize_(maxSize)//, queue_(maxSize) 19 | { 20 | }; 21 | 22 | void put(const T &x) 23 | { 24 | std::lock_guard g(mutex_); 25 | while (queue_.size() == maxSize_)//o(1) 26 | { 27 | cv_notFull.wait(g, [&] 28 | { return queue_ != maxSize_; }); 29 | } 30 | assert(queue_.size() != maxSize_); 31 | queue_.push_back(x); 32 | cv_notEmpty.notify_one(); 33 | } 34 | 35 | void put(T &&x) 36 | { 37 | std::unique_lock g(mutex_); 38 | while (queue_.size() == maxSize_)//o(1) 39 | { 40 | cv_notFull.wait(g, [&] 41 | { return queue_.size() != maxSize_; }); 42 | } 43 | assert(queue_.size() != maxSize_); 44 | queue_.push_back(std::move(x)); 45 | cv_notEmpty.notify_one(); 46 | } 47 | 48 | T take() 49 | { 50 | std::unique_lock g(mutex_); 51 | while (queue_.empty()) 52 | { 53 | cv_notEmpty.wait(g, [&] 54 | { return !queue_.empty(); }); 55 | } 56 | assert(!queue_.empty()); 57 | T front(queue_.front()); 58 | queue_.pop_front(); 59 | cv_notFull.notify_one(); 60 | return front; 61 | } 62 | 63 | bool full() const 64 | { 65 | std::lock_guard g(mutex_); 66 | return queue_.size() == maxSize_; 67 | } 68 | 69 | bool empty() const 70 | { 71 | std::lock_guard g(mutex_); 72 | return queue_.empty(); 73 | } 74 | 75 | size_t size() 76 | { 77 | 78 | std::lock_guard g(mutex_); 79 | return queue_.size(); 80 | } 81 | 82 | size_t capacity() const 83 | { 84 | 85 | std::lock_guard g(mutex_); 86 | return maxSize_; 87 | } 88 | 89 | private: 90 | std::mutex mutex_; 91 | std::condition_variable cv_notEmpty; 92 | std::condition_variable cv_notFull; 93 | std::deque queue_; 94 | int maxSize_; 95 | }; 96 | } 97 | #endif //TMUDUO_BOUNDEDBLOCKINGQUEUE_H 98 | -------------------------------------------------------------------------------- /muduo/log/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(log_SRE 2 | AsyncLogging.cpp 3 | LogFile.cpp 4 | Logging.cpp 5 | LogStream.cpp 6 | FileUtil.cpp 7 | ProcessInfo.cpp 8 | ) 9 | add_library(muduo_log ${log_SRE}) 10 | target_link_libraries(muduo_log muduo_base ) 11 | 12 | install(TARGETS muduo_log DESTINATION lib) 13 | 14 | file(GLOB HEADERS "*.h") 15 | install(FILES ${HEADERS} DESTINATION include/muduo/log) 16 | if(NOT CMAKE_BUILD_NO_EXAMPLES) 17 | add_subdirectory(tests) 18 | endif() -------------------------------------------------------------------------------- /muduo/log/FileUtil.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace muduo; 12 | 13 | FileUtil::AppendFile::AppendFile(StringArg filename) 14 | : fp_(::fopen(filename.c_str(), "ae")),//a:append,e:O_CLOEXEC 15 | writtenBytes_(0) 16 | { 17 | assert(fp_); 18 | ::setbuffer(fp_, buffer_, sizeof buffer_); 19 | } 20 | 21 | FileUtil::AppendFile::~AppendFile() 22 | { 23 | ::fclose(fp_); 24 | } 25 | 26 | void FileUtil::AppendFile::append(const char *logline, const size_t len) 27 | { 28 | size_t n = write(logline, len); 29 | size_t remain = len - n; 30 | while (remain > 0) 31 | { 32 | size_t x = write(logline + n, remain); 33 | if (x == 0) 34 | { 35 | int err = ferror(fp_); 36 | if (err) 37 | fprintf(stderr, "AppendFile::append() FAILED %s \n", "??"); 38 | 39 | break; 40 | } 41 | n += x; 42 | remain = len - n; 43 | } 44 | writtenBytes_ += len; 45 | } 46 | 47 | void FileUtil::AppendFile::flush() 48 | { 49 | ::fflush(fp_); 50 | } 51 | 52 | size_t FileUtil::AppendFile::write(const char *logline, size_t len) 53 | { 54 | auto it=::fwrite_unlocked(logline, 1, len, fp_);// thread unsafe 55 | return it; 56 | } 57 | //man 2 open 58 | FileUtil::ReadSmallFile::ReadSmallFile(StringArg filename) 59 | : err_(0) 60 | { 61 | 62 | fd_=(::open(filename.c_str(), O_RDONLY | O_CLOEXEC)); 63 | buf_[0] = '\0'; 64 | if (fd_ < 0) 65 | err_ = errno; 66 | } 67 | 68 | FileUtil::ReadSmallFile::~ReadSmallFile() 69 | { 70 | if (fd_ > 0) 71 | ::close(fd_); 72 | } 73 | 74 | template 75 | int FileUtil::ReadSmallFile::readToString(int maxSize, STring *content, int64_t *fileSize, int64_t *modifyTime, 76 | int64_t *createTime) 77 | { 78 | static_assert(sizeof(off_t) == 8, "_FILE_OFFSET_BITS = 64"); 79 | assert(content != NULL); 80 | int err = err_; 81 | if (fd_ >= 0) 82 | { 83 | content->clear(); 84 | if (fileSize) 85 | { 86 | struct stat statbuf; 87 | if (::fstat(fd_, &statbuf) == 0) 88 | { 89 | if (S_ISREG(statbuf.st_mode)) 90 | { 91 | *fileSize = statbuf.st_size; 92 | content->reserve(static_cast 93 | (std::min(implicit_cast(maxSize), 94 | *fileSize))); 95 | } else if (S_ISDIR((statbuf.st_mode))) 96 | { 97 | err = EISDIR; 98 | } 99 | if (modifyTime) 100 | { 101 | *modifyTime = statbuf.st_mtime; 102 | } 103 | if (createTime) 104 | { 105 | *createTime = statbuf.st_ctime; 106 | } 107 | } else 108 | { 109 | err = errno; 110 | } 111 | } 112 | while (content->size() < implicit_cast(maxSize)) 113 | { 114 | size_t toRead = std::min(implicit_cast(maxSize) - content->size(), 115 | sizeof(buf_)); 116 | ssize_t n = ::read(fd_, buf_, toRead); 117 | if (n > 0) 118 | content->append(buf_, n); 119 | else 120 | { 121 | if (n < 0) 122 | { err = errno; } 123 | break; 124 | } 125 | } 126 | } 127 | return err;//返回错误码 128 | } 129 | 130 | int FileUtil::ReadSmallFile::readToBuffer(int *size) 131 | { 132 | int err = err_; 133 | if (fd_ >= 0) 134 | { 135 | ssize_t n = ::pread(fd_, buf_, sizeof(buf_) - 1, 0); 136 | if (n >= 0) 137 | { 138 | if (size) 139 | { 140 | *size = static_cast(n); 141 | } 142 | buf_[n] = '\0'; 143 | } else 144 | err = errno; 145 | } 146 | return err; 147 | } 148 | 149 | //特化std::string 150 | template int FileUtil::readFile(StringArg filename, 151 | int maxSize, 152 | std::string *content, 153 | int64_t *fileSize = NULL, 154 | int64_t *modifyTime = NULL, 155 | int64_t *createTime = NULL); 156 | 157 | template 158 | int FileUtil::ReadSmallFile::readToString(int maxSize, 159 | std::string *content, 160 | int64_t *fileSize, 161 | int64_t *modifyTime, 162 | int64_t *createTime); 163 | 164 | -------------------------------------------------------------------------------- /muduo/log/FileUtil.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_FILEUTIL_H 4 | #define TMUDUO_FILEUTIL_H 5 | 6 | 7 | #include 8 | 9 | namespace muduo 10 | { 11 | namespace FileUtil 12 | { 13 | class ReadSmallFile : noncopyable 14 | { 15 | public: 16 | ReadSmallFile(StringArg filename); 17 | 18 | ~ReadSmallFile(); 19 | 20 | template 21 | int readToString(int maxSize, 22 | STring *content, int64_t *fileSize, 23 | int64_t *modifyTime, 24 | int64_t *createTime); 25 | 26 | int readToBuffer(int *size); 27 | 28 | static const int kBufferSize = 64 * 1024; 29 | private: 30 | int fd_; 31 | int err_; 32 | char buf_[kBufferSize]; 33 | }; 34 | 35 | template 36 | int readFile(StringArg filename, //欲打开的文件名称. 37 | int maxSize,//最大读取字节 38 | STring *content,//储存地点. 39 | int64_t *fileSize = NULL,//返回file的真实大小 40 | int64_t *modifyTime = NULL,//返回修改的日期. 41 | int64_t *createTime = NULL)//创建日期. 42 | { 43 | ReadSmallFile file(filename); 44 | return file.readToString(maxSize, content, fileSize, modifyTime, createTime); 45 | } 46 | 47 | class AppendFile : noncopyable 48 | { 49 | public: 50 | explicit AppendFile(StringArg filename); 51 | 52 | ~AppendFile(); 53 | 54 | void append(const char *logline, const size_t len); 55 | 56 | void flush(); 57 | 58 | size_t writtenBytes() const 59 | { return writtenBytes_; } 60 | 61 | private: 62 | size_t write(const char *logline, size_t len); 63 | 64 | FILE *fp_; 65 | char buffer_[64 * 1024]; 66 | size_t writtenBytes_; 67 | }; 68 | } 69 | 70 | 71 | } 72 | 73 | #endif //TMUDUO_FILEUTIL_H 74 | -------------------------------------------------------------------------------- /muduo/log/LogFile.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "LogFile.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muduo; 11 | 12 | LogFile::LogFile(const std::string &basename, 13 | size_t rollSize, 14 | bool threadSafe, 15 | int flushTnterval, 16 | int checkEveryN) 17 | : basename_(basename), 18 | rollSize_(rollSize), 19 | flushInterval_(flushTnterval), 20 | checkEveryN_(checkEveryN), 21 | count_(0), 22 | mutex_(threadSafe ? (new std::mutex) : nullptr), 23 | startOfPeriod_(0), 24 | lastRoll_(0), 25 | lastFlush_(0) 26 | { 27 | assert(basename.find('/')==std::string::npos); 28 | rollFile(); 29 | } 30 | 31 | LogFile::~LogFile() 32 | {} 33 | 34 | void LogFile::append(const char *logline, int len) 35 | { 36 | if(mutex_) 37 | { 38 | std::lock_guard g(*mutex_); 39 | append_unlocked(logline,len); 40 | } 41 | else 42 | { 43 | append_unlocked(logline,len); 44 | } 45 | } 46 | 47 | void LogFile::flush() 48 | { 49 | if(mutex_) 50 | { 51 | std::lock_guard g(*mutex_); 52 | file_->flush(); 53 | } 54 | else 55 | file_->flush(); 56 | } 57 | 58 | 59 | void LogFile::append_unlocked(const char *logline, int len) 60 | { 61 | file_->append(logline,len); 62 | if(file_->writtenBytes()>rollSize_) 63 | rollFile(); 64 | else 65 | { 66 | ++count_; 67 | if(count_>=checkEveryN_) 68 | { 69 | count_=0; 70 | time_t now=::time(NULL); 71 | time_t thisPeriod_=now/kRollPerSeconds_*kRollPerSeconds_; 72 | if(thisPeriod_!=startOfPeriod_) 73 | { 74 | rollFile(); 75 | } 76 | else if(now-lastFlush_ > flushInterval_) 77 | { 78 | lastFlush_=now; 79 | file_->flush(); 80 | } 81 | } 82 | } 83 | } 84 | 85 | bool LogFile::rollFile() 86 | { 87 | time_t now=0; 88 | std::string filename = getLogFileName(basename_,&now); 89 | time_t start=now/kRollPerSeconds_*kRollPerSeconds_; 90 | if(now>lastRoll_) 91 | { 92 | lastRoll_=now; 93 | lastFlush_=now; 94 | startOfPeriod_=start; 95 | file_.reset(new FileUtil::AppendFile(filename)); 96 | return true; 97 | } 98 | return false; 99 | } 100 | 101 | std::string LogFile::getLogFileName(const std::string &basename, time_t *now) 102 | { 103 | std::string filename; 104 | filename.reserve(basename.size()+64); 105 | filename=basename; 106 | char timebuf[32]; 107 | 108 | struct tm tm; 109 | *now=time(NULL); 110 | gmtime_r(now,&tm); 111 | strftime(timebuf,sizeof timebuf,".%Y%m%d-%H%M%S.",&tm); 112 | filename+=timebuf; 113 | filename+=ProcessInfo::hostname(); 114 | char pidbuf[32]; 115 | snprintf(pidbuf,sizeof pidbuf,".%d",ProcessInfo::pid()); 116 | filename+=pidbuf; 117 | filename+=".log"; 118 | return filename; 119 | } -------------------------------------------------------------------------------- /muduo/log/LogFile.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_LOGFILE_H 4 | #define TMUDUO_LOGFILE_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace muduo 12 | { 13 | namespace FileUtil 14 | { 15 | class AppendFile; 16 | } 17 | class LogFile : noncopyable 18 | { 19 | public: 20 | LogFile(const std::string &basename, 21 | size_t rollSize, 22 | bool threadSafe = true, 23 | int flushTnterval = 3, 24 | int checkEveryN = 1024); 25 | 26 | ~LogFile(); 27 | 28 | void append(const char *logline, int len); 29 | 30 | void flush(); 31 | 32 | bool rollFile(); 33 | 34 | private: 35 | void append_unlocked(const char *logline, int len); 36 | 37 | static std::string getLogFileName(const std::string &basename, time_t *now); 38 | 39 | const std::string basename_; 40 | const size_t rollSize_; 41 | const int flushInterval_; 42 | const int checkEveryN_; 43 | 44 | int count_; 45 | 46 | std::unique_ptr mutex_; 47 | time_t startOfPeriod_; 48 | time_t lastRoll_; 49 | time_t lastFlush_; 50 | 51 | std::unique_ptr file_; 52 | const static int kRollPerSeconds_ = 60 * 60 * 24; 53 | }; 54 | } 55 | #endif //TMUDUO_LOGFILE_H 56 | -------------------------------------------------------------------------------- /muduo/log/LogStream.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "LogStream.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace muduo; 12 | using namespace muduo::detail; 13 | 14 | namespace muduo 15 | { 16 | namespace detail 17 | { 18 | const char digits[] = "9876543210123456789"; 19 | const char *zero = digits + 9; 20 | static_assert(sizeof(digits) == 20, "wrong number of digits"); 21 | 22 | const char digitsHex[] = "0123456789ABCDEF"; 23 | static_assert(sizeof(digitsHex) == 17, "wrong number of digitsHex"); 24 | 25 | //int to string. 26 | template 27 | size_t convert(char buf[], T value) 28 | { 29 | T i = value; 30 | char *p = buf; 31 | 32 | do 33 | { 34 | int lsd = static_cast(i % 10); 35 | i /= 10; 36 | *p++ = zero[lsd]; 37 | } while (i != 0); 38 | 39 | if (value < 0) 40 | { 41 | *p++ = '-'; 42 | } 43 | *p = '\0'; 44 | std::reverse(buf, p); 45 | 46 | return p - buf; 47 | } 48 | 49 | size_t convertHex(char buf[], uintptr_t value) 50 | { 51 | uintptr_t i = value; 52 | char *p = buf; 53 | do 54 | { 55 | int lsd = static_cast(i % 16); 56 | i /= 16; 57 | *p++ = digitsHex[lsd]; 58 | } while (i != 0); 59 | *p = '\0'; 60 | std::reverse(buf, p); 61 | return p - buf; 62 | } 63 | 64 | template 65 | class FixedBuffer; 66 | 67 | template 68 | class FixedBuffer; 69 | } 70 | 71 | 72 | template 73 | const char *FixedBuffer::debugString() 74 | { 75 | *cur_ = '\0'; 76 | return data_; 77 | } 78 | 79 | template 80 | void FixedBuffer::cookieStart() 81 | {} 82 | 83 | template 84 | void FixedBuffer::cookieEnd() 85 | {} 86 | 87 | void LogStream::staticCheck() 88 | { 89 | static_assert(kMaxNumbericSize - 10 > std::numeric_limits::digits10, 90 | "kMaxNumbericSize is large enough"); 91 | static_assert(kMaxNumbericSize - 10 > std::numeric_limits::digits10, 92 | "kMaxNumbericSize is large enough"); 93 | static_assert(kMaxNumbericSize - 10 > std::numeric_limits::digits10, 94 | "kMaxNumbericSize is large enough"); 95 | static_assert(kMaxNumbericSize - 10 > std::numeric_limits::digits10, 96 | "kMaxNumbericSize is large enough"); 97 | } 98 | 99 | 100 | template 101 | void LogStream::formatInteger(T v) 102 | { 103 | if (buffer_.avail() >= kMaxNumbericSize) 104 | { 105 | size_t len = convert(buffer_.current(), v); 106 | buffer_.add(len); 107 | } 108 | } 109 | 110 | LogStream &LogStream::operator<<(short v) 111 | { 112 | *this << static_cast(v); 113 | return *this; 114 | } 115 | 116 | LogStream &LogStream::operator<<(unsigned short v) 117 | { 118 | *this << static_cast(v); 119 | return *this; 120 | } 121 | 122 | LogStream &LogStream::operator<<(int v) 123 | { 124 | formatInteger(v); 125 | return *this; 126 | } 127 | 128 | LogStream &LogStream::operator<<(unsigned int v) 129 | { 130 | formatInteger(v); 131 | return *this; 132 | } 133 | 134 | LogStream &LogStream::operator<<(long int v) 135 | { 136 | formatInteger(v); 137 | return *this; 138 | } 139 | 140 | LogStream &LogStream::operator<<(unsigned long int v) 141 | { 142 | formatInteger(v); 143 | return *this; 144 | } 145 | 146 | LogStream &LogStream::operator<<(long long int v) 147 | { 148 | formatInteger(v); 149 | return *this; 150 | } 151 | 152 | LogStream &LogStream::operator<<(unsigned long long int v) 153 | { 154 | formatInteger(v); 155 | return *this; 156 | } 157 | 158 | LogStream &LogStream::operator<<(const void *p) 159 | { 160 | uintptr_t v = reinterpret_cast(p); 161 | if (buffer_.avail() >= kMaxNumbericSize) 162 | { 163 | char *buf = buffer_.current(); 164 | buf[0] = '0'; 165 | buf[1] = 'x'; 166 | size_t len = convertHex(buf + 2, v); 167 | buffer_.add(len + 2); 168 | } 169 | return *this; 170 | } 171 | 172 | 173 | LogStream &LogStream::operator<<(double v) 174 | { 175 | if (buffer_.avail() >= kMaxNumbericSize) 176 | { 177 | int len = snprintf(buffer_.current(), kMaxNumbericSize, "%.12g", v);//只保留12位 178 | buffer_.add(len); 179 | } 180 | return *this; 181 | } 182 | 183 | /* template 184 | Fmt::Fmt(const char *fmt, T val) 185 | { 186 | //算术 187 | static_assert(std::is_arithmetic::value == true, "Must be arithmetic type"); 188 | 189 | length_ = snprintf(buf_, sizeof buf_, fmt, val); 190 | 191 | assert(static_cast(length_) < sizeof buf_); 192 | }*/ 193 | 194 | //template Fmt::Fmt(const cha *fmt, T val),显式实例化. 195 | template Fmt::Fmt(const char *fmt, char); 196 | template Fmt::Fmt(const char *fmt, unsigned short); 197 | template Fmt::Fmt(const char *fmt, int); 198 | template Fmt::Fmt(const char *fmt, unsigned int); 199 | template Fmt::Fmt(const char *fmt, long); 200 | template Fmt::Fmt(const char *fmt, unsigned long); 201 | template Fmt::Fmt(const char *fmt, long long); 202 | template Fmt::Fmt(const char *fmt, unsigned long long); 203 | template Fmt::Fmt(const char *fmt, float); 204 | template Fmt::Fmt(const char *fmt, double); 205 | 206 | 207 | 208 | } 209 | 210 | -------------------------------------------------------------------------------- /muduo/log/LogStream.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_LOGSTREAM_H 4 | #define TMUDUO_LOGSTREAM_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace muduo 13 | { 14 | namespace detail 15 | { 16 | const int kSmallBuffer = 4000;//4k 17 | const int kLargeBuffer = 4000 * 4000;//4M 18 | 19 | template 20 | class FixedBuffer : noncopyable 21 | { 22 | 23 | public: 24 | FixedBuffer() : cur_(data_) 25 | { 26 | setCookie(cookieStart); 27 | } 28 | 29 | ~FixedBuffer() 30 | { 31 | setCookie(cookieEnd); 32 | } 33 | 34 | /*restrict表明指针是访问一个数据对象的唯一且所有修改内容的操作都必须通过该指针来修改*/ 35 | void append(const char * /*restrict*/ buf, size_t len) 36 | { 37 | if (implicit_cast(avail()) > len) 38 | { 39 | memcpy(cur_, buf, len); 40 | cur_ += len; 41 | } 42 | } 43 | 44 | const char *data() const 45 | { return data_; } 46 | 47 | int length() const 48 | { return static_cast(cur_ - data_); } 49 | 50 | char *current() 51 | { return cur_; } 52 | 53 | int avail() const 54 | { return static_cast(end() - cur_); } 55 | 56 | void add(size_t len) 57 | { cur_ += len; } 58 | 59 | 60 | void reset() 61 | { cur_ = data_; }; 62 | 63 | void bzero() 64 | { ::bzero(data_, sizeof data_); } 65 | 66 | 67 | const char *debugString(); 68 | 69 | void setCookie(void(*cookie)()) 70 | { 71 | cookie_ = cookie; 72 | } 73 | 74 | std::string toString() const 75 | { 76 | //from sequence :string (const char* s, size_t n); 77 | return std::string(data_, length()); 78 | } 79 | 80 | 81 | StringPiece toStringPiece() const 82 | { 83 | return StringPiece(data_, length()); 84 | } 85 | 86 | private: 87 | const char *end() const 88 | { return data_ + sizeof data_; } 89 | 90 | static void cookieStart(); 91 | 92 | static void cookieEnd(); 93 | 94 | void (*cookie_)(); 95 | 96 | char data_[SIZE]; 97 | char *cur_; 98 | 99 | }; 100 | } 101 | 102 | class LogStream : noncopyable 103 | { 104 | typedef LogStream self; 105 | public: 106 | typedef detail::FixedBuffer Buffer; 107 | 108 | self &operator<<(bool v) 109 | { 110 | buffer_.append(v ? "1" : "0", 1); 111 | return *this; 112 | } 113 | 114 | self &operator<<(short); 115 | 116 | self &operator<<(unsigned short); 117 | 118 | self &operator<<(unsigned int); 119 | 120 | self &operator<<(int); 121 | 122 | self &operator<<(long); 123 | 124 | self &operator<<(unsigned long); 125 | 126 | self &operator<<(long long); 127 | 128 | self &operator<<(unsigned long long); 129 | 130 | self &operator<<(const void *); 131 | 132 | self &operator<<(float v) 133 | { 134 | *this << static_cast(v); 135 | return *this; 136 | } 137 | 138 | self &operator<<(double); 139 | 140 | self &operator<<(char v) 141 | { 142 | buffer_.append(&v, 1); 143 | return *this; 144 | } 145 | 146 | self &operator<<(const char *str) 147 | { 148 | if (str) 149 | buffer_.append(str, strlen(str)); 150 | else 151 | buffer_.append("(null)", 6); 152 | return *this; 153 | } 154 | 155 | self &operator<<(const unsigned char *str) 156 | { 157 | return operator<<(reinterpret_cast(str)); 158 | } 159 | 160 | self &operator<<(const std::string &v) 161 | { 162 | buffer_.append(v.c_str(), v.size()); 163 | return *this; 164 | } 165 | 166 | self &operator<<(const StringPiece &v) 167 | { 168 | buffer_.append(v.data(), v.size()); 169 | return *this; 170 | } 171 | 172 | self &operator<<(const Buffer &v) 173 | { 174 | *this << v.toStringPiece(); 175 | return *this; 176 | } 177 | 178 | void append(const char *data, int len) 179 | { 180 | buffer_.append(data, len); 181 | } 182 | 183 | const Buffer &buffer() const 184 | { return buffer_; } 185 | 186 | void resetBuffer() 187 | { 188 | buffer_.reset(); 189 | } 190 | 191 | 192 | private: 193 | 194 | void staticCheck(); 195 | 196 | template 197 | void formatInteger(T); 198 | 199 | Buffer buffer_; 200 | static const int kMaxNumbericSize = 32; 201 | }; 202 | 203 | class Fmt 204 | { 205 | public: 206 | template 207 | Fmt(const char *fmt, T val) 208 | { 209 | //算术 210 | static_assert(std::is_arithmetic::value == true, "Must be arithmetic type"); 211 | 212 | length_ = snprintf(buf_, sizeof buf_, fmt, val); 213 | 214 | assert(static_cast(length_) < sizeof buf_); 215 | }; 216 | 217 | const char *data() const 218 | { return buf_; } 219 | 220 | int length() const 221 | { return length_; } 222 | 223 | 224 | private: 225 | char buf_[32]; 226 | int length_; 227 | }; 228 | 229 | inline LogStream &operator<<(LogStream &s, const Fmt &fmt) 230 | { 231 | s.append(fmt.data(), fmt.length()); 232 | return s; 233 | } 234 | } 235 | #endif //TMUDUO_LOGSTREAM_H 236 | -------------------------------------------------------------------------------- /muduo/log/Logging.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace muduo 11 | { 12 | thread_local char t_errnobuf[512]; 13 | thread_local char t_time[32]; 14 | 15 | thread_local time_t t_lastScond; 16 | 17 | const char *strerror_tl(int savedErrno) 18 | { 19 | return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf); 20 | } 21 | 22 | Logger::LogLevel initLogLevel() 23 | { 24 | if(1) 25 | //if (::getenv("MUDUO_LOG_TRACE")) 26 | return Logger::TRACE; 27 | else if (::getenv("MUDUO_LOG_DEBUG")) 28 | return Logger::DEBUG; 29 | else 30 | return Logger::INFO; 31 | } 32 | 33 | Logger::LogLevel g_logLevel = initLogLevel(); 34 | 35 | const char *LogLevelName[Logger::NUM_LOG_LEVELS] =//6 36 | { 37 | "TRACE ", 38 | "DEBUG ", 39 | "INFO ", 40 | "WARN ", 41 | "ERROR ", 42 | "FATAL ", 43 | }; 44 | 45 | 46 | class T 47 | { 48 | public: 49 | T(const char *str, unsigned len) : 50 | str_(str), len_(len) 51 | { 52 | assert(strlen(str) == len_); 53 | } 54 | 55 | const char *str_; 56 | const unsigned len_; 57 | }; 58 | 59 | inline LogStream &operator<<(LogStream &s, T v) 60 | { 61 | s.append(v.str_, v.len_); 62 | return s; 63 | } 64 | 65 | inline LogStream &operator<<(LogStream &s, const Logger::SourceFile &v) 66 | { 67 | s.append(v.data_, v.size_); 68 | return s; 69 | } 70 | 71 | void defaultOutput(const char *msg, int len)//默认是标准输出. 72 | { 73 | size_t n = fwrite(msg, 1, len, stdout); 74 | (void) n; 75 | } 76 | 77 | void defaultFlush() 78 | { 79 | fflush(stdout); 80 | } 81 | 82 | 83 | Logger::OutputFunc g_output = defaultOutput; 84 | Logger::FlushFunc g_flush = defaultFlush; 85 | 86 | Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile &file, int line) 87 | : time_(ChronoTimestamp::now()), 88 | stream_(), 89 | level_(level), 90 | line_(line), 91 | basename_(file) 92 | { 93 | formatTime(); 94 | std::string s = std::to_string((::syscall(SYS_gettid))); 95 | s += " "; 96 | stream_ << T(s.c_str(), s.size()); 97 | stream_ << T(LogLevelName[level], 6); 98 | if (savedErrno != 0) 99 | stream_ << strerror(savedErrno) << "(errno=" << savedErrno << ") "; 100 | } 101 | 102 | void Logger::Impl::formatTime() 103 | { 104 | int64_t usSinceEpoch = time_.microSecondsSinceEpoch().count(); 105 | time_t seconds = static_cast(usSinceEpoch / ChronoTimestamp::kMicroSecondsPerSecond); 106 | int us = static_cast(usSinceEpoch % ChronoTimestamp::kMicroSecondsPerSecond); 107 | if (seconds != t_lastScond) 108 | { 109 | t_lastScond = seconds; 110 | struct tm tm_time; 111 | // if (g_logTimeZone.valid()) 112 | if (0) 113 | { 114 | // tm_time = g_logTimeZone.toLocalTime(seconds); 115 | } else 116 | { 117 | ::gmtime_r(&seconds, &tm_time); 118 | } 119 | 120 | int len = snprintf(t_time, sizeof(t_time), 121 | "%4d%02d%02d %02d:%02d:%02d", 122 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 123 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); 124 | assert(len == 17); 125 | (void) len; 126 | } 127 | 128 | // if(g_logTimeZone.valid()) 129 | if (0) 130 | { 131 | Fmt us_(".%06d ", us); 132 | assert(us_.length() == 8); 133 | stream_ << T(t_time, 17) << T(us_.data(), 8); 134 | } else 135 | { 136 | Fmt us_(".%06dZ ", us); 137 | assert(us_.length() == 9); 138 | stream_ << T(t_time, 17) << T(us_.data(), 9); 139 | } 140 | } 141 | 142 | void Logger::Impl::finish() 143 | { 144 | stream_ << " - "<< basename_<< ':'<< line_ << '\n'; 145 | } 146 | 147 | Logger::Logger(SourceFile file, int line): impl_(INFO, 0, file, line) 148 | { 149 | } 150 | 151 | //Logger(SourceFile file, int line, LogLevel level, const char *func); 152 | 153 | Logger::Logger (SourceFile file, int line, LogLevel level, const char *func) 154 | : impl_(level, 0, file, line) 155 | { 156 | impl_.stream_ << func << ' '; 157 | } 158 | 159 | Logger::Logger(SourceFile file, int line, LogLevel level) 160 | : impl_(level, 0, file, line) 161 | { 162 | }; 163 | 164 | Logger::Logger(SourceFile file, int line, bool toAbort) 165 | : impl_(toAbort ? FATAL : ERROR, errno, file, line) 166 | {} 167 | 168 | Logger::~Logger() 169 | { 170 | impl_.finish(); 171 | const LogStream::Buffer &buf(stream().buffer()); 172 | g_output(buf.data(), buf.length()); 173 | if (impl_.level_ == FATAL) 174 | { 175 | g_flush(); 176 | abort(); 177 | } 178 | } 179 | 180 | void Logger::setLogLevel(LogLevel level) 181 | { 182 | g_logLevel = level; 183 | } 184 | 185 | void Logger::setOutput(OutputFunc out) 186 | { 187 | g_output = out; 188 | } 189 | 190 | void Logger::setFlush(FlushFunc flush) 191 | { 192 | g_flush = flush; 193 | } 194 | 195 | void Logger::setTimeZone(const TimeZone &tz) 196 | { 197 | 198 | } 199 | 200 | } -------------------------------------------------------------------------------- /muduo/log/Logging.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_LOGGING_H 4 | #define TMUDUO_LOGGING_H 5 | 6 | #include 7 | #include 8 | 9 | namespace muduo 10 | { 11 | class TimeZone; 12 | 13 | class Logger 14 | { 15 | public: 16 | 17 | enum LogLevel 18 | { 19 | TRACE, 20 | DEBUG, 21 | INFO, 22 | WARN, 23 | ERROR, 24 | FATAL, 25 | NUM_LOG_LEVELS, 26 | }; 27 | 28 | class SourceFile 29 | { 30 | public: 31 | 32 | template 33 | inline SourceFile(const char(&arr)[N]) 34 | :data_(arr), size_(N - 1) 35 | { 36 | const char *slash = strrchr(data_, '/'); 37 | if (slash) 38 | { 39 | data_ = slash + 1; 40 | size_ -= static_cast(data_ - arr); 41 | } 42 | } 43 | 44 | explicit SourceFile(const char *filename) 45 | : data_(filename) 46 | { 47 | const char *slash = strrchr(filename, '/'); 48 | if (slash) 49 | { 50 | data_ = slash + 1; 51 | } 52 | size_ = static_cast(strlen(data_)); 53 | } 54 | 55 | 56 | const char *data_; 57 | int size_; 58 | }; 59 | 60 | Logger(SourceFile file, int line); 61 | 62 | Logger(SourceFile file, int line, LogLevel level); 63 | 64 | 65 | Logger(SourceFile file, int line, LogLevel level, const char *func); 66 | 67 | Logger(SourceFile file, int line, bool toAbort); 68 | 69 | ~Logger(); 70 | 71 | LogStream &stream() 72 | { return impl_.stream_; } 73 | 74 | static LogLevel logLevel(); 75 | 76 | static void setLogLevel(LogLevel level); 77 | 78 | using OutputFunc= void(*)(const char *msg, int len); 79 | 80 | using FlushFunc= void(*)(); 81 | 82 | static void setOutput(OutputFunc); 83 | 84 | static void setFlush(FlushFunc); 85 | 86 | static void setTimeZone(const TimeZone &tz); 87 | 88 | 89 | class Impl 90 | { 91 | public: 92 | using LogLevel= Logger::LogLevel ; 93 | 94 | Impl(LogLevel level, int old_errno, const SourceFile &file, int line); 95 | 96 | void formatTime(); 97 | 98 | void finish(); 99 | 100 | ChronoTimestamp time_; 101 | LogStream stream_; 102 | LogLevel level_; 103 | int line_; 104 | SourceFile basename_; 105 | }; 106 | private: 107 | Impl impl_; 108 | }; 109 | 110 | extern Logger::LogLevel g_logLevel; 111 | 112 | inline Logger::LogLevel Logger::logLevel() 113 | { 114 | return g_logLevel; 115 | } 116 | 117 | #define LOG_TRACE if(muduo::Logger::logLevel()<=muduo::Logger::TRACE) \ 118 | muduo::Logger(__FILE__,__LINE__,muduo::Logger::TRACE,__func__).stream() 119 | 120 | #define LOG_DEBUG if(muduo::Logger::logLevel()<=muduo::Logger::DEBUG)\ 121 | muduo::Logger(__FILE__,__LINE__,muduo::Logger::DEBUG,__func__).stream() 122 | 123 | #define LOG_INFO if(muduo::Logger::logLevel()<=muduo::Logger::INFO) \ 124 | muduo::Logger(__FILE__,__LINE__).stream() 125 | 126 | 127 | #define LOG_WARM muduo::Logger(__FILE__,__LINE__,muduo::Logger::WARN).stream() 128 | 129 | #define LOG_ERROR muduo::Logger(__FILE__,__LINE__,muduo::Logger::ERROR).stream() 130 | 131 | //#define LOG_FATAL muduo::Logger(__FILE__,__LINE__,muduo::Logger::FATAL,__func__).stream() 132 | 133 | #define LOG_FATAL muduo::Logger(__FILE__,__LINE__,muduo::Logger::FATAL).stream() 134 | #define LOG_SYSERR muduo::Logger(__FILE__,__LINE__, false).stream() 135 | 136 | #define LOG_SYSFATAL muduo::Logger(__FILE__,__LINE__,true).stream() 137 | 138 | const char *strerror_tl(int savedErrno);//返回savedErrno对应的字符串描述. 139 | 140 | #define CHECK_NOTNULL(val) \ 141 | ::muduo::CheckNotNull(__FILE__,__LINE__," '"#val"'must be non NULL ",(val)) 142 | 143 | template 144 | T *CheckNotNull(Logger::SourceFile file, int line, const char *names, T *ptr) 145 | { 146 | if (ptr == nullptr) 147 | Logger(file, line, Logger::FATAL).stream() << names; 148 | return ptr; 149 | } 150 | 151 | } 152 | #endif //TMUDUO_LOGGING_H 153 | -------------------------------------------------------------------------------- /muduo/log/ProcessInfo.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace muduo 18 | { 19 | namespace detail 20 | { 21 | thread_local int t_numOpenedFiles = 0; 22 | 23 | int fdDirFilter(const struct dirent *d) 24 | { 25 | if (::isdigit(d->d_name[0])) 26 | ++t_numOpenedFiles; 27 | return 0; 28 | } 29 | 30 | thread_local std::vector *t_pids = nullptr; 31 | 32 | int taskDirFilter(const struct dirent *d) 33 | { 34 | if (::isdigit(d->d_name[0])) 35 | t_pids->push_back(atoi(d->d_name)); 36 | return 0; 37 | } 38 | 39 | int scanDir(const char *dirpath, int(*filter)(const struct dirent *)) 40 | { 41 | struct dirent **namelist = nullptr; 42 | int result = ::scandir(dirpath, &namelist, filter, alphasort); 43 | assert(namelist == nullptr); 44 | return result; 45 | } 46 | 47 | ChronoTimestamp g_startTime = ChronoTimestamp::now(); 48 | 49 | int g_clockTicks = static_cast(::sysconf(_SC_CLK_TCK)); 50 | int g_pageSize = static_cast(::sysconf(_SC_PAGE_SIZE)); 51 | } 52 | } 53 | 54 | using namespace muduo; 55 | using namespace muduo::detail; 56 | 57 | pid_t ProcessInfo::pid() 58 | { 59 | return ::getpid(); 60 | } 61 | 62 | std::string ProcessInfo::pidString() 63 | { 64 | char buf[32]; 65 | snprintf(buf, sizeof buf, "%d", pid()); 66 | return buf; 67 | } 68 | 69 | uid_t ProcessInfo::uid() 70 | { 71 | return ::getuid(); 72 | } 73 | 74 | std::string ProcessInfo::username() 75 | { 76 | struct passwd pwd; 77 | struct passwd *result = NULL; 78 | char buf[8192]; 79 | 80 | const char *name = "unknownuser"; 81 | getpwuid_r(uid(), &pwd, buf, sizeof buf, &result); 82 | if (result) 83 | name = pwd.pw_name; 84 | return name; 85 | } 86 | 87 | uid_t ProcessInfo::euid() 88 | { 89 | return ::geteuid(); 90 | } 91 | 92 | ChronoTimestamp ProcessInfo::startTime() 93 | { 94 | return g_startTime; 95 | } 96 | 97 | int ProcessInfo::clockTicksPerSecond() 98 | { 99 | return g_clockTicks; 100 | } 101 | 102 | bool ProcessInfo::isDebugBuild() 103 | { 104 | #ifdef NDEBUG 105 | return false; 106 | #else 107 | return true; 108 | #endif 109 | } 110 | 111 | std::string ProcessInfo::hostname() 112 | { 113 | char buf[256]; 114 | if (::gethostname(buf, sizeof buf) == 0) 115 | { 116 | buf[sizeof(buf) - 1] = '\0'; 117 | return buf; 118 | } else 119 | 120 | return "unknownhost"; 121 | } 122 | 123 | std::string ProcessInfo::procname() 124 | { 125 | return procname(procStat()).as_string(); 126 | } 127 | 128 | StringPiece ProcessInfo::procname(const std::string &stat) 129 | { 130 | StringPiece name; 131 | size_t lp = stat.find('('); 132 | size_t rp = stat.rfind(')'); 133 | 134 | if (lp != std::string::npos && rp != std::string::npos && lp < rp) 135 | name.set(stat.data() + lp + 1, static_cast(rp - lp -1)); 136 | return name; 137 | } 138 | 139 | std::string ProcessInfo::procStatus() 140 | { 141 | std::string result; 142 | FileUtil::readFile("/proc/self/status",65536,&result); 143 | return result; 144 | } 145 | 146 | std::string ProcessInfo::procStat() 147 | { 148 | std::string result; 149 | FileUtil::readFile("/proc/self/stat",65536,&result); 150 | return result; 151 | } 152 | 153 | std::string ProcessInfo::threadStat() 154 | { 155 | char buf[64]; 156 | snprintf(buf,sizeof buf,"/proc/self/task/%ld/stat",(::syscall(SYS_gettid))); 157 | std::string result; 158 | FileUtil::readFile(buf,65536,&result); 159 | return result; 160 | } 161 | 162 | std::string ProcessInfo::exePath() 163 | { 164 | std::string result; 165 | char buf[1024]; 166 | ssize_t n=::readlink("/proc/self/exe",buf,sizeof buf); 167 | if(n>0) 168 | result.assign(buf,n); 169 | return result; 170 | } 171 | 172 | int ProcessInfo::openedFiles() 173 | { 174 | t_numOpenedFiles=0; 175 | scanDir("/proc/self/fd",fdDirFilter); 176 | return t_numOpenedFiles; 177 | } 178 | 179 | int ProcessInfo::maxOpenFiles() 180 | { 181 | struct rlimit rl; 182 | if(::getrlimit(RLIMIT_NOFILE,&rl)) 183 | return openedFiles(); 184 | else 185 | return static_cast(rl.rlim_cur); 186 | } 187 | 188 | 189 | ProcessInfo::CpuTime ProcessInfo::cpuTime() 190 | { 191 | ProcessInfo::CpuTime t; 192 | struct tms tms; 193 | if(::times(&tms)>=0) 194 | { 195 | const double hz= static_cast(clockTicksPerSecond()); 196 | t.userSeconds= static_cast(tms.tms_utime)/hz; 197 | t.systemSeconds= static_cast(tms.tms_stime)/hz; 198 | } 199 | return t; 200 | } 201 | 202 | int ProcessInfo::numThreads() 203 | { 204 | int result=0; 205 | std::string status=procStatus(); 206 | //std::cout<<"*******\nstatus:"< ProcessInfo::threads() 213 | { 214 | std::vectorresult; 215 | t_pids=&result; 216 | scanDir("/proc/self/task",taskDirFilter); 217 | t_pids=NULL; 218 | std::sort(result.begin(),result.end()); 219 | return result; 220 | } 221 | 222 | 223 | -------------------------------------------------------------------------------- /muduo/log/ProcessInfo.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_PROCESSINFO_H 4 | #define TMUDUO_PROCESSINFO_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace muduo 14 | { 15 | namespace ProcessInfo 16 | { 17 | pid_t pid(); 18 | 19 | string pidString(); 20 | 21 | uid_t uid(); 22 | 23 | std::string username(); 24 | 25 | uid_t euid(); 26 | 27 | ChronoTimestamp startTime(); 28 | 29 | int clockTicksPerSecond(); 30 | 31 | int pageSize(); 32 | 33 | bool isDebugBuild(); 34 | 35 | 36 | std::string hostname(); 37 | 38 | std::string procname(); 39 | 40 | StringPiece procname(const std::string &stat); 41 | 42 | 43 | // read /proc/self/stats 44 | std::string procStatus(); 45 | 46 | // read /proc/self/stat 47 | std::string procStat(); 48 | 49 | // read /proc/self/task/tid/stat 50 | std::string threadStat(); 51 | 52 | std::string exePath(); 53 | 54 | int openedFiles(); 55 | 56 | int maxOpenFiles(); 57 | 58 | class CpuTime 59 | { 60 | public: 61 | 62 | CpuTime() : 63 | userSeconds(0.0), systemSeconds(0.0) 64 | 65 | {} 66 | double userSeconds; 67 | double systemSeconds; 68 | }; 69 | 70 | CpuTime cpuTime(); 71 | int numThreads(); 72 | std::vectorthreads(); 73 | } 74 | } 75 | #endif //TMUDUO_PROCESSINFO_H 76 | -------------------------------------------------------------------------------- /muduo/log/SimpeCircularBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | //http://www.cplusplus.com/forum/beginner/176072/ 5 | struct ring_buffer 6 | { 7 | ring_buffer( std::size_t cap ) : buffer(cap) {} 8 | bool empty() const { return sz == 0 ; } 9 | bool full() const { return sz == buffer.size() ; } 10 | 11 | void push( std::string str ) 12 | { 13 | if( last >= buffer.size() ) last = 0 ; 14 | buffer[last] = str ; 15 | ++last ; 16 | if( full() ) first = (first+1) % buffer.size() ; 17 | else ++sz ; 18 | } 19 | 20 | std::string& operator[] ( std::size_t pos ) 21 | { 22 | auto p = ( first + pos ) % buffer.size() ; 23 | return buffer[p] ; 24 | } 25 | 26 | std::ostream& print( std::ostream& stm = std::cout ) const 27 | { 28 | if( first < last ) 29 | for( std::size_t i = first ; i < last ; ++i ) std::cout << buffer[i] << ' ' ; 30 | else 31 | { 32 | for( std::size_t i = first ; i < buffer.size() ; ++i ) std::cout << buffer[i] << ' ' ; 33 | for( std::size_t i = 0 ; i < last ; ++i ) std::cout << buffer[i] << ' ' ; 34 | } 35 | return stm ; 36 | } 37 | 38 | private: 39 | std::vector buffer ; 40 | std::size_t first = 0 ; 41 | std::size_t last = 0 ; 42 | std::size_t sz = 0 ; 43 | }; 44 | 45 | int main() 46 | { 47 | ring_buffer rb(8) ; 48 | 49 | for( int i = 10 ; i < 30 ; ++i ) 50 | { 51 | rb.push( std::to_string(i) ) ; 52 | rb.print() << '\n' ; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /muduo/log/tests/AsyncLogging_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int kRollSize = 500 * 1000 * 1000; 8 | 9 | muduo::AsyncLogging *g_asyncLog = NULL; 10 | 11 | void asyncOutput(const char *msg, int len) 12 | { 13 | g_asyncLog->append(msg,len); 14 | } 15 | 16 | void bench(bool logLog) 17 | { 18 | muduo::Logger::setOutput(asyncOutput); 19 | int cnt =0; 20 | const int kBatch=1000; 21 | std::string longStr(3000,'x'); 22 | longStr+=" "; 23 | std::string empty=""; 24 | for (int i = 0; i < 30; ++i) 25 | { 26 | muduo::ChronoTimestamp start=muduo::ChronoTimestamp::now(); 27 | for (int j = 0; j < kBatch; ++j) 28 | { 29 | LOG_INFO<<"Hello 0123456789"<<" abcdefghijklmnopqrstuvwxyz " 30 | <<(logLog?longStr:empty)<1; 57 | bench(longlog); 58 | return 0; 59 | } -------------------------------------------------------------------------------- /muduo/log/tests/BlockingQueue_bench.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "muduo/log/BlockingQueue.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | class Bench 16 | { 17 | public: 18 | Bench(int numThreads) 19 | { 20 | for (int i = 0; i < numThreads; ++i) 21 | { 22 | char name[32]; 23 | snprintf(name,sizeof(name),"work thread %d ",i); 24 | vthreads_.emplace_back(new std::thread(std::bind(&Bench::threadFunc,this,i))); 25 | } 26 | }; 27 | 28 | void run(int times) 29 | { 30 | printf("all threads started \n"); 31 | for (int i = 0; i < times; ++i) 32 | { 33 | muduo::ChronoTimestamp now(muduo::ChronoTimestamp::now()); 34 | queue_.put(now); 35 | usleep(1000); 36 | } 37 | } 38 | 39 | void joinAll() 40 | { 41 | for(size_t i=0;ijoin(); 47 | } 48 | private: 49 | 50 | void threadFunc(int i) 51 | { 52 | printf("tid=%ld,started %d\n",(::syscall(SYS_gettid)),i); 53 | std::mapdelays; 54 | bool running=true; 55 | while (running) 56 | { 57 | muduo::ChronoTimestamp t(queue_.take()); 58 | muduo::ChronoTimestamp now(muduo::ChronoTimestamp::now()); 59 | if(muduo::ChronoTimestamp()(muduo::timeDifference(now,t)*1000000); 62 | ++delays[delay]; 63 | } 64 | running=(muduo::ChronoTimestamp()first,it->second); 71 | //this_thread::yield(); 72 | } 73 | 74 | printf("tid=%ld,stopped\n",::syscall(SYS_gettid)); 75 | } 76 | muduo::BlockingQueue queue_; 77 | std::condition_variable cv; 78 | std::vector> vthreads_; 79 | }; 80 | 81 | int main() 82 | { 83 | printf("linux_tid=%d, main pid=%d \n", static_cast(::syscall(SYS_gettid)), ::getpid()); 84 | Bench t(5); 85 | t.run(10000);//主线程put 1M data.无界队列. 86 | t.joinAll(); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /muduo/log/tests/BlockingQueue_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | class Test 15 | { 16 | public: 17 | Test(int numthreads) 18 | { 19 | for (int i = 0; i < numthreads; ++i) 20 | { 21 | char name[32]; 22 | snprintf(name, sizeof name, "work thread %d ", i); 23 | threads_.emplace_back(new std::thread(std::bind(&Test::threadFunc, this))); 24 | printf("%s\n", name); 25 | } 26 | done = true; 27 | cv.notify_one();//显式唤醒等待的条件变量. 28 | cout << "all thread start \n"; 29 | } 30 | 31 | void run(int times) 32 | { 33 | printf("run "); 34 | { 35 | 36 | std::unique_lock lk(mutex_); 37 | while (done != true) 38 | cv.wait(lk, [&] 39 | { return done == true; }); 40 | } 41 | for (int i = 0; i < times; ++i) 42 | { 43 | char buf[32]; 44 | snprintf(buf, sizeof buf, "hello %d", i); 45 | queue_.put(buf); 46 | printf("linux_tid=%d ,put data=%s ,size=%zd\n", static_cast(::syscall(SYS_gettid)), 47 | buf, queue_.size()); 48 | this_thread::yield(); 49 | } 50 | 51 | } 52 | 53 | void joinAll() 54 | { 55 | for (int i = 0; i < threads_.size(); ++i) 56 | { 57 | queue_.put("stop"); 58 | } 59 | for (auto &thr:threads_) 60 | thr->join(); 61 | } 62 | 63 | private: 64 | 65 | void threadFunc() 66 | { 67 | printf("linux_tid=%d ,started\n", static_cast(::syscall(SYS_gettid))); 68 | bool running = true; 69 | while (running) 70 | { 71 | std::string d(queue_.take()); 72 | printf("linux_tid=%d ,get data=%s ,size=%zd \n", static_cast(::syscall(SYS_gettid)), 73 | d.c_str(), queue_.size()); 74 | running = (d != "stop"); 75 | this_thread::yield(); 76 | } 77 | 78 | printf("linux_tid=%d , stopped\n", static_cast(::syscall(SYS_gettid))); 79 | } 80 | 81 | muduo::BlockingQueue queue_; 82 | condition_variable cv; 83 | std::mutex mutex_; 84 | std::vector> threads_; 85 | muduo::Atomic_bool done{false}; 86 | 87 | }; 88 | 89 | void testMove() 90 | { 91 | muduo::BlockingQueue>queue; 92 | queue.put(std::unique_ptr(new int(42))); 93 | std::unique_ptr x=queue.take(); 94 | printf("took %d \n",*x); 95 | 96 | *x=123; 97 | queue.put(std::move(x)); 98 | std::unique_ptry=queue.take(); 99 | printf("took %d \n",*y); 100 | } 101 | 102 | int main() 103 | { 104 | printf("linux_tid=%d, main pid=%d \n", static_cast(::syscall(SYS_gettid)), ::getpid()); 105 | Test t(5); 106 | t.run(1000000);//主线程put 1M data.无界队列. 107 | t.joinAll(); 108 | 109 | testMove(); 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /muduo/log/tests/BlockingQueue_test2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | class Test 16 | { 17 | public: 18 | Test(int numthreads) 19 | { 20 | for (int i = 0; i < numthreads; ++i) 21 | { 22 | char name[32]; 23 | snprintf(name, sizeof name, "work thread %d ", i); 24 | threads_.emplace_back(new std::thread(std::bind(&Test::threadFunc, this))); 25 | printf("%s\n", name); 26 | } 27 | done = true; 28 | cout << "all thread start \n"; 29 | // sleep(1); 30 | } 31 | 32 | void run(int times) 33 | { 34 | printf("run "); 35 | { 36 | 37 | std::unique_lock lk(mutex_); 38 | while (done != true) 39 | cv.wait(lk, [&] 40 | { return done == true; }); 41 | } 42 | for (int i = 0; i < times; ++i) 43 | { 44 | char buf[32]; 45 | snprintf(buf, sizeof buf, "hello %d", i); 46 | queue_.put(buf); 47 | //cout<<"tid=%d "<(::syscall(SYS_gettid)), 49 | getcpptid, buf, queue_.size()); 50 | this_thread::yield(); 51 | } 52 | 53 | } 54 | 55 | void joinAll() 56 | { 57 | for (int i = 0; i < threads_.size(); ++i) 58 | { 59 | queue_.put("stop"); 60 | } 61 | for (auto &thr:threads_) 62 | thr->join(); 63 | } 64 | 65 | private: 66 | 67 | void threadFunc() 68 | { 69 | //cout<<" tid= "<(::syscall(SYS_gettid)), getcpptid); 71 | bool running = true; 72 | while (running) 73 | { 74 | std::string d(queue_.take()); 75 | //cout<<"tid= "<(::syscall(SYS_gettid)), 77 | getcpptid, d.c_str(), queue_.size()); 78 | running = (d != "stop"); 79 | this_thread::yield(); 80 | } 81 | 82 | printf("linux_tid=%d ,tid=%d stopped\n", static_cast(::syscall(SYS_gettid)), getcpptid); 83 | } 84 | 85 | muduo::BlockingQueue queue_; 86 | condition_variable cv; 87 | std::mutex mutex_; 88 | std::vector> threads_; 89 | muduo::Atomic_bool done{false}; 90 | 91 | }; 92 | 93 | int main() 94 | { 95 | //cout<<::getpid()<<" =pid,tid= "<(::syscall(SYS_gettid)), getcpptid); 97 | printf("pid=%d,tid=%d\n\n", ::getpid(), getcpptid); 98 | 99 | Test t(5); 100 | t.run(100); 101 | //sleep(1); 102 | t.joinAll(); 103 | 104 | 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /muduo/log/tests/BoundedBlockingQueue_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class Test 13 | { 14 | public: 15 | 16 | Test(int numThreads,int maxsize):queue_(maxsize)//,vthreads_(numThreads) 17 | { 18 | for (int i = 0; i < numThreads; ++i) 19 | { 20 | char name[32]; 21 | snprintf(name ,sizeof name,"work thread %d ",i); 22 | vthreads_.emplace_back(new std::thread(std::bind(&Test::threadFunc,this,i))); 23 | } 24 | done=true; 25 | } 26 | 27 | void run(int times) 28 | { 29 | std::unique_lock g(mutex_); 30 | cv.wait(g,[&]{return done== true;}); 31 | printf("all threads started\n"); 32 | 33 | for (int i = 0; i < times; ++i) 34 | { 35 | char buf[32]; 36 | snprintf(buf,sizeof buf,"hello %d",i); 37 | queue_.put(buf); 38 | printf("tid=%ld,put data=%s,size=%zd\n",::syscall(SYS_gettid),buf,queue_.size()); 39 | } 40 | } 41 | 42 | void joinAll() 43 | { 44 | for (int i = 0; i < vthreads_.size(); ++i) 45 | { 46 | queue_.put("stop"); 47 | } 48 | /* for (int j = 0; j < vthreads_.size(); ++j) 49 | { 50 | vthreads_[j]->join(); 51 | }*/ 52 | for(auto &it :vthreads_) 53 | it->join(); 54 | } 55 | private: 56 | 57 | void threadFunc(int i) 58 | { 59 | printf("tid=%ld,%d,started\n",::syscall(SYS_gettid),i); 60 | bool running = true; 61 | 62 | while (running) 63 | { 64 | std::string d(queue_.take()); 65 | printf("tid=%ld,get data=%s ,size=%zd\n",::syscall(SYS_gettid),d.c_str(),queue_.size()); 66 | running=(d!="stop"); 67 | } 68 | printf("tid=%ld,%d,stopped\n",::syscall(SYS_gettid),i); 69 | } 70 | 71 | muduo::Atomic_bool done{false}; 72 | std::mutex mutex_; 73 | muduo::BoundedBlockingQueuequeue_; 74 | std::condition_variable cv; 75 | std::vector> vthreads_; 76 | }; 77 | 78 | int main() 79 | { 80 | printf("pid=%d,tid=%ld\n",::getpid(),::syscall(SYS_gettid)); 81 | Test t(5,10); 82 | t.run(100000); 83 | t.joinAll(); 84 | 85 | } -------------------------------------------------------------------------------- /muduo/log/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_executable(LogStream_test LogStream_test.cpp) 3 | target_link_libraries(LogStream_test muduo_base gtest muduo_log) 4 | 5 | 6 | add_executable(LogStream_bench LogStream_bench.cpp) 7 | target_link_libraries(LogStream_bench muduo_base muduo_log) 8 | 9 | 10 | add_executable(BlockingQueue__test BlockingQueue_test.cpp) 11 | target_link_libraries(BlockingQueue__test muduo_base muduo_log) 12 | 13 | add_executable(BoundedBlockingQueue_test BoundedBlockingQueue_test.cpp) 14 | target_link_libraries(BoundedBlockingQueue_test muduo_base muduo_log) 15 | 16 | 17 | add_executable(BlockingQueue__bench BlockingQueue_bench.cpp) 18 | target_link_libraries(BlockingQueue__bench muduo_base muduo_log) 19 | 20 | 21 | add_executable(FileUtil_test FileUtil_test.cpp) 22 | target_link_libraries(FileUtil_test muduo_log) 23 | 24 | 25 | add_executable(LogFile_test LogFile_test.cpp) 26 | target_link_libraries(LogFile_test muduo_log) 27 | 28 | add_executable(ProcessInfo_test ProcessInfo_test.cpp ) 29 | target_link_libraries(ProcessInfo_test muduo_base muduo_log) 30 | 31 | add_executable(Logging_test Logging_test.cpp ) 32 | target_link_libraries(Logging_test muduo_base muduo_log) 33 | 34 | 35 | 36 | 37 | 38 | add_executable(AsyncLogging_test AsyncLogging_test.cpp ) 39 | target_link_libraries(AsyncLogging_test muduo_base muduo_log ) 40 | 41 | 42 | -------------------------------------------------------------------------------- /muduo/log/tests/FileUtil_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace muduo; 8 | using namespace std; 9 | 10 | /* 11 | * err兼容c的含义. 12 | * */ 13 | int main() 14 | { 15 | string result; 16 | int64_t size=0; 17 | int err = FileUtil::readFile("/proc/self",1024,&result,&size);//Is a directory 18 | printf("%d %zd %ld\n",err,result.size(),size); 19 | 20 | err=FileUtil::readFile("/proc/self",1024,&result,NULL);////Is a directory 21 | printf("%d %zd %ld\n",err,result.size(),size); 22 | 23 | err = FileUtil::readFile("/proc/self/cmdline", 1024, &result, &size);//命令行参数长度大小 24 | printf("%d %zd %ld\n", err, result.size(), size); 25 | 26 | 27 | err = FileUtil::readFile("/dev/null", 1024, &result, &size); 28 | printf("%d %zd %ld\n", err, result.size(), size); 29 | 30 | err = FileUtil::readFile("/dev/zero", 1024, &result, &size); 31 | printf("%d %zd %ld\n", err, result.size(), size); 32 | 33 | err = FileUtil::readFile("/notexist", 1024, &result, &size);//No such file or directory 34 | printf("%d %zd %ld\n", err, result.size(), size); 35 | 36 | err = FileUtil::readFile("/dev/zero", 102400, &result, &size); 37 | printf("%d %zd %ld\n", err, result.size(), size); 38 | 39 | err = FileUtil::readFile("/dev/zero", 102400, &result, NULL); 40 | printf("%d %zd %ld\n", err, result.size(), size); 41 | 42 | err = FileUtil::readFile("FileUtil_test.cpp", 102400, &result, &size); 43 | printf("%d %zd %ld\n--\n", err, result.size(), size); 44 | 45 | std::cout< 4 | #include 5 | #include 6 | #include 7 | 8 | std::unique_ptr g_logfile_ptr; 9 | 10 | void outputFunc(const char *msg, int len) 11 | { 12 | g_logfile_ptr->append(msg,len); 13 | } 14 | 15 | void flushFunc() 16 | { 17 | g_logfile_ptr->flush(); 18 | } 19 | 20 | int main(int argc,char* argv[]) 21 | { 22 | char name[256]; 23 | strncpy(name,argv[0],256); 24 | g_logfile_ptr.reset(new muduo::LogFile(::basename(name),200*1000)); 25 | muduo::Logger::setOutput(outputFunc); 26 | muduo::Logger::setFlush(flushFunc); 27 | std::string line="1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ "; 28 | 29 | //using namespace muduo; 30 | for (int i = 0; i < 10; ++i) 31 | { 32 | LOG_INFO< 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace muduo; 9 | using namespace std; 10 | const size_t N=1000000; 11 | template 12 | void benchPrint(const char *fmt) 13 | { 14 | char buf[32]; 15 | ChronoTimestamp start(ChronoTimestamp::now()); 16 | for (int i = 0; i < N; ++i) 17 | 18 | snprintf(buf,sizeof buf,fmt,(T)(i)); 19 | ChronoTimestamp end(ChronoTimestamp::now()); 20 | printf("benckPrintf %f \n",timeDifference(end,start)); 21 | 22 | } 23 | template 24 | void benchStringStream() 25 | { 26 | ChronoTimestamp start(ChronoTimestamp::now()); 27 | std::ostringstream os; 28 | for (int i = 0; i < N; ++i) 29 | { 30 | os<<(T)(i); 31 | os.seekp(0,std::ios_base::beg); 32 | } 33 | 34 | ChronoTimestamp end(ChronoTimestamp::now()); 35 | 36 | printf("benchStringStream %f \n",timeDifference(end,start)); 37 | } 38 | 39 | template 40 | void benchLogStream() 41 | { 42 | ChronoTimestamp start(ChronoTimestamp::now()); 43 | LogStream os; 44 | for (int i = 0; i < N; ++i) 45 | { 46 | os<<(T)(i); 47 | // if(i% 999==0) 48 | os.resetBuffer(); 49 | } 50 | ChronoTimestamp end(ChronoTimestamp::now()); 51 | printf("benchLogStream %f \n",timeDifference(end,start)); 52 | } 53 | int main() 54 | { 55 | benchPrint("%d"); 56 | 57 | puts("int"); 58 | benchPrint("%d"); 59 | benchStringStream(); 60 | benchLogStream(); 61 | 62 | puts("double"); 63 | benchPrint("%.12g"); 64 | benchStringStream(); 65 | benchLogStream(); 66 | 67 | puts("int64_t"); 68 | benchPrint("%ld"); 69 | benchStringStream(); 70 | benchLogStream(); 71 | 72 | puts("void*"); 73 | benchPrint("%p"); 74 | benchStringStream(); 75 | benchLogStream(); 76 | } 77 | -------------------------------------------------------------------------------- /muduo/log/tests/LogStream_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | //clang++ gtest_main.cc -I./ libgtest.a -pthread -o gtest_main 10 | 11 | GTEST_API_ int main(int argc, char **argv) 12 | { 13 | std::cout << "Running main() from gtest_main.cc\n"; 14 | 15 | //InitGoogleTest会解析参数。RUN_ALL_TESTS会把整个工程里的 16 | // TEST和TEST_F这些函数全部作为测试用例执行一遍。 17 | testing::InitGoogleTest(&argc, argv); 18 | return RUN_ALL_TESTS(); 19 | 20 | } 21 | 22 | TEST(LogStreamtest, bools) 23 | { 24 | muduo::LogStream os; 25 | const muduo::LogStream::Buffer &buf = os.buffer(); 26 | EXPECT_EQ(buf.toString(), string("")); 27 | os << true; 28 | EXPECT_EQ(buf.toString(), "1"); 29 | os << '\n'; 30 | EXPECT_EQ(buf.toString(), "1\n"); 31 | os << false; 32 | EXPECT_EQ(buf.toString(), "1\n0"); 33 | } 34 | 35 | TEST(LogStreamtest, INTeger) 36 | { 37 | muduo::LogStream os; 38 | const muduo::LogStream::Buffer &buf = os.buffer(); 39 | EXPECT_EQ(buf.toString(), string("")); 40 | os << 1; 41 | EXPECT_EQ(buf.toString(), string("1")); 42 | os << 0; 43 | EXPECT_EQ(buf.toString(), string("10")); 44 | os << -1; 45 | EXPECT_EQ(buf.toString(), string("10-1")); 46 | 47 | os.resetBuffer(); 48 | 49 | os << 0 << " " << 123 << 'x' << 0x64; 50 | EXPECT_EQ(buf.toString(), string("0 123x100")); 51 | } 52 | 53 | TEST(LogStreamtest, INTLimits) 54 | { 55 | muduo::LogStream os; 56 | const muduo::LogStream::Buffer &buf = os.buffer(); 57 | os << -2147483647; 58 | EXPECT_EQ(buf.toString(), string("-2147483647")); 59 | 60 | os << static_cast(-2147483647 - 1); 61 | 62 | EXPECT_EQ(buf.toString(), string("-2147483647-2147483648")); 63 | 64 | os << ' '; 65 | 66 | os << 2147483647; 67 | EXPECT_EQ(buf.toString(), string("-2147483647-2147483648 2147483647")); 68 | 69 | os.resetBuffer(); 70 | os << std::numeric_limits::min(); 71 | EXPECT_EQ(buf.toString(), string("-32768")); 72 | 73 | os.resetBuffer(); 74 | 75 | os.resetBuffer(); 76 | os << std::numeric_limits::max(); 77 | EXPECT_EQ(buf.toString(), string("32767")); 78 | 79 | os.resetBuffer(); 80 | 81 | os << std::numeric_limits::min(); 82 | EXPECT_EQ(buf.toString(), string("0")); 83 | os.resetBuffer(); 84 | 85 | 86 | os << std::numeric_limits::max(); 87 | EXPECT_EQ(buf.toString(), string("65535")); 88 | os.resetBuffer(); 89 | 90 | 91 | os << std::numeric_limits::min(); 92 | EXPECT_EQ(buf.toString(), string("-2147483648")); 93 | os.resetBuffer(); 94 | 95 | 96 | os << std::numeric_limits::max(); 97 | EXPECT_EQ(buf.toString(), string("2147483647")); 98 | os.resetBuffer(); 99 | 100 | os << std::numeric_limits::min(); 101 | EXPECT_EQ(buf.toString(), string("-9223372036854775808")); 102 | os.resetBuffer(); 103 | 104 | 105 | os << std::numeric_limits::max(); 106 | EXPECT_EQ(buf.toString(), string("18446744073709551615")); 107 | os.resetBuffer(); 108 | 109 | int16_t a = 0; 110 | int32_t b = 0; 111 | int64_t c = 0; 112 | 113 | os << a; 114 | os << b; 115 | os << c; 116 | EXPECT_EQ(buf.toString(), string("000")); 117 | } 118 | 119 | 120 | TEST(LogStreamtest, Floats) 121 | { 122 | muduo::LogStream os; 123 | const muduo::LogStream::Buffer &buf = os.buffer(); 124 | os << 0.0; 125 | EXPECT_EQ(buf.toString(), string("0")); 126 | 127 | os.resetBuffer(); 128 | os << 1.0; 129 | EXPECT_EQ(buf.toString(), string("1")); 130 | 131 | os.resetBuffer(); 132 | os << 0.1; 133 | EXPECT_EQ(buf.toString(), string("0.1")); 134 | os.resetBuffer(); 135 | 136 | os << 0.5; 137 | EXPECT_EQ(buf.toString(), string("0.5")); 138 | os.resetBuffer(); 139 | 140 | os << 0.001; 141 | EXPECT_EQ(buf.toString(), string("0.001")); 142 | os.resetBuffer(); 143 | 144 | double a = 0.1; 145 | os << a; 146 | EXPECT_EQ(buf.toString(), string("0.1")); 147 | os.resetBuffer(); 148 | 149 | double b = 0.23; 150 | os << b; 151 | EXPECT_EQ(buf.toString(), string("0.23")); 152 | 153 | os.resetBuffer(); 154 | os << a + b; 155 | EXPECT_EQ(buf.toString(), string("0.33")); 156 | 157 | os.resetBuffer(); 158 | os << 1.23456789; 159 | EXPECT_EQ(buf.toString(), string("1.23456789")); 160 | os.resetBuffer(); 161 | os << 1.234567890123456789; 162 | EXPECT_EQ(buf.toString(), string("1.23456789012"));//只保留12位. 163 | 164 | os.resetBuffer(); 165 | os << -1.234567890123456789; 166 | EXPECT_EQ(buf.toString(), string("-1.23456789012")); 167 | } 168 | 169 | TEST(LogStreamtest, Void) 170 | { 171 | muduo::LogStream os; 172 | 173 | const muduo::LogStream::Buffer &buf = os.buffer(); 174 | 175 | os << static_cast(0); 176 | 177 | EXPECT_EQ(buf.toString(), string("0x0")); 178 | 179 | os.resetBuffer(); 180 | os << reinterpret_cast(8888); 181 | EXPECT_EQ(buf.toString(), string("0x22B8"));//,hex(8888)=0x22b8。 182 | } 183 | 184 | TEST(LogStreamtest,String) 185 | { 186 | muduo::LogStream os; 187 | const muduo::LogStream::Buffer & buf=os.buffer(); 188 | os<<"Hello"; 189 | EXPECT_EQ(buf.toString(),string("Hello")); 190 | 191 | string s=" \n\0muduo"; 192 | os< 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int g_total; 10 | FILE *g_file; 11 | 12 | std::unique_ptr g_logfile_ptr; 13 | 14 | void dummyOutput(const char *msg, int len) 15 | { 16 | g_total += len; 17 | if (g_file) 18 | fwrite(msg, 1, len, g_file); 19 | else if (g_logfile_ptr) 20 | g_logfile_ptr->append(msg, len); 21 | } 22 | 23 | void bench(const char *type) 24 | { 25 | muduo::Logger::setOutput(dummyOutput); 26 | muduo::ChronoTimestamp start(muduo::ChronoTimestamp::now()); 27 | g_total = 0; 28 | int n = 1000 * 1000; 29 | const bool kLongLog = false; 30 | std::string empty=" "; 31 | std::string longStr(3000,'x'); 32 | longStr+=" "; 33 | for (int i = 0; i < n; ++i) 34 | { 35 | LOG_INFO<<"Hello 0123456789"<<" abcdefghijklmnopqrstuvwxyz"<<(kLongLog?longStr:empty)< 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | 10 | 11 | printf("pid= %d\n",muduo::ProcessInfo::pid()); 12 | printf("uid= %d\n",muduo::ProcessInfo::uid()); 13 | printf("euid= %d\n",muduo::ProcessInfo::euid()); 14 | printf("start time= %s\n",muduo::ProcessInfo::startTime().toFormattedString().c_str()); 15 | 16 | printf("hostname= %s \n",muduo::ProcessInfo::hostname().c_str()); 17 | 18 | printf("opened files= %d\n",muduo::ProcessInfo::openedFiles()); 19 | 20 | printf("threads= %zd \n",muduo::ProcessInfo::threads().size()); 21 | printf("num threads= %d \n",muduo::ProcessInfo::numThreads()); 22 | 23 | printf("--\nstatus= %s \n",muduo::ProcessInfo::procStatus().c_str()); 24 | 25 | 26 | 27 | printf("**\nprocStat= %s \n",muduo::ProcessInfo::procStat().c_str()); 28 | printf("**\nexepath= %s \n",muduo::ProcessInfo::exePath().c_str()); 29 | 30 | 31 | 32 | printf("**\nthreadStat= %s \n",muduo::ProcessInfo::threadStat().c_str()); 33 | } -------------------------------------------------------------------------------- /muduo/net/Acceptor.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace muduo; 12 | using namespace muduo::net; 13 | 14 | Acceptor::Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reuseport) 15 | : loop_(loop), 16 | acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())), 17 | acceptChannel_(loop, acceptSocket_.fd()), 18 | listenning_(false), 19 | idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) 20 | { 21 | assert(idleFd_ >= 0); 22 | acceptSocket_.setReuseAddr(true); 23 | acceptSocket_.setReusePort(reuseport); 24 | acceptSocket_.bindAddress(listenAddr); 25 | acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this)); 26 | } 27 | 28 | Acceptor::~Acceptor() 29 | { 30 | acceptChannel_.disableAll(); 31 | acceptChannel_.remove(); 32 | ::close(idleFd_); 33 | } 34 | 35 | void Acceptor::listen() 36 | { 37 | loop_->assertInLoopThread(); 38 | listenning_=true; 39 | acceptSocket_.listen(); 40 | acceptChannel_.enableReading(); 41 | } 42 | 43 | void Acceptor::handleRead() 44 | { 45 | loop_->assertInLoopThread(); 46 | InetAddress peerAddr; 47 | int confd=acceptSocket_.accept(&peerAddr); 48 | if(confd>=0) 49 | { 50 | if(newConnectionCallback_) 51 | newConnectionCallback_(confd,peerAddr); 52 | else 53 | sockets::close(confd); 54 | } 55 | else{ 56 | LOG_SYSERR<<"in Acceptor::handleRead"; 57 | if(errno==EMFILE) 58 | { 59 | ::close(idleFd_); 60 | idleFd_=::accept(acceptSocket_.fd(), nullptr, nullptr); 61 | ::close(idleFd_); 62 | idleFd_=::open("dev/null",O_RDONLY| O_CLOEXEC); 63 | } 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /muduo/net/Acceptor.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_ACCEPTOR_H 4 | #define TMUDUO_ACCEPTOR_H 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace muduo 11 | { 12 | namespace net 13 | { 14 | class EventLoop; 15 | 16 | class InetAddress; 17 | 18 | class Acceptor : noncopyable 19 | { 20 | 21 | public: 22 | using NewConnectionCallback =std::function; 23 | 24 | Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reuseport); 25 | 26 | ~Acceptor(); 27 | 28 | 29 | void setNewConnectionCallback(const NewConnectionCallback &cb) 30 | { 31 | newConnectionCallback_=cb; 32 | } 33 | 34 | bool listenning() const 35 | { 36 | return listenning_; 37 | } 38 | 39 | void listen(); 40 | 41 | private: 42 | void handleRead(); 43 | 44 | EventLoop *loop_; 45 | Socket acceptSocket_; 46 | Channel acceptChannel_; 47 | NewConnectionCallback newConnectionCallback_; 48 | bool listenning_; 49 | int idleFd_; 50 | 51 | }; 52 | } 53 | } 54 | #endif //TMUDUO_ACCEPTOR_H 55 | -------------------------------------------------------------------------------- /muduo/net/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(net_SRE 2 | Acceptor.cpp 3 | Channel.cpp 4 | Callbacks.cpp 5 | EventLoop.cpp 6 | InetAddress.cpp 7 | Poller.cpp 8 | SocketsOps.cc 9 | ) 10 | add_subdirectory(poller) 11 | add_library(muduo_net ${net_SRE}) 12 | target_link_libraries(muduo_net muduo_log muduo_base muduo_poller muduo_timer) 13 | 14 | install(TARGETS muduo_net DESTINATION lib) 15 | 16 | file(GLOB HEADERS "*.h") 17 | install(FILES ${HEADERS} DESTINATION include/muduo/net) 18 | if (NOT CMAKE_BUILD_NO_EXAMPLES) 19 | add_subdirectory(tests) 20 | endif () -------------------------------------------------------------------------------- /muduo/net/Callbacks.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "Callbacks.h" 4 | -------------------------------------------------------------------------------- /muduo/net/Callbacks.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_CALLBACKS_H 4 | #define TMUDUO_CALLBACKS_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace muduo 12 | { 13 | template 14 | inline T *get_pointer(const std::shared_ptr &ptr) 15 | { 16 | return ptr.get(); 17 | } 18 | 19 | template 20 | inline T *get_pointer(const std::unique_ptr &ptr) 21 | { 22 | return ptr.get(); 23 | } 24 | 25 | 26 | template 27 | inline ::std::shared_ptr down_pointer_cast(const ::std::shared_ptr &f) 28 | { 29 | if (false) 30 | muduo::implicit_cast(0); 31 | #ifndef NDEBUG 32 | assert(f == nullptr || dynamic_cast(get_pointer(f)) != nullptr); 33 | #endif 34 | return ::std::static_pointer_cast(f); 35 | }; 36 | 37 | 38 | namespace net 39 | { 40 | class Buffer; 41 | 42 | class TcpConnection; 43 | 44 | typedef std::shared_ptr TcpConnectionPtr; 45 | typedef std::function TimerCallback; 46 | typedef std::function ConnectionCallback; 47 | typedef std::function CloseCallback; 48 | 49 | typedef std::function WriteCompleteCallback; 50 | typedef std::function HighWaterMarkCallback; 51 | 52 | 53 | void defaultConnectionCallback(const TcpConnectionPtr &, 54 | Buffer *, ChronoTimestamp); 55 | 56 | void defaultMessageCallback(const TcpConnectionPtr &, 57 | Buffer *, ChronoTimestamp receiveTime); 58 | 59 | } 60 | } 61 | #endif //TMUDUO_CALLBACKS_H 62 | -------------------------------------------------------------------------------- /muduo/net/Channel.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | using namespace muduo::net; 12 | 13 | const int Channel::kNoneEvent = 0; 14 | const int Channel::kReadEvent = POLLIN | POLLPRI; 15 | const int Channel::kWriteEvent = POLLOUT; 16 | 17 | Channel::Channel(EventLoop *loop, int fd) 18 | : loop_(loop), fd_(fd), events_(0), index_(-1), logHup_(true), 19 | tied_(false), eventHandling_(false), addedToLoop_(false) 20 | { 21 | } 22 | 23 | Channel::~Channel() 24 | { 25 | assert(!eventHandling_); 26 | assert(!addedToLoop_); 27 | if (loop_->isInLoopThread()) 28 | { 29 | assert(!loop_->hasChannel(this)); 30 | } 31 | } 32 | 33 | void Channel::tie(const std::shared_ptr &obj) 34 | { 35 | tie_ = obj; 36 | loop_->updateChannel(this); 37 | } 38 | 39 | void Channel::update() 40 | { 41 | addedToLoop_ = true; 42 | loop_->updateChannel(this); 43 | } 44 | 45 | void Channel::remove() 46 | { 47 | assert(isNoneEvent()); 48 | addedToLoop_ = false; 49 | loop_->removeChannel(this); 50 | } 51 | 52 | void Channel::handleEvent(ChronoTimestamp receiveTime) 53 | { 54 | std::shared_ptr guard; 55 | if (tied_) 56 | { 57 | guard = tie_.lock(); 58 | if (guard) 59 | { 60 | handleEventWithGuard(receiveTime); 61 | } 62 | } else 63 | { 64 | handleEventWithGuard(receiveTime); 65 | } 66 | } 67 | 68 | void Channel::handleEventWithGuard(ChronoTimestamp receiveTime) 69 | { 70 | eventHandling_ = true; 71 | LOG_TRACE << reventsToString(); 72 | if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) 73 | { 74 | if (logHup_) 75 | { 76 | LOG_WARM << " fd= " << fd_ << " Channel::handle_event() POLLHUP"; 77 | } 78 | if (closeCallback_) 79 | closeCallback_(); 80 | } 81 | if (revents_ & POLLNVAL) 82 | { 83 | LOG_WARM << " fd= " << 84 | fd_ << " Channel::handle_event() POLLNVAL"; 85 | } 86 | 87 | if (revents_ & (POLLERR | POLLNVAL)) 88 | { 89 | if (errorCallback_) 90 | errorCallback_(); 91 | } 92 | 93 | if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) 94 | { 95 | if (readCallback_) 96 | readCallback_(receiveTime); 97 | } 98 | 99 | if (revents_ & POLLOUT) 100 | { 101 | if (writeCallback_) 102 | writeCallback_(); 103 | } 104 | eventHandling_ = false; 105 | } 106 | 107 | std::string Channel::reventsToString() const 108 | { 109 | return eventsToString(fd_, revents_); 110 | } 111 | 112 | std::string Channel::eventsToString() const 113 | { 114 | return eventsToString(fd_, events_); 115 | } 116 | 117 | std::string Channel::eventsToString(int fd, int ev) 118 | { 119 | std::ostringstream oss; 120 | oss << fd << ": "; //文件描述符 121 | if (ev & POLLIN) 122 | oss << "IN "; //可读 0x001 123 | if (ev & POLLPRI) 124 | oss << "PRI ";//紧急可读 0x002 125 | if (ev & POLLOUT) 126 | oss << "OUT ";//可写 0x004 127 | if (ev & POLLHUP) 128 | oss << "HUP ";//挂起 0x0010 129 | if (ev & POLLRDHUP) 130 | oss << "RDHUP ";//对端关闭 0x2000 131 | if (ev & POLLERR) 132 | oss << "ERR ";//错误 0x008 133 | if (ev & POLLNVAL) 134 | oss << "NVAL ";//无效请求:fd未打开.0x0020 135 | 136 | return oss.str().c_str(); 137 | } -------------------------------------------------------------------------------- /muduo/net/Channel.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TMUDUO_CHANNEL_H 3 | #define TMUDUO_CHANNEL_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace muduo 11 | { 12 | namespace net 13 | { 14 | class EventLoop; 15 | 16 | /************************************************* 17 | Channel是selectable IO channel,负责注册与响应IO事件,但不拥有文件描述符fd 18 | 一个Channel只属于一个Eventloop,Channel处理文件描述符的IO事件. 19 | 本质是对文件描述符IO处理事件的抽象 20 | *************************************************/ 21 | class Channel : noncopyable 22 | { 23 | public: 24 | using EventCallback= std::function; 25 | using ReadEventCallback= std::function; 26 | 27 | Channel(EventLoop *loop, int fd);/*构造函数传递一个Eventloop对象,一个文件描述符*/ 28 | 29 | ~Channel(); 30 | 31 | void handleEvent(ChronoTimestamp receiveTime); 32 | 33 | void setReadCallback(const ReadEventCallback &cb) 34 | { 35 | readCallback_ = cb; 36 | } 37 | 38 | void setWriteCallback(const EventCallback &cb) 39 | { 40 | writeCallback_ = cb; 41 | } 42 | 43 | void setCloseCallback(const EventCallback &cb) 44 | { 45 | closeCallback_ = cb; 46 | } 47 | 48 | void setErrorCallback(const EventCallback &cb) 49 | { 50 | errorCallback_ = cb; 51 | } 52 | 53 | //to do: && 54 | 55 | void tie(const std::shared_ptr &); 56 | 57 | int fd() const 58 | { 59 | return fd_; 60 | } 61 | 62 | int events() const 63 | { 64 | return events_; 65 | } 66 | 67 | void set_revents(int revt) 68 | { 69 | revents_ = revt; 70 | } 71 | 72 | bool isNoneEvent() const 73 | { 74 | return events_ == kNoneEvent; 75 | } 76 | 77 | void enableReading() 78 | { 79 | events_ |= kReadEvent; 80 | update(); 81 | } 82 | 83 | void disableReading() 84 | { 85 | events_ &= ~kReadEvent; 86 | update(); 87 | } 88 | 89 | void enableWriting() 90 | { 91 | events_ |= kWriteEvent; 92 | update(); 93 | } 94 | 95 | void disableWriting() 96 | { 97 | events_ &= ~kWriteEvent; 98 | update(); 99 | } 100 | 101 | void disableAll() 102 | { 103 | events_ = kNoneEvent; 104 | update(); 105 | } 106 | 107 | bool isWriting() const 108 | { 109 | return events_ & kWriteEvent; 110 | } 111 | 112 | 113 | bool isReading() const 114 | { 115 | return events_ & kReadEvent; 116 | } 117 | 118 | int index() 119 | { 120 | return index_; 121 | } 122 | 123 | void set_index(int idx) 124 | { 125 | index_ = idx; 126 | } 127 | 128 | 129 | std::string reventsToString() const; 130 | 131 | std::string eventsToString() const; 132 | 133 | void doNotLogHup() 134 | { 135 | logHup_ = false; 136 | }; 137 | 138 | /*Channel 对象所属的loop线程,一个Channel只能属于一个Eventloop*/ 139 | EventLoop *ownerLoop() 140 | { 141 | return loop_; 142 | } 143 | 144 | void remove(); 145 | 146 | private: 147 | static std::string eventsToString(int fd, int ev); 148 | 149 | void update(); /*调用update()导致Eventloop调用updateChannel,注册到loop中*/ 150 | 151 | void handleEventWithGuard(ChronoTimestamp receiveTime); 152 | 153 | static const int kNoneEvent; 154 | static const int kReadEvent; 155 | static const int kWriteEvent; 156 | 157 | EventLoop *loop_; 158 | const int fd_; 159 | 160 | int events_; /*关注的事件*/ 161 | int revents_; /*poll/epoll返回的事件*/ 162 | int index_; /*在poll的事件数组中的序号*/ 163 | 164 | bool logHup_; 165 | 166 | std::weak_ptr tie_; 167 | 168 | bool tied_; 169 | 170 | bool eventHandling_; 171 | 172 | bool addedToLoop_; 173 | 174 | ReadEventCallback readCallback_; 175 | EventCallback writeCallback_; 176 | EventCallback closeCallback_; 177 | EventCallback errorCallback_; 178 | 179 | 180 | }; 181 | 182 | 183 | } 184 | } 185 | 186 | #endif //TMUDUO_CHANNEL_H 187 | -------------------------------------------------------------------------------- /muduo/net/Endian.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_ENDIAN_H 4 | #define TMUDUO_ENDIAN_H 5 | 6 | #include 7 | #include 8 | 9 | //网络字节序是大端. 10 | namespace muduo 11 | { 12 | namespace net 13 | { 14 | namespace sockets 15 | {// be是表示大端,le是表示小端。 16 | inline uint64_t hostToNetWork64(uint64_t hosts64) 17 | { 18 | return htobe64(hosts64); 19 | } 20 | 21 | inline uint32_t hostToNetWork32(uint32_t hosts32) 22 | { 23 | return htobe32(hosts32); 24 | } 25 | 26 | inline uint16_t hostToNetWork16(uint16_t host16) 27 | { 28 | return htobe16(host16); 29 | } 30 | inline uint64_t networkToHost64(uint64_t net64) 31 | { 32 | return be64toh(net64); 33 | } 34 | inline uint32_t networkToHost32(uint32_t net32) 35 | { 36 | return be32toh(net32); 37 | } 38 | 39 | inline uint16_t networkToHost16(uint16_t net16) 40 | { 41 | return be16toh(net16); 42 | } 43 | } 44 | } 45 | } 46 | #endif //TMUDUO_ENDIAN_H 47 | -------------------------------------------------------------------------------- /muduo/net/EventLoop.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace muduo; 16 | using namespace muduo::net; 17 | 18 | namespace 19 | { 20 | thread_local EventLoop *t_loopInThisThread = 0; 21 | const int kPollTimeMs = 10000;//默认10s轮询一次. 22 | 23 | int createEventfd() 24 | { 25 | int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 26 | if (evtfd < 0) 27 | { 28 | LOG_SYSFATAL << "Failed in eventfd"; 29 | abort(); 30 | } 31 | return evtfd; 32 | } 33 | 34 | 35 | class IgnoreSigPipe 36 | { 37 | public: 38 | IgnoreSigPipe() 39 | { 40 | ::signal(SIGPIPE, SIG_IGN); 41 | } 42 | }; 43 | 44 | IgnoreSigPipe initObj; 45 | } 46 | 47 | EventLoop *EventLoop::getEventLoopOfCurrentThread() 48 | { 49 | return t_loopInThisThread; 50 | } 51 | 52 | EventLoop::EventLoop() 53 | : looping_(false), 54 | quit_(false), 55 | eventHandling_(false), 56 | callingPendingFunctors_(false), 57 | iteration_(0), 58 | threadId_(::syscall(SYS_gettid)), 59 | poller_(Poller::newDefaultPoller(this)), 60 | timerQueue_(new TimerQueue(this)), 61 | wakeupFd_(createEventfd()), 62 | wakeupChannel_(new Channel(this, wakeupFd_)), 63 | currentActiveChannel_(nullptr) 64 | { 65 | LOG_DEBUG << "EventLoop created " << this << " in thread " << threadId_; 66 | if (t_loopInThisThread) 67 | LOG_FATAL << "Another EventLoop " << t_loopInThisThread << " exists in this thread " << threadId_; 68 | else 69 | t_loopInThisThread = this; 70 | 71 | wakeupChannel_->setReadCallback( 72 | std::bind(&EventLoop::handleRead, this)); 73 | wakeupChannel_->enableReading(); 74 | } 75 | 76 | 77 | EventLoop::~EventLoop() 78 | { 79 | LOG_DEBUG << "EventLoop " << this << " of thread " << threadId_ << 80 | " destructs in thread " << ::syscall(SYS_gettid); 81 | 82 | wakeupChannel_->disableAll(); 83 | wakeupChannel_->remove(); 84 | 85 | ::close(wakeupFd_); 86 | t_loopInThisThread = nullptr; 87 | } 88 | 89 | void EventLoop::loop()//核心环节 90 | { 91 | assert(!looping_); 92 | assertInLoopThread(); 93 | looping_ = true; 94 | quit_ = false; 95 | LOG_TRACE << "EventLoop " << this << " start looping"; 96 | 97 | 98 | while (!quit_)//调用quit()之后则不再循环 99 | { 100 | activeChannels_.clear();//why? 避免过期. 101 | 102 | pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);//每3秒轮洵一次,返回活跃的通道 103 | ++iteration_; 104 | if (Logger::LogLevel() <= Logger::TRACE) 105 | { 106 | printActiveChannels(); 107 | } 108 | 109 | eventHandling_ = true; 110 | for (ChanneList::iterator it = activeChannels_.begin(); it != activeChannels_.end(); ++it) 111 | { 112 | currentActiveChannel_ = *it; 113 | currentActiveChannel_->handleEvent(pollReturnTime_);//开始处理IO事件。 114 | } 115 | 116 | currentActiveChannel_ = nullptr; 117 | eventHandling_ = false; 118 | doPendingFunctors(); 119 | } 120 | 121 | LOG_TRACE << "EventLoop " << this << " stop looping"; 122 | looping_ = false; 123 | } 124 | 125 | //可以跨线程调用 126 | void EventLoop::quit() 127 | { 128 | quit_ = true; 129 | if (!isInLoopThread()) 130 | wakeup();//why this?  131 | } 132 | 133 | void EventLoop::runInLoop(const Functor &cb) 134 | { 135 | if (isInLoopThread()) 136 | cb(); 137 | else 138 | queueInLoop(cb); 139 | } 140 | 141 | void EventLoop::queueInLoop(const Functor &cb) 142 | { 143 | { 144 | std::lock_guard g(mutex_); 145 | pendingFunctors_.push_back(cb); 146 | } 147 | 148 | if (!isInLoopThread() || callingPendingFunctors_) 149 | wakeup(); 150 | } 151 | 152 | size_t EventLoop::queueSize() 153 | { 154 | std::lock_guard g(mutex_); 155 | return pendingFunctors_.size(); 156 | } 157 | 158 | TimerId EventLoop::runAt(const ChronoTimestamp &time, const TimerCallback &cb) 159 | { 160 | return timerQueue_->addTimer(cb, time, 0.0); 161 | } 162 | 163 | TimerId EventLoop::runAfter(double delay, const TimerCallback &cb) 164 | { 165 | ChronoTimestamp time(addTime(ChronoTimestamp::now(), delay)); 166 | return runAt(time, cb); 167 | } 168 | 169 | TimerId EventLoop::runEvery(double interval, const TimerCallback &cb) 170 | { 171 | ChronoTimestamp time(addTime(ChronoTimestamp::now(), interval)); 172 | return timerQueue_->addTimer(cb, time, interval); 173 | } 174 | 175 | void EventLoop::cancel(TimerId timerId) 176 | { 177 | return timerQueue_->cancel(timerId); 178 | } 179 | 180 | void EventLoop::updateChannel(Channel *channel) 181 | { 182 | assert(channel->ownerLoop() == this); 183 | assertInLoopThread(); 184 | poller_->updateChannel(channel); 185 | } 186 | 187 | void EventLoop::removeChannel(Channel *channel) 188 | { 189 | assert(channel->ownerLoop() == this); 190 | assertInLoopThread(); 191 | if (eventHandling_) 192 | { 193 | assert(currentActiveChannel_ == channel || 194 | std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end()); 195 | } 196 | poller_->removeChannel(channel); 197 | } 198 | 199 | 200 | bool EventLoop::hasChannel(Channel *channel) 201 | { 202 | assert(channel->ownerLoop() == this); 203 | assertInLoopThread(); 204 | return poller_->hasChannel(channel); 205 | } 206 | 207 | void EventLoop::abortNotInLoopThread() 208 | { 209 | LOG_FATAL << "EventLoop::abortNotInLoopThread -EventLoop " << this 210 | << " was created in threadId_= " << threadId_ << ", current thread id =" << ::syscall(SYS_gettid); 211 | } 212 | 213 | void EventLoop::wakeup() 214 | { 215 | uint64_t one = 1; 216 | ssize_t n = sockets::write(wakeupFd_, &one, sizeof(one)); 217 | if (n != sizeof(one)) 218 | LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes insted of 8"; 219 | } 220 | 221 | void EventLoop::handleRead() 222 | { 223 | uint64_t one = 1; 224 | ssize_t n = sockets::read(wakeupFd_, &one, sizeof(one)); 225 | if (n != sizeof(one)) 226 | LOG_ERROR << "EventLoop::handleRead() reads " << n << " bytes instead of 8"; 227 | } 228 | 229 | void EventLoop::doPendingFunctors() 230 | { 231 | std::vector functors; 232 | callingPendingFunctors_ = true; 233 | { 234 | std::lock_guard g(mutex_); 235 | functors.swap(pendingFunctors_); 236 | } 237 | for (size_t i = 0; i < functors.size(); ++i) 238 | { 239 | functors[i](); 240 | } 241 | 242 | callingPendingFunctors_ = false; 243 | } 244 | 245 | void EventLoop::printActiveChannels() const 246 | { 247 | for (auto it = activeChannels_.begin(); it != activeChannels_.end(); ++it) 248 | { 249 | const Channel *ch = *it; 250 | LOG_TRACE << "{" << ch->reventsToString() << "} "; 251 | } 252 | } -------------------------------------------------------------------------------- /muduo/net/EventLoop.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_EVENTLOOP_H 4 | #define TMUDUO_EVENTLOOP_H 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace muduo 18 | { 19 | namespace net 20 | { 21 | class Channel; 22 | 23 | class Poller; 24 | 25 | class TimerQueue; 26 | /************************************************* 27 | EventLoop 事件循环 28 | *************************************************/ 29 | class EventLoop : noncopyable 30 | { 31 | public: 32 | using Functor=std::function; 33 | 34 | EventLoop(); 35 | 36 | ~EventLoop(); 37 | 38 | void loop();//只能在创建EventLoop对象的线程中调用.不能跨线程调用 39 | 40 | void quit(); 41 | 42 | ChronoTimestamp pollReturnTime() const 43 | { 44 | return pollReturnTime_; 45 | } 46 | 47 | int64_t iteration() const 48 | { return iteration_; } 49 | 50 | void runInLoop(const Functor &cb); 51 | 52 | // void runInLoop(Functor &&cb); 53 | 54 | void queueInLoop(const Functor &cb); 55 | 56 | // void queueInLoop(Functor &&cb); 57 | 58 | size_t queueSize() ; 59 | 60 | 61 | TimerId runAt(const ChronoTimestamp &time, const TimerCallback &cb); 62 | 63 | // TimerId runAt(const ChronoTimestamp &time, const TimerCallback &&cb); 64 | 65 | 66 | TimerId runAfter(double delay, const TimerCallback &cb); 67 | 68 | // TimerId runAfter(double delay, const TimerCallback &&cb); 69 | 70 | TimerId runEvery(double interval, const TimerCallback &cb); 71 | 72 | // TimerId runEvery(double interval, const TimerCallback &&cb); 73 | 74 | void cancel(TimerId timerId); 75 | 76 | 77 | void wakeup(); 78 | 79 | void updateChannel(Channel *channel);/*在Poller中添加或者更新Channel*/ 80 | 81 | void removeChannel(Channel *channel);/*在Poller中移除通道*/ 82 | 83 | bool hasChannel(Channel *channel); 84 | 85 | void assertInLoopThread() 86 | { 87 | if (!isInLoopThread()) 88 | abortNotInLoopThread(); 89 | }; 90 | 91 | bool isInLoopThread() const 92 | { 93 | return threadId_ == (::syscall(SYS_gettid)); 94 | } 95 | 96 | bool eventHandling() const 97 | { 98 | return eventHandling_; 99 | } 100 | 101 | void setContext(const boost::any &context) 102 | { 103 | context_ = context; 104 | } 105 | 106 | const boost::any &getContext() const 107 | { 108 | return context_; 109 | } 110 | 111 | boost::any *getMutableContext() 112 | { 113 | return &context_; 114 | } 115 | 116 | static EventLoop *getEventLoopOfCurrentThread(); 117 | 118 | private: 119 | 120 | void abortNotInLoopThread(); 121 | 122 | void handleRead(); 123 | 124 | void doPendingFunctors(); 125 | 126 | void printActiveChannels() const; 127 | 128 | using ChanneList= std::vector ; 129 | 130 | Atomic_bool looping_; 131 | Atomic_bool quit_; 132 | Atomic_bool eventHandling_; 133 | Atomic_bool callingPendingFunctors_; 134 | int64_t iteration_; 135 | const pid_t threadId_;/*当前对象所属线程ID*/ 136 | 137 | ChronoTimestamp pollReturnTime_; 138 | std::unique_ptr poller_; 139 | 140 | std::unique_ptr timerQueue_; 141 | int wakeupFd_; 142 | 143 | std::unique_ptr wakeupChannel_; 144 | 145 | boost::any context_; 146 | 147 | ChanneList activeChannels_;/*Poller返回的活动的Channel*/ 148 | 149 | Channel *currentActiveChannel_;/*当前正在处理的活动Channel,是activeChannels_中的一个*/ 150 | 151 | std::mutex mutex_; 152 | std::vector pendingFunctors_; 153 | 154 | }; 155 | } 156 | } 157 | #endif //TMUDUO_EVENTLOOP_H 158 | -------------------------------------------------------------------------------- /muduo/net/GzipFile.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_GZIPFILE_H 4 | #define TMUDUO_GZIPFILE_H 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace muduo 11 | { 12 | class GzipFile : noncopyable 13 | { 14 | public: 15 | GzipFile(GzipFile &&rhs) 16 | { 17 | rhs.file_ = nullptr; 18 | } 19 | 20 | ~GzipFile() 21 | { 22 | if (file_) 23 | ::gzclose(file_); 24 | } 25 | GzipFile&operator=(GzipFile&& rhs) 26 | { 27 | swap(rhs); 28 | return *this; 29 | } 30 | 31 | bool valid()const 32 | { 33 | return file_!= nullptr; 34 | } 35 | 36 | void swap(GzipFile& rhs) 37 | { 38 | std::swap(file_,rhs.file_); 39 | } 40 | 41 | bool setBuffer(int size) 42 | { 43 | return ::gzbuffer(file_,size)==0; 44 | } 45 | 46 | int read(void* buf,int len) 47 | { 48 | return ::gzread(file_,buf,len); 49 | } 50 | 51 | int write(StringPiece buf) 52 | { 53 | return ::gzwrite(file_,buf.data(),buf.size()); 54 | } 55 | 56 | off_t tell() const 57 | { 58 | return ::gztell(file_); 59 | } 60 | int flush(int f) 61 | { 62 | return ::gzflush(file_,f); 63 | } 64 | 65 | static GzipFile openForRead(StringArg filename) 66 | { 67 | return GzipFile(::gzopen(filename.c_str(),"rbe")); 68 | } 69 | 70 | static GzipFile openForAppend(StringArg filename) 71 | { 72 | return GzipFile(::gzopen(filename.c_str(),"abe")); 73 | } 74 | 75 | static GzipFile openForWriteExclusive(StringArg filename) 76 | { 77 | return GzipFile(::gzopen(filename.c_str(),"wbxe")); 78 | } 79 | 80 | static GzipFile openForWriteTruncate(StringArg filename) 81 | { 82 | return GzipFile(::gzopen(filename.c_str(),"wbe")); 83 | } 84 | 85 | private: 86 | explicit GzipFile(gzFile file) : 87 | file_(file) 88 | {} 89 | 90 | gzFile file_; 91 | }; 92 | } 93 | #endif //TMUDUO_GZIPFILE_H 94 | -------------------------------------------------------------------------------- /muduo/net/How to implement multithread safe singleton in C++11 without using .txt: -------------------------------------------------------------------------------- 1 | http://stackoverflow.com/questions/11711920/how-to-implement-multithread-safe-singleton-in-c11-without-using-mutex 2 | 3 | http://stackoverflow.com/questions/26955001/thread-safe-singleton-in-c11 4 | http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11 5 | 6 | http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/ 7 | 8 | 9 | class Singleton 10 | { 11 | public: 12 | static Singleton & Instance() 13 | { 14 | // Since it's a static variable, if the class has already been created, 15 | // It won't be created again. 16 | // And it **is** thread-safe in C++11. 17 | 18 | static Singleton myInstance; 19 | 20 | // Return a reference to our instance. 21 | return myInstance; 22 | } 23 | 24 | // delete copy and move constructors and assign operators 25 | Singleton(Singleton const&) = delete; // Copy construct 26 | Singleton(Singleton&&) = delete; // Move construct 27 | Singleton& operator=(Singleton const&) = delete; // Copy assign 28 | Singleton& operator=(Singleton &&) = delete; // Move assign 29 | 30 | // Any other public methods 31 | 32 | protected: 33 | Singleton() 34 | { 35 | // Constructor code goes here. 36 | } 37 | 38 | ~Singleton() 39 | { 40 | // Destructor code goes here. 41 | } 42 | 43 | // And any other protected methods. 44 | } -------------------------------------------------------------------------------- /muduo/net/InetAddress.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static const in_addr_t kInaddrAny = INADDR_ANY; 12 | 13 | static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK; 14 | 15 | using namespace muduo; 16 | using namespace muduo::net; 17 | 18 | // struct sockaddr_in 19 | // { 20 | // 21 | // in_port_t sin_port; /* Port number. */ 22 | // struct in_addr sin_addr; /* Internet address. */ 23 | // 24 | // /* Pad to size of `struct sockaddr'. */ 25 | // unsigned char sin_zero[sizeof (struct sockaddr) - 26 | // __SOCKADDR_COMMON_SIZE - 27 | // sizeof (in_port_t) - 28 | // sizeof (struct in_addr)]; 29 | // }; 30 | 31 | // /* Ditto, for IPv6. */ 32 | // struct sockaddr_in6 33 | // { 34 | // in_port_t sin6_port; /* Transport layer port # */ 35 | // uint32_t sin6_flowinfo; /* IPv6 flow information */ 36 | // struct in6_addr sin6_addr; /* IPv6 address */ 37 | // uint32_t sin6_scope_id; /* IPv6 scope-id */ 38 | // }; 39 | // 40 | 41 | 42 | 43 | static_assert(sizeof(InetAddress) == sizeof(struct sockaddr_in6),"InetAddress==sockaddr_in6"); 44 | static_assert(offsetof(sockaddr_in, sin_family) == 0, "sin_family offset 0"); 45 | static_assert(offsetof(sockaddr_in6, sin6_family) == 0, "sin6_family offset 0"); 46 | static_assert(offsetof(sockaddr_in, sin_port) == 2, "sin_port offset 2"); 47 | static_assert(offsetof(sockaddr_in6, sin6_port) == 2, "sin6_port offset 2"); 48 | 49 | InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6) 50 | { 51 | static_assert(offsetof(InetAddress, addr6_) == 0, "addr6_ offset 0"); 52 | static_assert(offsetof(InetAddress, addr_) == 0, "addr_ offset 0"); 53 | if (ipv6) 54 | { 55 | bzero(&addr6_, sizeof(addr6_)); 56 | addr6_.sin6_family = AF_INET6; 57 | in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any; 58 | addr6_.sin6_addr = ip; 59 | addr6_.sin6_port = sockets::hostToNetWork16(port); 60 | } else 61 | { 62 | bzero(&addr_, sizeof(addr_)); 63 | addr_.sin_family = AF_INET; 64 | in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; 65 | addr_.sin_addr.s_addr = sockets::hostToNetWork32(ip); 66 | addr_.sin_port = sockets::hostToNetWork16(port); 67 | } 68 | } 69 | 70 | InetAddress::InetAddress(StringArg ip, uint16_t port, bool ipv6) 71 | { 72 | if (ipv6) 73 | { 74 | bzero(&addr6_, sizeof(addr6_)); 75 | sockets::fromIpPort(ip.c_str(), port, &addr6_); 76 | } else 77 | { 78 | bzero(&addr_, sizeof(addr_)); 79 | sockets::fromIpPort(ip.c_str(), port, &addr_); 80 | } 81 | } 82 | 83 | std::string InetAddress::toIpPort() const 84 | { 85 | char buf[64] = ""; 86 | sockets::toIpPort(buf, sizeof(buf), getSockAddr()); 87 | return buf; 88 | } 89 | 90 | std::string InetAddress::toIp() const 91 | { 92 | char buf[64] = ""; 93 | sockets::toIp(buf, sizeof(buf), getSockAddr()); 94 | return buf; 95 | } 96 | 97 | uint32_t InetAddress::ipNetEndian() const 98 | { 99 | assert(family() == AF_INET); 100 | return addr_.sin_addr.s_addr; 101 | } 102 | 103 | uint16_t InetAddress::toPort() const 104 | { 105 | return sockets::networkToHost16(portNetEndian()); 106 | } 107 | 108 | static thread_local char t_resolveBuffer[64 * 1024]; 109 | 110 | bool InetAddress::resolve(StringArg hostname, InetAddress *out) 111 | { 112 | assert(out!= nullptr); 113 | struct hostent hent; 114 | struct hostent* he= nullptr; 115 | int herrno=0; 116 | bzero(&hent, sizeof(hent)); 117 | int ret=gethostbyname_r(hostname.c_str(),&hent,t_resolveBuffer, sizeof(t_resolveBuffer),&he,&herrno); 118 | if(ret==0&& he!= nullptr) 119 | { 120 | assert(he->h_addrtype==AF_INET && he->h_length== sizeof(uint32_t)); 121 | out->addr_.sin_addr=*reinterpret_cast(he->h_addr_list); 122 | return true; 123 | } 124 | else 125 | { 126 | if(ret) 127 | { 128 | LOG_SYSERR<<"InetAddress::resolve"; 129 | } 130 | return false; 131 | } 132 | } 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /muduo/net/InetAddress.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_INETADDRESS_H 4 | #define TMUDUO_INETADDRESS_H 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace muduo 11 | { 12 | namespace net 13 | { 14 | namespace sockets 15 | { 16 | const struct sockaddr *sockaddr_cast(const struct sockaddr_in6 *addr); 17 | } 18 | 19 | class InetAddress : public muduo::copyable 20 | { 21 | public: 22 | 23 | explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false); 24 | 25 | InetAddress(StringArg ip, uint16_t port, bool ipv6 = false); 26 | 27 | explicit InetAddress(const struct sockaddr_in &addr) 28 | : addr_(addr) 29 | { 30 | } 31 | 32 | explicit InetAddress(const struct sockaddr_in6& addr) 33 | : addr6_(addr) 34 | {} 35 | 36 | sa_family_t family() const 37 | { 38 | return addr_.sin_family; 39 | } 40 | 41 | std::string toIp() const; 42 | 43 | std::string toIpPort() const; 44 | 45 | uint16_t toPort() const; 46 | 47 | const struct sockaddr *getSockAddr() const 48 | { 49 | return sockets::sockaddr_cast(&addr6_); 50 | } 51 | 52 | void setSockAddrInet6(const struct sockaddr_in6 &addr6) 53 | 54 | { 55 | addr6_=addr6; 56 | } 57 | 58 | uint32_t ipNetEndian() const; 59 | 60 | uint16_t portNetEndian() const 61 | { 62 | return addr_.sin_port; 63 | } 64 | 65 | static bool resolve(StringArg hostname, InetAddress *result); 66 | 67 | 68 | private: 69 | union 70 | { 71 | struct sockaddr_in addr_; 72 | struct sockaddr_in6 addr6_; 73 | }; 74 | }; 75 | 76 | 77 | } 78 | 79 | 80 | } 81 | #endif //TMUDUO_INETADDRESS_H 82 | -------------------------------------------------------------------------------- /muduo/net/Poller.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | using namespace muduo; 6 | using namespace muduo::net; 7 | 8 | Poller::Poller(EventLoop *loop) 9 | : ownerLoop_(loop) 10 | {} 11 | 12 | Poller::~Poller() 13 | {} 14 | 15 | bool Poller::hasChannel(Channel *channel) const 16 | { 17 | assertInLoopThread(); 18 | ChannelMap ::const_iterator it=channels_.find(channel->fd()); 19 | return it!=channels_.end() && it->second==channel; 20 | } -------------------------------------------------------------------------------- /muduo/net/Poller.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_POLLER_H 4 | #define TMUDUO_POLLER_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace muduo 12 | { 13 | namespace net 14 | { 15 | class Channel; 16 | 17 | /************************************************* 18 | Poller,不可拷贝, 19 | *************************************************/ 20 | class Poller : noncopyable 21 | { 22 | public: 23 | 24 | using ChannelList=std::vector; 25 | 26 | Poller(EventLoop *loop); 27 | 28 | virtual ~Poller(); 29 | 30 | virtual ChronoTimestamp poll(int timeoutMs, ChannelList *activeChannels)=0; 31 | 32 | virtual void updateChannel(Channel *channel)=0; 33 | 34 | virtual void removeChannel(Channel *channel)=0; 35 | 36 | virtual bool hasChannel(Channel *channel) const; 37 | 38 | static Poller *newDefaultPoller(EventLoop *loop); 39 | 40 | void assertInLoopThread() const 41 | { 42 | ownerLoop_->assertInLoopThread(); 43 | } 44 | 45 | protected: 46 | using ChannelMap=std::map; /*key是文件描述符,value是Channel* */ 47 | ChannelMap channels_; 48 | private: 49 | EventLoop *ownerLoop_; 50 | 51 | }; 52 | } 53 | } 54 | #endif //TMUDUO_POLLER_H 55 | -------------------------------------------------------------------------------- /muduo/net/Sockets.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "Sockets.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace muduo; 14 | using namespace muduo::net; 15 | 16 | Socket::~Socket() 17 | { 18 | sockets::close(sockfd_); 19 | } 20 | 21 | bool Socket::getTcpInfo(struct tcp_info *tcpi) const 22 | { 23 | socklen_t len = sizeof(*tcpi); 24 | bzero(tcpi, len); 25 | return ::getsockopt(sockfd_, SOL_TCP, TCP_INFO, tcpi, &len) == 0; 26 | } 27 | 28 | bool Socket::getTcpInfoString(char *buf, int len) const 29 | { 30 | struct tcp_info tcpi; 31 | bool ok = getTcpInfo(&tcpi); 32 | if (ok) 33 | { 34 | snprintf(buf, len, "unrecovered=%u " 35 | "rto=%u ato=%u snd_mss=%u rcv_mss=%u " 36 | "lost=%u retrans=%u rtt=%u rttvar=%u " 37 | "sshthresh=%u cwnd=%u total_retrans=%u", 38 | tcpi.tcpi_retransmits, 39 | 40 | tcpi.tcpi_rto, 41 | tcpi.tcpi_ato, 42 | tcpi.tcpi_snd_mss, 43 | tcpi.tcpi_rcv_mss, 44 | 45 | tcpi.tcpi_lost, 46 | tcpi.tcpi_retrans, 47 | tcpi.tcpi_rtt, 48 | tcpi.tcpi_rttvar, 49 | 50 | tcpi.tcpi_snd_ssthresh, 51 | tcpi.tcpi_snd_cwnd, 52 | tcpi.tcpi_total_retrans 53 | ); 54 | } 55 | return ok; 56 | } 57 | 58 | void Socket::bindAddress(const InetAddress &localaddr) 59 | { 60 | sockets::bindOrDie(sockfd_, localaddr.getSockAddr()); 61 | } 62 | 63 | void Socket::listen() 64 | { 65 | sockets::listenOrDie(sockfd_); 66 | } 67 | 68 | int Socket::accept(InetAddress *peeraddr) 69 | { 70 | struct sockaddr_in6 addr; 71 | bzero(&addr, sizeof(addr)); 72 | int connfd = sockets::accept(sockfd_, &addr); 73 | if (connfd >= 0) 74 | { 75 | peeraddr->setSockAddrInet6(addr); 76 | } 77 | return connfd; 78 | } 79 | 80 | 81 | void Socket::shutdownWrite() 82 | { 83 | sockets::shutdownWrite(sockfd_); 84 | } 85 | 86 | void Socket::setTcpNoDelay(bool on) 87 | { 88 | int optval = on ? 1 : 0; 89 | ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, &optval, static_cast(sizeof(optval))); 90 | } 91 | 92 | void Socket::setReuseAddr(bool on) 93 | { 94 | int optval = on ? 1 : 0; 95 | ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &optval, static_cast (sizeof(optval))); 96 | } 97 | 98 | void Socket::setReusePort(bool on) 99 | { 100 | int optval = on ? 1 : 0; 101 | int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, &optval, static_cast(sizeof(optval))); 102 | if (ret < 0 && on) 103 | LOG_SYSFATAL << "SO_REUSEPORT failed"; 104 | } 105 | 106 | void Socket::setKeepAlive(bool on) 107 | { 108 | int optval = on ? 1 : 0; 109 | ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, &optval, static_cast(sizeof(optval))); 110 | } 111 | 112 | 113 | -------------------------------------------------------------------------------- /muduo/net/Sockets.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_SOCKETS_H 4 | #define TMUDUO_SOCKETS_H 5 | 6 | #include 7 | 8 | struct tcp_info; 9 | 10 | namespace muduo 11 | { 12 | namespace net 13 | { 14 | class InetAddress; 15 | 16 | class Socket : noncopyable 17 | { 18 | public: 19 | explicit Socket(int sockfd) : 20 | sockfd_(sockfd) 21 | {} 22 | 23 | ~Socket(); 24 | 25 | int fd() const 26 | { 27 | return sockfd_; 28 | } 29 | 30 | bool getTcpInfo(struct tcp_info *) const; 31 | 32 | bool getTcpInfoString(char *buf, int len) const; 33 | 34 | void bindAddress(const InetAddress &localaddr); 35 | 36 | void listen(); 37 | 38 | int accept(InetAddress *peeraddr); 39 | 40 | void shutdownWrite(); 41 | 42 | void setTcpNoDelay(bool on); 43 | void setReuseAddr(bool on); 44 | 45 | void setReusePort(bool on); 46 | void setKeepAlive(bool on); 47 | 48 | private: 49 | const int sockfd_; 50 | }; 51 | } 52 | } 53 | #endif //TMUDUO_SOCKETS_H 54 | -------------------------------------------------------------------------------- /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(sa_family_t family); 27 | 28 | int connect(int sockfd, const struct sockaddr* addr); 29 | void bindOrDie(int sockfd, const struct sockaddr* addr); 30 | void listenOrDie(int sockfd); 31 | int accept(int sockfd, struct sockaddr_in6* 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* addr); 40 | void toIp(char* buf, size_t size, 41 | const struct sockaddr* addr); 42 | 43 | void fromIpPort(const char* ip, uint16_t port, 44 | struct sockaddr_in* addr); 45 | void fromIpPort(const char* ip, uint16_t port, 46 | struct sockaddr_in6* addr); 47 | 48 | int getSocketError(int sockfd); 49 | 50 | const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr); 51 | const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); 52 | struct sockaddr* sockaddr_cast(struct sockaddr_in6* addr); 53 | const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr); 54 | const struct sockaddr_in6* sockaddr_in6_cast(const struct sockaddr* addr); 55 | 56 | struct sockaddr_in6 getLocalAddr(int sockfd); 57 | struct sockaddr_in6 getPeerAddr(int sockfd); 58 | bool isSelfConnect(int sockfd); 59 | 60 | } 61 | } 62 | } 63 | 64 | #endif // MUDUO_NET_SOCKETSOPS_H 65 | -------------------------------------------------------------------------------- /muduo/net/inner class .cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | class Outer 4 | { 5 | public: 6 | Outer(){m_outerInt=0;} 7 | //内部类定义开始 8 | class Inner 9 | { 10 | public: 11 | Inner(){m_innerInt=1;} 12 | void DisplayIn(){cout< 68 | #define METHOD_PROLOGUE(theClass, localClass) \ 69 | theClass* pThis = ((theClass*)((char*)(this) - \ 70 | offsetof(theClass, m_x##localClass))); \ 71 | 72 | using namespace std; 73 | 74 | class Outer 75 | { 76 | public: 77 | Outer(){m_outerInt=0;} 78 | private: 79 | int m_outerInt; 80 | public: 81 | //内部类定义开始 82 | class Inner 83 | { 84 | public: 85 | Inner(){m_innerInt=1;} 86 | private: 87 | int m_innerInt; 88 | public: 89 | void DisplayIn(){cout<m_outerInt=10; 95 | } 96 | } m_xInner; 97 | //End内部类 98 | public: 99 | void DisplayOut(){cout<task_id = 16; 216 |   printf("外围类成员变量值被嵌套类访问并修改之后的值:%d\n",aaaa.task_id); 217 |   aaaa.task_id = aaaa.gh_b.attribute; 218 |   printf("嵌套类访问到外围类成员变量值:%d\n",aaaa.gh_b.parent->task_id); 219 | 220 |    221 | 222 | 输出结果: 223 | 224 | 225 | 226 | 227 | 这里,我们用到一个C++库函数,原型是: 228 | size_t offsetof( 229 | structName, 230 | memberName 231 | ); 232 | 以下是MSDN上的一些介绍: 233 | 234 | Parameters 235 | 236 | structName 237 | Name of the parent data structure. 238 | 239 | memberName 240 | Name of the member in the parent data structure for which to determine the offset. 241 | 242 | Return Value 243 | offsetof returns the offset in bytes of the specified member from the beginning of its parent data structure. It is undefined for bit fields. 244 | 245 | 246 | 247 | 此外,再来介绍一下局部类 248 | 249 |   在一个函数体内定义的类称为局部类。局部类中只能使用它的外围作用域中的对象和函数进行联系,因为外围作用域中的变量与该局部类的对象无关。局部类不能被外部所继承。在定义局部类时需要注意:局部类中不能说明静态成员函数,并且所有成员函数都必须定义在类体内。在实践中,局部类是很少使用的。下面是一个局部类的例子。 250 | 251 | int a; 252 | void fun() 253 | { 254 | static int s; 255 | class A 256 | { 257 |   public: 258 |   void init(int i) 259 | { s = i; } 260 | }; 261 | A 262 | m; 263 | m.init(10); 264 | } 265 |   局部类的另一个用途是用来实现类型转化,如下代码: 266 | 267 | class Interface 268 | { 269 | public: 270 | virtual void Fun() 271 | = 0; 272 | }; 273 | 274 | template 276 | Interface* 277 | MakeAdapter(const T& 278 | obj, const P& 279 | arg) 280 | { 281 | int x; 282 | class Local 283 | : public Interface 284 | { 285 | public: 286 | Local(const T& 287 | obj, const P& 288 | arg) 289 | : 290 | obj_(obj), arg_(arg) {} 291 | virtual void Fun() 292 | { 293 | x 294 | = 100; 295 | obj_.Call(arg_); 296 | } 297 | private: 298 | T 299 | obj_; 300 | P 301 | arg_; 302 | }; 303 | return new Local(obj, 304 | arg); 305 | } 306 | 307 | 308 | */ -------------------------------------------------------------------------------- /muduo/net/move_vector_size.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | static int count = 0; 9 | 10 | /*class test 11 | { 12 | public: 13 | test(int i = 0) 14 | { 15 | value_ = i; 16 | ++count; 17 | cout << "test(),i="<value_=test1.value_; 30 | cout<<"test(test& test) \n"; 31 | } 32 | test(test&& test1 ) 33 | { 34 | *this=std::move(test1); 35 | *this=std::move(test1); 36 | cout<<"test(test&& test) \n"; 37 | } 38 | 39 | test& operator =(const test& test2) 40 | { 41 | this->value_=test2.value_; 42 | cout<<"operator=(test& test1) \n"; 43 | return *this; 44 | } 45 | 46 | test& operator =( test&& test2) 47 | { 48 | *this=std::move(test2); 49 | cout<<"operator=(test& test1) \n"; 50 | return *this; 51 | } 52 | 53 | int value_ = 0; 54 | }; 55 | int main() 56 | { 57 | test t1() 58 | vector v1{1, 2, 3}; 59 | vector v2{9, 8, 7}; 60 | 61 | test i(0); 62 | test j(-1); 63 | 64 | cout<<"**--**\n\n"; 65 | v1.push_back(std::move(j));//此后,对j的值不应该做任何假设. 66 | 67 | i = std::move(v2.back());//此后,对v2.back()的值不应该做任何假设.move没有影响v2的size()大小. 68 | 69 | 70 | cout<<"**print**\n\n"; 71 | for (auto &it:v1) 72 | cout << it.value_ << " ,"; 73 | cout << "\n"; 74 | for (auto &it:v2) 75 | cout << it.value_ << " ,"; 76 | cout << "i=" << i.value_ << " j=" << j.value_ << endl; 77 | 78 | 79 | cout << "------\n"; 80 | 81 | v2.back(); 82 | 83 | for (auto &it:v1) 84 | cout << it.value_ << " ,"; 85 | cout << "\n"; 86 | for (auto &it:v2) 87 | cout << it.value_ << " ,"; 88 | cout << "i=" << i.value_ << " j=" << j.value_ << endl; 89 | 90 | cout << "v2.size()= " << v2.size() << endl; 91 | } 92 | */ 93 | 94 | 95 | class test 96 | { 97 | public: 98 | test() 99 | { 100 | ++count; 101 | cout << "test()" << value_ << " " << count << " \n"; 102 | } 103 | 104 | test(int i = 0) 105 | { 106 | value_ = i; 107 | ++count; 108 | cout << "test(int ),i=" << value_ << " " << count << " \n"; 109 | } 110 | 111 | ~test() 112 | { 113 | 114 | cout << "~test(),i=" << value_ << " " << count << " \n"; 115 | --count; 116 | } 117 | 118 | test(const test &test1) 119 | { 120 | this->value_ = test1.value_; 121 | cout << "test(test& test) \n"; 122 | } 123 | 124 | test(test &&test1) noexcept 125 | { 126 | //*this = std::move(test1); 127 | this->value_=(test1.value_); 128 | cout << "test(test&& test) \n"; 129 | } 130 | 131 | test &operator=(const test &test2) 132 | { 133 | if(&test2==this) 134 | return *this; 135 | this->value_ = test2.value_; 136 | cout << "operator=(test& test1) \n"; 137 | return *this; 138 | } 139 | 140 | test &operator=(test &&test2) noexcept 141 | { 142 | if(&test2==this) 143 | return *this; 144 | this->value_ = std::move(test2.value_); 145 | cout << "operator=(test&& test1) \n"; 146 | return *this; 147 | } 148 | 149 | int value_ = 0; 150 | }; 151 | 152 | int main() 153 | { 154 | test t1(1), t2(2), t3(3), t9(9), t8(8), t7(7); 155 | 156 | vector v1; 157 | v1.push_back(t1); 158 | v1.push_back(t2); 159 | v1.push_back(t3); 160 | vector v2; 161 | v2.push_back(t9); 162 | v2.push_back(t8); 163 | v2.push_back(t7); 164 | 165 | test i(0); 166 | test j(-1); 167 | 168 | cout << "**--**\n\n"; 169 | v1.push_back(std::move(j));//此后,对j的值不应该做任何假设. 170 | 171 | i = std::move(v2.back());//此后,对v2.back()的值不应该做任何假设.move没有影响v2的size()大小. 172 | 173 | 174 | cout << "**print**\n\n"; 175 | for (auto &it:v1) 176 | cout << it.value_ << " ,"; 177 | cout << "\n"; 178 | for (auto &it:v2) 179 | cout << it.value_ << " ,"; 180 | cout << "i=" << i.value_ << " j=" << j.value_ << endl; 181 | 182 | 183 | cout << "------\n"; 184 | 185 | v2.back(); 186 | 187 | for (auto &it:v1) 188 | cout << it.value_ << " ,"; 189 | cout << "\n"; 190 | for (auto &it:v2) 191 | cout << it.value_ << " ,"; 192 | cout << "i=" << i.value_ << " j=" << j.value_ << endl; 193 | 194 | cout << "v2.size()= " << v2.size() << endl; 195 | } 196 | 197 | /*std::vector 要求保存的类型要可以调用”拷贝构造函数“和”赋值运算符函数”。 198 | 4.解决办法 199 | 1、不要在类中用const 成员 200 | 2、不要企图在vector中,使用含有const成员的类型 201 | 3、使用支持C++2011标准的编译器,C++2011标准要求,类型可以“赋值”,或者可以”拷贝“即可。 202 | */ 203 | 204 | 205 | int main1() 206 | { 207 | vector v1{1, 2, 3}; 208 | vector v2{9, 8, 7}; 209 | 210 | int i = 0; 211 | int j = -1; 212 | 213 | v1.push_back(std::move(j));//此后,对j的值不应该做任何假设. 214 | 215 | i = std::move(v2.back());//此后,对v2.back()的值不应该做任何假设.move没有影响v2的size()大小. 216 | 217 | for (auto &it:v1) 218 | cout << it << " ,"; 219 | cout << "\n"; 220 | for (auto &it:v2) 221 | cout << it << " ,"; 222 | cout << "i=" << i << " j=" << j << endl; 223 | 224 | 225 | cout << "------\n"; 226 | 227 | v2.back(); 228 | 229 | for (auto &it:v1) 230 | cout << it << " ,"; 231 | cout << "\n"; 232 | for (auto &it:v2) 233 | cout << it << " ,"; 234 | cout << "i=" << i << " j=" << j << endl; 235 | 236 | cout << "v2.size()= " << v2.size() << endl; 237 | return 0; 238 | } -------------------------------------------------------------------------------- /muduo/net/note-.txt: -------------------------------------------------------------------------------- 1 | %ld 表示输出 64位长整数(long long) 2 | %zd 表示输出size_t 整数 3 | size_t在c99里面 与机器相关的unsigned类型比如 size-t在32位系统下是4个字节 64位下是8个字节 4 | 就是unsigned int 的增强版(可以适应编译环境) -------------------------------------------------------------------------------- /muduo/net/poller/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(poll_src 2 | DefaultPoller.cpp 3 | PollPoller.cpp 4 | ) 5 | add_library(muduo_poller ${poll_src}) 6 | target_link_libraries(muduo_poller muduo_net) 7 | -------------------------------------------------------------------------------- /muduo/net/poller/DefaultPoller.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | using namespace muduo::net; 6 | Poller* Poller::newDefaultPoller(EventLoop *loop) 7 | { 8 | if(::getenv("USE_EPOOL")) 9 | { 10 | return static_cast(0)/*new Poller(loop)*/; 11 | } 12 | else 13 | { 14 | return new PollPoller(loop); 15 | } 16 | } -------------------------------------------------------------------------------- /muduo/net/poller/PollPoller.cpp: -------------------------------------------------------------------------------- 1 | 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 | PollPoller::PollPoller(EventLoop *loop) 14 | : Poller(loop)//,pollfds_() 15 | {}; 16 | 17 | PollPoller::~PollPoller() 18 | {} 19 | 20 | ChronoTimestamp PollPoller::poll(int timeoutMs, ChannelList *activeChannels) 21 | { 22 | int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); 23 | int savedErrno = errno; 24 | 25 | ChronoTimestamp now(ChronoTimestamp::now()); 26 | if (numEvents > 0) 27 | { 28 | LOG_TRACE << numEvents << " events happended"; 29 | fillActivityChannels(numEvents, activeChannels); /*将pollfds_中的事件返回到活动通道中*/ 30 | } else if (numEvents == 0) 31 | { 32 | LOG_TRACE << " nothing happended"; 33 | } else 34 | { 35 | if (savedErrno != EINTR) 36 | { 37 | errno = savedErrno; 38 | LOG_SYSERR << "PollPoller::poll()"; 39 | } 40 | } 41 | return now; 42 | } 43 | 44 | void PollPoller::fillActivityChannels(int numEvents, ChannelList *activeChannels) const 45 | { 46 | for (auto it = pollfds_.begin(); it != pollfds_.end(); ++it) 47 | { 48 | if (it->revents > 0) 49 | { 50 | --numEvents; 51 | auto ch = channels_.find(it->fd); //找到对应的文件描述符 52 | assert(ch != channels_.end()); 53 | Channel *channel = ch->second; //找到对应的Channel 54 | assert(channel->fd() == it->fd); 55 | channel->set_revents(it->revents); //设置poll/epoll的返回事件 56 | activeChannels->push_back(channel); //注册到活动通道中 57 | } 58 | } 59 | } 60 | 61 | void PollPoller::updateChannel(Channel *channel) 62 | { 63 | Poller::assertInLoopThread(); 64 | LOG_TRACE << "fd = " << channel->fd() << " events =" << channel->events(); 65 | if (channel->index() < 0)//说明channel是一个新通道 66 | { 67 | assert(channels_.find(channel->fd()) == channels_.end()); 68 | struct pollfd pfd; 69 | pfd.fd = channel->fd(); 70 | pfd.events = static_cast(channel->events()); 71 | pfd.revents = 0; 72 | pollfds_.push_back(pfd);//pollfds_ -> std::vector; 73 | int idx = static_cast(pollfds_.size() - 1); 74 | channel->set_index(idx); 75 | channels_[pfd.fd] = channel; 76 | } else//说明已有channel通道 77 | { 78 | assert(channels_.find(channel->fd()) != channels_.end()); 79 | assert(channels_[channel->fd()] == channel); 80 | int idx = channel->index(); 81 | assert(0 <= idx && idx < static_cast(pollfds_.size())); 82 | struct pollfd &pfd = pollfds_[idx]; 83 | assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd() - 1); 84 | pfd.events = static_cast(channel->events()); 85 | pfd.revents = 0; 86 | 87 | /*将一个通道暂时更改为不关注事件,但不从Poller中移除,目的:为了removeChannel优化.pfd.fd可以设置为-1(不再关注) */ 88 | if (channel->isNoneEvent()) 89 | pfd.fd = -channel->fd() - 1; 90 | } 91 | } 92 | 93 | 94 | void PollPoller::removeChannel(Channel *channel) 95 | { 96 | Poller::assertInLoopThread(); 97 | LOG_TRACE << "fd= " << channel->fd(); 98 | assert(channels_.find(channel->fd()) != channels_.end()); 99 | assert(channels_[channel->fd()] == channel); 100 | assert(channel->isNoneEvent()); 101 | int idx = channel->index(); 102 | assert(0 <= idx && idx < static_cast(pollfds_.size())); 103 | 104 | const struct pollfd &pfd = pollfds_[idx]; 105 | assert(pfd.fd == -channel->fd() - 1 && pfd.events == channel->events()); 106 | size_t n = channels_.erase(channel->fd()); 107 | assert(n == 1); 108 | if (implicit_cast(idx) == pollfds_.size() - 1) 109 | { 110 | pollfds_.pop_back(); 111 | } else//移除算法,O(1) 112 | { 113 | int channelAtEnd = pollfds_.back().fd; 114 | iter_swap(pollfds_.begin() + idx, pollfds_.end() - 1); 115 | 116 | if (channelAtEnd < 0) //主要是为了下一步更新channels_ -> std::map; 117 | channelAtEnd = -channelAtEnd - 1; //还原fd 118 | 119 | channels_[channelAtEnd]->set_index(idx); 120 | pollfds_.pop_back(); 121 | } 122 | } -------------------------------------------------------------------------------- /muduo/net/poller/PollPoller.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TMUDUO_POLLPOLLER_H 4 | #define TMUDUO_POLLPOLLER_H 5 | 6 | #include 7 | #include 8 | 9 | namespace muduo 10 | { 11 | namespace net 12 | { 13 | class PollPoller : public Poller 14 | { 15 | public: 16 | PollPoller(EventLoop *loop); 17 | 18 | virtual ~PollPoller(); 19 | 20 | virtual ChronoTimestamp poll(int timeoutMs, ChannelList *activeChannels); 21 | 22 | virtual void updateChannel(Channel *channel); 23 | 24 | virtual void removeChannel(Channel *channel); 25 | 26 | private: 27 | void fillActivityChannels(int numEvents, ChannelList *activeChannels) const; 28 | 29 | using PollFdList=std::vector; 30 | PollFdList pollfds_; 31 | }; 32 | } 33 | } 34 | #endif //TMUDUO_POLLPOLLER_H 35 | -------------------------------------------------------------------------------- /muduo/net/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | add_executable(EventLoop_test_simple0 EventLoop_test_simple0.cpp) 4 | target_link_libraries(EventLoop_test_simple0 muduo_net ) 5 | 6 | 7 | add_executable(EventLoop_test_simple1 EventLoop_test_simple1.cpp) 8 | target_link_libraries( EventLoop_test_simple1 muduo_net) 9 | 10 | add_executable(EventLoop_test_simple2 EventLoop_test_simple2.cpp) 11 | target_link_libraries( EventLoop_test_simple2 muduo_net) 12 | 13 | 14 | add_executable(GzipFile_test GzipFile_test.cpp ) 15 | target_link_libraries(GzipFile_test z muduo_net) 16 | -------------------------------------------------------------------------------- /muduo/net/tests/EventLoop_test_simple0.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace muduo; 7 | using namespace muduo::net; 8 | 9 | EventLoop* g_loop; 10 | 11 | void callback() 12 | { 13 | printf("callback():pid=%d ,tid= %ld\n",getpid(),::syscall(SYS_gettid)); 14 | EventLoop anotherLoop;//程序会中断 15 | }; 16 | 17 | void threadFunc() 18 | { 19 | printf("threadfunc():pid=%d ,tid= %ld\n",getpid(),::syscall(SYS_gettid)); 20 | assert(EventLoop::getEventLoopOfCurrentThread()==NULL); 21 | EventLoop loop; 22 | assert(EventLoop::getEventLoopOfCurrentThread()==&loop); 23 | loop.runAfter(3.0,callback); 24 | loop.loop(); 25 | } 26 | 27 | int main() 28 | { 29 | printf("main():pid=%d ,tid= %ld\n",getpid(),::syscall(SYS_gettid)); 30 | assert(EventLoop::getEventLoopOfCurrentThread()==NULL); 31 | EventLoop loop; 32 | assert(EventLoop::getEventLoopOfCurrentThread()==&loop); 33 | std::thread t(threadFunc); 34 | 35 | loop.loop(); 36 | t.join(); 37 | } -------------------------------------------------------------------------------- /muduo/net/tests/EventLoop_test_simple1.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace muduo; 9 | using namespace muduo::net; 10 | using namespace std::placeholders; 11 | EventLoop *g_loop; 12 | int timerfd; 13 | 14 | void timeout(ChronoTimestamp receivetime) 15 | { 16 | printf("time out! \n"); 17 | uint64_t howmany; 18 | //ssize_t read(int fd, void *buf, size_t count); 19 | ::read(timerfd, &howmany, sizeof(howmany)); 20 | g_loop->quit(); 21 | } 22 | 23 | 24 | /* 25 | int timerfd_create(int clockid, int flags); 26 | 27 | int timerfd_settime(int fd, int flags, 28 | const struct itimerspec *new_value, 29 | struct itimerspec *old_value); 30 | 31 | int timerfd_gettime(int fd, struct itimerspec *curr_value); 32 | */ 33 | 34 | int main() 35 | { 36 | EventLoop loop; 37 | 38 | g_loop = &loop; 39 | timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); 40 | 41 | LOG_TRACE << "timerfd= " << timerfd; 42 | Channel *channel(new Channel(&loop, timerfd)); 43 | 44 | //使用Channel响应io事件 45 | channel->setReadCallback(std::bind(timeout, std::placeholders::_1));//,std::placeholders::_1 46 | channel->enableReading();//产生了哪些操作? 47 | 48 | struct itimerspec howlong; 49 | bzero(&howlong, sizeof(howlong)); 50 | 51 | howlong.it_value.tv_sec = 3; 52 | ::timerfd_settime(timerfd, 0, &howlong, nullptr); 53 | 54 | 55 | loop.loop(); 56 | ::close(timerfd); 57 | LOG_TRACE << " done "; 58 | } -------------------------------------------------------------------------------- /muduo/net/tests/EventLoop_test_simple2.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace muduo; 9 | using namespace muduo::net; 10 | using namespace std::placeholders; 11 | EventLoop *g_loop; 12 | int timerfd; 13 | 14 | void timeout(ChronoTimestamp receivetime) 15 | { 16 | printf("time out! \n"); 17 | uint64_t howmany; 18 | ::read(timerfd,&howmany, sizeof(howmany)); 19 | g_loop->quit(); 20 | } 21 | int main() 22 | { 23 | /* EventLoop loop; 24 | g_loop=&loop;*/ 25 | 26 | g_loop=new EventLoop; 27 | EventLoop & loop=*g_loop; 28 | timerfd=::timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK|TFD_CLOEXEC); 29 | Channel *channel(new Channel(&loop,timerfd)); 30 | channel->setReadCallback(std::bind(timeout,std::placeholders::_1));//,std::placeholders::_1 31 | channel->enableReading(); 32 | struct itimerspec howlong; 33 | bzero(&howlong, sizeof(howlong)); 34 | howlong.it_value.tv_sec=3; 35 | ::timerfd_settime(timerfd,0,&howlong, nullptr); 36 | loop.loop(); 37 | ::close(timerfd); 38 | delete g_loop; 39 | // delete channel; 40 | LOG_TRACE<<" done "; 41 | } -------------------------------------------------------------------------------- /muduo/net/tests/GzipFile_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | const char *filename = "gztest.gz"; 9 | ::unlink(filename); 10 | const char data[] = "1234567890||1234567890||1234567890||1234567890\n"; 11 | 12 | { 13 | muduo::GzipFile writer = muduo::GzipFile::openForAppend(filename); 14 | if (writer.valid()) 15 | { 16 | LOG_INFO << "tell " << writer.tell(); 17 | LOG_INFO << "wrote " << writer.write(data); 18 | LOG_INFO << "tell " << writer.tell(); 19 | } 20 | } 21 | 22 | { 23 | printf("\ntest reader \n"); 24 | muduo::GzipFile reader = muduo::GzipFile::openForRead(filename); 25 | if (reader.valid()) 26 | { 27 | char buf[256]; 28 | LOG_INFO << "tell " << reader.tell(); 29 | int nr = reader.read(buf, sizeof buf); 30 | printf("read %d \n", nr); 31 | 32 | if (nr >= 0) 33 | { 34 | buf[nr] = '\0'; 35 | printf("data is: %s", buf); 36 | } 37 | LOG_INFO << "tell " << reader.tell(); 38 | 39 | if(strncmp(buf,data,strlen(data))!=0) 40 | { 41 | printf("failed!!!\n"); 42 | abort(); 43 | } else 44 | printf("PASSED\n"); 45 | } 46 | } 47 | { 48 | muduo::GzipFile writer =muduo::GzipFile::openForWriteExclusive(filename); 49 | if(writer.valid()||errno!= EEXIST) 50 | printf("FAILED \n"); 51 | } 52 | } -------------------------------------------------------------------------------- /muduo/net/tiny_boost_any.cpp: -------------------------------------------------------------------------------- 1 | // See http://www.boost.org/libs/any for Documentation. 2 | 3 | #ifndef BOOST_ANY_INCLUDED 4 | #define BOOST_ANY_INCLUDED 5 | 6 | 7 | #include 8 | 9 | #include "boost/config.hpp" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace boost 25 | { 26 | class any 27 | { 28 | public: // structors 29 | 30 | any() noexcept 31 | : content(0) 32 | { 33 | } 34 | 35 | template 36 | any(const ValueType &value) 37 | : content(new holder(value)) 38 | { 39 | } 40 | 41 | any(const any &other) 42 | : content(other.content ? other.content->clone() : 0) 43 | { 44 | } 45 | 46 | 47 | ~any() noexcept 48 | { 49 | delete content; 50 | } 51 | 52 | public: // modifiers 53 | 54 | any &swap(any &rhs) noexcept 55 | { 56 | std::swap(content, rhs.content); 57 | return *this; 58 | } 59 | 60 | 61 | any &operator=(const any &rhs) 62 | { 63 | any(rhs).swap(*this); 64 | return *this; 65 | } 66 | 67 | // move assignement 68 | any &operator=(any &&rhs) noexcept 69 | { 70 | rhs.swap(*this); 71 | any().swap(rhs); 72 | return *this; 73 | } 74 | 75 | // Perfect forwarding of ValueType 76 | template 77 | any &operator=(ValueType &&rhs) 78 | { 79 | any(static_cast(rhs)).swap(*this); 80 | return *this; 81 | } 82 | 83 | public: // queries 84 | 85 | bool empty() const noexcept 86 | { 87 | return !content; 88 | } 89 | 90 | void clear() noexcept 91 | { 92 | any().swap(*this); 93 | } 94 | 95 | const std::type_info &type() const noexcept 96 | { 97 | return content ? content->type() : std::type_id(nullptr).type_info(); 98 | } 99 | 100 | private: 101 | 102 | class placeholder 103 | { 104 | public: // structors 105 | 106 | virtual ~placeholder() 107 | { 108 | } 109 | 110 | public: // queries 111 | 112 | virtual const std::type_info &type() const noexcept = 0; 113 | 114 | virtual placeholder *clone() const = 0; 115 | 116 | }; 117 | 118 | template 119 | class holder : public placeholder 120 | { 121 | public: // structors 122 | 123 | holder(const ValueType &value) 124 | : held(value) 125 | { 126 | } 127 | 128 | public: // queries 129 | 130 | virtual const std::type_info &type() const noexcept 131 | { 132 | return std::type_id(ValueType).type_info(); 133 | } 134 | 135 | virtual placeholder *clone() const 136 | { 137 | return new holder(held); 138 | } 139 | 140 | public: // representation 141 | 142 | ValueType held; 143 | 144 | private: // intentionally left unimplemented 145 | holder &operator=(const holder &); 146 | }; 147 | 148 | 149 | private: // representation 150 | 151 | template 152 | friend ValueType *any_cast(any *) noexcept; 153 | 154 | template 155 | friend ValueType *unsafe_any_cast(any *) noexcept; 156 | 157 | 158 | placeholder *content; 159 | 160 | }; 161 | 162 | inline void swap(any &lhs, any &rhs) noexcept 163 | { 164 | lhs.swap(rhs); 165 | } 166 | 167 | class bad_any_cast : public std::exception 168 | { 169 | public: 170 | virtual const char *what() const noexcept 171 | { 172 | return "boost::bad_any_cast: failed conversion using boost::any_cast"; 173 | } 174 | }; 175 | 176 | template 177 | ValueType *any_cast(any *operand) noexcept 178 | { 179 | return operand && operand->type() ==std::type_id(ValueType) 180 | ? &static_cast::type *>(operand->content)->held 181 | : 0; 182 | } 183 | 184 | template 185 | inline const ValueType *any_cast(const any *operand) noexcept 186 | { 187 | return any_cast(const_cast(operand)); 188 | } 189 | 190 | template 191 | ValueType any_cast(any &operand) 192 | { 193 | typedef typename remove_reference::type nonref; 194 | 195 | 196 | nonref *result = any_cast(&operand); 197 | if (!result) 198 | boost::throw_exception(bad_any_cast()); 199 | 200 | // Attempt to avoid construction of a temporary object in cases when 201 | // `ValueType` is not a reference. Example: 202 | // `static_cast(*result);` 203 | // which is equal to `std::string(*result);` 204 | typedef typename boost::mpl::if_< 205 | boost::is_reference, 206 | ValueType, 207 | typename boost::add_reference::type 208 | >::type ref_type; 209 | 210 | return static_cast(*result); 211 | } 212 | 213 | template 214 | inline ValueType any_cast(const any &operand) 215 | { 216 | typedef typename remove_reference::type nonref; 217 | return any_cast(const_cast(operand)); 218 | } 219 | 220 | 221 | // Note: The "unsafe" versions of any_cast are not part of the 222 | // public interface and may be removed at any time. They are 223 | // required where we know what type is stored in the any and can't 224 | // use typeid() comparison, e.g., when our types may travel across 225 | // different shared libraries. 226 | template 227 | inline ValueType *unsafe_any_cast(any *operand) noexcept 228 | { 229 | return &static_cast *>(operand->content)->held; 230 | } 231 | 232 | template 233 | inline const ValueType *unsafe_any_cast(const any *operand) noexcept 234 | { 235 | return unsafe_any_cast(const_cast(operand)); 236 | } 237 | } 238 | 239 | // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. 240 | // 241 | // Distributed under the Boost Software License, Version 1.0. (See 242 | // accompanying file LICENSE_1_0.txt or copy at 243 | // http://www.boost.org/LICENSE_1_0.txt) 244 | 245 | #endif 246 | -------------------------------------------------------------------------------- /muduo/timer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(timer_SRE 2 | 3 | Timer.cpp 4 | TimerQueue.cpp 5 | ) 6 | 7 | add_library(muduo_timer ${timer_SRE}) 8 | target_link_libraries(muduo_timer muduo_net) 9 | 10 | install(TARGETS muduo_timer DESTINATION lib) 11 | 12 | file(GLOB HEADERS "*.h") 13 | install(FILES ${HEADERS} DESTINATION include/muduo/timer) 14 | if (NOT CMAKE_BUILD_NO_EXAMPLES) 15 | add_subdirectory(tests) 16 | endif () -------------------------------------------------------------------------------- /muduo/timer/Timer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | using namespace muduo; 5 | using namespace muduo::net; 6 | AtomicInt64 Timer::s_numCreated_(0); 7 | 8 | void Timer::restart(ChronoTimestamp now) 9 | { 10 | if (repeat_) 11 | experation_ = addTime(now,interval_); 12 | else 13 | experation_ = ChronoTimestamp::invalid(); 14 | } 15 | -------------------------------------------------------------------------------- /muduo/timer/Timer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TMUDUO_TIMER_H 3 | #define TMUDUO_TIMER_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace muduo 11 | { 12 | namespace net 13 | { 14 | /************************************************* 15 | Timer是定时器. 16 | *************************************************/ 17 | class Timer : noncopyable 18 | { 19 | public: 20 | Timer(const TimerCallback &cb, ChronoTimestamp when, double interval) 21 | : callback_(cb), 22 | experation_(when), 23 | interval_(interval), 24 | repeat_(interval > 0.0), 25 | sequence_(++s_numCreated_) 26 | { 27 | } 28 | 29 | Timer(TimerCallback &&cb, ChronoTimestamp when, double interval) 30 | : callback_(std::move(cb)), 31 | experation_(when), 32 | interval_(interval), 33 | repeat_(interval > 0.0), 34 | sequence_(++s_numCreated_) 35 | { 36 | } 37 | 38 | void run() 39 | { 40 | callback_(); 41 | } 42 | 43 | ChronoTimestamp expiration() const 44 | { 45 | return experation_; 46 | } 47 | 48 | bool repeat() const 49 | { 50 | return repeat_; 51 | } 52 | 53 | int64_t sequence() const 54 | { 55 | return sequence_; 56 | } 57 | 58 | void restart(ChronoTimestamp now); 59 | 60 | static int64_t numCreated() 61 | { 62 | return s_numCreated_; 63 | } 64 | 65 | 66 | 67 | private: 68 | const TimerCallback callback_; //回调函数 69 | ChronoTimestamp experation_; //下一次超时时间 70 | const double interval_; //超时时间间隔,为0时表示一次性定时器.单位是s 71 | const bool repeat_; 72 | const int64_t sequence_; //定时器序列号 73 | static AtomicInt64 s_numCreated_; 74 | }; 75 | } 76 | } 77 | #endif //TMUDUO_TIMER_H 78 | -------------------------------------------------------------------------------- /muduo/timer/TimerId.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TMUDUO_TIMERID_H 3 | #define TMUDUO_TIMERID_H 4 | 5 | #include 6 | 7 | namespace muduo 8 | { 9 | namespace net 10 | { 11 | class Timer; 12 | /************************************************* 13 | Timer,TimerId,TimerQueue三者是定时器.后两个是内部实现,外部接口只可见到TimerId 14 | *************************************************/ 15 | class TimerId : public muduo::copyable 16 | { 17 | public: 18 | TimerId() 19 | : timer_(nullptr), 20 | sequence_(0) 21 | {} 22 | 23 | TimerId(Timer *timer, int64_t seq) 24 | : timer_(timer), 25 | sequence_(seq) 26 | {} 27 | 28 | friend class TimerQueue; 29 | private: 30 | Timer *timer_; 31 | int64_t sequence_; 32 | }; 33 | } 34 | } 35 | #endif //TMUDUO_TIMERID_H 36 | -------------------------------------------------------------------------------- /muduo/timer/TimerQueue.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace muduo 9 | { 10 | namespace net 11 | { 12 | namespace detail 13 | { 14 | 15 | 16 | int createTimerfd() 17 | { 18 | int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); 19 | if (timerfd < 0) 20 | { 21 | LOG_SYSFATAL << "Failed in timerfd _create"; 22 | } 23 | 24 | return timerfd; 25 | } 26 | 27 | struct timespec howMuchTimeFromNow(ChronoTimestamp when) 28 | { 29 | int64_t microseconds = when.microSecondsSinceEpoch().count() - 30 | ChronoTimestamp::now().microSecondsSinceEpoch().count(); 31 | if (microseconds < 100) 32 | microseconds = 100; 33 | 34 | struct timespec ts; 35 | 36 | ts.tv_sec = static_cast 37 | (microseconds / ChronoTimestamp::kMicroSecondsPerSecond); 38 | ts.tv_nsec = static_cast 39 | (microseconds % ChronoTimestamp::kMicroSecondsPerSecond) * 1000; 40 | return ts; 41 | } 42 | 43 | 44 | void readTimerfd(int timerfd, ChronoTimestamp now) 45 | { 46 | uint64_t howmany; 47 | ssize_t n = ::read(timerfd, &howmany, sizeof howmany); 48 | LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); 49 | if (n != sizeof howmany) 50 | LOG_TRACE << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; 51 | } 52 | 53 | void resetTimerfd(int timerfd, ChronoTimestamp expiration) 54 | { 55 | // /* POSIX.1b structure for timer start values and intervals. */ 56 | // struct itimerspec 57 | // { 58 | // struct timespec it_interval; 59 | // struct timespec it_value; 60 | // }; 61 | struct itimerspec newValue; 62 | struct itimerspec oldValue; 63 | 64 | bzero(&newValue, sizeof newValue); 65 | bzero(&oldValue, sizeof oldValue); 66 | 67 | newValue.it_value = howMuchTimeFromNow(expiration); 68 | int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); 69 | if (ret) 70 | LOG_SYSERR << " timerfd_settime() "; 71 | } 72 | } 73 | } 74 | } 75 | 76 | using namespace muduo; 77 | using namespace muduo::net; 78 | using namespace muduo::net::detail; 79 | 80 | TimerQueue::TimerQueue(EventLoop *loop) 81 | : loop_(loop), timerfd_(createTimerfd()), 82 | timerfdChannel_(loop, timerfd_), 83 | timers_(), 84 | callingExpiredTimers_(false) 85 | { 86 | timerfdChannel_.setReadCallback( 87 | std::bind(&TimerQueue::handleRead, this)); 88 | timerfdChannel_.enableReading(); 89 | } 90 | 91 | TimerQueue::~TimerQueue() 92 | { 93 | timerfdChannel_.disableAll(); 94 | timerfdChannel_.remove(); 95 | ::close(timerfd_); 96 | for (auto it = timers_.begin(); it != timers_.end(); ++it) 97 | { 98 | delete it->second; 99 | } 100 | } 101 | 102 | TimerId TimerQueue::addTimer(const TimerCallback &cb, ChronoTimestamp when, double interval) 103 | { 104 | Timer *timer = new Timer(cb, when, interval); 105 | loop_->runInLoop(std::bind(&TimerQueue::addTimerInLoop, this, timer)); 106 | 107 | return TimerId(timer, timer->sequence()); 108 | } 109 | 110 | void TimerQueue::cancel(TimerId timerId) 111 | { 112 | loop_->runInLoop( 113 | std::bind(&TimerQueue::cancelInLoop, this, timerId) 114 | ); 115 | } 116 | 117 | void TimerQueue::addTimerInLoop(Timer *timer) 118 | { 119 | loop_->assertInLoopThread(); 120 | bool earliestChanged = insert(timer); 121 | if (earliestChanged) 122 | resetTimerfd(timerfd_, timer->expiration()); 123 | } 124 | 125 | void TimerQueue::cancelInLoop(TimerId timerId) 126 | { 127 | loop_->assertInLoopThread(); 128 | assert(timers_.size() == activeTimers_.size()); 129 | ActiveTimer timer(timerId.timer_, timerId.sequence_); 130 | ActiveTimerSet::iterator it = activeTimers_.find(timer); 131 | if (it != activeTimers_.end()) 132 | { 133 | size_t n = timers_.erase(Entry(it->first->expiration(), it->first)); 134 | assert(n == 1); 135 | delete it->first; 136 | activeTimers_.erase(it); 137 | } else if (callingExpiredTimers_) 138 | { 139 | cancelingTimers_.insert(timer); 140 | } 141 | assert(timers_.size() == activeTimers_.size()); 142 | } 143 | 144 | void TimerQueue::handleRead() 145 | { 146 | loop_->assertInLoopThread(); 147 | ChronoTimestamp now(ChronoTimestamp::now()); 148 | readTimerfd(timerfd_, now); 149 | std::vector expired = getExpired(now); 150 | callingExpiredTimers_ = true; 151 | cancelingTimers_.clear(); 152 | 153 | for (auto it = expired.begin(); it != expired.end(); ++it) 154 | { 155 | it->second->run(); 156 | } 157 | callingExpiredTimers_ = false; 158 | reset(expired, now); 159 | } 160 | 161 | std::vector TimerQueue::getExpired(ChronoTimestamp now) 162 | { 163 | assert(timers_.size() == activeTimers_.size()); 164 | std::vector expired; 165 | Entry sentry(now, reinterpret_cast(UINTPTR_MAX));//18446744073709551615UL 166 | auto end = timers_.lower_bound(sentry); 167 | assert(end == timers_.end() || now < end->first); 168 | std::copy(timers_.begin(), end, back_inserter(expired)); 169 | timers_.erase(timers_.begin(), end); 170 | for (auto it = expired.begin(); it != expired.end(); ++it) 171 | { 172 | ActiveTimer timer(it->second, it->second->sequence()); 173 | size_t n = activeTimers_.erase(timer); 174 | assert(n == 1); 175 | } 176 | assert(timers_.size() == activeTimers_.size()); 177 | return expired; 178 | } 179 | 180 | 181 | void TimerQueue::reset(const std::vector &expired, ChronoTimestamp now) 182 | { 183 | ChronoTimestamp nextExpire; 184 | for (auto it = expired.begin(); it != expired.end(); ++it) 185 | { 186 | ActiveTimer timer(it->second, it->second->sequence()); 187 | if (it->second->repeat() 188 | && cancelingTimers_.find(timer) == cancelingTimers_.end() 189 | ) 190 | { 191 | it->second->restart(now); 192 | insert(it->second); 193 | } else 194 | { 195 | delete it->second; 196 | } 197 | } 198 | 199 | if (!timers_.empty()) 200 | { 201 | nextExpire = timers_.begin()->second->expiration(); 202 | } 203 | if (nextExpire.valid()) 204 | { 205 | resetTimerfd(timerfd_, nextExpire); 206 | } 207 | 208 | } 209 | bool TimerQueue::insert(Timer *timer) 210 | { 211 | loop_->assertInLoopThread(); 212 | assert(timers_.size()==activeTimers_.size()); 213 | bool earliestChanged=false; 214 | ChronoTimestamp when=timer->expiration(); 215 | TimerList::iterator it=timers_.begin(); 216 | if(it==timers_.end()|| whenfirst) 217 | earliestChanged=true; 218 | 219 | { 220 | auto result=timers_.insert(Entry(when,timer)); 221 | assert(result.second); 222 | } 223 | { 224 | auto result= activeTimers_.insert(ActiveTimer(timer,timer->sequence())); 225 | assert(result.second); 226 | } 227 | return earliestChanged; 228 | } -------------------------------------------------------------------------------- /muduo/timer/TimerQueue.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TMUDUO_TIMERQUEUE_H 3 | #define TMUDUO_TIMERQUEUE_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace muduo 15 | { 16 | namespace net 17 | { 18 | class EventLoop; 19 | 20 | class Timer; 21 | 22 | class TimerId; 23 | /************************************************* 24 | 定时器队列. 25 | *************************************************/ 26 | class TimerQueue : noncopyable 27 | { 28 | public: 29 | TimerQueue(EventLoop *loop); 30 | 31 | ~TimerQueue(); 32 | 33 | TimerId addTimer(const TimerCallback &cb, ChronoTimestamp when, double interval); 34 | 35 | //TO DO: && 36 | //TimerId addTimer(ChronoTimestamp &&cb, ChronoTimestamp when, double interval); 37 | 38 | void cancel(TimerId timerId); 39 | 40 | 41 | private: 42 | 43 | using Entry= std::pair; 44 | 45 | using TimerList= std::set; 46 | 47 | using ActiveTimer= std::pair; 48 | 49 | using ActiveTimerSet= std::set; 50 | 51 | void addTimerInLoop(Timer *timer); 52 | 53 | void cancelInLoop(TimerId timerId); 54 | 55 | void handleRead(); 56 | 57 | std::vector getExpired(ChronoTimestamp now); 58 | 59 | void reset(const std::vector &expired, ChronoTimestamp now); 60 | 61 | bool insert(Timer *timer); 62 | 63 | EventLoop *loop_; 64 | 65 | const int timerfd_; 66 | Channel timerfdChannel_; 67 | TimerList timers_; 68 | 69 | ActiveTimerSet activeTimers_; 70 | 71 | bool callingExpiredTimers_; 72 | 73 | ActiveTimerSet cancelingTimers_; 74 | 75 | 76 | }; 77 | } 78 | } 79 | 80 | #endif //TMUDUO_TIMERQUEUE_H 81 | -------------------------------------------------------------------------------- /muduo/timer/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_executable(Timer_test Timer_test.cpp ) 3 | target_link_libraries(Timer_test muduo_timer) -------------------------------------------------------------------------------- /muduo/timer/tests/Timer_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace muduo::net; 8 | using namespace muduo; 9 | void f1() 10 | { 11 | cout << "f()...\n"; 12 | } 13 | 14 | void f2() 15 | { 16 | cout << "f2()...\n"; 17 | } 18 | 19 | int main() 20 | { 21 | 22 | Timer t1(f1,ChronoTimestamp::now(), 3); 23 | Timer t2(f2, ChronoTimestamp::now(), 4); 24 | 25 | t1.run(); 26 | t2.run(); 27 | cout<