From 88c05ee2bb3909734554718b8bed8db9e3bd06b9 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 12 Mar 2010 18:47:28 +0000 Subject: [PATCH 001/371] Migrate to CMake. --- CMakeLists.txt | 7 +++ muduo/base/CMakeLists.txt | 6 +++ muduo/base/Types.h | 11 ++++ muduo/base/UtcTime.cc | 34 ++++++++++++ muduo/base/UtcTime.h | 79 ++++++++++++++++++++++++++++ muduo/base/tests/CMakeLists.txt | 3 ++ muduo/base/tests/UtcTime_unittest.cc | 21 ++++++++ 7 files changed, 161 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 muduo/base/CMakeLists.txt create mode 100644 muduo/base/Types.h create mode 100644 muduo/base/UtcTime.cc create mode 100644 muduo/base/UtcTime.h create mode 100644 muduo/base/tests/CMakeLists.txt create mode 100644 muduo/base/tests/UtcTime_unittest.cc diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..106e06de2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.6) + +project(muduo CXX) + +include_directories(${PROJECT_SOURCE_DIR}) +add_subdirectory(muduo/base) +add_subdirectory(muduo/net) diff --git a/muduo/base/CMakeLists.txt b/muduo/base/CMakeLists.txt new file mode 100644 index 000000000..6226d5939 --- /dev/null +++ b/muduo/base/CMakeLists.txt @@ -0,0 +1,6 @@ +set(base_SRCS + UtcTime.cc) + +add_library(muduo_base ${base_SRCS}) + +add_subdirectory(tests) diff --git a/muduo/base/Types.h b/muduo/base/Types.h new file mode 100644 index 000000000..a3deb36db --- /dev/null +++ b/muduo/base/Types.h @@ -0,0 +1,11 @@ +#ifndef MUDUO_BASE_TYPES_H +#define MUDUO_BASE_TYPES_H + +#include +#include +#include + +// typedef __gnu_cxx::__versa_string, std::allocator > string; +typedef __gnu_cxx::__sso_string string; + +#endif diff --git a/muduo/base/UtcTime.cc b/muduo/base/UtcTime.cc new file mode 100644 index 000000000..2d0977587 --- /dev/null +++ b/muduo/base/UtcTime.cc @@ -0,0 +1,34 @@ +#include + +#include +#include +#define __STDC_FORMAT_MACROS +#include + +UtcTime::UtcTime() + : microSecondsSinceEpoch_(0) +{ +} + +UtcTime::UtcTime(int64_t microseconds) + : microSecondsSinceEpoch_(microseconds) +{ +} + +string UtcTime::toString() const +{ + char buf[32] = {0}; + int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond; + int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond; + snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds); + return buf; +} + +UtcTime UtcTime::now() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t seconds = tv.tv_sec; + return UtcTime(seconds * kMicroSecondsPerSecond + tv.tv_usec); +} + diff --git a/muduo/base/UtcTime.h b/muduo/base/UtcTime.h new file mode 100644 index 000000000..bd3d1ebed --- /dev/null +++ b/muduo/base/UtcTime.h @@ -0,0 +1,79 @@ +#ifndef MUDUO_BASE_UTCTIME_H +#define MUDUO_BASE_UTCTIME_H + +#include + +/// +/// Time stamp in UTC. +/// +/// This class is immutable. +/// It's recommended to pass it by value, since it's passed in register on x64. +/// +class UtcTime +{ + public: + /// + /// Constucts an invalid UtcTime. + /// + UtcTime(); + + /// + /// Constucts a UtcTime at specific time + /// + /// @param microSecondsSinceEpoch + explicit UtcTime(int64_t microSecondsSinceEpoch); + + // default copy/assignment are Okay + + string toString() const; + + bool valid() const { return microSecondsSinceEpoch_ > 0; } + + bool before(UtcTime rhs) const + { + return microSecondsSinceEpoch_ < rhs.microSecondsSinceEpoch_; + } + + bool after(UtcTime rhs) const + { + return microSecondsSinceEpoch_ > rhs.microSecondsSinceEpoch_; + } + + bool equals(UtcTime rhs) const + { + return microSecondsSinceEpoch_ == rhs.microSecondsSinceEpoch_; + } + + // for internal usage. + int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; } + + static UtcTime now(); + static const int kMicroSecondsPerSecond = 1000 * 1000; + + private: + int64_t microSecondsSinceEpoch_; +}; + +inline bool operator<(UtcTime lhs, UtcTime rhs) +{ + return lhs.before(rhs); +} + +inline bool operator==(UtcTime lhs, UtcTime rhs) +{ + return lhs.equals(rhs); +} + +/// +/// Gets time difference of two timestamps, result in seconds. +/// +/// @param high, low +/// @return (high-low) in seconds +/// +inline double timeDifference(UtcTime high, UtcTime low) +{ + int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch(); + return static_cast(diff) / UtcTime::kMicroSecondsPerSecond; +} + +#endif diff --git a/muduo/base/tests/CMakeLists.txt b/muduo/base/tests/CMakeLists.txt new file mode 100644 index 000000000..66cfe2ac2 --- /dev/null +++ b/muduo/base/tests/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(utctime_unittest UtcTime_unittest.cc) +target_link_libraries(utctime_unittest muduo_base) + diff --git a/muduo/base/tests/UtcTime_unittest.cc b/muduo/base/tests/UtcTime_unittest.cc new file mode 100644 index 000000000..3fe0979e1 --- /dev/null +++ b/muduo/base/tests/UtcTime_unittest.cc @@ -0,0 +1,21 @@ +#include +#include + +void passByConstReference(const UtcTime& x) +{ + printf("%s\n", x.toString().c_str()); +} + +void passByValue(UtcTime x) +{ + printf("%s\n", x.toString().c_str()); +} + +int main() +{ + UtcTime now(UtcTime::now()); + printf("%s\n", now.toString().c_str()); + passByValue(now); + passByConstReference(now); +} + From fd18e9e0b6b8421130c656cd6ef489ebe076c9b1 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 13 Mar 2010 01:22:05 +0000 Subject: [PATCH 002/371] Add doxygen, move to muduo namespace. --- Doxyfile | 1514 +++++++++++++++++++++++++++++++++++++++++ build.sh | 8 + muduo/base/Types.h | 8 + muduo/base/UtcTime.cc | 3 + muduo/base/UtcTime.h | 4 + 5 files changed, 1537 insertions(+) create mode 100644 Doxyfile create mode 100755 build.sh diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 000000000..6c9257839 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,1514 @@ +# Doxyfile 1.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Muduo + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.1 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../build + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = muduo + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = muduo + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */.svn/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) +# there is already a search function so this one should typically +# be disabled. + +SEARCHENGINE = YES + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..b1b69bc85 --- /dev/null +++ b/build.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +SOURCE_DIR=`pwd` +BUILD_DIR=${BUILD_DIR:-../build} +cd $BUILD_DIR +cmake $SOURCE_DIR +make + diff --git a/muduo/base/Types.h b/muduo/base/Types.h index a3deb36db..921b40998 100644 --- a/muduo/base/Types.h +++ b/muduo/base/Types.h @@ -5,7 +5,15 @@ #include #include +/// +/// The most common stuffs. +/// +namespace muduo +{ + // typedef __gnu_cxx::__versa_string, std::allocator > string; typedef __gnu_cxx::__sso_string string; +} + #endif diff --git a/muduo/base/UtcTime.cc b/muduo/base/UtcTime.cc index 2d0977587..ed5c491ec 100644 --- a/muduo/base/UtcTime.cc +++ b/muduo/base/UtcTime.cc @@ -4,6 +4,9 @@ #include #define __STDC_FORMAT_MACROS #include +#undef __STDC_FORMAT_MACROS + +using namespace muduo; UtcTime::UtcTime() : microSecondsSinceEpoch_(0) diff --git a/muduo/base/UtcTime.h b/muduo/base/UtcTime.h index bd3d1ebed..02eb56301 100644 --- a/muduo/base/UtcTime.h +++ b/muduo/base/UtcTime.h @@ -3,6 +3,9 @@ #include +namespace muduo +{ + /// /// Time stamp in UTC. /// @@ -76,4 +79,5 @@ inline double timeDifference(UtcTime high, UtcTime low) return static_cast(diff) / UtcTime::kMicroSecondsPerSecond; } +} #endif From 856d45c337afca5c6c5fa0ba1f0c49e68cb3957a Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 13 Mar 2010 04:42:07 +0000 Subject: [PATCH 003/371] A third try of muduo. --- CMakeLists.txt | 3 + muduo/base/UtcTime.cc | 5 ++ muduo/base/UtcTime.h | 19 +++++- muduo/base/tests/UtcTime_unittest.cc | 2 + muduo/net/CMakeLists.txt | 14 +++++ muduo/net/Channel.cc | 16 +++++ muduo/net/Channel.h | 43 +++++++++++++ muduo/net/DefaultPoller.cc | 7 +++ muduo/net/EventLoop.cc | 85 ++++++++++++++++++++++++++ muduo/net/EventLoop.h | 58 ++++++++++++++++++ muduo/net/PollPoller.cc | 34 +++++++++++ muduo/net/PollPoller.h | 33 ++++++++++ muduo/net/Poller.cc | 8 +++ muduo/net/Poller.h | 27 ++++++++ muduo/net/Socket.cc | 16 +++++ muduo/net/Socket.h | 35 +++++++++++ muduo/net/Timer.cc | 16 +++++ muduo/net/Timer.h | 50 +++++++++++++++ muduo/net/TimerId.h | 26 ++++++++ muduo/net/TimerQueue.cc | 61 ++++++++++++++++++ muduo/net/TimerQueue.h | 46 ++++++++++++++ muduo/net/tests/CMakeLists.txt | 3 + muduo/net/tests/EventLoop_unittest.cc | 8 +++ muduo/net/tests/TimerQueue_unittest.cc | 6 ++ 24 files changed, 620 insertions(+), 1 deletion(-) create mode 100644 muduo/net/CMakeLists.txt create mode 100644 muduo/net/Channel.cc create mode 100644 muduo/net/Channel.h create mode 100644 muduo/net/DefaultPoller.cc create mode 100644 muduo/net/EventLoop.cc create mode 100644 muduo/net/EventLoop.h create mode 100644 muduo/net/PollPoller.cc create mode 100644 muduo/net/PollPoller.h create mode 100644 muduo/net/Poller.cc create mode 100644 muduo/net/Poller.h create mode 100644 muduo/net/Socket.cc create mode 100644 muduo/net/Socket.h create mode 100644 muduo/net/Timer.cc create mode 100644 muduo/net/Timer.h create mode 100644 muduo/net/TimerId.h create mode 100644 muduo/net/TimerQueue.cc create mode 100644 muduo/net/TimerQueue.h create mode 100644 muduo/net/tests/CMakeLists.txt create mode 100644 muduo/net/tests/EventLoop_unittest.cc create mode 100644 muduo/net/tests/TimerQueue_unittest.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 106e06de2..11fdbcc2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 2.6) project(muduo CXX) +set(CMAKE_CXX_FLAGS + "-g -Wall -Wextra -Werror -Wconversion -Wold-style-cast -Wpointer-arith -Wshadow -Wno-unused-parameter -Wwrite-strings -rdynamic" + ) include_directories(${PROJECT_SOURCE_DIR}) add_subdirectory(muduo/base) add_subdirectory(muduo/net) diff --git a/muduo/base/UtcTime.cc b/muduo/base/UtcTime.cc index ed5c491ec..fd7daafce 100644 --- a/muduo/base/UtcTime.cc +++ b/muduo/base/UtcTime.cc @@ -35,3 +35,8 @@ UtcTime UtcTime::now() return UtcTime(seconds * kMicroSecondsPerSecond + tv.tv_usec); } +UtcTime UtcTime::invalid() +{ + return UtcTime(); +} + diff --git a/muduo/base/UtcTime.h b/muduo/base/UtcTime.h index 02eb56301..0525322ea 100644 --- a/muduo/base/UtcTime.h +++ b/muduo/base/UtcTime.h @@ -7,7 +7,7 @@ namespace muduo { /// -/// Time stamp in UTC. +/// Time stamp in UTC, in microseconds resolution. /// /// This class is immutable. /// It's recommended to pass it by value, since it's passed in register on x64. @@ -50,7 +50,12 @@ class UtcTime // for internal usage. int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; } + /// + /// Get time of now. + /// static UtcTime now(); + static UtcTime invalid(); + static const int kMicroSecondsPerSecond = 1000 * 1000; private: @@ -79,5 +84,17 @@ inline double timeDifference(UtcTime high, UtcTime low) return static_cast(diff) / UtcTime::kMicroSecondsPerSecond; } +/// +/// Add @c seconds to given timestamp. +/// +/// @param high, low +/// @return (high-low) in seconds +/// +inline UtcTime addTime(UtcTime timestamp, double seconds) +{ + int64_t delta = static_cast(seconds * UtcTime::kMicroSecondsPerSecond); + return UtcTime(timestamp.microSecondsSinceEpoch() + delta); +} + } #endif diff --git a/muduo/base/tests/UtcTime_unittest.cc b/muduo/base/tests/UtcTime_unittest.cc index 3fe0979e1..858ab42c9 100644 --- a/muduo/base/tests/UtcTime_unittest.cc +++ b/muduo/base/tests/UtcTime_unittest.cc @@ -1,6 +1,8 @@ #include #include +using muduo::UtcTime; + void passByConstReference(const UtcTime& x) { printf("%s\n", x.toString().c_str()); diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt new file mode 100644 index 000000000..b6d27c57b --- /dev/null +++ b/muduo/net/CMakeLists.txt @@ -0,0 +1,14 @@ +set(net_SRCS + Channel.cc + DefaultPoller.cc + EventLoop.cc + Poller.cc + PollPoller.cc + Socket.cc + Timer.cc + TimerQueue.cc + ) + +add_library(muduo_net ${net_SRCS}) + +add_subdirectory(tests) diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc new file mode 100644 index 000000000..678715f9a --- /dev/null +++ b/muduo/net/Channel.cc @@ -0,0 +1,16 @@ +#include + +using namespace muduo; +using namespace muduo::net; + +Channel::Channel(EventLoop* loop, Socket sock) + : loop_(loop), + sock_(sock), + events_(0) +{ +} + +Channel::~Channel() +{ +} + diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h new file mode 100644 index 000000000..36faa9142 --- /dev/null +++ b/muduo/net/Channel.h @@ -0,0 +1,43 @@ +#ifndef NET_CHANNEL_H +#define NET_CHANNEL_H + +#include + +#include + +namespace muduo +{ +namespace net +{ + +class EventLoop; + +class Channel : boost::noncopyable +{ + public: + Channel(EventLoop* loop, Socket sock); + ~Channel(); + + void handle(int revents); + + /* + int fd() { return fd_; } + void set_fd(int _fd) { fd_ = _fd; } + + int events() { return events_; } + void set_events(int events0) { events_ = events0; } + */ + + EventLoop* getLoop() { return loop_; } + + // void set_loop(EventLoop* loop) { loop_ = loop; } + + private: + EventLoop* loop_; + Socket sock_; + int events_; +}; + +} +} +#endif diff --git a/muduo/net/DefaultPoller.cc b/muduo/net/DefaultPoller.cc new file mode 100644 index 000000000..2e053213b --- /dev/null +++ b/muduo/net/DefaultPoller.cc @@ -0,0 +1,7 @@ +#include +#include + +Poller* Poller::newDefaultPoller() +{ + return new PollPoller; +} diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc new file mode 100644 index 000000000..67700626b --- /dev/null +++ b/muduo/net/EventLoop.cc @@ -0,0 +1,85 @@ +#include + +#include +#include +//#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +EventLoop::EventLoop() + : poller_(Poller::newDefaultPoller()), + timerQueue_(new TimerQueue), + quit_(false) +{ + init(); +} + +EventLoop::~EventLoop() +{ +} + +void EventLoop::loop() +{ + while (!quit_) + { + poller_->poll(1000); + } + /* + while (!quit_) + { + UtcTime now(UtcTime::now()); + UtcTime next(timerQueue_->tick(now)); + int timeout = next.valid() ? static_cast((timeDifference(next, now))*1000) : 1000; + if (timeout <= 0) + { + timeout = 1; + } + + NetLogInfo << "polling " << timeout << NetSend; + poller_->poll(timeout); + } + */ +} + +void EventLoop::quit() +{ + quit_ = true; +} + +void EventLoop::addChannel(Channel* channel) +{ + assert(channel->getLoop() == this); + // channel->set_loop(this); + // poller_->addChannel(channel); +} + +void EventLoop::removeChannel(Channel* channel) +{ + assert(channel->getLoop() == this); + // poller_->removeChannel(channel); +} + +void EventLoop::init() +{ +} + +TimerId EventLoop::runAt(const UtcTime& time, const TimerCallback& cb) +{ + return timerQueue_->schedule(cb, time, 0.0); +} + +TimerId EventLoop::runAfter(double delay, const TimerCallback& cb) +{ + UtcTime time(addTime(UtcTime::now(), delay)); + return runAt(time, cb); +} + +TimerId EventLoop::runEvery(double interval, const TimerCallback& cb) +{ + UtcTime time(addTime(UtcTime::now(), interval)); + return timerQueue_->schedule(cb, time, interval); +} + diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h new file mode 100644 index 000000000..d8c15f594 --- /dev/null +++ b/muduo/net/EventLoop.h @@ -0,0 +1,58 @@ +#ifndef MUDUO_NET_EVENTLOOP_H +#define MUDUO_NET_EVENTLOOP_H + +#include +#include +#include + +#include +#include + +namespace muduo +{ +namespace net +{ + +class Channel; +class Poller; +class TimerQueue; + +/// +/// Reactor, at most one per thread. +/// +class EventLoop : boost::noncopyable +{ + public: + typedef boost::function TimerCallback; + + EventLoop(); + ~EventLoop(); + + /// + /// Loops forever. + /// + void loop(); + + void quit(); + void wakeup(); + + // timers + TimerId runAt(const UtcTime& time, const TimerCallback& cb); + TimerId runAfter(double delay, const TimerCallback& cb); + TimerId runEvery(double interval, const TimerCallback& cb); + void cancel(TimerId timerId); + + void addChannel(Channel* channel); + void removeChannel(Channel* channel); + + private: + void init(); + + boost::scoped_ptr poller_; + boost::scoped_ptr timerQueue_; + bool quit_; /* atomic */ +}; + +} +} +#endif diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc new file mode 100644 index 000000000..e752e0a35 --- /dev/null +++ b/muduo/net/PollPoller.cc @@ -0,0 +1,34 @@ +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +PollPoller::~PollPoller() +{ +} + +void PollPoller::poll(int timeoutMs) +{ + // make a copy + PollFdList pollfds(pollfds_); + int numEvents = ::poll(&*pollfds.begin(), pollfds.size(), timeoutMs); + + for (PollFdList::iterator pfd = pollfds.begin(); + pfd != pollfds.end() && numEvents > 0; ++pfd) + { + if (pfd->revents > 0) + { + --numEvents; + /* + NetLogDebug << "fd:revents " << pfd->fd << " : " << pfd->revents << NetSend; + // assert(0 <= pfd->fd && pfd->fd < static_cast(channels_.size())); + Channel* channel = channels_[pfd->fd]; + assert(channel->fd() == pfd->fd); + channel->handle(pfd->revents); + */ + } + } +} + diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h new file mode 100644 index 000000000..6ddd2b41e --- /dev/null +++ b/muduo/net/PollPoller.h @@ -0,0 +1,33 @@ +#ifndef MUDUO_NET_POLLPOLLER_H +#define MUDUO_NET_POLLPOLLER_H + +#include + +#include + +#include + +namespace muduo +{ +namespace net +{ + +/// +/// IO Multiplexing with poll(2). +/// +class PollPoller : public Poller +{ + public: + + virtual ~PollPoller(); + + virtual void poll(int timeoutMs); + + private: + typedef std::vector PollFdList; + PollFdList pollfds_; +}; + +} +} +#endif diff --git a/muduo/net/Poller.cc b/muduo/net/Poller.cc new file mode 100644 index 000000000..8d342eed3 --- /dev/null +++ b/muduo/net/Poller.cc @@ -0,0 +1,8 @@ +#include + +using namespace muduo; +using namespace muduo::net; + +Poller::~Poller() +{ +} diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h new file mode 100644 index 000000000..6b6945e9c --- /dev/null +++ b/muduo/net/Poller.h @@ -0,0 +1,27 @@ +#ifndef MUDUO_NET_POLLER_H +#define MUDUO_NET_POLLER_H + +#include + +namespace muduo +{ +namespace net +{ + +/// +/// Base class for IO Multiplexing +/// +class Poller : boost::noncopyable +{ + public: + + virtual ~Poller(); + + virtual void poll(int timeoutMs) = 0; + + static Poller* newDefaultPoller(); +}; + +} +} +#endif diff --git a/muduo/net/Socket.cc b/muduo/net/Socket.cc new file mode 100644 index 000000000..0b0d442a8 --- /dev/null +++ b/muduo/net/Socket.cc @@ -0,0 +1,16 @@ +#include + +#include +#include +#include +//#include + +using namespace muduo; +using namespace muduo::net; + +void Socket::setTcpNoDelay(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, + &optval, sizeof optval); +} diff --git a/muduo/net/Socket.h b/muduo/net/Socket.h new file mode 100644 index 000000000..e3d1fe8d7 --- /dev/null +++ b/muduo/net/Socket.h @@ -0,0 +1,35 @@ +#ifndef MUDUO_NET_SOCKET_H +#define MUDUO_NET_SOCKET_H + +namespace muduo +{ +/// +/// TCP networking. +/// +namespace net +{ + +/// +/// Wrapper of socket file descriptor. +/// +class Socket +{ + public: + explicit Socket(int sockfd) + : sockfd_(sockfd) + { } + + int fd() { return sockfd_; } + + /// + /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). + /// + void setTcpNoDelay(bool on); + + private: + int sockfd_; +}; + +} +} +#endif diff --git a/muduo/net/Timer.cc b/muduo/net/Timer.cc new file mode 100644 index 000000000..e555b2b1f --- /dev/null +++ b/muduo/net/Timer.cc @@ -0,0 +1,16 @@ +#include + +using namespace muduo; +using namespace muduo::net; + +void Timer::restart(UtcTime now) +{ + if (repeat_) + { + expiration_ = addTime(now, interval_); + } + else + { + expiration_ = UtcTime::invalid(); + } +} diff --git a/muduo/net/Timer.h b/muduo/net/Timer.h new file mode 100644 index 000000000..5250effdc --- /dev/null +++ b/muduo/net/Timer.h @@ -0,0 +1,50 @@ +#ifndef MUDUO_NET_TIMER_H +#define MUDUO_NET_TIMER_H + +#include + +#include +#include + +#include + +namespace muduo +{ +namespace net +{ + +/// +/// Internal class for timer event. +/// +class Timer : boost::noncopyable +{ + public: + typedef boost::function TimerCallback; + + Timer(const TimerCallback& cb, UtcTime at, double interval) + : cb_(cb), + expiration_(at), + interval_(interval), + repeat_(interval > 0.0) + { } + + void run() const + { + cb_(); + } + + UtcTime expiration() const { return expiration_; } + bool repeat() const { return repeat_; } + + void restart(UtcTime now); + + private: + const TimerCallback cb_; + UtcTime expiration_; + const double interval_; + const bool repeat_; +}; + +} +} +#endif diff --git a/muduo/net/TimerId.h b/muduo/net/TimerId.h new file mode 100644 index 000000000..142f0ee5e --- /dev/null +++ b/muduo/net/TimerId.h @@ -0,0 +1,26 @@ +#ifndef MUDUO_NET_TIMERID_H +#define MUDUO_NET_TIMERID_H + +namespace muduo +{ +namespace net +{ + +class Timer; + +class TimerId +{ + public: + explicit TimerId(Timer* timer) + : value_(timer) + { + } + + private: + Timer* value_; +}; + +} +} + +#endif diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc new file mode 100644 index 000000000..c41f7b075 --- /dev/null +++ b/muduo/net/TimerQueue.cc @@ -0,0 +1,61 @@ +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +TimerQueue::TimerQueue() +{ +} + +TimerQueue::~TimerQueue() +{ + /* + for (Alarms::iterator it(alarms_.begin()); + it != alarms_.end(); + ++it) + { + delete it->second; + } + */ +} + +void TimerQueue::tick(UtcTime now) +{ + /* + while (!alarms_.empty()) + { + Alarms::iterator head(alarms_.begin()); + if (head->first.after(now)) + { + break; + } + else + { + Alarm* alarm = head->second; + alarm->run(); + UtcTime next = alarm->getNextTime(now); + if (next.valid()) + { + alarms_.insert(std::make_pair(next, alarm)); + } + else + { + delete alarm; + } + alarms_.erase(head); + } + } + return alarms_.empty() ? UtcTime() : alarms_.begin()->first; + */ +} + +TimerId TimerQueue::schedule(const TimerCallback& cb, UtcTime at, double interval) +{ + Timer* timer = new Timer(cb, at, interval); + timers_.push_front(timer); + return TimerId(timer); +} + diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h new file mode 100644 index 000000000..f52a15b50 --- /dev/null +++ b/muduo/net/TimerQueue.h @@ -0,0 +1,46 @@ +#ifndef MUDUO_NET_TIMERQUEUE_H +#define MUDUO_NET_TIMERQUEUE_H + +#include + +#include +#include + +#include + +namespace muduo +{ +namespace net +{ + +class Timer; +class TimerId; + +class TimerQueue : boost::noncopyable +{ + public: + typedef boost::function TimerCallback; + + TimerQueue(); + ~TimerQueue(); + + void tick(UtcTime now); + + /// + /// Schedules the callback to be run at given time, + /// repeats if @c interval > 0.0. + /// + TimerId schedule(const TimerCallback& cb, UtcTime at, double interval); + + void cancel(TimerId timerId); + + private: + + // typedef std::multimap Timers; + typedef std::list Timers; + Timers timers_; +}; + +} +} +#endif diff --git a/muduo/net/tests/CMakeLists.txt b/muduo/net/tests/CMakeLists.txt new file mode 100644 index 000000000..ffa0fefd9 --- /dev/null +++ b/muduo/net/tests/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(EventLoop_unittest EventLoop_unittest.cc) +target_link_libraries(EventLoop_unittest muduo_net muduo_base) + diff --git a/muduo/net/tests/EventLoop_unittest.cc b/muduo/net/tests/EventLoop_unittest.cc new file mode 100644 index 000000000..470d2f430 --- /dev/null +++ b/muduo/net/tests/EventLoop_unittest.cc @@ -0,0 +1,8 @@ +#include + +using namespace muduo::net; + +int main() +{ + EventLoop theLoop; +} diff --git a/muduo/net/tests/TimerQueue_unittest.cc b/muduo/net/tests/TimerQueue_unittest.cc new file mode 100644 index 000000000..7318e3984 --- /dev/null +++ b/muduo/net/tests/TimerQueue_unittest.cc @@ -0,0 +1,6 @@ +#include + +int main() +{ + TimerQueue queue; +} From f0f663214bb4e6303d478ac1c49122444bcd957c Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 13 Mar 2010 07:31:39 +0000 Subject: [PATCH 004/371] TimerQueue half done. --- CMakeLists.txt | 2 +- Doxyfile | 2 +- build.sh | 5 +- muduo/base/CMakeLists.txt | 4 +- muduo/base/Mutex.h | 66 +++++++++++++++++++++++++++ muduo/base/Thread.cc | 55 ++++++++++++++++++++++ muduo/base/Thread.h | 34 ++++++++++++++ muduo/base/UtcTime.h | 3 +- muduo/net/Channel.cc | 29 +++++++++++- muduo/net/Channel.h | 31 +++++++++---- muduo/net/EventLoop.cc | 34 ++++++-------- muduo/net/EventLoop.h | 10 +++- muduo/net/PollPoller.cc | 21 ++++----- muduo/net/PollPoller.h | 4 +- muduo/net/Poller.h | 5 +- muduo/net/TimerId.h | 3 ++ muduo/net/TimerQueue.cc | 35 +++++++++++++- muduo/net/TimerQueue.h | 12 +++-- muduo/net/tests/EventLoop_unittest.cc | 3 ++ 19 files changed, 300 insertions(+), 58 deletions(-) create mode 100644 muduo/base/Mutex.h create mode 100644 muduo/base/Thread.cc create mode 100644 muduo/base/Thread.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 11fdbcc2b..714dd72a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.6) project(muduo CXX) set(CMAKE_CXX_FLAGS - "-g -Wall -Wextra -Werror -Wconversion -Wold-style-cast -Wpointer-arith -Wshadow -Wno-unused-parameter -Wwrite-strings -rdynamic" + "-g -Wall -Wextra -Werror -Wconversion -Wold-style-cast -Wpointer-arith -Wshadow -Wno-unused-parameter -Wwrite-strings -rdynamic -lpthread" ) include_directories(${PROJECT_SOURCE_DIR}) add_subdirectory(muduo/base) diff --git a/Doxyfile b/Doxyfile index 6c9257839..352a7ea67 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1400,7 +1400,7 @@ GROUP_GRAPHS = YES # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. -UML_LOOK = YES +UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. diff --git a/build.sh b/build.sh index b1b69bc85..ffc4060f1 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,6 @@ SOURCE_DIR=`pwd` BUILD_DIR=${BUILD_DIR:-../build} -cd $BUILD_DIR -cmake $SOURCE_DIR -make +mkdir -p $BUILD_DIR +cd $BUILD_DIR && cmake $SOURCE_DIR && make diff --git a/muduo/base/CMakeLists.txt b/muduo/base/CMakeLists.txt index 6226d5939..65ef86aa6 100644 --- a/muduo/base/CMakeLists.txt +++ b/muduo/base/CMakeLists.txt @@ -1,5 +1,7 @@ set(base_SRCS - UtcTime.cc) + Thread.cc + UtcTime.cc + ) add_library(muduo_base ${base_SRCS}) diff --git a/muduo/base/Mutex.h b/muduo/base/Mutex.h new file mode 100644 index 000000000..e78461753 --- /dev/null +++ b/muduo/base/Mutex.h @@ -0,0 +1,66 @@ +#ifndef MUDUO_BASE_MUTEX_H +#define MUDUO_BASE_MUTEX_H + +#include + +#include + +namespace muduo +{ + +class MutexLock : boost::noncopyable +{ + public: + MutexLock() + { + pthread_mutex_init(&mutex_, NULL); + } + + ~MutexLock() + { + pthread_mutex_destroy(&mutex_); + } + + void lock() + { + pthread_mutex_lock(&mutex_); + } + + void unlock() + { + pthread_mutex_unlock(&mutex_); + } + + pthread_mutex_t* getPthreadMutex() /* non-const */ + { + return &mutex_; + } + + private: + + pthread_mutex_t mutex_; +}; + +class MutexLockGuard : boost::noncopyable +{ + public: + explicit MutexLockGuard(MutexLock& mutex) : mutex_(mutex) + { + mutex_.lock(); + } + + ~MutexLockGuard() + { + mutex_.unlock(); + } + + private: + + MutexLock& mutex_; +}; + +} + +#define MutexLockGuard(x) error + +#endif diff --git a/muduo/base/Thread.cc b/muduo/base/Thread.cc new file mode 100644 index 000000000..8d6c98f0b --- /dev/null +++ b/muduo/base/Thread.cc @@ -0,0 +1,55 @@ +#include + +#include +#include +#include +#include + +namespace +{ + __thread pid_t t_tid = 0; + + pid_t gettid() + { + return static_cast(::syscall(SYS_gettid)); + } + + void* startThread(void* cb) + { + muduo::Thread::ThreadFunc* func = static_cast(cb); + t_tid = gettid(); + (*func)(); + return NULL; + } +} + +using namespace muduo; + +Thread::Thread(const ThreadFunc& func) + : ptid_(0), + func_(func) +{ +} + +Thread::~Thread() +{ +} + +void Thread::start() +{ + pthread_create(&ptid_, NULL, &startThread, &func_); +} + +void Thread::join() +{ + pthread_join(ptid_, NULL); +} + +pid_t CurrentThread::tid() +{ + if (t_tid == 0) { + t_tid = gettid(); + } + return t_tid; +} + diff --git a/muduo/base/Thread.h b/muduo/base/Thread.h new file mode 100644 index 000000000..4ebb5b6f5 --- /dev/null +++ b/muduo/base/Thread.h @@ -0,0 +1,34 @@ +#ifndef MUDUO_BASE_THREAD_H +#define MUDUO_BASE_THREAD_H + +#include +#include + +namespace muduo +{ + +class Thread +{ + public: + typedef boost::function ThreadFunc; + + explicit Thread(const ThreadFunc&); + ~Thread(); + + void start(); + void join(); + + private: + + pthread_t ptid_; + ThreadFunc func_; +}; + +namespace CurrentThread +{ + pid_t tid(); +} + +} + +#endif diff --git a/muduo/base/UtcTime.h b/muduo/base/UtcTime.h index 0525322ea..7496385eb 100644 --- a/muduo/base/UtcTime.h +++ b/muduo/base/UtcTime.h @@ -87,8 +87,7 @@ inline double timeDifference(UtcTime high, UtcTime low) /// /// Add @c seconds to given timestamp. /// -/// @param high, low -/// @return (high-low) in seconds +/// @return timestamp+seconds as UtcTime /// inline UtcTime addTime(UtcTime timestamp, double seconds) { diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 678715f9a..46029819d 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -1,11 +1,15 @@ #include +#include + using namespace muduo; using namespace muduo::net; -Channel::Channel(EventLoop* loop, Socket sock) +const int Channel::kReadEvent = POLLIN; + +Channel::Channel(EventLoop* loop, int fd__) : loop_(loop), - sock_(sock), + fd_(fd__), events_(0) { } @@ -14,3 +18,24 @@ Channel::~Channel() { } +void Channel::handle_event() +{ + if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) + { + //FIXME handleClose(); + } + + if (revents_ & (POLLERR|POLLNVAL)) + { + if (errorCallback_) errorCallback_(); + } + if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) + { + if (readCallback_) readCallback_(); + } + if (revents_ & POLLOUT) + { + if (writeCallback_) writeCallback_(); + } +} + diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 36faa9142..58e69197f 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -1,6 +1,7 @@ #ifndef NET_CHANNEL_H #define NET_CHANNEL_H +#include #include #include @@ -12,21 +13,31 @@ namespace net class EventLoop; +/// +/// A selectable I/O channel. +/// The class doesn't own the file descriptor. +/// class Channel : boost::noncopyable { public: - Channel(EventLoop* loop, Socket sock); + typedef boost::function EventCallback; + static const int kNoneEvent; + static const int kReadEvent; + static const int kWriteEvent; + static const int kErrorvent; + + Channel(EventLoop* loop, int fd); ~Channel(); - void handle(int revents); + void handle_event(); + void setReadCallback(const EventCallback& cb) { readCallback_ = cb; } + void setWriteCallback(const EventCallback& cb) { writeCallback_ = cb; } + void setErrorCallback(const EventCallback& cb) { errorCallback_ = cb; } - /* int fd() { return fd_; } - void set_fd(int _fd) { fd_ = _fd; } - int events() { return events_; } - void set_events(int events0) { events_ = events0; } - */ + void set_events(int evt) { events_ = evt; } + void set_revents(int revt) { revents_ = revt; } EventLoop* getLoop() { return loop_; } @@ -34,8 +45,12 @@ class Channel : boost::noncopyable private: EventLoop* loop_; - Socket sock_; + const int fd_; int events_; + int revents_; + EventCallback readCallback_; + EventCallback writeCallback_; + EventCallback errorCallback_; }; } diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 67700626b..c840496bb 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -1,8 +1,8 @@ #include -#include +#include +#include #include -//#include #include #include @@ -11,8 +11,10 @@ using namespace muduo::net; EventLoop::EventLoop() : poller_(Poller::newDefaultPoller()), - timerQueue_(new TimerQueue), - quit_(false) + timerQueue_(new TimerQueue(this)), + looping_(false), + quit_(false), + thread_(CurrentThread::tid()) { init(); } @@ -23,25 +25,19 @@ EventLoop::~EventLoop() void EventLoop::loop() { + assert(!looping_); + looping_ = true; while (!quit_) { - poller_->poll(1000); - } - /* - while (!quit_) - { - UtcTime now(UtcTime::now()); - UtcTime next(timerQueue_->tick(now)); - int timeout = next.valid() ? static_cast((timeDifference(next, now))*1000) : 1000; - if (timeout <= 0) + activeChannels_.clear(); + poller_->poll(1000, &activeChannels_); + for (ChannelList::iterator it = activeChannels_.begin(); + it != activeChannels_.end(); ++it) { - timeout = 1; + (*it)->handle_event(); } - - NetLogInfo << "polling " << timeout << NetSend; - poller_->poll(timeout); } - */ + looping_ = false; } void EventLoop::quit() @@ -49,7 +45,7 @@ void EventLoop::quit() quit_ = true; } -void EventLoop::addChannel(Channel* channel) +void EventLoop::updateChannel(Channel* channel) { assert(channel->getLoop() == this); // channel->set_loop(this); diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index d8c15f594..158d773e9 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -1,6 +1,8 @@ #ifndef MUDUO_NET_EVENTLOOP_H #define MUDUO_NET_EVENTLOOP_H +#include + #include #include #include @@ -31,6 +33,8 @@ class EventLoop : boost::noncopyable /// /// Loops forever. /// + /// Must be called in the same thread as creation of the object. + /// void loop(); void quit(); @@ -42,15 +46,19 @@ class EventLoop : boost::noncopyable TimerId runEvery(double interval, const TimerCallback& cb); void cancel(TimerId timerId); - void addChannel(Channel* channel); + void updateChannel(Channel* channel); void removeChannel(Channel* channel); private: + typedef std::vector ChannelList; void init(); boost::scoped_ptr poller_; boost::scoped_ptr timerQueue_; + bool looping_; /* atomic */ bool quit_; /* atomic */ + pid_t thread_; + ChannelList activeChannels_; }; } diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index e752e0a35..14bacfef9 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -1,6 +1,8 @@ #include -#include +#include + +#include using namespace muduo; using namespace muduo::net; @@ -9,25 +11,20 @@ PollPoller::~PollPoller() { } -void PollPoller::poll(int timeoutMs) +void PollPoller::poll(int timeoutMs, ChannelList* activeChannels) { - // make a copy - PollFdList pollfds(pollfds_); - int numEvents = ::poll(&*pollfds.begin(), pollfds.size(), timeoutMs); + int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); - for (PollFdList::iterator pfd = pollfds.begin(); - pfd != pollfds.end() && numEvents > 0; ++pfd) + for (PollFdList::iterator pfd = pollfds_.begin(); + pfd != pollfds_.end() && numEvents > 0; ++pfd) { if (pfd->revents > 0) { --numEvents; - /* - NetLogDebug << "fd:revents " << pfd->fd << " : " << pfd->revents << NetSend; - // assert(0 <= pfd->fd && pfd->fd < static_cast(channels_.size())); Channel* channel = channels_[pfd->fd]; assert(channel->fd() == pfd->fd); - channel->handle(pfd->revents); - */ + channel->set_revents(pfd->revents); + activeChannels->push_back(channel); } } } diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index 6ddd2b41e..aa1d9dfb2 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -3,6 +3,7 @@ #include +#include #include #include @@ -21,11 +22,12 @@ class PollPoller : public Poller virtual ~PollPoller(); - virtual void poll(int timeoutMs); + virtual void poll(int timeoutMs, ChannelList* activeChannels); private: typedef std::vector PollFdList; PollFdList pollfds_; + std::map channels_; }; } diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index 6b6945e9c..55df32f95 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -1,6 +1,7 @@ #ifndef MUDUO_NET_POLLER_H #define MUDUO_NET_POLLER_H +#include #include namespace muduo @@ -8,16 +9,18 @@ namespace muduo namespace net { +class Channel; /// /// Base class for IO Multiplexing /// class Poller : boost::noncopyable { public: + typedef std::vector ChannelList; virtual ~Poller(); - virtual void poll(int timeoutMs) = 0; + virtual void poll(int timeoutMs, ChannelList* activeChannels) = 0; static Poller* newDefaultPoller(); }; diff --git a/muduo/net/TimerId.h b/muduo/net/TimerId.h index 142f0ee5e..d9bccddd8 100644 --- a/muduo/net/TimerId.h +++ b/muduo/net/TimerId.h @@ -8,6 +8,9 @@ namespace net class Timer; +/// +/// An opaque identifier, for canceling Timer. +/// class TimerId { public: diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index c41f7b075..7cff5a753 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -1,17 +1,44 @@ #include +#include #include #include +#include + +#include +#include + using namespace muduo; using namespace muduo::net; -TimerQueue::TimerQueue() +namespace +{ +int createTimerfd() +{ + int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + if (timerfd < 0) + { + perror("Failed in timerfd_create"); + abort(); + } + return timerfd; +} +} + +TimerQueue::TimerQueue(EventLoop* loop) + : loop_(loop), + timerfd_(createTimerfd()), + timerfdChannel_(loop, timerfd_), + timers_() { + timerfdChannel_.setReadCallback(boost::bind(&TimerQueue::timeout, this)); } TimerQueue::~TimerQueue() { + ::close(timerfd_); + // do not remove channel, since we're in EventLoop::dtor(); /* for (Alarms::iterator it(alarms_.begin()); it != alarms_.end(); @@ -22,7 +49,7 @@ TimerQueue::~TimerQueue() */ } -void TimerQueue::tick(UtcTime now) +void TimerQueue::timeout() { /* while (!alarms_.empty()) @@ -50,12 +77,16 @@ void TimerQueue::tick(UtcTime now) } return alarms_.empty() ? UtcTime() : alarms_.begin()->first; */ + timerfdChannel_.set_events(0); + loop_->updateChannel(&timerfdChannel_); } TimerId TimerQueue::schedule(const TimerCallback& cb, UtcTime at, double interval) { Timer* timer = new Timer(cb, at, interval); timers_.push_front(timer); + timerfdChannel_.set_events(Channel::kReadEvent); + loop_->updateChannel(&timerfdChannel_); return TimerId(timer); } diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index f52a15b50..ad62f0546 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -7,12 +7,14 @@ #include #include +#include namespace muduo { namespace net { +class EventLoop; class Timer; class TimerId; @@ -21,11 +23,9 @@ class TimerQueue : boost::noncopyable public: typedef boost::function TimerCallback; - TimerQueue(); + TimerQueue(EventLoop* loop); ~TimerQueue(); - void tick(UtcTime now); - /// /// Schedules the callback to be run at given time, /// repeats if @c interval > 0.0. @@ -35,9 +35,13 @@ class TimerQueue : boost::noncopyable void cancel(TimerId timerId); private: + void timeout(); - // typedef std::multimap Timers; typedef std::list Timers; + + EventLoop* loop_; + int timerfd_; + Channel timerfdChannel_; Timers timers_; }; diff --git a/muduo/net/tests/EventLoop_unittest.cc b/muduo/net/tests/EventLoop_unittest.cc index 470d2f430..d3adf5161 100644 --- a/muduo/net/tests/EventLoop_unittest.cc +++ b/muduo/net/tests/EventLoop_unittest.cc @@ -1,8 +1,11 @@ #include +#include + using namespace muduo::net; int main() { EventLoop theLoop; + theLoop.loop(); } From 71ac3413a86755db278895e7bcc8c427645b57ac Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 13 Mar 2010 07:47:32 +0000 Subject: [PATCH 005/371] Add EPollPoller placeholder. --- muduo/net/CMakeLists.txt | 1 + muduo/net/DefaultPoller.cc | 7 +++++-- muduo/net/EPollPoller.cc | 18 ++++++++++++++++++ muduo/net/EPollPoller.h | 31 +++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 muduo/net/EPollPoller.cc create mode 100644 muduo/net/EPollPoller.h diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index b6d27c57b..41ebc1a81 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -1,6 +1,7 @@ set(net_SRCS Channel.cc DefaultPoller.cc + EPollPoller.cc EventLoop.cc Poller.cc PollPoller.cc diff --git a/muduo/net/DefaultPoller.cc b/muduo/net/DefaultPoller.cc index 2e053213b..e6eddbbd9 100644 --- a/muduo/net/DefaultPoller.cc +++ b/muduo/net/DefaultPoller.cc @@ -1,5 +1,8 @@ -#include -#include +#include +#include +#include + +using namespace muduo::net; Poller* Poller::newDefaultPoller() { diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc new file mode 100644 index 000000000..03a5cc1d3 --- /dev/null +++ b/muduo/net/EPollPoller.cc @@ -0,0 +1,18 @@ +#include + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +EPollPoller::~EPollPoller() +{ +} + +void EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) +{ +} + diff --git a/muduo/net/EPollPoller.h b/muduo/net/EPollPoller.h new file mode 100644 index 000000000..09703e5e4 --- /dev/null +++ b/muduo/net/EPollPoller.h @@ -0,0 +1,31 @@ +#ifndef MUDUO_NET_EPOLLPOLLER_H +#define MUDUO_NET_EPOLLPOLLER_H + +#include + +#include +#include + +namespace muduo +{ +namespace net +{ + +/// +/// IO Multiplexing with epoll(4). +/// +class EPollPoller : public Poller +{ + public: + + virtual ~EPollPoller(); + + virtual void poll(int timeoutMs, ChannelList* activeChannels); + + private: + std::map channels_; +}; + +} +} +#endif From 90537a6c5db08d1951fc8eb7c2f4d9a8c52470ad Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 13 Mar 2010 11:57:25 +0000 Subject: [PATCH 006/371] Better build files. --- CMakeLists.txt | 22 ++++++- muduo/net/CMakeLists.txt | 1 + muduo/net/Channel.cc | 2 +- muduo/net/Channel.h | 4 +- muduo/net/EPollPoller.cc | 23 ++++++++ muduo/net/EPollPoller.h | 1 + muduo/net/EventLoop.cc | 59 +++++++++++++++++-- muduo/net/EventLoop.h | 24 +++++++- muduo/net/PollPoller.cc | 4 ++ muduo/net/PollPoller.h | 1 + muduo/net/Poller.h | 2 + muduo/net/Socket.h | 4 ++ muduo/net/TimerQueue.cc | 85 ++++++++++++++++++--------- muduo/net/TimerQueue.h | 13 +++- muduo/net/tests/CMakeLists.txt | 2 +- muduo/net/tests/EventLoop_unittest.cc | 16 ++++- 16 files changed, 216 insertions(+), 47 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 714dd72a0..e3efc6e57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,25 @@ cmake_minimum_required(VERSION 2.6) project(muduo CXX) -set(CMAKE_CXX_FLAGS - "-g -Wall -Wextra -Werror -Wconversion -Wold-style-cast -Wpointer-arith -Wshadow -Wno-unused-parameter -Wwrite-strings -rdynamic -lpthread" - ) +set(CXX_FLAGS + -g + -Wall + -Wextra + -Werror + -Wconversion + -Wno-unused-parameter + -Wold-style-cast + -Wpointer-arith + -Wshadow + -Wwrite-strings + -rdynamic + -lpthread + ) +string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") + +set(CMAKE_CXX_FLAGS_DEBUG "-O0") +set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") + include_directories(${PROJECT_SOURCE_DIR}) add_subdirectory(muduo/base) add_subdirectory(muduo/net) diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 41ebc1a81..3d7af6919 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -11,5 +11,6 @@ set(net_SRCS ) add_library(muduo_net ${net_SRCS}) +target_link_libraries(muduo_net muduo_base) add_subdirectory(tests) diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 46029819d..951b57679 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -25,7 +25,7 @@ void Channel::handle_event() //FIXME handleClose(); } - if (revents_ & (POLLERR|POLLNVAL)) + if (revents_ & (POLLERR | POLLNVAL)) { if (errorCallback_) errorCallback_(); } diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 58e69197f..e05e6d379 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -4,8 +4,6 @@ #include #include -#include - namespace muduo { namespace net @@ -15,8 +13,8 @@ class EventLoop; /// /// A selectable I/O channel. -/// The class doesn't own the file descriptor. /// +/// This class doesn't own the file descriptor. class Channel : boost::noncopyable { public: diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc index 03a5cc1d3..f77888496 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/EPollPoller.cc @@ -3,11 +3,34 @@ #include #include +#include #include using namespace muduo; using namespace muduo::net; +namespace +{ + // On Linux, the constants of poll(2) and epoll(4) + // are expected to be the same. + char poll_epoll_event_diff_in[EPOLLIN == POLLIN ? 1 : -1]; + char poll_epoll_event_diff_pri[EPOLLPRI == POLLPRI ? 1 : -1]; + char poll_epoll_event_diff_out[EPOLLOUT == POLLOUT ? 1 : -1]; + char poll_epoll_event_diff_rdhup[EPOLLRDHUP == POLLRDHUP ? 1 : -1]; + char poll_epoll_event_diff_err[EPOLLERR == POLLERR ? 1 : -1]; + char poll_epoll_event_diff_hup[EPOLLHUP == POLLHUP ? 1 : -1]; + + void nowarning() + { + (void)poll_epoll_event_diff_in; + (void)poll_epoll_event_diff_out; + (void)poll_epoll_event_diff_pri; + (void)poll_epoll_event_diff_rdhup; + (void)poll_epoll_event_diff_err; + (void)poll_epoll_event_diff_hup; + } +} + EPollPoller::~EPollPoller() { } diff --git a/muduo/net/EPollPoller.h b/muduo/net/EPollPoller.h index 09703e5e4..26d1b19d4 100644 --- a/muduo/net/EPollPoller.h +++ b/muduo/net/EPollPoller.h @@ -21,6 +21,7 @@ class EPollPoller : public Poller virtual ~EPollPoller(); virtual void poll(int timeoutMs, ChannelList* activeChannels); + virtual void updateChannel(Channel* channel); private: std::map channels_; diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index c840496bb..e9f5f1a89 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -6,21 +6,48 @@ #include #include +#include + +#include // FIXME +#include + using namespace muduo; using namespace muduo::net; +namespace +{ +const int kPollTimeMs = 10000; + +int createEventfd() +{ + int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (evtfd < 0) + { + perror("Failed in eventfd"); + abort(); + } + return evtfd; +} +} + EventLoop::EventLoop() : poller_(Poller::newDefaultPoller()), timerQueue_(new TimerQueue(this)), looping_(false), quit_(false), - thread_(CurrentThread::tid()) + threadId_(CurrentThread::tid()), + wakeupFd_(createEventfd()), + wakeupChannel_(new Channel(this, wakeupFd_)) { - init(); + wakeupChannel_->setReadCallback(boost::bind(&EventLoop::wakedup, this)); + // we are always reading the wakeupfd, like the old pipe(2) way. + wakeupChannel_->set_events(Channel::kReadEvent); + updateChannel(get_pointer(wakeupChannel_)); } EventLoop::~EventLoop() { + ::close(wakeupFd_); } void EventLoop::loop() @@ -30,7 +57,7 @@ void EventLoop::loop() while (!quit_) { activeChannels_.clear(); - poller_->poll(1000, &activeChannels_); + poller_->poll(kPollTimeMs, &activeChannels_); for (ChannelList::iterator it = activeChannels_.begin(); it != activeChannels_.end(); ++it) { @@ -49,7 +76,7 @@ void EventLoop::updateChannel(Channel* channel) { assert(channel->getLoop() == this); // channel->set_loop(this); - // poller_->addChannel(channel); + poller_->updateChannel(channel); } void EventLoop::removeChannel(Channel* channel) @@ -58,8 +85,16 @@ void EventLoop::removeChannel(Channel* channel) // poller_->removeChannel(channel); } -void EventLoop::init() +void EventLoop::runInLoop(const Functor& cb) { + if (threadId_ == CurrentThread::tid()) + { + cb(); + } + else + { + abort(); + } } TimerId EventLoop::runAt(const UtcTime& time, const TimerCallback& cb) @@ -79,3 +114,17 @@ TimerId EventLoop::runEvery(double interval, const TimerCallback& cb) return timerQueue_->schedule(cb, time, interval); } +void EventLoop::wakeup() +{ + uint64_t one = 1; + ssize_t n = ::write(wakeupFd_, &one, sizeof one); + if (n != sizeof one) + { + fprintf(stderr, "EventLoop::wakeup() write %zd bytes instead of 8\n", n); + } +} + +void EventLoop::wakedup() +{ + // what's up +} diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 158d773e9..70a5d91a1 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -25,6 +25,7 @@ class TimerQueue; class EventLoop : boost::noncopyable { public: + typedef boost::function Functor; typedef boost::function TimerCallback; EventLoop(); @@ -41,23 +42,42 @@ class EventLoop : boost::noncopyable void wakeup(); // timers + + /// Runs callback immediately in the loop thread. + /// It wakes up the loop, and run the cb. + /// Safe to call from other threads. + void runInLoop(const Functor& cb); + /// TimerId runAt(const UtcTime& time, const TimerCallback& cb); + /// + /// Runs callback after @c delay seconds. + /// Safe to call from other threads. TimerId runAfter(double delay, const TimerCallback& cb); + /// + /// Runs callback every @c interval seconds. + /// Safe to call from other threads. TimerId runEvery(double interval, const TimerCallback& cb); + /// Cancels the timer. + /// Safe to call from other threads. void cancel(TimerId timerId); void updateChannel(Channel* channel); void removeChannel(Channel* channel); private: + void wakedup(); + typedef std::vector ChannelList; - void init(); boost::scoped_ptr poller_; boost::scoped_ptr timerQueue_; bool looping_; /* atomic */ bool quit_; /* atomic */ - pid_t thread_; + const pid_t threadId_; + int wakeupFd_; + // unlink in TimerQueue, which is an internal class, + // we don't expose Channel to client. + boost::scoped_ptr wakeupChannel_; ChannelList activeChannels_; }; diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index 14bacfef9..b291ab3a8 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -29,3 +29,7 @@ void PollPoller::poll(int timeoutMs, ChannelList* activeChannels) } } +void PollPoller::updateChannel(Channel* channel) +{ +} + diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index aa1d9dfb2..d66edf7eb 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -23,6 +23,7 @@ class PollPoller : public Poller virtual ~PollPoller(); virtual void poll(int timeoutMs, ChannelList* activeChannels); + virtual void updateChannel(Channel* channel); private: typedef std::vector PollFdList; diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index 55df32f95..9370b4db7 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -13,6 +13,7 @@ class Channel; /// /// Base class for IO Multiplexing /// +/// This class doesn't own the Channel objects. class Poller : boost::noncopyable { public: @@ -21,6 +22,7 @@ class Poller : boost::noncopyable virtual ~Poller(); virtual void poll(int timeoutMs, ChannelList* activeChannels) = 0; + virtual void updateChannel(Channel* channel) = 0; static Poller* newDefaultPoller(); }; diff --git a/muduo/net/Socket.h b/muduo/net/Socket.h index e3d1fe8d7..be92d10ac 100644 --- a/muduo/net/Socket.h +++ b/muduo/net/Socket.h @@ -12,6 +12,8 @@ namespace net /// /// Wrapper of socket file descriptor. /// +/// It closes the sockfd when desctructs. +/// class Socket { public: @@ -19,6 +21,8 @@ class Socket : sockfd_(sockfd) { } + ~Socket(); + int fd() { return sockfd_; } /// diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index 7cff5a753..efae84d8e 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -6,7 +6,10 @@ #include -#include +#define __STDC_FORMAT_MACROS +#include // FIXME remove +#undef __STDC_FORMAT_MACROS +#include // FIXME perror #include using namespace muduo; @@ -24,6 +27,20 @@ int createTimerfd() } return timerfd; } + +struct timespec howMuchTimeFromNow(UtcTime then) +{ + int64_t microseconds = then.microSecondsSinceEpoch() + - UtcTime::now().microSecondsSinceEpoch(); + if (microseconds < 100) + { + microseconds = 100; + } + struct timespec ts; + ts.tv_sec = static_cast(microseconds / UtcTime::kMicroSecondsPerSecond); + ts.tv_nsec = static_cast((microseconds % UtcTime::kMicroSecondsPerSecond) * 1000); + return ts; +} } TimerQueue::TimerQueue(EventLoop* loop) @@ -33,6 +50,9 @@ TimerQueue::TimerQueue(EventLoop* loop) timers_() { timerfdChannel_.setReadCallback(boost::bind(&TimerQueue::timeout, this)); + // we are always reading the timerfd, we disarm it with timerfd_settime. + timerfdChannel_.set_events(Channel::kReadEvent); + loop_->updateChannel(&timerfdChannel_); } TimerQueue::~TimerQueue() @@ -51,42 +71,53 @@ TimerQueue::~TimerQueue() void TimerQueue::timeout() { - /* - while (!alarms_.empty()) + uint64_t howmany; + ssize_t n = ::read(timerfd_, &howmany, sizeof howmany); + printf("timeout %" PRIu64 "\n", howmany); + if (n != sizeof howmany) + { + fprintf(stderr, "TimerQueue::timeout() reads %zd bytes instead of 8\n", n); + } +} + +TimerId TimerQueue::schedule(const TimerCallback& cb, UtcTime at, double interval) +{ + Timer* timer = new Timer(cb, at, interval); + + bool earliestChanged = false; { - Alarms::iterator head(alarms_.begin()); - if (head->first.after(now)) + MutexLockGuard lock(mutex_); + TimerList::iterator it = timers_.begin(); + if (it == timers_.end() || (*it)->expiration().after(at)) { - break; + timers_.push_front(timer); + earliestChanged = true; } else { - Alarm* alarm = head->second; - alarm->run(); - UtcTime next = alarm->getNextTime(now); - if (next.valid()) + while (it != timers_.end() && (*it)->expiration().before(at)) { - alarms_.insert(std::make_pair(next, alarm)); + ++it; } - else - { - delete alarm; - } - alarms_.erase(head); + timers_.insert(it, timer); } } - return alarms_.empty() ? UtcTime() : alarms_.begin()->first; - */ - timerfdChannel_.set_events(0); - loop_->updateChannel(&timerfdChannel_); -} -TimerId TimerQueue::schedule(const TimerCallback& cb, UtcTime at, double interval) -{ - Timer* timer = new Timer(cb, at, interval); - timers_.push_front(timer); - timerfdChannel_.set_events(Channel::kReadEvent); - loop_->updateChannel(&timerfdChannel_); + if (earliestChanged) + { + // wake up loop by timerfd_settime() + struct itimerspec newValue; + struct itimerspec oldValue; + bzero(&newValue, sizeof newValue); + bzero(&oldValue, sizeof oldValue); + newValue.it_value = howMuchTimeFromNow(at); + int ret = timerfd_settime(timerfd_, 0, &newValue, &oldValue); + if (ret) + { + perror("Error in timerfd_settime"); + } + } + return TimerId(timer); } diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index ad62f0546..d81236abc 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -18,6 +19,10 @@ class EventLoop; class Timer; class TimerId; +/// +/// A best efforts timer queue. +/// No guarantee that the callback will be on time. +/// class TimerQueue : boost::noncopyable { public: @@ -30,6 +35,7 @@ class TimerQueue : boost::noncopyable /// Schedules the callback to be run at given time, /// repeats if @c interval > 0.0. /// + /// Must be thread safe. TimerId schedule(const TimerCallback& cb, UtcTime at, double interval); void cancel(TimerId timerId); @@ -37,12 +43,13 @@ class TimerQueue : boost::noncopyable private: void timeout(); - typedef std::list Timers; + typedef std::list TimerList; EventLoop* loop_; - int timerfd_; + const int timerfd_; Channel timerfdChannel_; - Timers timers_; + MutexLock mutex_; + TimerList timers_; // GuardedBy mutex_ }; } diff --git a/muduo/net/tests/CMakeLists.txt b/muduo/net/tests/CMakeLists.txt index ffa0fefd9..086d9adec 100644 --- a/muduo/net/tests/CMakeLists.txt +++ b/muduo/net/tests/CMakeLists.txt @@ -1,3 +1,3 @@ add_executable(EventLoop_unittest EventLoop_unittest.cc) -target_link_libraries(EventLoop_unittest muduo_net muduo_base) +target_link_libraries(EventLoop_unittest muduo_net) diff --git a/muduo/net/tests/EventLoop_unittest.cc b/muduo/net/tests/EventLoop_unittest.cc index d3adf5161..3aa6f194f 100644 --- a/muduo/net/tests/EventLoop_unittest.cc +++ b/muduo/net/tests/EventLoop_unittest.cc @@ -1,11 +1,23 @@ #include +#include #include +using namespace muduo; using namespace muduo::net; +void print() +{ + printf("%s\n", UtcTime::now().toString().c_str()); +} + int main() { - EventLoop theLoop; - theLoop.loop(); + printf("pid = %d\n", getpid()); + EventLoop loop; + + print(); + loop.runAfter(1.0, print); + + loop.loop(); } From 946581879061ab575b1c83cc722a7ca429356baf Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 13 Mar 2010 12:09:47 +0000 Subject: [PATCH 007/371] Build both types. --- Doxyfile | 2 +- build.sh | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Doxyfile b/Doxyfile index 352a7ea67..b0bda9f26 100644 --- a/Doxyfile +++ b/Doxyfile @@ -515,7 +515,7 @@ LAYOUT_FILE = # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. -QUIET = NO +QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank diff --git a/build.sh b/build.sh index ffc4060f1..97478709d 100755 --- a/build.sh +++ b/build.sh @@ -1,7 +1,15 @@ #!/bin/sh +set -x + SOURCE_DIR=`pwd` BUILD_DIR=${BUILD_DIR:-../build} -mkdir -p $BUILD_DIR -cd $BUILD_DIR && cmake $SOURCE_DIR && make +BUILD_TYPE=${BUILD_TYPE:-Debug} + +mkdir -p $BUILD_DIR/$BUILD_TYPE \ + && cd $BUILD_DIR/$BUILD_TYPE \ + && cmake --graphviz=dep.dot -DCMAKE_BUILD_TYPE=$BUILD_TYPE $SOURCE_DIR \ + && make + +cd $SOURCE_DIR && doxygen From f4c439720c7980bc3fa84479099fbab67b4af49f Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 13 Mar 2010 14:39:18 +0000 Subject: [PATCH 008/371] Repeat and one shot timers work. --- muduo/net/Channel.cc | 10 +- muduo/net/Channel.h | 4 + muduo/net/EventLoop.cc | 47 ++++++---- muduo/net/EventLoop.h | 7 +- muduo/net/PollPoller.cc | 57 ++++++++++- muduo/net/PollPoller.h | 5 +- muduo/net/Poller.h | 5 + muduo/net/Timer.h | 4 +- muduo/net/TimerQueue.cc | 130 +++++++++++++++++++------- muduo/net/TimerQueue.h | 10 +- muduo/net/tests/CMakeLists.txt | 4 +- muduo/net/tests/EventLoop_unittest.cc | 35 +++++-- 12 files changed, 244 insertions(+), 74 deletions(-) diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 951b57679..51e227fb4 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -1,6 +1,7 @@ #include #include +#include // FIXME using namespace muduo; using namespace muduo::net; @@ -10,7 +11,9 @@ const int Channel::kReadEvent = POLLIN; Channel::Channel(EventLoop* loop, int fd__) : loop_(loop), fd_(fd__), - events_(0) + events_(0), + revents_(0), + index_(-1) { } @@ -25,6 +28,11 @@ void Channel::handle_event() //FIXME handleClose(); } + if (revents_ & POLLNVAL) + { + perror("Channel::handle_event() POLLNVAL"); + } + if (revents_ & (POLLERR | POLLNVAL)) { if (errorCallback_) errorCallback_(); diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index e05e6d379..28605b077 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -37,6 +37,9 @@ class Channel : boost::noncopyable void set_events(int evt) { events_ = evt; } void set_revents(int revt) { revents_ = revt; } + int index() { return index_; } + void set_index(int idx) { index_ = idx; } + EventLoop* getLoop() { return loop_; } // void set_loop(EventLoop* loop) { loop_ = loop; } @@ -46,6 +49,7 @@ class Channel : boost::noncopyable const int fd_; int events_; int revents_; + int index_; // used by PollPoller. EventCallback readCallback_; EventCallback writeCallback_; EventCallback errorCallback_; diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index e9f5f1a89..c35999d86 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -31,11 +31,11 @@ int createEventfd() } EventLoop::EventLoop() - : poller_(Poller::newDefaultPoller()), - timerQueue_(new TimerQueue(this)), - looping_(false), + : looping_(false), quit_(false), threadId_(CurrentThread::tid()), + poller_(Poller::newDefaultPoller()), + timerQueue_(new TimerQueue(this)), wakeupFd_(createEventfd()), wakeupChannel_(new Channel(this, wakeupFd_)) { @@ -53,6 +53,7 @@ EventLoop::~EventLoop() void EventLoop::loop() { assert(!looping_); + assertInLoopThread(); looping_ = true; while (!quit_) { @@ -72,17 +73,14 @@ void EventLoop::quit() quit_ = true; } -void EventLoop::updateChannel(Channel* channel) -{ - assert(channel->getLoop() == this); - // channel->set_loop(this); - poller_->updateChannel(channel); -} - -void EventLoop::removeChannel(Channel* channel) +void EventLoop::wakeup() { - assert(channel->getLoop() == this); - // poller_->removeChannel(channel); + uint64_t one = 1; + ssize_t n = ::write(wakeupFd_, &one, sizeof one); + if (n != sizeof one) + { + fprintf(stderr, "EventLoop::wakeup() write %zd bytes instead of 8\n", n); + } } void EventLoop::runInLoop(const Functor& cb) @@ -114,17 +112,26 @@ TimerId EventLoop::runEvery(double interval, const TimerCallback& cb) return timerQueue_->schedule(cb, time, interval); } -void EventLoop::wakeup() +void EventLoop::updateChannel(Channel* channel) { - uint64_t one = 1; - ssize_t n = ::write(wakeupFd_, &one, sizeof one); - if (n != sizeof one) - { - fprintf(stderr, "EventLoop::wakeup() write %zd bytes instead of 8\n", n); - } + assert(channel->getLoop() == this); + assertInLoopThread(); + poller_->updateChannel(channel); +} + +void EventLoop::removeChannel(Channel* channel) +{ + assert(channel->getLoop() == this); + // poller_->removeChannel(channel); +} + +void EventLoop::assertInLoopThread() +{ + assert(threadId_ == CurrentThread::tid()); } void EventLoop::wakedup() { // what's up } + diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 70a5d91a1..1860a4588 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -64,16 +64,19 @@ class EventLoop : boost::noncopyable void updateChannel(Channel* channel); void removeChannel(Channel* channel); + pid_t threadId() { return threadId_; } + void assertInLoopThread(); + private: void wakedup(); typedef std::vector ChannelList; - boost::scoped_ptr poller_; - boost::scoped_ptr timerQueue_; bool looping_; /* atomic */ bool quit_; /* atomic */ const pid_t threadId_; + boost::scoped_ptr poller_; + boost::scoped_ptr timerQueue_; int wakeupFd_; // unlink in TimerQueue, which is an internal class, // we don't expose Channel to client. diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index b291ab3a8..3aef4ed37 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -3,6 +3,7 @@ #include #include +#include using namespace muduo; using namespace muduo::net; @@ -13,17 +14,37 @@ PollPoller::~PollPoller() void PollPoller::poll(int timeoutMs, ChannelList* activeChannels) { + // XXX pollfds_ shouldn't change int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); + if (numEvents > 0) + { + fillActiveChannels(numEvents, activeChannels); + } + else if (numEvents == 0) + { + printf("nothing\n"); + } + else + { + perror("PollPoller::poll"); + } + +} - for (PollFdList::iterator pfd = pollfds_.begin(); +void PollPoller::fillActiveChannels(int numEvents, ChannelList* activeChannels) const +{ + for (PollFdList::const_iterator pfd = pollfds_.begin(); pfd != pollfds_.end() && numEvents > 0; ++pfd) { if (pfd->revents > 0) { --numEvents; - Channel* channel = channels_[pfd->fd]; + ChannelMap::const_iterator ch = channels_.find(pfd->fd); + assert(ch != channels_.end()); + Channel* channel = ch->second; assert(channel->fd() == pfd->fd); channel->set_revents(pfd->revents); + // pfd->revents = 0; activeChannels->push_back(channel); } } @@ -31,5 +52,37 @@ void PollPoller::poll(int timeoutMs, ChannelList* activeChannels) void PollPoller::updateChannel(Channel* channel) { + // assert(channel->getLoop() + + if (channel->index() < 0) + { + // a new one, add to pollfds_ + assert(channels_.find(channel->fd()) == channels_.end()); + struct pollfd pfd; + pfd.fd = channel->fd(); + pfd.events = static_cast(channel->events()); + pfd.revents = 0; + pollfds_.push_back(pfd); + channel->set_index(pollfds_.size()-1); + channels_[pfd.fd] = channel; + } + else + { + // update existing one + assert(channels_.find(channel->fd()) != channels_.end()); + assert(channels_[channel->fd()] == channel); + int idx = channel->index(); + assert(0 <= idx && idx < static_cast(pollfds_.size())); + struct pollfd& pfd = pollfds_[idx]; + assert(pfd.fd == channel->fd() || pfd.fd == -1); + pfd.events = static_cast(channel->events()); + if (pfd.events == 0) + { + // ignore this pollfd + pfd.fd = -1; + printf("set pfd.fd=-1 for fd=%d\n", channel->fd()); + } + } + } diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index d66edf7eb..89666bca8 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -26,9 +26,12 @@ class PollPoller : public Poller virtual void updateChannel(Channel* channel); private: + void fillActiveChannels(int numEvents, ChannelList* activeChannels) const; + typedef std::vector PollFdList; + typedef std::map ChannelMap; PollFdList pollfds_; - std::map channels_; + ChannelMap channels_; }; } diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index 9370b4db7..78d67c73e 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -21,7 +21,12 @@ class Poller : boost::noncopyable virtual ~Poller(); + /// Polls the I/O events. + /// Must be called in the loop thread. virtual void poll(int timeoutMs, ChannelList* activeChannels) = 0; + + /// Changes the interested I/O events. + /// Must be called in the loop thread. virtual void updateChannel(Channel* channel) = 0; static Poller* newDefaultPoller(); diff --git a/muduo/net/Timer.h b/muduo/net/Timer.h index 5250effdc..95f6263d5 100644 --- a/muduo/net/Timer.h +++ b/muduo/net/Timer.h @@ -21,9 +21,9 @@ class Timer : boost::noncopyable public: typedef boost::function TimerCallback; - Timer(const TimerCallback& cb, UtcTime at, double interval) + Timer(const TimerCallback& cb, UtcTime when, double interval) : cb_(cb), - expiration_(at), + expiration_(when), interval_(interval), repeat_(interval > 0.0) { } diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index efae84d8e..3d7a5929f 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -28,9 +28,9 @@ int createTimerfd() return timerfd; } -struct timespec howMuchTimeFromNow(UtcTime then) +struct timespec howMuchTimeFromNow(UtcTime when) { - int64_t microseconds = then.microSecondsSinceEpoch() + int64_t microseconds = when.microSecondsSinceEpoch() - UtcTime::now().microSecondsSinceEpoch(); if (microseconds < 100) { @@ -41,6 +41,21 @@ struct timespec howMuchTimeFromNow(UtcTime then) ts.tv_nsec = static_cast((microseconds % UtcTime::kMicroSecondsPerSecond) * 1000); return ts; } + +void resetTimerfd(int timerfd, UtcTime when) +{ + // wake up loop by timerfd_settime() + struct itimerspec newValue; + struct itimerspec oldValue; + bzero(&newValue, sizeof newValue); + bzero(&oldValue, sizeof oldValue); + newValue.it_value = howMuchTimeFromNow(when); + int ret = timerfd_settime(timerfd, 0, &newValue, &oldValue); + if (ret) + { + perror("Error in timerfd_settime"); + } +} } TimerQueue::TimerQueue(EventLoop* loop) @@ -59,65 +74,114 @@ TimerQueue::~TimerQueue() { ::close(timerfd_); // do not remove channel, since we're in EventLoop::dtor(); - /* - for (Alarms::iterator it(alarms_.begin()); - it != alarms_.end(); - ++it) + for (TimerList::iterator it = timers_.begin(); + it != timers_.end(); ++it) { - delete it->second; + delete *it; } - */ } +// FIXME replace linked-list operations with binary-heap. void TimerQueue::timeout() { + loop_->assertInLoopThread(); + UtcTime now(UtcTime::now()); uint64_t howmany; ssize_t n = ::read(timerfd_, &howmany, sizeof howmany); - printf("timeout %" PRIu64 "\n", howmany); + printf("TimerQueue::timeout() timeout %" PRIu64 " at %s\n", howmany, now.toString().c_str()); if (n != sizeof howmany) { fprintf(stderr, "TimerQueue::timeout() reads %zd bytes instead of 8\n", n); } -} -TimerId TimerQueue::schedule(const TimerCallback& cb, UtcTime at, double interval) -{ - Timer* timer = new Timer(cb, at, interval); - - bool earliestChanged = false; + TimerList expired; + + // move out all expired timers { MutexLockGuard lock(mutex_); + // shall never callback in critical section TimerList::iterator it = timers_.begin(); - if (it == timers_.end() || (*it)->expiration().after(at)) + while (it != timers_.end() && !(*it)->expiration().after(now)) { - timers_.push_front(timer); - earliestChanged = true; + ++it; } - else + assert(it == timers_.end() || (*it)->expiration().after(now)); + expired.splice(expired.begin(), timers_, timers_.begin(), it); + } + + // safe to callback outside critical section + for (TimerList::iterator it = expired.begin(); + it != expired.end(); ++it) + { + (*it)->run(); + } + + UtcTime nextExpire; + { + MutexLockGuard lock(mutex_); + // shall never callback in critical section + + for (TimerList::iterator it = expired.begin(); + it != expired.end(); ++it) { - while (it != timers_.end() && (*it)->expiration().before(at)) + if ((*it)->repeat()) + { + (*it)->restart(now); + insertWithLockHold(*it); + } + else { - ++it; + delete *it; } - timers_.insert(it, timer); + } + if (!timers_.empty()) + { + nextExpire = timers_.front()->expiration(); } } + if (nextExpire.valid()) + { + resetTimerfd(timerfd_, nextExpire); + } +} + +TimerId TimerQueue::schedule(const TimerCallback& cb, UtcTime when, double interval) +{ + Timer* timer = new Timer(cb, when, interval); + + bool earliestChanged = false; + { + MutexLockGuard lock(mutex_); + // shall never callback in critical section + earliestChanged = insertWithLockHold(timer); + } if (earliestChanged) { - // wake up loop by timerfd_settime() - struct itimerspec newValue; - struct itimerspec oldValue; - bzero(&newValue, sizeof newValue); - bzero(&oldValue, sizeof oldValue); - newValue.it_value = howMuchTimeFromNow(at); - int ret = timerfd_settime(timerfd_, 0, &newValue, &oldValue); - if (ret) - { - perror("Error in timerfd_settime"); - } + resetTimerfd(timerfd_, when); } return TimerId(timer); } +bool TimerQueue::insertWithLockHold(Timer* timer) +{ + bool earliestChanged = false; + UtcTime when = timer->expiration(); + TimerList::iterator it = timers_.begin(); + if (it == timers_.end() || (*it)->expiration().after(when)) + { + timers_.push_front(timer); + earliestChanged = true; + } + else + { + while (it != timers_.end() && (*it)->expiration().before(when)) + { + ++it; + } + timers_.insert(it, timer); + } + return earliestChanged; +} + diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index d81236abc..e54a892d8 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -35,21 +35,23 @@ class TimerQueue : boost::noncopyable /// Schedules the callback to be run at given time, /// repeats if @c interval > 0.0. /// - /// Must be thread safe. - TimerId schedule(const TimerCallback& cb, UtcTime at, double interval); + /// Must be thread safe. Usually be called from other threads. + TimerId schedule(const TimerCallback& cb, UtcTime when, double interval); void cancel(TimerId timerId); private: - void timeout(); + void timeout(); // called when timerfd arms + bool insertWithLockHold(Timer* timer); // insert timer in sorted list. + // FIXME: use unique_ptr instead of raw pointers. typedef std::list TimerList; EventLoop* loop_; const int timerfd_; Channel timerfdChannel_; MutexLock mutex_; - TimerList timers_; // GuardedBy mutex_ + TimerList timers_; // Timer list sorted by expiration, @GuardedBy mutex_ }; } diff --git a/muduo/net/tests/CMakeLists.txt b/muduo/net/tests/CMakeLists.txt index 086d9adec..84fe2a710 100644 --- a/muduo/net/tests/CMakeLists.txt +++ b/muduo/net/tests/CMakeLists.txt @@ -1,3 +1,3 @@ -add_executable(EventLoop_unittest EventLoop_unittest.cc) -target_link_libraries(EventLoop_unittest muduo_net) +add_executable(eventloop_unittest EventLoop_unittest.cc) +target_link_libraries(eventloop_unittest muduo_net) diff --git a/muduo/net/tests/EventLoop_unittest.cc b/muduo/net/tests/EventLoop_unittest.cc index 3aa6f194f..ed5c7e415 100644 --- a/muduo/net/tests/EventLoop_unittest.cc +++ b/muduo/net/tests/EventLoop_unittest.cc @@ -1,4 +1,7 @@ #include +#include + +#include #include #include @@ -6,18 +9,36 @@ using namespace muduo; using namespace muduo::net; -void print() +int cnt = 0; +EventLoop* g_loop; + +void print(const char* msg) { - printf("%s\n", UtcTime::now().toString().c_str()); + printf("msg %s %s\n", UtcTime::now().toString().c_str(), msg); + if (++cnt == 20) + { + g_loop->quit(); + } } int main() { - printf("pid = %d\n", getpid()); - EventLoop loop; + printf("pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + sleep(10); + { + EventLoop loop; + g_loop = &loop; - print(); - loop.runAfter(1.0, print); + print("main"); + loop.runAfter(1, boost::bind(print, "once1")); + loop.runAfter(1.5, boost::bind(print, "once1.5")); + loop.runAfter(2.5, boost::bind(print, "once2.5")); + loop.runAfter(3.5, boost::bind(print, "once3.5")); + loop.runEvery(2, boost::bind(print, "every2")); + loop.runEvery(3, boost::bind(print, "every3")); - loop.loop(); + loop.loop(); + print("exit"); + } + sleep(30); } From cd28062bf89d2024bbffdc4ddf12da570f97aa00 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 13 Mar 2010 14:44:35 +0000 Subject: [PATCH 009/371] Fix on 64-bit. --- muduo/net/PollPoller.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index 3aef4ed37..c47413755 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -63,7 +63,7 @@ void PollPoller::updateChannel(Channel* channel) pfd.events = static_cast(channel->events()); pfd.revents = 0; pollfds_.push_back(pfd); - channel->set_index(pollfds_.size()-1); + channel->set_index(static_cast(pollfds_.size())-1); channels_[pfd.fd] = channel; } else From ebf1f5c8beb7e523ec63448a5b120d748697f05c Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 14 Mar 2010 01:03:03 +0000 Subject: [PATCH 010/371] Add acceptor. --- CMakeLists.txt | 1 + muduo/base/Mutex.h | 7 +++- muduo/net/Acceptor.cc | 29 +++++++++++++ muduo/net/Acceptor.h | 56 ++++++++++++++++++++++++++ muduo/net/CMakeLists.txt | 3 ++ muduo/net/Channel.h | 6 +-- muduo/net/InetAddress.cc | 50 +++++++++++++++++++++++ muduo/net/InetAddress.h | 48 ++++++++++++++++++++++ muduo/net/Socket.h | 20 ++++++++- muduo/net/SocketsOps.cc | 44 ++++++++++++++++++++ muduo/net/SocketsOps.h | 56 ++++++++++++++++++++++++++ muduo/net/TcpServer.h | 34 ++++++++++++++++ muduo/net/Timer.h | 4 +- muduo/net/TimerId.h | 2 +- muduo/net/TimerQueue.cc | 1 + muduo/net/tests/CMakeLists.txt | 3 ++ muduo/net/tests/EventLoop_unittest.cc | 34 +++++----------- muduo/net/tests/TimerQueue_unittest.cc | 42 ++++++++++++++++++- 18 files changed, 403 insertions(+), 37 deletions(-) create mode 100644 muduo/net/Acceptor.cc create mode 100644 muduo/net/Acceptor.h create mode 100644 muduo/net/InetAddress.cc create mode 100644 muduo/net/InetAddress.h create mode 100644 muduo/net/SocketsOps.cc create mode 100644 muduo/net/SocketsOps.h create mode 100644 muduo/net/TcpServer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e3efc6e57..4473e3b1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ set(CXX_FLAGS -Wconversion -Wno-unused-parameter -Wold-style-cast + -MMD -Wpointer-arith -Wshadow -Wwrite-strings diff --git a/muduo/base/Mutex.h b/muduo/base/Mutex.h index e78461753..81b6b9009 100644 --- a/muduo/base/Mutex.h +++ b/muduo/base/Mutex.h @@ -61,6 +61,9 @@ class MutexLockGuard : boost::noncopyable } -#define MutexLockGuard(x) error +// Prevent misuse like: +// MutexLockGuard(mutex_); +// A tempory object doesn't hold the lock for long! +#define MutexLockGuard(x) error "Missing guard object name" -#endif +#endif // MUDUO_BASE_MUTEX_H diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc new file mode 100644 index 000000000..8c4d09867 --- /dev/null +++ b/muduo/net/Acceptor.cc @@ -0,0 +1,29 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +Acceptor::Acceptor(EventLoop* loop, const InetAddress& serverAddr) + : loop_(loop), + acceptSocket_(sockets::createNonblockingOrDie()), + acceptChannel_(loop, acceptSocket_.fd()), + listenning_(false) +{ +} + diff --git a/muduo/net/Acceptor.h b/muduo/net/Acceptor.h new file mode 100644 index 000000000..de8da928c --- /dev/null +++ b/muduo/net/Acceptor.h @@ -0,0 +1,56 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MUDUO_NET_ACCEPTOR_H +#define MUDUO_NET_ACCEPTOR_H + +#include +#include + +#include +#include + +namespace muduo +{ +namespace net +{ + +class EventLoop; +class InetAddress; + +/// +/// Acceptor of incoming TCP connections. +/// +class Acceptor : boost::noncopyable +{ + public: + Acceptor(EventLoop* loop, const InetAddress& serverAddr); + ~Acceptor(); + + void accept(); + + bool listenning() { return listenning_; } + void listen(); + + private: + EventLoop* loop_; + Socket acceptSocket_; + Channel acceptChannel_; + bool listenning_; +}; + +} +} + +#endif // MUDUO_NET_ACCEPTOR_H diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 3d7af6919..c35f7fc5c 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -1,11 +1,14 @@ set(net_SRCS + Acceptor.cc Channel.cc DefaultPoller.cc EPollPoller.cc EventLoop.cc + InetAddress.cc Poller.cc PollPoller.cc Socket.cc + SocketsOps.cc Timer.cc TimerQueue.cc ) diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 28605b077..357748cf4 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -1,5 +1,5 @@ -#ifndef NET_CHANNEL_H -#define NET_CHANNEL_H +#ifndef MUDUO_NET_CHANNEL_H +#define MUDUO_NET_CHANNEL_H #include #include @@ -57,4 +57,4 @@ class Channel : boost::noncopyable } } -#endif +#endif // MUDUO_NET_CHANNEL_H diff --git a/muduo/net/InetAddress.cc b/muduo/net/InetAddress.cc new file mode 100644 index 000000000..cea62d1cc --- /dev/null +++ b/muduo/net/InetAddress.cc @@ -0,0 +1,50 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include + +#include +#include +// #include + +typedef struct sockaddr SA; +static const int kListenSize = SOMAXCONN; +static const in_addr_t kInaddrAny = 0; // INADDR_ANY + +// /* Structure describing an Internet socket address. */ +// struct sockaddr_in { +// sa_family_t sin_family; /* address family: AF_INET */ +// uint16_t sin_port; /* port in network byte order */ +// struct in_addr sin_addr; /* internet address */ +// }; + +// /* Internet address. */ +// typedef uint32_t in_addr_t; +// struct in_addr { +// in_addr_t s_addr; /* address in network byte order */ +// }; + +using namespace muduo; +using namespace muduo::net; + +InetAddress::InetAddress(uint16_t port) +{ + bzero(&addr_, sizeof addr_); + addr_.sin_family = AF_INET; + addr_.sin_addr.s_addr = sockets::hostToNetwork32(kInaddrAny); + addr_.sin_port = sockets::hostToNetwork16(port); +} + diff --git a/muduo/net/InetAddress.h b/muduo/net/InetAddress.h new file mode 100644 index 000000000..c940e96ca --- /dev/null +++ b/muduo/net/InetAddress.h @@ -0,0 +1,48 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MUDUO_NET_INETADDRESS_H +#define MUDUO_NET_INETADDRESS_H + +#include "muduo/base/Types.h" + +#include + +namespace muduo +{ +namespace net +{ + +/// +/// Wrapper of sockaddr_in. +/// +class InetAddress +{ + public: + /// Constructs an endpoint with given port number. + /// Mostly used in TcpServer. + explicit InetAddress(uint16_t port); + + /// Constructs an endpoint with given host and port. + /// @c host could either be "1.2.3.4" or "example.com" + InetAddress(string host, uint16_t port); + + private: + struct sockaddr_in addr_; +}; + +} +} + +#endif // MUDUO_NET_INETADDRESS_H diff --git a/muduo/net/Socket.h b/muduo/net/Socket.h index be92d10ac..5fe0e8b06 100644 --- a/muduo/net/Socket.h +++ b/muduo/net/Socket.h @@ -1,6 +1,22 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef MUDUO_NET_SOCKET_H #define MUDUO_NET_SOCKET_H +#include + namespace muduo { /// @@ -14,7 +30,7 @@ namespace net /// /// It closes the sockfd when desctructs. /// -class Socket +class Socket : boost::noncopyable { public: explicit Socket(int sockfd) @@ -36,4 +52,4 @@ class Socket } } -#endif +#endif // MUDUO_NET_SOCKET_H diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc new file mode 100644 index 000000000..6fc34c2d1 --- /dev/null +++ b/muduo/net/SocketsOps.cc @@ -0,0 +1,44 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int sockets::createNonblockingOrDie() +{ + // socket + int sockfd = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + // reuse addr + int one = 1; + ::setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one); + + // non-block + int flags = ::fcntl(sockfd, F_GETFL, 0); + flags |= O_NONBLOCK; + int ret = ::fcntl(sockfd, F_SETFL, flags); + + // close-on-exec + flags = ::fcntl(sockfd, F_GETFD, 0); + flags |= FD_CLOEXEC; + ret = ::fcntl(sockfd, F_SETFD, flags); + + return sockfd; +} + diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h new file mode 100644 index 000000000..40f2ea1db --- /dev/null +++ b/muduo/net/SocketsOps.h @@ -0,0 +1,56 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MUDUO_NET_SOCKETSOPS_H +#define MUDUO_NET_SOCKETSOPS_H + +#include + +namespace muduo +{ +namespace net +{ +namespace sockets +{ + +inline uint32_t hostToNetwork32(uint32_t hostlong) +{ + return htonl(hostlong); +} + +inline uint16_t hostToNetwork16(uint16_t hostshort) +{ + return htons(hostshort); +} + +inline uint32_t networkToHost32(uint32_t netlong) +{ + return ntohl(netlong); +} + +inline uint16_t networkToHost16(uint16_t netshort) +{ + return ntohs(netshort); +} + +/// +/// Creates a non-blocking socket file descriptor, +/// abort if any error. +int createNonblockingOrDie(); + +} +} +} + +#endif // MUDUO_NET_SOCKETSOPS_H diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h new file mode 100644 index 000000000..b855cae92 --- /dev/null +++ b/muduo/net/TcpServer.h @@ -0,0 +1,34 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MUDUO_NET_TCPSERVER_H +#define MUDUO_NET_TCPSERVER_H + +#include + +namespace muduo +{ +namespace net +{ + +class TcpServer : boost::noncopyable +{ + public: + + private: +}; + +} +} + diff --git a/muduo/net/Timer.h b/muduo/net/Timer.h index 95f6263d5..34fd6c0d0 100644 --- a/muduo/net/Timer.h +++ b/muduo/net/Timer.h @@ -12,7 +12,6 @@ namespace muduo { namespace net { - /// /// Internal class for timer event. /// @@ -44,7 +43,6 @@ class Timer : boost::noncopyable const double interval_; const bool repeat_; }; - } } -#endif +#endif // MUDUO_NET_TIMER_H diff --git a/muduo/net/TimerId.h b/muduo/net/TimerId.h index d9bccddd8..3dd6cc985 100644 --- a/muduo/net/TimerId.h +++ b/muduo/net/TimerId.h @@ -11,7 +11,7 @@ class Timer; /// /// An opaque identifier, for canceling Timer. /// -class TimerId +class TimerId // muduo::copyable { public: explicit TimerId(Timer* timer) diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index 3d7a5929f..d5c53d450 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -131,6 +131,7 @@ void TimerQueue::timeout() } else { + // FIXME move to a free list delete *it; } } diff --git a/muduo/net/tests/CMakeLists.txt b/muduo/net/tests/CMakeLists.txt index 84fe2a710..026a403b0 100644 --- a/muduo/net/tests/CMakeLists.txt +++ b/muduo/net/tests/CMakeLists.txt @@ -1,3 +1,6 @@ add_executable(eventloop_unittest EventLoop_unittest.cc) target_link_libraries(eventloop_unittest muduo_net) +add_executable(timerqueue_unittest TimerQueue_unittest.cc) +target_link_libraries(timerqueue_unittest muduo_net) + diff --git a/muduo/net/tests/EventLoop_unittest.cc b/muduo/net/tests/EventLoop_unittest.cc index ed5c7e415..bdd8fcbbf 100644 --- a/muduo/net/tests/EventLoop_unittest.cc +++ b/muduo/net/tests/EventLoop_unittest.cc @@ -9,36 +9,22 @@ using namespace muduo; using namespace muduo::net; -int cnt = 0; EventLoop* g_loop; -void print(const char* msg) +void threadFunc() { - printf("msg %s %s\n", UtcTime::now().toString().c_str(), msg); - if (++cnt == 20) - { - g_loop->quit(); - } + EventLoop loop; + loop.loop(); } int main() { printf("pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); - sleep(10); - { - EventLoop loop; - g_loop = &loop; - - print("main"); - loop.runAfter(1, boost::bind(print, "once1")); - loop.runAfter(1.5, boost::bind(print, "once1.5")); - loop.runAfter(2.5, boost::bind(print, "once2.5")); - loop.runAfter(3.5, boost::bind(print, "once3.5")); - loop.runEvery(2, boost::bind(print, "every2")); - loop.runEvery(3, boost::bind(print, "every3")); - - loop.loop(); - print("exit"); - } - sleep(30); + + EventLoop loop; + + Thread thread(threadFunc); + thread.start(); + + loop.loop(); } diff --git a/muduo/net/tests/TimerQueue_unittest.cc b/muduo/net/tests/TimerQueue_unittest.cc index 7318e3984..ed5c7e415 100644 --- a/muduo/net/tests/TimerQueue_unittest.cc +++ b/muduo/net/tests/TimerQueue_unittest.cc @@ -1,6 +1,44 @@ -#include +#include +#include + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int cnt = 0; +EventLoop* g_loop; + +void print(const char* msg) +{ + printf("msg %s %s\n", UtcTime::now().toString().c_str(), msg); + if (++cnt == 20) + { + g_loop->quit(); + } +} int main() { - TimerQueue queue; + printf("pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + sleep(10); + { + EventLoop loop; + g_loop = &loop; + + print("main"); + loop.runAfter(1, boost::bind(print, "once1")); + loop.runAfter(1.5, boost::bind(print, "once1.5")); + loop.runAfter(2.5, boost::bind(print, "once2.5")); + loop.runAfter(3.5, boost::bind(print, "once3.5")); + loop.runEvery(2, boost::bind(print, "every2")); + loop.runEvery(3, boost::bind(print, "every3")); + + loop.loop(); + print("exit"); + } + sleep(30); } From 960a14dba687180ef86d3caa5cf551584acbf4fd Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 14 Mar 2010 04:01:33 +0000 Subject: [PATCH 011/371] Add muduo::copyable. --- CMakeLists.txt | 4 +-- muduo/base/Thread.cc | 47 +++++++++++++++----------- muduo/base/Thread.h | 9 ++++- muduo/base/UtcTime.cc | 4 +++ muduo/base/UtcTime.h | 3 +- muduo/base/copyable.h | 15 ++++++++ muduo/net/Acceptor.cc | 2 +- muduo/net/Acceptor.h | 4 +-- muduo/net/CMakeLists.txt | 1 + muduo/net/Channel.cc | 5 +-- muduo/net/Channel.h | 2 ++ muduo/net/EPollPoller.cc | 30 +++++----------- muduo/net/EPollPoller.h | 2 +- muduo/net/EventLoop.cc | 13 +++++++ muduo/net/EventLoop.h | 5 +-- muduo/net/InetAddress.cc | 10 +++++- muduo/net/InetAddress.h | 8 +++-- muduo/net/PollPoller.h | 2 +- muduo/net/Poller.h | 2 +- muduo/net/Socket.cc | 7 +++- muduo/net/SocketsOps.h | 4 +++ muduo/net/TcpConnection.h | 35 +++++++++++++++++++ muduo/net/TcpServer.cc | 35 +++++++++++++++++++ muduo/net/TcpServer.h | 19 +++++++++++ muduo/net/TimerId.h | 6 ++-- muduo/net/TimerQueue.h | 2 +- muduo/net/boilerplate | 35 +++++++++++++++++++ muduo/net/tests/CMakeLists.txt | 2 ++ muduo/net/tests/EchoServer_unittest.cc | 43 +++++++++++++++++++++++ muduo/net/tests/EventLoop_unittest.cc | 11 +++++- 30 files changed, 304 insertions(+), 63 deletions(-) create mode 100644 muduo/base/copyable.h create mode 100644 muduo/net/TcpConnection.h create mode 100644 muduo/net/TcpServer.cc create mode 100644 muduo/net/boilerplate create mode 100644 muduo/net/tests/EchoServer_unittest.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 4473e3b1c..a00bd4a94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,9 +6,9 @@ set(CXX_FLAGS -g -Wall -Wextra - -Werror + # -Werror -Wconversion - -Wno-unused-parameter + -Wunused-parameter -Wold-style-cast -MMD -Wpointer-arith diff --git a/muduo/base/Thread.cc b/muduo/base/Thread.cc index 8d6c98f0b..bd80299da 100644 --- a/muduo/base/Thread.cc +++ b/muduo/base/Thread.cc @@ -7,26 +7,30 @@ namespace { - __thread pid_t t_tid = 0; +__thread pid_t t_cachedTid = 0; - pid_t gettid() - { - return static_cast(::syscall(SYS_gettid)); - } +pid_t gettid() +{ + return static_cast(::syscall(SYS_gettid)); +} - void* startThread(void* cb) - { - muduo::Thread::ThreadFunc* func = static_cast(cb); - t_tid = gettid(); - (*func)(); - return NULL; - } } using namespace muduo; +pid_t CurrentThread::tid() +{ + if (t_cachedTid == 0) + { + t_cachedTid = gettid(); + } + return t_cachedTid; +} + Thread::Thread(const ThreadFunc& func) - : ptid_(0), + : started_(false), + pthreadId_(0), + tid_(0), func_(func) { } @@ -37,19 +41,22 @@ Thread::~Thread() void Thread::start() { - pthread_create(&ptid_, NULL, &startThread, &func_); + assert(!started_); + started_ = true; + pthread_create(&pthreadId_, NULL, &startThread, this); } void Thread::join() { - pthread_join(ptid_, NULL); + assert(started_); + pthread_join(pthreadId_, NULL); } -pid_t CurrentThread::tid() +void* Thread::startThread(void* obj) { - if (t_tid == 0) { - t_tid = gettid(); - } - return t_tid; + Thread* thread = static_cast(obj); + thread->tid_ = CurrentThread::tid(); + thread->func_(); + return NULL; } diff --git a/muduo/base/Thread.h b/muduo/base/Thread.h index 4ebb5b6f5..988de403c 100644 --- a/muduo/base/Thread.h +++ b/muduo/base/Thread.h @@ -18,9 +18,16 @@ class Thread void start(); void join(); + bool started() const { return started_; } + pthread_t pthreadId() const { return pthreadId_; } + pid_t tid() const { return tid_; } + private: + static void* startThread(void* thread); - pthread_t ptid_; + bool started_; + pthread_t pthreadId_; + pid_t tid_; ThreadFunc func_; }; diff --git a/muduo/base/UtcTime.cc b/muduo/base/UtcTime.cc index fd7daafce..4c7509e23 100644 --- a/muduo/base/UtcTime.cc +++ b/muduo/base/UtcTime.cc @@ -6,8 +6,12 @@ #include #undef __STDC_FORMAT_MACROS +#include + using namespace muduo; +BOOST_STATIC_ASSERT(sizeof(UtcTime) == sizeof(int64_t)); + UtcTime::UtcTime() : microSecondsSinceEpoch_(0) { diff --git a/muduo/base/UtcTime.h b/muduo/base/UtcTime.h index 7496385eb..5495287c5 100644 --- a/muduo/base/UtcTime.h +++ b/muduo/base/UtcTime.h @@ -1,6 +1,7 @@ #ifndef MUDUO_BASE_UTCTIME_H #define MUDUO_BASE_UTCTIME_H +#include #include namespace muduo @@ -12,7 +13,7 @@ namespace muduo /// This class is immutable. /// It's recommended to pass it by value, since it's passed in register on x64. /// -class UtcTime +class UtcTime : public muduo::copyable { public: /// diff --git a/muduo/base/copyable.h b/muduo/base/copyable.h new file mode 100644 index 000000000..f3259ec50 --- /dev/null +++ b/muduo/base/copyable.h @@ -0,0 +1,15 @@ +#ifndef MUDUO_BASE_COPYABLE_H +#define MUDUO_BASE_COPYABLE_H + +namespace muduo +{ + +/// A tag class emphasises the objects are copyable. +/// The empty base class optimization applies. +class copyable +{ +}; + +}; + +#endif // MUDUO_BASE_COPYABLE_H diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index 8c4d09867..f046cb0df 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -19,7 +19,7 @@ using namespace muduo; using namespace muduo::net; -Acceptor::Acceptor(EventLoop* loop, const InetAddress& serverAddr) +Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr) : loop_(loop), acceptSocket_(sockets::createNonblockingOrDie()), acceptChannel_(loop, acceptSocket_.fd()), diff --git a/muduo/net/Acceptor.h b/muduo/net/Acceptor.h index de8da928c..b141a6099 100644 --- a/muduo/net/Acceptor.h +++ b/muduo/net/Acceptor.h @@ -35,8 +35,8 @@ class InetAddress; class Acceptor : boost::noncopyable { public: - Acceptor(EventLoop* loop, const InetAddress& serverAddr); - ~Acceptor(); + Acceptor(EventLoop* loop, const InetAddress& listenAddr); + // ~Acceptor(); void accept(); diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index c35f7fc5c..2fa271ad5 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -9,6 +9,7 @@ set(net_SRCS PollPoller.cc Socket.cc SocketsOps.cc + TcpServer.cc Timer.cc TimerQueue.cc ) diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 51e227fb4..8e672954f 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -6,7 +6,8 @@ using namespace muduo; using namespace muduo::net; -const int Channel::kReadEvent = POLLIN; +const int Channel::kReadEvent = POLLIN | POLLPRI; +const int Channel::kWriteEvent = POLLOUT; Channel::Channel(EventLoop* loop, int fd__) : loop_(loop), @@ -25,7 +26,7 @@ void Channel::handle_event() { if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) { - //FIXME handleClose(); + if (closeCallback_) closeCallback_(); } if (revents_ & POLLNVAL) diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 357748cf4..961764d9c 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -30,6 +30,7 @@ class Channel : boost::noncopyable void handle_event(); void setReadCallback(const EventCallback& cb) { readCallback_ = cb; } void setWriteCallback(const EventCallback& cb) { writeCallback_ = cb; } + void setCloseCallback(const EventCallback& cb) { closeCallback_ = cb; } void setErrorCallback(const EventCallback& cb) { errorCallback_ = cb; } int fd() { return fd_; } @@ -52,6 +53,7 @@ class Channel : boost::noncopyable int index_; // used by PollPoller. EventCallback readCallback_; EventCallback writeCallback_; + EventCallback closeCallback_; EventCallback errorCallback_; }; diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc index f77888496..01b0003c6 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/EPollPoller.cc @@ -6,30 +6,18 @@ #include #include +#include using namespace muduo; using namespace muduo::net; -namespace -{ - // On Linux, the constants of poll(2) and epoll(4) - // are expected to be the same. - char poll_epoll_event_diff_in[EPOLLIN == POLLIN ? 1 : -1]; - char poll_epoll_event_diff_pri[EPOLLPRI == POLLPRI ? 1 : -1]; - char poll_epoll_event_diff_out[EPOLLOUT == POLLOUT ? 1 : -1]; - char poll_epoll_event_diff_rdhup[EPOLLRDHUP == POLLRDHUP ? 1 : -1]; - char poll_epoll_event_diff_err[EPOLLERR == POLLERR ? 1 : -1]; - char poll_epoll_event_diff_hup[EPOLLHUP == POLLHUP ? 1 : -1]; - - void nowarning() - { - (void)poll_epoll_event_diff_in; - (void)poll_epoll_event_diff_out; - (void)poll_epoll_event_diff_pri; - (void)poll_epoll_event_diff_rdhup; - (void)poll_epoll_event_diff_err; - (void)poll_epoll_event_diff_hup; - } -} +// On Linux, the constants of poll(2) and epoll(4) +// are expected to be the same. +BOOST_STATIC_ASSERT(EPOLLIN == POLLIN); +BOOST_STATIC_ASSERT(EPOLLPRI == POLLPRI); +BOOST_STATIC_ASSERT(EPOLLOUT == POLLOUT); +BOOST_STATIC_ASSERT(EPOLLRDHUP == POLLRDHUP); +BOOST_STATIC_ASSERT(EPOLLERR == POLLERR); +BOOST_STATIC_ASSERT(EPOLLHUP == POLLHUP); EPollPoller::~EPollPoller() { diff --git a/muduo/net/EPollPoller.h b/muduo/net/EPollPoller.h index 26d1b19d4..ef1c7eadd 100644 --- a/muduo/net/EPollPoller.h +++ b/muduo/net/EPollPoller.h @@ -29,4 +29,4 @@ class EPollPoller : public Poller } } -#endif +#endif // MUDUO_NET_EPOLLPOLLER_H diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index c35999d86..49aa4a119 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -16,6 +16,8 @@ using namespace muduo::net; namespace { +__thread EventLoop* t_loopInThisThread = 0; + const int kPollTimeMs = 10000; int createEventfd() @@ -39,6 +41,16 @@ EventLoop::EventLoop() wakeupFd_(createEventfd()), wakeupChannel_(new Channel(this, wakeupFd_)) { + if (t_loopInThisThread) + { + fprintf(stderr, "Another EventLoop %p exists in this thread %d\n", + t_loopInThisThread, threadId_); + abort(); + } + else + { + t_loopInThisThread = this; + } wakeupChannel_->setReadCallback(boost::bind(&EventLoop::wakedup, this)); // we are always reading the wakeupfd, like the old pipe(2) way. wakeupChannel_->set_events(Channel::kReadEvent); @@ -48,6 +60,7 @@ EventLoop::EventLoop() EventLoop::~EventLoop() { ::close(wakeupFd_); + t_loopInThisThread = NULL; } void EventLoop::loop() diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 1860a4588..d3ebc04e2 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -22,6 +22,7 @@ class TimerQueue; /// /// Reactor, at most one per thread. /// +/// This is an interface class, so don't expose too much details. class EventLoop : boost::noncopyable { public: @@ -29,7 +30,7 @@ class EventLoop : boost::noncopyable typedef boost::function TimerCallback; EventLoop(); - ~EventLoop(); + ~EventLoop(); // force out-line dtor, for scoped_ptr members. /// /// Loops forever. @@ -86,4 +87,4 @@ class EventLoop : boost::noncopyable } } -#endif +#endif // MUDUO_NET_EVENTLOOP_H diff --git a/muduo/net/InetAddress.cc b/muduo/net/InetAddress.cc index cea62d1cc..ba6ba2139 100644 --- a/muduo/net/InetAddress.cc +++ b/muduo/net/InetAddress.cc @@ -20,9 +20,15 @@ #include // #include +#include + typedef struct sockaddr SA; static const int kListenSize = SOMAXCONN; -static const in_addr_t kInaddrAny = 0; // INADDR_ANY + +// INADDR_ANY use (type)value casting. +#pragma GCC diagnostic ignored "-Wold-style-cast" +static const in_addr_t kInaddrAny = INADDR_ANY; +#pragma GCC diagnostic error "-Wold-style-cast" // /* Structure describing an Internet socket address. */ // struct sockaddr_in { @@ -40,6 +46,8 @@ static const in_addr_t kInaddrAny = 0; // INADDR_ANY using namespace muduo; using namespace muduo::net; +BOOST_STATIC_ASSERT(sizeof(InetAddress) == sizeof(struct sockaddr_in)); + InetAddress::InetAddress(uint16_t port) { bzero(&addr_, sizeof addr_); diff --git a/muduo/net/InetAddress.h b/muduo/net/InetAddress.h index c940e96ca..c807aad20 100644 --- a/muduo/net/InetAddress.h +++ b/muduo/net/InetAddress.h @@ -15,7 +15,8 @@ #ifndef MUDUO_NET_INETADDRESS_H #define MUDUO_NET_INETADDRESS_H -#include "muduo/base/Types.h" +#include +#include #include @@ -27,7 +28,8 @@ namespace net /// /// Wrapper of sockaddr_in. /// -class InetAddress +/// This is an interface class. +class InetAddress : public muduo::copyable { public: /// Constructs an endpoint with given port number. @@ -38,6 +40,8 @@ class InetAddress /// @c host could either be "1.2.3.4" or "example.com" InetAddress(string host, uint16_t port); + // default copy/assignment are Okay + private: struct sockaddr_in addr_; }; diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index 89666bca8..8f287a6f3 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -36,4 +36,4 @@ class PollPoller : public Poller } } -#endif +#endif // MUDUO_NET_POLLPOLLER_H diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index 78d67c73e..0d2b0919d 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -34,4 +34,4 @@ class Poller : boost::noncopyable } } -#endif +#endif // MUDUO_NET_POLLER_H diff --git a/muduo/net/Socket.cc b/muduo/net/Socket.cc index 0b0d442a8..e86381075 100644 --- a/muduo/net/Socket.cc +++ b/muduo/net/Socket.cc @@ -3,11 +3,16 @@ #include #include #include -//#include +#include using namespace muduo; using namespace muduo::net; +Socket::~Socket() +{ + ::close(sockfd_); +} + void Socket::setTcpNoDelay(bool on) { int optval = on ? 1 : 0; diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h index 40f2ea1db..6a3da2060 100644 --- a/muduo/net/SocketsOps.h +++ b/muduo/net/SocketsOps.h @@ -24,6 +24,9 @@ namespace net namespace sockets { +// the inline assembler code makes type blur, +// so we disable warnings for a while. +#pragma GCC diagnostic ignored "-Wconversion" inline uint32_t hostToNetwork32(uint32_t hostlong) { return htonl(hostlong); @@ -43,6 +46,7 @@ inline uint16_t networkToHost16(uint16_t netshort) { return ntohs(netshort); } +#pragma GCC diagnostic error "-Wconversion" /// /// Creates a non-blocking socket file descriptor, diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h new file mode 100644 index 000000000..413b54d93 --- /dev/null +++ b/muduo/net/TcpConnection.h @@ -0,0 +1,35 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MUDUO_NET_TCPCONNECTION_H +#define MUDUO_NET_TCPCONNECTION_H + +#include + +namespace muduo +{ +namespace net +{ + +class TcpConnection : boost::noncopyable +{ + public: + + private: +}; + +} +} + +#endif // MUDUO_NET_TCPCONNECTION_H diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc new file mode 100644 index 000000000..b7ab1897a --- /dev/null +++ b/muduo/net/TcpServer.cc @@ -0,0 +1,35 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + acceptor_(new Acceptor(loop, listenAddr)) +{ +} + +TcpServer::~TcpServer() +{ +} + +void TcpServer::start() +{ +} + diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index b855cae92..8e21bd52c 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -16,19 +16,38 @@ #define MUDUO_NET_TCPSERVER_H #include +#include namespace muduo { namespace net { +class Acceptor; +class EventLoop; +class InetAddress; + +/// +/// TCP server, supports single-threaded and thread-pool models. +/// +/// This is an interface class, so don't expose too much details. class TcpServer : boost::noncopyable { public: + TcpServer(EventLoop* loop, const InetAddress& listenAddr); + ~TcpServer(); // force out-line dtor, for scoped_ptr members. + + /// Starts the server if it's not listenning. + /// + /// It's harmless to call it multiple times. + void start(); private: + EventLoop* loop_; + boost::scoped_ptr acceptor_; // avoid revealing Acceptor }; } } +#endif // MUDUO_NET_TCPSERVER_H diff --git a/muduo/net/TimerId.h b/muduo/net/TimerId.h index 3dd6cc985..f4f5ca0c2 100644 --- a/muduo/net/TimerId.h +++ b/muduo/net/TimerId.h @@ -1,6 +1,8 @@ #ifndef MUDUO_NET_TIMERID_H #define MUDUO_NET_TIMERID_H +#include + namespace muduo { namespace net @@ -11,7 +13,7 @@ class Timer; /// /// An opaque identifier, for canceling Timer. /// -class TimerId // muduo::copyable +class TimerId : public muduo::copyable { public: explicit TimerId(Timer* timer) @@ -26,4 +28,4 @@ class TimerId // muduo::copyable } } -#endif +#endif // MUDUO_NET_TIMERID_H diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index e54a892d8..aba08358e 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -56,4 +56,4 @@ class TimerQueue : boost::noncopyable } } -#endif +#endif // MUDUO_NET_TIMERQUEUE_H diff --git a/muduo/net/boilerplate b/muduo/net/boilerplate new file mode 100644 index 000000000..6abcbf438 --- /dev/null +++ b/muduo/net/boilerplate @@ -0,0 +1,35 @@ +// Copyright 2010 Shuo Chen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MUDUO_NET_BOILERPLATE_H +#define MUDUO_NET_BOILERPLATE_H + +#include + +namespace muduo +{ +namespace net +{ + +class BoilerPlate : boost::noncopyable +{ + public: + + private: +}; + +} +} + +#endif // MUDUO_NET_BOILERPLATE_H diff --git a/muduo/net/tests/CMakeLists.txt b/muduo/net/tests/CMakeLists.txt index 026a403b0..49a5e30cd 100644 --- a/muduo/net/tests/CMakeLists.txt +++ b/muduo/net/tests/CMakeLists.txt @@ -4,3 +4,5 @@ target_link_libraries(eventloop_unittest muduo_net) add_executable(timerqueue_unittest TimerQueue_unittest.cc) target_link_libraries(timerqueue_unittest muduo_net) +add_executable(echoserver_unittest EchoServer_unittest.cc) +target_link_libraries(echoserver_unittest muduo_net) diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc new file mode 100644 index 000000000..4623ef972 --- /dev/null +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -0,0 +1,43 @@ +#include +#include +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +class EchoServer +{ + public: + EchoServer(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr) + { + } + + void start() + { + server_.start(); + } + // void stop(); + + private: + EventLoop* loop_; + TcpServer server_; +}; + +void threadFunc(uint16_t port) +{ +} + +int main() +{ + EventLoop loop; + InetAddress listenAddr(2000); + EchoServer server(&loop, listenAddr); + server.start(); + + loop.loop(); +} + diff --git a/muduo/net/tests/EventLoop_unittest.cc b/muduo/net/tests/EventLoop_unittest.cc index bdd8fcbbf..fa5747a97 100644 --- a/muduo/net/tests/EventLoop_unittest.cc +++ b/muduo/net/tests/EventLoop_unittest.cc @@ -11,15 +11,24 @@ using namespace muduo::net; EventLoop* g_loop; +void callback() +{ + printf("callback(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + EventLoop anotherLoop; +} + void threadFunc() { + printf("threadFunc(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + EventLoop loop; + loop.runAfter(1.0, callback); loop.loop(); } int main() { - printf("pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + printf("main(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); EventLoop loop; From 9f1763d3dd8ef7906c3a09f2ca811df44b7127d4 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 14 Mar 2010 06:00:14 +0000 Subject: [PATCH 012/371] Add email address. --- muduo/net/Acceptor.cc | 5 +++- muduo/net/Acceptor.h | 2 +- muduo/net/CMakeLists.txt | 2 +- muduo/net/Callbacks.h | 35 ++++++++++++++++++++++++++ muduo/net/EventLoop.h | 2 +- muduo/net/InetAddress.cc | 2 +- muduo/net/InetAddress.h | 2 +- muduo/net/Socket.cc | 19 ++++++++++++++ muduo/net/Socket.h | 10 +++++--- muduo/net/SocketsOps.cc | 2 +- muduo/net/SocketsOps.h | 2 +- muduo/net/TcpConnection.cc | 16 ++++++++++++ muduo/net/TcpConnection.h | 2 +- muduo/net/TcpServer.cc | 2 +- muduo/net/TcpServer.h | 10 +++++++- muduo/net/Timer.h | 4 +-- muduo/net/TimerQueue.cc | 4 +-- muduo/net/TimerQueue.h | 4 +-- muduo/net/boilerplate | 2 +- muduo/net/tests/EchoServer_unittest.cc | 3 +++ 20 files changed, 106 insertions(+), 24 deletions(-) create mode 100644 muduo/net/Callbacks.h create mode 100644 muduo/net/TcpConnection.cc diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index f046cb0df..86636aa4b 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -27,3 +27,6 @@ Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr) { } +void Acceptor::listen() +{ +} diff --git a/muduo/net/Acceptor.h b/muduo/net/Acceptor.h index b141a6099..901340a67 100644 --- a/muduo/net/Acceptor.h +++ b/muduo/net/Acceptor.h @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 2fa271ad5..9d4ab8cc9 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -1,4 +1,4 @@ -set(net_SRCS +set(net_SRCS Acceptor.cc Channel.cc DefaultPoller.cc diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h new file mode 100644 index 000000000..fc819e150 --- /dev/null +++ b/muduo/net/Callbacks.h @@ -0,0 +1,35 @@ +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MUDUO_NET_CALLBACKS_H +#define MUDUO_NET_CALLBACKS_H + +#include + +namespace muduo +{ +namespace net +{ + +// All client visible callbacks go here. + +class TcpConnection; +typedef boost::function TimerCallback; +typedef boost::function ConnectionCallback; +typedef boost::function ReadCallback; + +} +} + +#endif // MUDUO_NET_CALLBACKS_H diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index d3ebc04e2..ffffa5f11 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -8,6 +8,7 @@ #include #include +#include #include namespace muduo @@ -27,7 +28,6 @@ class EventLoop : boost::noncopyable { public: typedef boost::function Functor; - typedef boost::function TimerCallback; EventLoop(); ~EventLoop(); // force out-line dtor, for scoped_ptr members. diff --git a/muduo/net/InetAddress.cc b/muduo/net/InetAddress.cc index ba6ba2139..3047b4057 100644 --- a/muduo/net/InetAddress.cc +++ b/muduo/net/InetAddress.cc @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/muduo/net/InetAddress.h b/muduo/net/InetAddress.h index c807aad20..1d55ccd3d 100644 --- a/muduo/net/InetAddress.h +++ b/muduo/net/InetAddress.h @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/muduo/net/Socket.cc b/muduo/net/Socket.cc index e86381075..cda9fa7cf 100644 --- a/muduo/net/Socket.cc +++ b/muduo/net/Socket.cc @@ -1,3 +1,17 @@ +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include #include @@ -13,6 +27,11 @@ Socket::~Socket() ::close(sockfd_); } +void Socket::shutdown() +{ + // ::shutdown(sockfd_); +} + void Socket::setTcpNoDelay(bool on) { int optval = on ? 1 : 0; diff --git a/muduo/net/Socket.h b/muduo/net/Socket.h index 5fe0e8b06..5e38a8c76 100644 --- a/muduo/net/Socket.h +++ b/muduo/net/Socket.h @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ namespace net /// Wrapper of socket file descriptor. /// /// It closes the sockfd when desctructs. -/// +/// It's thread safe, all operations are delagated to OS. class Socket : boost::noncopyable { public: @@ -39,7 +39,9 @@ class Socket : boost::noncopyable ~Socket(); - int fd() { return sockfd_; } + int fd() const { return sockfd_; } + + void shutdown(); /// /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). @@ -47,7 +49,7 @@ class Socket : boost::noncopyable void setTcpNoDelay(bool on); private: - int sockfd_; + const int sockfd_; }; } diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index 6fc34c2d1..725f5dd6f 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h index 6a3da2060..5af1021de 100644 --- a/muduo/net/SocketsOps.h +++ b/muduo/net/SocketsOps.h @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc new file mode 100644 index 000000000..6dccbcc90 --- /dev/null +++ b/muduo/net/TcpConnection.cc @@ -0,0 +1,16 @@ +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index 413b54d93..2c4252c91 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index b7ab1897a..26416cce6 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index 8e21bd52c..f35fa47bc 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ #ifndef MUDUO_NET_TCPSERVER_H #define MUDUO_NET_TCPSERVER_H +#include + #include #include @@ -34,6 +36,7 @@ class InetAddress; class TcpServer : boost::noncopyable { public: + TcpServer(EventLoop* loop, const InetAddress& listenAddr); ~TcpServer(); // force out-line dtor, for scoped_ptr members. @@ -42,9 +45,14 @@ class TcpServer : boost::noncopyable /// It's harmless to call it multiple times. void start(); + void setConnectionCallback(ConnectionCallback cb); + void setReadCallback(ReadCallback cb); + private: EventLoop* loop_; boost::scoped_ptr acceptor_; // avoid revealing Acceptor + ConnectionCallback connectionCb_; + ReadCallback messageCb_; }; } diff --git a/muduo/net/Timer.h b/muduo/net/Timer.h index 34fd6c0d0..e85b9f5be 100644 --- a/muduo/net/Timer.h +++ b/muduo/net/Timer.h @@ -3,10 +3,10 @@ #include -#include #include #include +#include namespace muduo { @@ -18,8 +18,6 @@ namespace net class Timer : boost::noncopyable { public: - typedef boost::function TimerCallback; - Timer(const TimerCallback& cb, UtcTime when, double interval) : cb_(cb), expiration_(when), diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index d5c53d450..31bdc8662 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -150,7 +150,7 @@ void TimerQueue::timeout() TimerId TimerQueue::schedule(const TimerCallback& cb, UtcTime when, double interval) { Timer* timer = new Timer(cb, when, interval); - + bool earliestChanged = false; { MutexLockGuard lock(mutex_); @@ -161,7 +161,7 @@ TimerId TimerQueue::schedule(const TimerCallback& cb, UtcTime when, double inter { resetTimerfd(timerfd_, when); } - + return TimerId(timer); } diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index aba08358e..29e9235be 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -3,11 +3,11 @@ #include -#include #include #include #include +#include #include namespace muduo @@ -26,8 +26,6 @@ class TimerId; class TimerQueue : boost::noncopyable { public: - typedef boost::function TimerCallback; - TimerQueue(EventLoop* loop); ~TimerQueue(); diff --git a/muduo/net/boilerplate b/muduo/net/boilerplate index 6abcbf438..c3f9846dd 100644 --- a/muduo/net/boilerplate +++ b/muduo/net/boilerplate @@ -1,4 +1,4 @@ -// Copyright 2010 Shuo Chen +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 4623ef972..362fd0189 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -14,6 +14,7 @@ class EchoServer : loop_(loop), server_(loop, listenAddr) { + server_.setReadCallback(boost::bind(&EchoServer::onRead, this)); } void start() @@ -23,6 +24,8 @@ class EchoServer // void stop(); private: + void onRead(); + EventLoop* loop_; TcpServer server_; }; From 3404c2eb2b75e0c1fae0b1a62975084c2f8bc285 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 14 Mar 2010 12:31:05 +0000 Subject: [PATCH 013/371] Acceptor works. --- ChangeLog | 19 ++++++ muduo/net/Acceptor.cc | 31 ++++++++++ muduo/net/Acceptor.h | 12 +++- muduo/net/Callbacks.h | 6 +- muduo/net/Channel.h | 12 ++-- muduo/net/EventLoop.cc | 3 +- muduo/net/InetAddress.cc | 13 ++-- muduo/net/InetAddress.h | 7 ++- muduo/net/PollPoller.cc | 3 +- muduo/net/PollPoller.h | 3 +- muduo/net/Socket.cc | 40 +++++++++++- muduo/net/Socket.h | 17 +++++ muduo/net/SocketsOps.cc | 86 ++++++++++++++++++++++++-- muduo/net/SocketsOps.h | 7 +++ muduo/net/TcpServer.cc | 12 ++++ muduo/net/TcpServer.h | 19 ++++-- muduo/net/TimerQueue.cc | 10 ++- muduo/net/TimerQueue.h | 13 ++-- muduo/net/tests/EchoServer_unittest.cc | 18 +++++- 19 files changed, 294 insertions(+), 37 deletions(-) create mode 100644 ChangeLog diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..7ce60b924 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,19 @@ +2010-??-?? Shuo Chen + + * First alpha release, version 0.1.0 + +2010-03-15 Shuo Chen + + * TcpConnection at server side works. + +2010-03-14 Shuo Chen + + * Acceptor works. + +2010-03-13 Shuo Chen + + * TimerQueue works. + +2010-03-12 Shuo Chen + + * Starts working on Muduo. diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index 86636aa4b..da94452ce 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -14,8 +14,14 @@ #include +#include +#include #include +#include + +#include + using namespace muduo; using namespace muduo::net; @@ -25,8 +31,33 @@ Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr) acceptChannel_(loop, acceptSocket_.fd()), listenning_(false) { + acceptSocket_.setReuseAddr(true); + acceptSocket_.bindAddress(listenAddr); + acceptChannel_.setReadCallback( + boost::bind(&Acceptor::accept, this)); } void Acceptor::listen() { + listenning_ = true; + acceptSocket_.listen(); + acceptChannel_.set_events(Channel::kReadEvent); + loop_->updateChannel(&acceptChannel_); +} + +void Acceptor::accept() +{ + InetAddress peerAddr(0); + int connfd = acceptSocket_.accept(&peerAddr); + string hostport = peerAddr.toHostPort(); + printf("Connecting from %s\n", hostport.c_str()); + if (newConnectionCallback_) + { + newConnectionCallback_(connfd, peerAddr); + } + else + { + sockets::close(connfd); + } } + diff --git a/muduo/net/Acceptor.h b/muduo/net/Acceptor.h index 901340a67..86ab0c73f 100644 --- a/muduo/net/Acceptor.h +++ b/muduo/net/Acceptor.h @@ -35,18 +35,24 @@ class InetAddress; class Acceptor : boost::noncopyable { public: + typedef boost::function + NewConnectionCallback; + Acceptor(EventLoop* loop, const InetAddress& listenAddr); // ~Acceptor(); - void accept(); - - bool listenning() { return listenning_; } + void setNewConnectionCallback(const NewConnectionCallback& cb) + { newConnectionCallback_ = cb; } + bool listenning() const { return listenning_; } void listen(); private: + void accept(); + EventLoop* loop_; Socket acceptSocket_; Channel acceptChannel_; + NewConnectionCallback newConnectionCallback_; bool listenning_; }; diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index fc819e150..c9f7ac2ec 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -27,7 +27,11 @@ namespace net class TcpConnection; typedef boost::function TimerCallback; typedef boost::function ConnectionCallback; -typedef boost::function ReadCallback; + +// the data has been read to (buf, len) +typedef boost::function MessageCallback; } } diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 961764d9c..3b728aa15 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -28,10 +28,14 @@ class Channel : boost::noncopyable ~Channel(); void handle_event(); - void setReadCallback(const EventCallback& cb) { readCallback_ = cb; } - void setWriteCallback(const EventCallback& cb) { writeCallback_ = cb; } - void setCloseCallback(const EventCallback& cb) { closeCallback_ = cb; } - void setErrorCallback(const EventCallback& cb) { errorCallback_ = cb; } + void setReadCallback(const EventCallback& cb) + { readCallback_ = cb; } + void setWriteCallback(const EventCallback& cb) + { writeCallback_ = cb; } + void setCloseCallback(const EventCallback& cb) + { closeCallback_ = cb; } + void setErrorCallback(const EventCallback& cb) + { errorCallback_ = cb; } int fd() { return fd_; } int events() { return events_; } diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 49aa4a119..6300dde12 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -51,7 +51,8 @@ EventLoop::EventLoop() { t_loopInThisThread = this; } - wakeupChannel_->setReadCallback(boost::bind(&EventLoop::wakedup, this)); + wakeupChannel_->setReadCallback( + boost::bind(&EventLoop::wakedup, this)); // we are always reading the wakeupfd, like the old pipe(2) way. wakeupChannel_->set_events(Channel::kReadEvent); updateChannel(get_pointer(wakeupChannel_)); diff --git a/muduo/net/InetAddress.cc b/muduo/net/InetAddress.cc index 3047b4057..184418045 100644 --- a/muduo/net/InetAddress.cc +++ b/muduo/net/InetAddress.cc @@ -16,15 +16,11 @@ #include -#include +#include // bzero #include -// #include #include -typedef struct sockaddr SA; -static const int kListenSize = SOMAXCONN; - // INADDR_ANY use (type)value casting. #pragma GCC diagnostic ignored "-Wold-style-cast" static const in_addr_t kInaddrAny = INADDR_ANY; @@ -56,3 +52,10 @@ InetAddress::InetAddress(uint16_t port) addr_.sin_port = sockets::hostToNetwork16(port); } +string InetAddress::toHostPort() +{ + char buf[32]; + sockets::toHostPort(buf, sizeof buf, addr_); + return buf; +} + diff --git a/muduo/net/InetAddress.h b/muduo/net/InetAddress.h index 1d55ccd3d..9c6990934 100644 --- a/muduo/net/InetAddress.h +++ b/muduo/net/InetAddress.h @@ -28,7 +28,7 @@ namespace net /// /// Wrapper of sockaddr_in. /// -/// This is an interface class. +/// This is an POD interface class. class InetAddress : public muduo::copyable { public: @@ -40,8 +40,13 @@ class InetAddress : public muduo::copyable /// @c host could either be "1.2.3.4" or "example.com" InetAddress(string host, uint16_t port); + string toHostPort(); + // default copy/assignment are Okay + const struct sockaddr_in& getSockAddrInet() const { return addr_; } + struct sockaddr_in* getMutableSockAddrInet() { return &addr_; } + private: struct sockaddr_in addr_; }; diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index c47413755..de12b6c94 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -31,7 +31,8 @@ void PollPoller::poll(int timeoutMs, ChannelList* activeChannels) } -void PollPoller::fillActiveChannels(int numEvents, ChannelList* activeChannels) const +void PollPoller::fillActiveChannels(int numEvents, + ChannelList* activeChannels) const { for (PollFdList::const_iterator pfd = pollfds_.begin(); pfd != pollfds_.end() && numEvents > 0; ++pfd) diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index 8f287a6f3..d66b365f8 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -26,7 +26,8 @@ class PollPoller : public Poller virtual void updateChannel(Channel* channel); private: - void fillActiveChannels(int numEvents, ChannelList* activeChannels) const; + void fillActiveChannels(int numEvents, + ChannelList* activeChannels) const; typedef std::vector PollFdList; typedef std::map ChannelMap; diff --git a/muduo/net/Socket.cc b/muduo/net/Socket.cc index cda9fa7cf..4495153e1 100644 --- a/muduo/net/Socket.cc +++ b/muduo/net/Socket.cc @@ -14,17 +14,41 @@ #include +#include +#include + #include #include -#include -#include +#include // bzero using namespace muduo; using namespace muduo::net; Socket::~Socket() { - ::close(sockfd_); + sockets::close(sockfd_); +} + +void Socket::bindAddress(const InetAddress& addr) +{ + sockets::bindOrDie(sockfd_, addr.getSockAddrInet()); +} + +void Socket::listen() +{ + sockets::listenOrDie(sockfd_); +} + +int Socket::accept(InetAddress* peeraddr) +{ + struct sockaddr_in addr; + bzero(&addr, sizeof addr); + int connfd = sockets::accept(sockfd_, &addr); + if (connfd >= 0) + { + *peeraddr->getMutableSockAddrInet() = addr; + } + return connfd; } void Socket::shutdown() @@ -37,4 +61,14 @@ void Socket::setTcpNoDelay(bool on) int optval = on ? 1 : 0; ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof optval); + // FIXME CHECK +} + +void Socket::setReuseAddr(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, + &optval, sizeof optval); + // FIXME CHECK } + diff --git a/muduo/net/Socket.h b/muduo/net/Socket.h index 5e38a8c76..d27250a61 100644 --- a/muduo/net/Socket.h +++ b/muduo/net/Socket.h @@ -25,6 +25,8 @@ namespace muduo namespace net { +class InetAddress; + /// /// Wrapper of socket file descriptor. /// @@ -41,6 +43,16 @@ class Socket : boost::noncopyable int fd() const { return sockfd_; } + /// abort if address in use + void bindAddress(const InetAddress& localaddr); + /// abort if address in use + void listen(); + + /// On success, returns a non-negative integer that is + /// a descriptor for the accepted socket, which has been + /// set to non-blocking and close-on-exec. *peeraddr is assigned. + /// On error, -1 is returned, and *peeraddr is untouched. + int accept(InetAddress* peeraddr); void shutdown(); /// @@ -48,6 +60,11 @@ class Socket : boost::noncopyable /// void setTcpNoDelay(bool on); + /// + /// Enable/disable SO_REUSEADDR + /// + void setReuseAddr(bool on); + private: const int sockfd_; }; diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index 725f5dd6f..b426012c9 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -14,31 +14,109 @@ #include +#include #include +#include // FIXME +#include // FIXME #include +#include using namespace muduo; using namespace muduo::net; +typedef struct sockaddr SA; + int sockets::createNonblockingOrDie() { // socket int sockfd = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - - // reuse addr - int one = 1; - ::setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one); + // FIXME check // non-block int flags = ::fcntl(sockfd, F_GETFL, 0); flags |= O_NONBLOCK; int ret = ::fcntl(sockfd, F_SETFL, flags); + // FIXME check // close-on-exec flags = ::fcntl(sockfd, F_GETFD, 0); flags |= FD_CLOEXEC; ret = ::fcntl(sockfd, F_SETFD, flags); + // FIXME check return sockfd; } +void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) +{ + int ret = ::bind(sockfd, reinterpret_cast(&addr), sizeof addr); + if (ret) + { + perror("sockets::bindOrDie"); + abort(); + } +} + +void sockets::listenOrDie(int sockfd) +{ + int ret = ::listen(sockfd, SOMAXCONN); + if (ret) + { + perror("sockets::listenOrDie"); + abort(); + } +} + +int sockets::accept(int sockfd, struct sockaddr_in* addr) +{ + socklen_t addrlen = sizeof *addr; + int connfd = ::accept4(sockfd, reinterpret_cast(addr), + &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); + if (connfd == -1) + { + int savedErrno = errno; + perror("Socket::accept"); + switch (savedErrno) + { + case EAGAIN: + case ECONNABORTED: + case EINTR: + case EPROTO: // ??? + case EPERM: + // expected errors + break; + case EBADF: + case EFAULT: + case EINVAL: + case EMFILE: // per-process lmit of open file desctiptor ??? + case ENFILE: + case ENOBUFS: + case ENOMEM: + case ENOTSOCK: + case EOPNOTSUPP: + // unexpected errors + abort(); + break; + default: + // unknown errors + abort(); + break; + } + } + return connfd; +} + +void sockets::close(int sockfd) +{ + ::close(sockfd); + // FIXME EINTR +} + +void sockets::toHostPort(char* buf, size_t size, const struct sockaddr_in& addr) +{ + char host[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); + uint16_t port = sockets::networkToHost16(addr.sin_port); + snprintf(buf, size, "%s:%u", host, port); +} + diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h index 5af1021de..f5f2491c8 100644 --- a/muduo/net/SocketsOps.h +++ b/muduo/net/SocketsOps.h @@ -53,6 +53,13 @@ inline uint16_t networkToHost16(uint16_t netshort) /// abort if any error. int createNonblockingOrDie(); +void bindOrDie(int sockfd, const struct sockaddr_in& addr); +void listenOrDie(int sockfd); +int accept(int sockfd, struct sockaddr_in* addr); +void close(int sockfd); + +void toHostPort(char* buf, size_t size, const struct sockaddr_in& addr); + } } } diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 26416cce6..bfc5c712f 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -16,6 +16,8 @@ #include +#include + using namespace muduo; using namespace muduo::net; @@ -23,6 +25,8 @@ TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr) : loop_(loop), acceptor_(new Acceptor(loop, listenAddr)) { + acceptor_->setNewConnectionCallback( + boost::bind(&TcpServer::newConnection, this, _1, _2)); } TcpServer::~TcpServer() @@ -31,5 +35,13 @@ TcpServer::~TcpServer() void TcpServer::start() { + if (!acceptor_->listenning()) + { + acceptor_->listen(); + } } +void TcpServer::newConnection(int fd, const InetAddress& peerAddr) +{ + +} diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index f35fa47bc..a584c2781 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -43,16 +43,27 @@ class TcpServer : boost::noncopyable /// Starts the server if it's not listenning. /// /// It's harmless to call it multiple times. + /// Not thread safe. void start(); - void setConnectionCallback(ConnectionCallback cb); - void setReadCallback(ReadCallback cb); + /// Set connection callback. + /// Not thread safe. + void setConnectionCallback(const ConnectionCallback& cb) + { connectionCallback_ = cb; } + + /// Set message callback. + /// Not thread safe. + void setMessageCallback(const MessageCallback& cb) + { messageCallback_ = cb; } private: + /// Not thread safe. + void newConnection(int fd, const InetAddress& peerAddr); + EventLoop* loop_; boost::scoped_ptr acceptor_; // avoid revealing Acceptor - ConnectionCallback connectionCb_; - ReadCallback messageCb_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; }; } diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index 31bdc8662..dbd64d273 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -64,7 +64,8 @@ TimerQueue::TimerQueue(EventLoop* loop) timerfdChannel_(loop, timerfd_), timers_() { - timerfdChannel_.setReadCallback(boost::bind(&TimerQueue::timeout, this)); + timerfdChannel_.setReadCallback( + boost::bind(&TimerQueue::timeout, this)); // we are always reading the timerfd, we disarm it with timerfd_settime. timerfdChannel_.set_events(Channel::kReadEvent); loop_->updateChannel(&timerfdChannel_); @@ -88,7 +89,8 @@ void TimerQueue::timeout() UtcTime now(UtcTime::now()); uint64_t howmany; ssize_t n = ::read(timerfd_, &howmany, sizeof howmany); - printf("TimerQueue::timeout() timeout %" PRIu64 " at %s\n", howmany, now.toString().c_str()); + printf("TimerQueue::timeout() timeout %" PRIu64 " at %s\n", + howmany, now.toString().c_str()); if (n != sizeof howmany) { fprintf(stderr, "TimerQueue::timeout() reads %zd bytes instead of 8\n", n); @@ -147,7 +149,9 @@ void TimerQueue::timeout() } } -TimerId TimerQueue::schedule(const TimerCallback& cb, UtcTime when, double interval) +TimerId TimerQueue::schedule(const TimerCallback& cb, + UtcTime when, + double interval) { Timer* timer = new Timer(cb, when, interval); diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index 29e9235be..4936cdfd8 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -34,13 +34,17 @@ class TimerQueue : boost::noncopyable /// repeats if @c interval > 0.0. /// /// Must be thread safe. Usually be called from other threads. - TimerId schedule(const TimerCallback& cb, UtcTime when, double interval); + TimerId schedule(const TimerCallback& cb, + UtcTime when, + double interval); void cancel(TimerId timerId); private: - void timeout(); // called when timerfd arms - bool insertWithLockHold(Timer* timer); // insert timer in sorted list. + // called when timerfd arms + void timeout(); + // insert timer in sorted list. + bool insertWithLockHold(Timer* timer); // FIXME: use unique_ptr instead of raw pointers. typedef std::list TimerList; @@ -49,7 +53,8 @@ class TimerQueue : boost::noncopyable const int timerfd_; Channel timerfdChannel_; MutexLock mutex_; - TimerList timers_; // Timer list sorted by expiration, @GuardedBy mutex_ + // Timer list sorted by expiration, @GuardedBy mutex_ + TimerList timers_; }; } diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 362fd0189..1b276065a 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -1,9 +1,12 @@ +#include #include #include #include #include +#include + using namespace muduo; using namespace muduo::net; @@ -14,7 +17,10 @@ class EchoServer : loop_(loop), server_(loop, listenAddr) { - server_.setReadCallback(boost::bind(&EchoServer::onRead, this)); + server_.setConnectionCallback( + boost::bind(&EchoServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&EchoServer::onMessage, this, _1, _2, _3)); } void start() @@ -24,7 +30,13 @@ class EchoServer // void stop(); private: - void onRead(); + void onConnection(TcpConnection*) + { + } + + void onMessage(TcpConnection*, const void* buf, ssize_t len) + { + } EventLoop* loop_; TcpServer server_; @@ -36,9 +48,11 @@ void threadFunc(uint16_t port) int main() { + printf("main(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); EventLoop loop; InetAddress listenAddr(2000); EchoServer server(&loop, listenAddr); + server.start(); loop.loop(); From 40fb9d8f79f5f8fc4e3e1a6656b880e63f3df291 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 14 Mar 2010 14:44:52 +0000 Subject: [PATCH 014/371] Add Condition. --- muduo/base/Condition.h | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 muduo/base/Condition.h diff --git a/muduo/base/Condition.h b/muduo/base/Condition.h new file mode 100644 index 000000000..250b8ab25 --- /dev/null +++ b/muduo/base/Condition.h @@ -0,0 +1,47 @@ +#ifndef MUDUO_BASE_CONDITION_H +#define MUDUO_BASE_CONDITION_H + +#include + +#include + +#include + +namespace muduo +{ + +class Condition : boost::noncopyable +{ + public: + Condition(MutexLock& mutex) : mutex_(mutex) + { + pthread_cond_init(&pcond_, NULL); + } + + ~Condition() + { + pthread_cond_destroy(&pcond_); + } + + void wait() + { + pthread_cond_wait(&pcond_, mutex_.getPthreadMutex()); + } + + void notify() + { + pthread_cond_signal(&pcond_); + } + + void notifyAll() + { + pthread_cond_broadcast(&pcond_); + } + + private: + MutexLock& mutex_; + pthread_cond_t pcond_; +}; + +} +#endif // MUDUO_BASE_CONDITION_H From 6fe8d165b20bc73b6864a782ea016b43cb35844f Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 14 Mar 2010 15:06:37 +0000 Subject: [PATCH 015/371] Add ThreadModel for TcpServer. --- muduo/net/CMakeLists.txt | 1 + muduo/net/EventLoop.cc | 1 + muduo/net/TcpServer.cc | 17 +++- muduo/net/TcpServer.h | 17 +++- muduo/net/ThreadModel.cc | 109 ++++++++++++++++++++++++ muduo/net/ThreadModel.h | 60 +++++++++++++ muduo/net/tests/CMakeLists.txt | 8 +- muduo/net/tests/EchoServer_unittest.cc | 3 +- muduo/net/tests/ThreadModel_unittest.cc | 59 +++++++++++++ 9 files changed, 270 insertions(+), 5 deletions(-) create mode 100644 muduo/net/ThreadModel.cc create mode 100644 muduo/net/ThreadModel.h create mode 100644 muduo/net/tests/ThreadModel_unittest.cc diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 9d4ab8cc9..5e0c0d040 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -10,6 +10,7 @@ set(net_SRCS Socket.cc SocketsOps.cc TcpServer.cc + ThreadModel.cc Timer.cc TimerQueue.cc ) diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 6300dde12..836bf6379 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -41,6 +41,7 @@ EventLoop::EventLoop() wakeupFd_(createEventfd()), wakeupChannel_(new Channel(this, wakeupFd_)) { + printf("EventLoop created in thread %d\n", threadId_); if (t_loopInThisThread) { fprintf(stderr, "Another EventLoop %p exists in this thread %d\n", diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index bfc5c712f..f25dbc606 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -15,6 +15,7 @@ #include #include +#include #include @@ -23,7 +24,9 @@ using namespace muduo::net; TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr) : loop_(loop), - acceptor_(new Acceptor(loop, listenAddr)) + acceptor_(new Acceptor(loop, listenAddr)), + threadModel_(new ThreadModel(loop)), + started_(false) { acceptor_->setNewConnectionCallback( boost::bind(&TcpServer::newConnection, this, _1, _2)); @@ -33,8 +36,20 @@ TcpServer::~TcpServer() { } +void TcpServer::setThreadNum(int numThreads) +{ + assert(0 <= numThreads); + threadModel_->setThreadNum(numThreads); +} + void TcpServer::start() { + if (!started_) + { + started_ = true; + threadModel_->start(); + } + if (!acceptor_->listenning()) { acceptor_->listen(); diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index a584c2781..f3d508514 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -28,6 +28,7 @@ namespace net class Acceptor; class EventLoop; class InetAddress; +class ThreadModel; /// /// TCP server, supports single-threaded and thread-pool models. @@ -40,6 +41,18 @@ class TcpServer : boost::noncopyable TcpServer(EventLoop* loop, const InetAddress& listenAddr); ~TcpServer(); // force out-line dtor, for scoped_ptr members. + /// Set the number of threads for handling input. + /// + /// Always accepts new connection in loop's thread. + /// Must be called before @c start + /// @param numThreads + /// - 0 means all I/O in loop's thread, no thread will created. + /// this is the default value. + /// - 1 means all I/O in another thread. + /// - N means a thread pool with N threads, new connections + /// are assigned on a round-robin basis. + void setThreadNum(int numThreads); + /// Starts the server if it's not listenning. /// /// It's harmless to call it multiple times. @@ -60,10 +73,12 @@ class TcpServer : boost::noncopyable /// Not thread safe. void newConnection(int fd, const InetAddress& peerAddr); - EventLoop* loop_; + EventLoop* loop_; // the acceptor loop boost::scoped_ptr acceptor_; // avoid revealing Acceptor + boost::scoped_ptr threadModel_; ConnectionCallback connectionCallback_; MessageCallback messageCallback_; + bool started_; }; } diff --git a/muduo/net/ThreadModel.cc b/muduo/net/ThreadModel.cc new file mode 100644 index 000000000..83e3db4e1 --- /dev/null +++ b/muduo/net/ThreadModel.cc @@ -0,0 +1,109 @@ +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include + +#include + +using namespace muduo; +using namespace muduo::net; + + +ThreadModel::ThreadModel(EventLoop* baseLoop) + : baseLoop_(baseLoop), + started_(false), + exiting_(false), + numThreads_(0), + next_(0), + mutex_(), + cond_(mutex_) +{ +} + +ThreadModel::~ThreadModel() +{ + exiting_ = true; + for (size_t i = 0; i < loopPool_.size(); ++i) + { + loopPool_[i]->quit(); + // Don't delete loop, it's stack variable + } + for (size_t i = 0; i < threads_.size(); ++i) + { + Thread* t = threads_[i]; + t->join(); + delete t; + } +} + +void ThreadModel::start() +{ + assert(!started_); + baseLoop_->assertInLoopThread(); + + started_ = true; + + Thread::ThreadFunc func = boost::bind(&ThreadModel::threadFunc, this); + + for (int i = 0; i < numThreads_; ++i) + { + Thread* t = new Thread(func); + t->start(); + threads_.push_back(t); + } + + { + MutexLockGuard lock(mutex_); + while (static_cast(loopPool_.size()) != numThreads_) + { + cond_.wait(); + } + } +} + +EventLoop* ThreadModel::getNextLoop() +{ + baseLoop_->assertInLoopThread(); + EventLoop* loop = baseLoop_; + + if (!loopPool_.empty()) + { + // round-robin + loop = loopPool_[next_]; + ++next_; + if (next_ >= static_cast(loopPool_.size())) + { + next_ = 0; + } + } + return loop; +} + +void ThreadModel::threadFunc() +{ + EventLoop loop; + + { + MutexLockGuard lock(mutex_); + loopPool_.push_back(&loop); + cond_.notify(); + } + + loop.loop(); + assert(exiting_); +} + diff --git a/muduo/net/ThreadModel.h b/muduo/net/ThreadModel.h new file mode 100644 index 000000000..0cadda046 --- /dev/null +++ b/muduo/net/ThreadModel.h @@ -0,0 +1,60 @@ +// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MUDUO_NET_THREADMODEL_H +#define MUDUO_NET_THREADMODEL_H + +#include +#include + +#include +#include + +namespace muduo +{ + +class Thread; + +namespace net +{ + +class EventLoop; + +class ThreadModel : boost::noncopyable +{ + public: + ThreadModel(EventLoop* baseLoop); + ~ThreadModel(); + void setThreadNum(int numThreads) { numThreads_ = numThreads; } + void start(); + EventLoop* getNextLoop(); + + private: + void threadFunc(); + + EventLoop* baseLoop_; + bool started_; + bool exiting_; + int numThreads_; + int next_; + std::vector threads_; + MutexLock mutex_; + Condition cond_; + std::vector loopPool_; // @GuardedBy mutex_ +}; + +} +} + +#endif // MUDUO_NET_THREADMODEL_H diff --git a/muduo/net/tests/CMakeLists.txt b/muduo/net/tests/CMakeLists.txt index 49a5e30cd..f45d65f1b 100644 --- a/muduo/net/tests/CMakeLists.txt +++ b/muduo/net/tests/CMakeLists.txt @@ -1,8 +1,12 @@ +add_executable(echoserver_unittest EchoServer_unittest.cc) +target_link_libraries(echoserver_unittest muduo_net) + add_executable(eventloop_unittest EventLoop_unittest.cc) target_link_libraries(eventloop_unittest muduo_net) +add_executable(threadmodel_unittest ThreadModel_unittest.cc) +target_link_libraries(threadmodel_unittest muduo_net) + add_executable(timerqueue_unittest TimerQueue_unittest.cc) target_link_libraries(timerqueue_unittest muduo_net) -add_executable(echoserver_unittest EchoServer_unittest.cc) -target_link_libraries(echoserver_unittest muduo_net) diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 1b276065a..6f4e618d4 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -1,7 +1,8 @@ +#include + #include #include #include -#include #include diff --git a/muduo/net/tests/ThreadModel_unittest.cc b/muduo/net/tests/ThreadModel_unittest.cc new file mode 100644 index 000000000..56eca7f3c --- /dev/null +++ b/muduo/net/tests/ThreadModel_unittest.cc @@ -0,0 +1,59 @@ +#include +#include +#include + +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +void print() +{ + printf("main(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); +} + +int main() +{ + print(); + + EventLoop loop; + loop.runAfter(11, boost::bind(&EventLoop::quit, &loop)); + + { + printf("Single thread:\n"); + ThreadModel model(&loop); + model.setThreadNum(0); + model.start(); + assert(model.getNextLoop() == &loop); + assert(model.getNextLoop() == &loop); + assert(model.getNextLoop() == &loop); + } + + { + printf("Another thread:\n"); + ThreadModel model(&loop); + model.setThreadNum(1); + model.start(); + EventLoop* nextLoop = model.getNextLoop(); + assert(nextLoop != &loop); + assert(nextLoop == model.getNextLoop()); + assert(nextLoop == model.getNextLoop()); + } + + { + printf("Three threads:\n"); + ThreadModel model(&loop); + model.setThreadNum(3); + model.start(); + EventLoop* nextLoop = model.getNextLoop(); + assert(nextLoop != &loop); + assert(nextLoop != model.getNextLoop()); + assert(nextLoop != model.getNextLoop()); + assert(nextLoop == model.getNextLoop()); + } + + loop.loop(); +} + From 523bca869677f03352861330209e016a30fdf6a8 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 14 Mar 2010 17:01:48 +0000 Subject: [PATCH 016/371] Create TcpConnection. --- muduo/net/Acceptor.cc | 17 ++++++--- muduo/net/CMakeLists.txt | 1 + muduo/net/Callbacks.h | 6 ++-- muduo/net/Channel.cc | 3 +- muduo/net/Channel.h | 2 ++ muduo/net/InetAddress.cc | 2 +- muduo/net/InetAddress.h | 12 +++++-- muduo/net/Socket.cc | 2 +- muduo/net/SocketsOps.cc | 11 +++++- muduo/net/SocketsOps.h | 5 ++- muduo/net/TcpConnection.cc | 22 ++++++++++++ muduo/net/TcpConnection.h | 50 +++++++++++++++++++++++++- muduo/net/TcpServer.cc | 27 ++++++++++++-- muduo/net/TcpServer.h | 12 ++++++- muduo/net/tests/EchoServer_unittest.cc | 6 ++-- 15 files changed, 157 insertions(+), 21 deletions(-) diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index da94452ce..e5f8cc9f8 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -49,15 +49,22 @@ void Acceptor::accept() { InetAddress peerAddr(0); int connfd = acceptSocket_.accept(&peerAddr); - string hostport = peerAddr.toHostPort(); - printf("Connecting from %s\n", hostport.c_str()); - if (newConnectionCallback_) + if (connfd >= 0) { - newConnectionCallback_(connfd, peerAddr); + string hostport = peerAddr.toHostPort(); + printf("Connecting from %s\n", hostport.c_str()); + if (newConnectionCallback_) + { + newConnectionCallback_(connfd, peerAddr); + } + else + { + sockets::close(connfd); + } } else { - sockets::close(connfd); + //FIXME log error } } diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 5e0c0d040..3ab23c7cf 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -9,6 +9,7 @@ set(net_SRCS PollPoller.cc Socket.cc SocketsOps.cc + TcpConnection.cc TcpServer.cc ThreadModel.cc Timer.cc diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index c9f7ac2ec..17351bba2 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -16,6 +16,7 @@ #define MUDUO_NET_CALLBACKS_H #include +#include namespace muduo { @@ -25,11 +26,12 @@ namespace net // All client visible callbacks go here. class TcpConnection; +typedef boost::shared_ptr TcpConnectionPtr; typedef boost::function TimerCallback; -typedef boost::function ConnectionCallback; +typedef boost::function ConnectionCallback; // the data has been read to (buf, len) -typedef boost::function MessageCallback; diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 8e672954f..6a98ad2f8 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -26,12 +26,13 @@ void Channel::handle_event() { if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) { + printf("Channel::handle_event() POLLHUP"); if (closeCallback_) closeCallback_(); } if (revents_ & POLLNVAL) { - perror("Channel::handle_event() POLLNVAL"); + printf("Channel::handle_event() POLLNVAL"); } if (revents_ & (POLLERR | POLLNVAL)) diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 3b728aa15..62db1d711 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -15,6 +15,8 @@ class EventLoop; /// A selectable I/O channel. /// /// This class doesn't own the file descriptor. +/// The file descriptor could be a socket, +/// an eventfd, a timerfd, or a signalfd class Channel : boost::noncopyable { public: diff --git a/muduo/net/InetAddress.cc b/muduo/net/InetAddress.cc index 184418045..9bca60368 100644 --- a/muduo/net/InetAddress.cc +++ b/muduo/net/InetAddress.cc @@ -52,7 +52,7 @@ InetAddress::InetAddress(uint16_t port) addr_.sin_port = sockets::hostToNetwork16(port); } -string InetAddress::toHostPort() +string InetAddress::toHostPort() const { char buf[32]; sockets::toHostPort(buf, sizeof buf, addr_); diff --git a/muduo/net/InetAddress.h b/muduo/net/InetAddress.h index 9c6990934..607b22ce5 100644 --- a/muduo/net/InetAddress.h +++ b/muduo/net/InetAddress.h @@ -33,19 +33,25 @@ class InetAddress : public muduo::copyable { public: /// Constructs an endpoint with given port number. - /// Mostly used in TcpServer. + /// Mostly used in TcpServer listening. explicit InetAddress(uint16_t port); /// Constructs an endpoint with given host and port. /// @c host could either be "1.2.3.4" or "example.com" InetAddress(string host, uint16_t port); - string toHostPort(); + /// Constructs an endpoint with given struct @c sockaddr_in + /// Mostly used when accepting new connections + InetAddress(const struct sockaddr_in& addr) + : addr_(addr) + { } + + string toHostPort() const; // default copy/assignment are Okay const struct sockaddr_in& getSockAddrInet() const { return addr_; } - struct sockaddr_in* getMutableSockAddrInet() { return &addr_; } + void setSockAddrInet(const struct sockaddr_in& addr) { addr_ = addr; } private: struct sockaddr_in addr_; diff --git a/muduo/net/Socket.cc b/muduo/net/Socket.cc index 4495153e1..6369d14d8 100644 --- a/muduo/net/Socket.cc +++ b/muduo/net/Socket.cc @@ -46,7 +46,7 @@ int Socket::accept(InetAddress* peeraddr) int connfd = sockets::accept(sockfd_, &addr); if (connfd >= 0) { - *peeraddr->getMutableSockAddrInet() = addr; + peeraddr->setSockAddrInet(addr); } return connfd; } diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index b426012c9..e83dc3230 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -112,7 +112,8 @@ void sockets::close(int sockfd) // FIXME EINTR } -void sockets::toHostPort(char* buf, size_t size, const struct sockaddr_in& addr) +void sockets::toHostPort(char* buf, size_t size, + const struct sockaddr_in& addr) { char host[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); @@ -120,3 +121,11 @@ void sockets::toHostPort(char* buf, size_t size, const struct sockaddr_in& addr) snprintf(buf, size, "%s:%u", host, port); } +struct sockaddr_in sockets::getLocalAddr(int sockfd) +{ + struct sockaddr_in localaddr; + socklen_t addrlen = sizeof(localaddr); + ::getsockname(sockfd, reinterpret_cast(&localaddr), &addrlen); + // FIXME check + return localaddr; +} diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h index f5f2491c8..3da945303 100644 --- a/muduo/net/SocketsOps.h +++ b/muduo/net/SocketsOps.h @@ -58,7 +58,10 @@ void listenOrDie(int sockfd); int accept(int sockfd, struct sockaddr_in* addr); void close(int sockfd); -void toHostPort(char* buf, size_t size, const struct sockaddr_in& addr); +void toHostPort(char* buf, size_t size, + const struct sockaddr_in& addr); + +struct sockaddr_in getLocalAddr(int sockfd); } } diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 6dccbcc90..461e7bc7a 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -14,3 +14,25 @@ #include +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +TcpConnection::TcpConnection(const string& name, + EventLoop* loop, + int fd, + const InetAddress& localAddr, + const InetAddress& peerAddr) + : name_(name), + loop_(loop), + socket_(new Socket(fd)), + channel_(new Channel(loop, fd)), + localAddr_(localAddr), + peerAddr_(peerAddr) +{ + loop_->updateChannel(get_pointer(channel_)); +} + diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index 2c4252c91..075784e24 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -15,20 +15,68 @@ #ifndef MUDUO_NET_TCPCONNECTION_H #define MUDUO_NET_TCPCONNECTION_H +#include +#include +#include + +#include #include +#include +#include namespace muduo { namespace net { -class TcpConnection : boost::noncopyable +class Channel; +class EventLoop; +class Socket; + +/// +/// TCP connection, for both client and server usage. +/// +/// This is an interface class, so don't expose too much details. +class TcpConnection : public boost::enable_shared_from_this, + boost::noncopyable { public: + /// Constructs a TcpConnection with a connected sockfd + /// + TcpConnection(const string& name, + EventLoop* loop, + int sockfd, + const InetAddress& localAddr, + const InetAddress& peerAddr); + + const InetAddress& localAddr() { return localAddr_; } + const InetAddress& peerAddr() { return peerAddr_; } + + void setConnectionCallback(ConnectionCallback cb) + { connectionCallback_ = cb; } + + void setMessageCallback(MessageCallback cb) + { messageCallback_ = cb; } + + /// Internal use only. + void setCloseCallback(ConnectionCallback cb) + { closeCallback_ = cb; } private: + string name_; + EventLoop* loop_; + // we don't expose those classes to client. + boost::scoped_ptr socket_; + boost::scoped_ptr channel_; + InetAddress localAddr_; + InetAddress peerAddr_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + ConnectionCallback closeCallback_; }; +typedef boost::shared_ptr TcpConnectionPtr; + } } diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index f25dbc606..fae06531c 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -15,10 +15,14 @@ #include #include +#include +#include #include #include +#include + using namespace muduo; using namespace muduo::net; @@ -26,7 +30,8 @@ TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr) : loop_(loop), acceptor_(new Acceptor(loop, listenAddr)), threadModel_(new ThreadModel(loop)), - started_(false) + started_(false), + nextConnId_(1) { acceptor_->setNewConnectionCallback( boost::bind(&TcpServer::newConnection, this, _1, _2)); @@ -56,7 +61,25 @@ void TcpServer::start() } } -void TcpServer::newConnection(int fd, const InetAddress& peerAddr) +void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) { + EventLoop* ioLoop = threadModel_->getNextLoop(); + char buf[32]; + snprintf(buf, sizeof buf, "#%d", nextConnId_); + ++nextConnId_; + string connName = serverName_ + buf; + + InetAddress localAddr(sockets::getLocalAddr(sockfd)); + TcpConnectionPtr conn( + new TcpConnection(connName, ioLoop, sockfd, localAddr, peerAddr)); + connections_[connName] = conn; + conn->setConnectionCallback(connectionCallback_); + conn->setMessageCallback(messageCallback_); + conn->setCloseCallback( + boost::bind(&TcpServer::removeConnection, this, _1)); + ioLoop->runInLoop(boost::bind(connectionCallback_, conn)); +} +void TcpServer::removeConnection(const TcpConnectionPtr& conn) +{ } diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index f3d508514..41863c183 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -15,8 +15,11 @@ #ifndef MUDUO_NET_TCPSERVER_H #define MUDUO_NET_TCPSERVER_H +#include #include +#include +#include #include #include @@ -71,14 +74,21 @@ class TcpServer : boost::noncopyable private: /// Not thread safe. - void newConnection(int fd, const InetAddress& peerAddr); + void newConnection(int sockfd, const InetAddress& peerAddr); + void removeConnection(const TcpConnectionPtr& conn); + + typedef std::map ConnectionMap; EventLoop* loop_; // the acceptor loop boost::scoped_ptr acceptor_; // avoid revealing Acceptor boost::scoped_ptr threadModel_; ConnectionCallback connectionCallback_; MessageCallback messageCallback_; + const string serverName_; bool started_; + // always in loop thread + int nextConnId_; + ConnectionMap connections_; }; } diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 6f4e618d4..9919e7eeb 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -31,11 +31,13 @@ class EchoServer // void stop(); private: - void onConnection(TcpConnection*) + void onConnection(const TcpConnectionPtr& conn) { + printf("conn %s -> %s\n", conn->peerAddr().toHostPort().c_str(), + conn->localAddr().toHostPort().c_str()); } - void onMessage(TcpConnection*, const void* buf, ssize_t len) + void onMessage(const TcpConnectionPtr&, const void* buf, ssize_t len) { } From 3f8c39c80461a31a969a282693a088d0f616f336 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Mon, 15 Mar 2010 17:33:19 +0000 Subject: [PATCH 017/371] add ChannelBuffer. TcpConnection reading. BSD License in muduo/net. --- muduo/base/Types.h | 24 ++++ muduo/base/UtcTime.h | 3 +- muduo/net/Acceptor.cc | 37 ++++-- muduo/net/Acceptor.h | 40 ++++-- muduo/net/CMakeLists.txt | 1 + muduo/net/Callbacks.h | 44 +++++-- muduo/net/Channel.cc | 30 +++++ muduo/net/Channel.h | 34 +++++ muduo/net/ChannelBuffer.cc | 69 +++++++++++ muduo/net/ChannelBuffer.h | 164 +++++++++++++++++++++++++ muduo/net/DefaultPoller.cc | 30 +++++ muduo/net/EPollPoller.cc | 30 +++++ muduo/net/EPollPoller.h | 34 +++++ muduo/net/EventLoop.cc | 30 +++++ muduo/net/EventLoop.h | 34 +++++ muduo/net/InetAddress.cc | 36 ++++-- muduo/net/InetAddress.h | 40 ++++-- muduo/net/PollPoller.cc | 30 +++++ muduo/net/PollPoller.h | 34 +++++ muduo/net/Poller.cc | 30 +++++ muduo/net/Poller.h | 34 +++++ muduo/net/Socket.cc | 36 ++++-- muduo/net/Socket.h | 40 ++++-- muduo/net/SocketsOps.cc | 36 ++++-- muduo/net/SocketsOps.h | 40 ++++-- muduo/net/TcpConnection.cc | 85 +++++++++++-- muduo/net/TcpConnection.h | 51 ++++++-- muduo/net/TcpServer.cc | 39 ++++-- muduo/net/TcpServer.h | 40 ++++-- muduo/net/ThreadModel.cc | 36 ++++-- muduo/net/ThreadModel.h | 40 ++++-- muduo/net/Timer.cc | 30 +++++ muduo/net/Timer.h | 34 +++++ muduo/net/TimerId.h | 34 +++++ muduo/net/TimerQueue.cc | 42 ++++++- muduo/net/TimerQueue.h | 34 +++++ muduo/net/boilerplate | 35 ------ muduo/net/boilerplate.cc | 39 ++++++ muduo/net/boilerplate.h | 56 +++++++++ muduo/net/tests/EchoServer_unittest.cc | 6 +- 40 files changed, 1366 insertions(+), 195 deletions(-) create mode 100644 muduo/net/ChannelBuffer.cc create mode 100644 muduo/net/ChannelBuffer.h delete mode 100644 muduo/net/boilerplate create mode 100644 muduo/net/boilerplate.cc create mode 100644 muduo/net/boilerplate.h diff --git a/muduo/base/Types.h b/muduo/base/Types.h index 921b40998..d3b766855 100644 --- a/muduo/base/Types.h +++ b/muduo/base/Types.h @@ -14,6 +14,30 @@ namespace muduo // typedef __gnu_cxx::__versa_string, std::allocator > string; typedef __gnu_cxx::__sso_string string; +// Taken from google-protobuf stubs/common.h +// +// Use implicit_cast as a safe version of static_cast or const_cast +// for upcasting in the type hierarchy (i.e. casting a pointer to Foo +// to a pointer to SuperclassOfFoo or casting a pointer to Foo to +// a const pointer to Foo). +// When you use implicit_cast, the compiler checks that the cast is safe. +// Such explicit implicit_casts are necessary in surprisingly many +// situations where C++ demands an exact type match instead of an +// argument type convertable to a target type. +// +// The From type can be inferred, so the preferred syntax for using +// implicit_cast is the same as for static_cast etc.: +// +// implicit_cast(expr) +// +// implicit_cast would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +template +inline To implicit_cast(From const &f) { + return f; +} + } #endif diff --git a/muduo/base/UtcTime.h b/muduo/base/UtcTime.h index 5495287c5..23123f55d 100644 --- a/muduo/base/UtcTime.h +++ b/muduo/base/UtcTime.h @@ -78,7 +78,8 @@ inline bool operator==(UtcTime lhs, UtcTime rhs) /// /// @param high, low /// @return (high-low) in seconds -/// +/// @c double has 52-bit precision, enough for one-microseciond +/// resolution for next 100 years. inline double timeDifference(UtcTime high, UtcTime low) { int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch(); diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index e5f8cc9f8..e34a19732 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -1,16 +1,32 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include @@ -39,6 +55,7 @@ Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr) void Acceptor::listen() { + loop_->assertInLoopThread(); listenning_ = true; acceptSocket_.listen(); acceptChannel_.set_events(Channel::kReadEvent); diff --git a/muduo/net/Acceptor.h b/muduo/net/Acceptor.h index 86ab0c73f..f341e8f6a 100644 --- a/muduo/net/Acceptor.h +++ b/muduo/net/Acceptor.h @@ -1,16 +1,36 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. #ifndef MUDUO_NET_ACCEPTOR_H #define MUDUO_NET_ACCEPTOR_H diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 3ab23c7cf..2ec10afdf 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -1,6 +1,7 @@ set(net_SRCS Acceptor.cc Channel.cc + ChannelBuffer.cc DefaultPoller.cc EPollPoller.cc EventLoop.cc diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index 17351bba2..6000c3aad 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -1,16 +1,36 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. #ifndef MUDUO_NET_CALLBACKS_H #define MUDUO_NET_CALLBACKS_H @@ -25,6 +45,7 @@ namespace net // All client visible callbacks go here. +class ChannelBuffer; class TcpConnection; typedef boost::shared_ptr TcpConnectionPtr; typedef boost::function TimerCallback; @@ -32,8 +53,7 @@ typedef boost::function ConnectionCallback; // the data has been read to (buf, len) typedef boost::function MessageCallback; + ChannelBuffer*)> MessageCallback; } } diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 6a98ad2f8..01e809c26 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -1,3 +1,33 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #include #include diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 62db1d711..af3b3b595 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -1,3 +1,37 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + #ifndef MUDUO_NET_CHANNEL_H #define MUDUO_NET_CHANNEL_H diff --git a/muduo/net/ChannelBuffer.cc b/muduo/net/ChannelBuffer.cc new file mode 100644 index 000000000..75f23805e --- /dev/null +++ b/muduo/net/ChannelBuffer.cc @@ -0,0 +1,69 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include + +#include // implicit_cast + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +ssize_t ChannelBuffer::readFd(int fd, int* savedErrno) +{ + char extrabuf[65536]; + struct iovec vec[2]; + size_t writable = writableBytes(); + vec[0].iov_base = begin()+writerIndex_; + vec[0].iov_len = writable; + vec[1].iov_base = extrabuf; + vec[1].iov_len = sizeof extrabuf; + ssize_t n = readv(fd, vec, 2); + if (n < 0) + { + *savedErrno = errno; + } + else if (implicit_cast(n) <= writable) + { + writerIndex_ += n; + } + else + { + writerIndex_ = buffer_.size(); + append(extrabuf, n - writable); + } + return n; +} + diff --git a/muduo/net/ChannelBuffer.h b/muduo/net/ChannelBuffer.h new file mode 100644 index 000000000..af563b08a --- /dev/null +++ b/muduo/net/ChannelBuffer.h @@ -0,0 +1,164 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_CHANNELBUFFER_H +#define MUDUO_NET_CHANNELBUFFER_H + +#include +#include + +#include + +#include +//#include // ssize_t + +namespace muduo +{ +namespace net +{ + +/// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer +/// +/// @code +/// +-------------------+------------------+------------------+ +/// | prependable bytes | readable bytes | writable bytes | +/// | | (CONTENT) | | +/// +-------------------+------------------+------------------+ +/// | | | | +/// 0 <= readerIndex <= writerIndex <= size +/// @endcode +class ChannelBuffer : public muduo::copyable +{ + public: + static const size_t kCheapPrepend = 8; + static const size_t kInitialSize = 1024; + + ChannelBuffer() + : buffer_(kCheapPrepend + kInitialSize), + readerIndex_(kCheapPrepend), + writerIndex_(kCheapPrepend) + { + assert(readableBytes() == 0); + assert(writableBytes() == kInitialSize); + assert(prependableBytes() == kCheapPrepend); + } + + size_t readableBytes() + { return writerIndex_ - readerIndex_; } + + size_t writableBytes() + { return buffer_.size() - writerIndex_; } + + size_t prependableBytes() + { return readerIndex_; } + + const char* peek() const + { return begin() + readerIndex_; } + + char* retrieve(size_t len) + { + assert(len <= readableBytes()); + char* p = begin() + readerIndex_; + readerIndex_ += len; + return p; + } + + string retrieveAsString() + { + string str(peek(), readableBytes()); + readerIndex_ = kCheapPrepend; + writerIndex_ = kCheapPrepend; + return str; + } + + void append(const char* /*restrict*/ data, size_t len) + { + if (writableBytes() < len) + { + makeSpace(len); + } + assert(len <= writableBytes()); + std::copy(data, data+len, begin()+writerIndex_); + writerIndex_ += len; + } + + void prepend(const char* /*restrict*/ data, size_t len) + { + assert(len <= prependableBytes()); + readerIndex_ -= len; + std::copy(data, data+len, begin()+readerIndex_); + } + + /// Read data directly into buffer. + /// + /// It may implement with readv(2) + /// @return result of read(2), @c errno is saved + ssize_t readFd(int fd, int* savedErrno); + + private: + char* begin() + { return &*buffer_.begin(); } + + const char* begin() const + { return &*buffer_.begin(); } + + void makeSpace(size_t more) + { + if (writableBytes() + prependableBytes() < more + kCheapPrepend) + { + buffer_.resize(writerIndex_+more); + } + else + { + // move readable data to the front, make space inside buffer + size_t used = readableBytes(); + std::copy(begin()+readerIndex_, + begin()+writerIndex_, + begin()+kCheapPrepend); + readerIndex_ = kCheapPrepend; + writerIndex_ = readerIndex_ + used; + assert(used = readableBytes()); + } + } + + private: + std::vector buffer_; + size_t readerIndex_; + size_t writerIndex_; +}; + +} +} + +#endif // MUDUO_NET_CHANNELBUFFER_H diff --git a/muduo/net/DefaultPoller.cc b/muduo/net/DefaultPoller.cc index e6eddbbd9..9ae6fb0d3 100644 --- a/muduo/net/DefaultPoller.cc +++ b/muduo/net/DefaultPoller.cc @@ -1,3 +1,33 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #include #include #include diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc index 01b0003c6..f52493163 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/EPollPoller.cc @@ -1,3 +1,33 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #include #include diff --git a/muduo/net/EPollPoller.h b/muduo/net/EPollPoller.h index ef1c7eadd..ea711fed0 100644 --- a/muduo/net/EPollPoller.h +++ b/muduo/net/EPollPoller.h @@ -1,3 +1,37 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + #ifndef MUDUO_NET_EPOLLPOLLER_H #define MUDUO_NET_EPOLLPOLLER_H diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 836bf6379..036fe053e 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -1,3 +1,33 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #include #include diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index ffffa5f11..caafee5fe 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -1,3 +1,37 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + #ifndef MUDUO_NET_EVENTLOOP_H #define MUDUO_NET_EVENTLOOP_H diff --git a/muduo/net/InetAddress.cc b/muduo/net/InetAddress.cc index 9bca60368..38f150159 100644 --- a/muduo/net/InetAddress.cc +++ b/muduo/net/InetAddress.cc @@ -1,16 +1,32 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include diff --git a/muduo/net/InetAddress.h b/muduo/net/InetAddress.h index 607b22ce5..bdc99285e 100644 --- a/muduo/net/InetAddress.h +++ b/muduo/net/InetAddress.h @@ -1,16 +1,36 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. #ifndef MUDUO_NET_INETADDRESS_H #define MUDUO_NET_INETADDRESS_H diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index de12b6c94..e7983f5ef 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -1,3 +1,33 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #include #include diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index d66b365f8..a663b6502 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -1,3 +1,37 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + #ifndef MUDUO_NET_POLLPOLLER_H #define MUDUO_NET_POLLPOLLER_H diff --git a/muduo/net/Poller.cc b/muduo/net/Poller.cc index 8d342eed3..97afc120d 100644 --- a/muduo/net/Poller.cc +++ b/muduo/net/Poller.cc @@ -1,3 +1,33 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #include using namespace muduo; diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index 0d2b0919d..41b57151b 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -1,3 +1,37 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + #ifndef MUDUO_NET_POLLER_H #define MUDUO_NET_POLLER_H diff --git a/muduo/net/Socket.cc b/muduo/net/Socket.cc index 6369d14d8..eaa16d53c 100644 --- a/muduo/net/Socket.cc +++ b/muduo/net/Socket.cc @@ -1,16 +1,32 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include diff --git a/muduo/net/Socket.h b/muduo/net/Socket.h index d27250a61..15d9c61ab 100644 --- a/muduo/net/Socket.h +++ b/muduo/net/Socket.h @@ -1,16 +1,36 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. #ifndef MUDUO_NET_SOCKET_H #define MUDUO_NET_SOCKET_H diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index e83dc3230..fbc0111a9 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -1,16 +1,32 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h index 3da945303..148b6e97a 100644 --- a/muduo/net/SocketsOps.h +++ b/muduo/net/SocketsOps.h @@ -1,16 +1,36 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. #ifndef MUDUO_NET_SOCKETSOPS_H #define MUDUO_NET_SOCKETSOPS_H diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 461e7bc7a..1e34f0a0e 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -1,16 +1,32 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include @@ -18,6 +34,8 @@ #include #include +#include + using namespace muduo; using namespace muduo::net; @@ -33,6 +51,53 @@ TcpConnection::TcpConnection(const string& name, localAddr_(localAddr), peerAddr_(peerAddr) { + // we don't use shared_from_this, + // because we hold strong reference of channel_ + channel_->setReadCallback( + boost::bind(&TcpConnection::handleRead, this)); + channel_->setWriteCallback( + boost::bind(&TcpConnection::handleWrite, this)); + channel_->setCloseCallback( + boost::bind(&TcpConnection::handleClose, this)); + channel_->setErrorCallback( + boost::bind(&TcpConnection::handleError, this)); +} + +void TcpConnection::connected() +{ + channel_->set_events(Channel::kReadEvent); loop_->updateChannel(get_pointer(channel_)); + + connectionCallback_(shared_from_this()); +} + +void TcpConnection::handleRead() +{ + int savedErrno; + ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno); + if (n > 0) + { + messageCallback_(shared_from_this(), &inputBuffer_); + } + else if (n == 0) + { + handleClose(); + } + else + { + // check savedErrno + } +} + +void TcpConnection::handleWrite() +{ +} + +void TcpConnection::handleClose() +{ +} + +void TcpConnection::handleError() +{ } diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index 075784e24..fbecaf9ee 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -1,22 +1,43 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. #ifndef MUDUO_NET_TCPCONNECTION_H #define MUDUO_NET_TCPCONNECTION_H #include #include +#include #include #include @@ -62,7 +83,15 @@ class TcpConnection : public boost::enable_shared_from_this, void setCloseCallback(ConnectionCallback cb) { closeCallback_ = cb; } + // called when TcpServer accepts a new connection + void connected(); + private: + void handleRead(); + void handleWrite(); + void handleClose(); + void handleError(); + string name_; EventLoop* loop_; // we don't expose those classes to client. @@ -73,6 +102,8 @@ class TcpConnection : public boost::enable_shared_from_this, ConnectionCallback connectionCallback_; MessageCallback messageCallback_; ConnectionCallback closeCallback_; + ChannelBuffer inputBuffer_; + ChannelBuffer outputBuffer_; }; typedef boost::shared_ptr TcpConnectionPtr; diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index fae06531c..8b91fe413 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -1,16 +1,32 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include @@ -70,6 +86,7 @@ void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) string connName = serverName_ + buf; InetAddress localAddr(sockets::getLocalAddr(sockfd)); + // FIXME poll with zero timeout to double confirm the new connection TcpConnectionPtr conn( new TcpConnection(connName, ioLoop, sockfd, localAddr, peerAddr)); connections_[connName] = conn; @@ -77,7 +94,7 @@ void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) conn->setMessageCallback(messageCallback_); conn->setCloseCallback( boost::bind(&TcpServer::removeConnection, this, _1)); - ioLoop->runInLoop(boost::bind(connectionCallback_, conn)); + ioLoop->runInLoop(boost::bind(&TcpConnection::connected, conn)); } void TcpServer::removeConnection(const TcpConnectionPtr& conn) diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index 41863c183..9ec7b8eda 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -1,16 +1,36 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. #ifndef MUDUO_NET_TCPSERVER_H #define MUDUO_NET_TCPSERVER_H diff --git a/muduo/net/ThreadModel.cc b/muduo/net/ThreadModel.cc index 83e3db4e1..4000aa9c9 100644 --- a/muduo/net/ThreadModel.cc +++ b/muduo/net/ThreadModel.cc @@ -1,16 +1,32 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include diff --git a/muduo/net/ThreadModel.h b/muduo/net/ThreadModel.h index 0cadda046..46328c192 100644 --- a/muduo/net/ThreadModel.h +++ b/muduo/net/ThreadModel.h @@ -1,16 +1,36 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// http://www.apache.org/licenses/LICENSE-2.0 +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. #ifndef MUDUO_NET_THREADMODEL_H #define MUDUO_NET_THREADMODEL_H diff --git a/muduo/net/Timer.cc b/muduo/net/Timer.cc index e555b2b1f..0c28c170a 100644 --- a/muduo/net/Timer.cc +++ b/muduo/net/Timer.cc @@ -1,3 +1,33 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #include using namespace muduo; diff --git a/muduo/net/Timer.h b/muduo/net/Timer.h index e85b9f5be..f0c68ccf1 100644 --- a/muduo/net/Timer.h +++ b/muduo/net/Timer.h @@ -1,3 +1,37 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + #ifndef MUDUO_NET_TIMER_H #define MUDUO_NET_TIMER_H diff --git a/muduo/net/TimerId.h b/muduo/net/TimerId.h index f4f5ca0c2..0e8f2af9a 100644 --- a/muduo/net/TimerId.h +++ b/muduo/net/TimerId.h @@ -1,3 +1,37 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + #ifndef MUDUO_NET_TIMERID_H #define MUDUO_NET_TIMERID_H diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index dbd64d273..85d699fb7 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -1,3 +1,33 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #include #include @@ -19,7 +49,8 @@ namespace { int createTimerfd() { - int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + int timerfd = ::timerfd_create(CLOCK_MONOTONIC, + TFD_NONBLOCK | TFD_CLOEXEC); if (timerfd < 0) { perror("Failed in timerfd_create"); @@ -37,8 +68,10 @@ struct timespec howMuchTimeFromNow(UtcTime when) microseconds = 100; } struct timespec ts; - ts.tv_sec = static_cast(microseconds / UtcTime::kMicroSecondsPerSecond); - ts.tv_nsec = static_cast((microseconds % UtcTime::kMicroSecondsPerSecond) * 1000); + ts.tv_sec = static_cast( + microseconds / UtcTime::kMicroSecondsPerSecond); + ts.tv_nsec = static_cast( + (microseconds % UtcTime::kMicroSecondsPerSecond) * 1000); return ts; } @@ -93,7 +126,8 @@ void TimerQueue::timeout() howmany, now.toString().c_str()); if (n != sizeof howmany) { - fprintf(stderr, "TimerQueue::timeout() reads %zd bytes instead of 8\n", n); + fprintf(stderr, "TimerQueue::timeout() " + "reads %zd bytes instead of 8\n", n); } TimerList expired; diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index 4936cdfd8..dec9a650f 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -1,3 +1,37 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + #ifndef MUDUO_NET_TIMERQUEUE_H #define MUDUO_NET_TIMERQUEUE_H diff --git a/muduo/net/boilerplate b/muduo/net/boilerplate deleted file mode 100644 index c3f9846dd..000000000 --- a/muduo/net/boilerplate +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2010 Shuo Chen (chenshuo at chenshuo dot com) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef MUDUO_NET_BOILERPLATE_H -#define MUDUO_NET_BOILERPLATE_H - -#include - -namespace muduo -{ -namespace net -{ - -class BoilerPlate : boost::noncopyable -{ - public: - - private: -}; - -} -} - -#endif // MUDUO_NET_BOILERPLATE_H diff --git a/muduo/net/boilerplate.cc b/muduo/net/boilerplate.cc new file mode 100644 index 000000000..3d761a595 --- /dev/null +++ b/muduo/net/boilerplate.cc @@ -0,0 +1,39 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include + +using namespace muduo; +using namespace muduo::net; + + diff --git a/muduo/net/boilerplate.h b/muduo/net/boilerplate.h new file mode 100644 index 000000000..98da03554 --- /dev/null +++ b/muduo/net/boilerplate.h @@ -0,0 +1,56 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_BOILERPLATE_H +#define MUDUO_NET_BOILERPLATE_H + +#include + +namespace muduo +{ +namespace net +{ + +class BoilerPlate : boost::noncopyable +{ + public: + + private: +}; + +} +} + +#endif // MUDUO_NET_BOILERPLATE_H diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 9919e7eeb..3172457fa 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -21,7 +21,7 @@ class EchoServer server_.setConnectionCallback( boost::bind(&EchoServer::onConnection, this, _1)); server_.setMessageCallback( - boost::bind(&EchoServer::onMessage, this, _1, _2, _3)); + boost::bind(&EchoServer::onMessage, this, _1, _2)); } void start() @@ -37,8 +37,10 @@ class EchoServer conn->localAddr().toHostPort().c_str()); } - void onMessage(const TcpConnectionPtr&, const void* buf, ssize_t len) + void onMessage(const TcpConnectionPtr&, ChannelBuffer* buf) { + string msg(buf->retrieveAsString()); + printf("recv %zu bytes '%s'", msg.size(), msg.c_str()); } EventLoop* loop_; From 9254c010163f1cad9e6ecb49af117d30764c64a8 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 16 Mar 2010 02:36:13 +0000 Subject: [PATCH 018/371] Safe deletion. --- CMakeLists.txt | 3 +- License | 30 ++++++++++++++++ muduo/net/Acceptor.cc | 1 + muduo/net/Channel.cc | 29 ++++++++++++++-- muduo/net/Channel.h | 13 ++++++- muduo/net/EventLoop.cc | 10 ++++-- muduo/net/EventLoop.h | 5 +++ muduo/net/PollPoller.cc | 37 +++++++++++++++++--- muduo/net/PollPoller.h | 1 + muduo/net/Poller.h | 4 +++ muduo/net/SocketsOps.cc | 13 +++++-- muduo/net/SocketsOps.h | 1 + muduo/net/TcpConnection.cc | 48 ++++++++++++++++++++++---- muduo/net/TcpConnection.h | 22 ++++++++---- muduo/net/TcpServer.cc | 19 ++++++++-- muduo/net/TcpServer.h | 9 +++++ muduo/net/tests/EchoServer_unittest.cc | 25 ++++++++++++-- 17 files changed, 238 insertions(+), 32 deletions(-) create mode 100644 License diff --git a/CMakeLists.txt b/CMakeLists.txt index a00bd4a94..818c3a525 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,8 +20,9 @@ set(CXX_FLAGS string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "-O0") -set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE "-O2") # no NDEBUG in Release, keep asserting. include_directories(${PROJECT_SOURCE_DIR}) add_subdirectory(muduo/base) add_subdirectory(muduo/net) + diff --git a/License b/License new file mode 100644 index 000000000..6847f52e0 --- /dev/null +++ b/License @@ -0,0 +1,30 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index e34a19732..df223e2a9 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -64,6 +64,7 @@ void Acceptor::listen() void Acceptor::accept() { + loop_->assertInLoopThread(); InetAddress peerAddr(0); int connfd = acceptSocket_.accept(&peerAddr); if (connfd >= 0) diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 01e809c26..7f1cb681a 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -36,6 +36,7 @@ using namespace muduo; using namespace muduo::net; +const int Channel::kNoneEvent = 0; const int Channel::kReadEvent = POLLIN | POLLPRI; const int Channel::kWriteEvent = POLLOUT; @@ -44,7 +45,8 @@ Channel::Channel(EventLoop* loop, int fd__) fd_(fd__), events_(0), revents_(0), - index_(-1) + index_(-1), + tied_(false) { } @@ -52,7 +54,30 @@ Channel::~Channel() { } -void Channel::handle_event() +void Channel::tie(const boost::shared_ptr& obj) +{ + tie_ = obj; + tied_ = true; +} + +void Channel::handleEvent() +{ + boost::shared_ptr guard; + if (tied_) + { + guard = tie_.lock(); + if (guard) + { + handleEventWithGuard(); + } + } + else + { + handleEventWithGuard(); + } +} + +void Channel::handleEventWithGuard() { if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) { diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index af3b3b595..c97225ace 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -37,6 +37,8 @@ #include #include +#include +#include namespace muduo { @@ -63,7 +65,7 @@ class Channel : boost::noncopyable Channel(EventLoop* loop, int fd); ~Channel(); - void handle_event(); + void handleEvent(); void setReadCallback(const EventCallback& cb) { readCallback_ = cb; } void setWriteCallback(const EventCallback& cb) @@ -73,6 +75,10 @@ class Channel : boost::noncopyable void setErrorCallback(const EventCallback& cb) { errorCallback_ = cb; } + /// Tie this channel to the owner object managed by shared_ptr, + /// prevent the owner object being destroyed in handleEvent. + void tie(const boost::shared_ptr&); + int fd() { return fd_; } int events() { return events_; } void set_events(int evt) { events_ = evt; } @@ -86,11 +92,16 @@ class Channel : boost::noncopyable // void set_loop(EventLoop* loop) { loop_ = loop; } private: + void handleEventWithGuard(); + EventLoop* loop_; const int fd_; int events_; int revents_; int index_; // used by PollPoller. + + boost::weak_ptr tie_; + bool tied_; EventCallback readCallback_; EventCallback writeCallback_; EventCallback closeCallback_; diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 036fe053e..2d9d53db4 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -107,8 +107,10 @@ void EventLoop::loop() for (ChannelList::iterator it = activeChannels_.begin(); it != activeChannels_.end(); ++it) { - (*it)->handle_event(); + (*it)->handleEvent(); + // FIXME if one handleEvent() destroys XXX HACK } + //pendingDestructs(); } looping_ = false; } @@ -140,6 +142,10 @@ void EventLoop::runInLoop(const Functor& cb) } } +void EventLoop::runDelayDestruct(const Functor& cb) +{ +} + TimerId EventLoop::runAt(const UtcTime& time, const TimerCallback& cb) { return timerQueue_->schedule(cb, time, 0.0); @@ -167,7 +173,7 @@ void EventLoop::updateChannel(Channel* channel) void EventLoop::removeChannel(Channel* channel) { assert(channel->getLoop() == this); - // poller_->removeChannel(channel); + poller_->removeChannel(channel); } void EventLoop::assertInLoopThread() diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index caafee5fe..2850d9a41 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -80,8 +80,13 @@ class EventLoop : boost::noncopyable /// Runs callback immediately in the loop thread. /// It wakes up the loop, and run the cb. + /// If in the same loop thread, cb is run within the function. /// Safe to call from other threads. void runInLoop(const Functor& cb); + /// Queues callback in the loop thread. + /// Runs after finish pooling. + /// Safe to call from other threads. + void runDelayDestruct(const Functor& cb); /// TimerId runAt(const UtcTime& time, const TimerCallback& cb); /// diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index e7983f5ef..a469f8ab2 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -30,6 +30,7 @@ #include +#include #include #include @@ -84,6 +85,7 @@ void PollPoller::fillActiveChannels(int numEvents, void PollPoller::updateChannel(Channel* channel) { // assert(channel->getLoop() + //assert in loop thread if (channel->index() < 0) { @@ -94,7 +96,8 @@ void PollPoller::updateChannel(Channel* channel) pfd.events = static_cast(channel->events()); pfd.revents = 0; pollfds_.push_back(pfd); - channel->set_index(static_cast(pollfds_.size())-1); + int idx = static_cast(pollfds_.size())-1; + channel->set_index(idx); channels_[pfd.fd] = channel; } else @@ -105,15 +108,39 @@ void PollPoller::updateChannel(Channel* channel) int idx = channel->index(); assert(0 <= idx && idx < static_cast(pollfds_.size())); struct pollfd& pfd = pollfds_[idx]; - assert(pfd.fd == channel->fd() || pfd.fd == -1); + assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); pfd.events = static_cast(channel->events()); - if (pfd.events == 0) + if (pfd.events == Channel::kNoneEvent) { // ignore this pollfd - pfd.fd = -1; - printf("set pfd.fd=-1 for fd=%d\n", channel->fd()); + pfd.fd = -channel->fd()-1; + printf("set pfd.fd=-fd-1 for fd=%d\n", channel->fd()); } } +} +void PollPoller::removeChannel(Channel* channel) +{ + //assert in loop thread + assert(channels_.find(channel->fd()) != channels_.end()); + assert(channels_[channel->fd()] == channel); + // assert(channel->events() == Channel::kNoneEvent); + int idx = channel->index(); + assert(0 <= idx && idx < static_cast(pollfds_.size())); + const struct pollfd& pfd = pollfds_[idx]; + // assert(pfd.fd == -channel->fd()-1 && pfd.events == Channel::kNoneEvent); + size_t n = channels_.erase(channel->fd()); + assert(n == 1); + if (implicit_cast(idx) == pollfds_.size()-1) + { + pollfds_.pop_back(); + } + else + { + int channelAtEnd = pollfds_.back().fd; + iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); + channels_[channelAtEnd]->set_index(idx); + pollfds_.pop_back(); + } } diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index a663b6502..9222a93b1 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -58,6 +58,7 @@ class PollPoller : public Poller virtual void poll(int timeoutMs, ChannelList* activeChannels); virtual void updateChannel(Channel* channel); + virtual void removeChannel(Channel* channel); private: void fillActiveChannels(int numEvents, diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index 41b57151b..b597864c0 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -63,6 +63,10 @@ class Poller : boost::noncopyable /// Must be called in the loop thread. virtual void updateChannel(Channel* channel) = 0; + /// Remove the channel, when it destructs. + /// Must be called in the loop thread. + virtual void removeChannel(Channel* channel) = 0; + static Poller* newDefaultPoller(); }; diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index fbc0111a9..35e920ee6 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -86,8 +86,10 @@ void sockets::listenOrDie(int sockfd) int sockets::accept(int sockfd, struct sockaddr_in* addr) { socklen_t addrlen = sizeof *addr; - int connfd = ::accept4(sockfd, reinterpret_cast(addr), - &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); + int connfd = ::accept(sockfd, reinterpret_cast(addr), + &addrlen);//, SOCK_NONBLOCK | SOCK_CLOEXEC); + // int connfd = ::accept4(sockfd, reinterpret_cast(addr), + // &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); if (connfd == -1) { int savedErrno = errno; @@ -115,6 +117,7 @@ int sockets::accept(int sockfd, struct sockaddr_in* addr) break; default: // unknown errors + fprintf(stderr, "errno = %d\n", savedErrno); abort(); break; } @@ -128,6 +131,12 @@ void sockets::close(int sockfd) // FIXME EINTR } +void sockets::shutdown(int sockfd) +{ + ::shutdown(sockfd, SHUT_RDWR); + // FIXME EINTR +} + void sockets::toHostPort(char* buf, size_t size, const struct sockaddr_in& addr) { diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h index 148b6e97a..3077a17d6 100644 --- a/muduo/net/SocketsOps.h +++ b/muduo/net/SocketsOps.h @@ -77,6 +77,7 @@ void bindOrDie(int sockfd, const struct sockaddr_in& addr); void listenOrDie(int sockfd); int accept(int sockfd, struct sockaddr_in* addr); void close(int sockfd); +void shutdown(int sockfd); void toHostPort(char* buf, size_t size, const struct sockaddr_in& addr); diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 1e34f0a0e..a0c3ff756 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -33,26 +33,28 @@ #include #include #include +#include #include +#include + using namespace muduo; using namespace muduo::net; -TcpConnection::TcpConnection(const string& name, - EventLoop* loop, +TcpConnection::TcpConnection(EventLoop* loop, + const string& name__, int fd, const InetAddress& localAddr, const InetAddress& peerAddr) - : name_(name), - loop_(loop), + : loop_(loop), + name_(name__), + state_(kDisconnected), socket_(new Socket(fd)), channel_(new Channel(loop, fd)), localAddr_(localAddr), peerAddr_(peerAddr) { - // we don't use shared_from_this, - // because we hold strong reference of channel_ channel_->setReadCallback( boost::bind(&TcpConnection::handleRead, this)); channel_->setWriteCallback( @@ -61,18 +63,40 @@ TcpConnection::TcpConnection(const string& name, boost::bind(&TcpConnection::handleClose, this)); channel_->setErrorCallback( boost::bind(&TcpConnection::handleError, this)); + printf("%p %s ctor\n", this, name_.c_str()); +} + +TcpConnection::~TcpConnection() +{ + loop_->assertInLoopThread(); + loop_->removeChannel(get_pointer(channel_)); + printf("%p %s dtor\n", this, name_.c_str()); +} + +void TcpConnection::shutdown() +{ + sockets::shutdown(channel_->fd()); + loop_->runInLoop(boost::bind(&TcpConnection::handleClose, this)); } -void TcpConnection::connected() +void TcpConnection::connectEstablished() { + loop_->assertInLoopThread(); + state_ = kConnected; + channel_->tie(shared_from_this()); channel_->set_events(Channel::kReadEvent); loop_->updateChannel(get_pointer(channel_)); connectionCallback_(shared_from_this()); } +void TcpConnection::connectDestroyed() +{ +} + void TcpConnection::handleRead() { + loop_->assertInLoopThread(); int savedErrno; ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno); if (n > 0) @@ -95,6 +119,16 @@ void TcpConnection::handleWrite() void TcpConnection::handleClose() { + loop_->assertInLoopThread(); + // we don't close fd, leave it to dtor, so we can find leaks easily. + state_ = kDisconnected; + channel_->set_events(Channel::kNoneEvent); + loop_->updateChannel(get_pointer(channel_)); + + TcpConnectionPtr guardThis(shared_from_this()); + connectionCallback_(guardThis); + // must be the last line + closeCallback_(guardThis); } void TcpConnection::handleError() diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index fbecaf9ee..eb3727a09 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -64,14 +64,21 @@ class TcpConnection : public boost::enable_shared_from_this, public: /// Constructs a TcpConnection with a connected sockfd /// - TcpConnection(const string& name, - EventLoop* loop, + TcpConnection(EventLoop* loop, + const string& name, int sockfd, const InetAddress& localAddr, const InetAddress& peerAddr); + ~TcpConnection(); - const InetAddress& localAddr() { return localAddr_; } - const InetAddress& peerAddr() { return peerAddr_; } + EventLoop* getLoop() const { return loop_; } + const string& name() const { return name_; } + const InetAddress& localAddress() { return localAddr_; } + const InetAddress& peerAddress() { return peerAddr_; } + bool connected() const { return state_ == kConnected; } + bool connecting() const { return state_ == kConnecting; } + + void shutdown(); void setConnectionCallback(ConnectionCallback cb) { connectionCallback_ = cb; } @@ -84,16 +91,19 @@ class TcpConnection : public boost::enable_shared_from_this, { closeCallback_ = cb; } // called when TcpServer accepts a new connection - void connected(); + void connectEstablished(); + void connectDestroyed(); private: + enum States { kDisconnected, kConnecting, kConnected }; void handleRead(); void handleWrite(); void handleClose(); void handleError(); - string name_; EventLoop* loop_; + string name_; + States state_; // we don't expose those classes to client. boost::scoped_ptr socket_; boost::scoped_ptr channel_; diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 8b91fe413..99114dd60 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -44,6 +44,7 @@ using namespace muduo::net; TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr) : loop_(loop), + name_(listenAddr.toHostPort()), acceptor_(new Acceptor(loop, listenAddr)), threadModel_(new ThreadModel(loop)), started_(false), @@ -79,24 +80,36 @@ void TcpServer::start() void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) { + loop_->assertInLoopThread(); EventLoop* ioLoop = threadModel_->getNextLoop(); char buf[32]; - snprintf(buf, sizeof buf, "#%d", nextConnId_); + snprintf(buf, sizeof buf, "%s#%d", name_.c_str(), nextConnId_); ++nextConnId_; string connName = serverName_ + buf; InetAddress localAddr(sockets::getLocalAddr(sockfd)); // FIXME poll with zero timeout to double confirm the new connection TcpConnectionPtr conn( - new TcpConnection(connName, ioLoop, sockfd, localAddr, peerAddr)); + new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr)); connections_[connName] = conn; conn->setConnectionCallback(connectionCallback_); conn->setMessageCallback(messageCallback_); conn->setCloseCallback( boost::bind(&TcpServer::removeConnection, this, _1)); - ioLoop->runInLoop(boost::bind(&TcpConnection::connected, conn)); + ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn)); } void TcpServer::removeConnection(const TcpConnectionPtr& conn) { + loop_->runInLoop(boost::bind(&TcpServer::removeConnectionInLoop, this, conn)); } + +void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) +{ + loop_->assertInLoopThread(); + size_t n = connections_.erase(conn->name()); + assert(n == 1); + EventLoop* ioLoop = conn->getLoop(); + ioLoop->runDelayDestruct(boost::bind(&TcpConnection::connectDestroyed, conn)); +} + diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index 9ec7b8eda..cba66c2cb 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -62,8 +62,13 @@ class TcpServer : boost::noncopyable public: TcpServer(EventLoop* loop, const InetAddress& listenAddr); + TcpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name); ~TcpServer(); // force out-line dtor, for scoped_ptr members. + const string& name() const { return name_; } + /// Set the number of threads for handling input. /// /// Always accepts new connection in loop's thread. @@ -95,11 +100,15 @@ class TcpServer : boost::noncopyable private: /// Not thread safe. void newConnection(int sockfd, const InetAddress& peerAddr); + /// Thread safe. void removeConnection(const TcpConnectionPtr& conn); + /// Not thread safe. + void removeConnectionInLoop(const TcpConnectionPtr& conn); typedef std::map ConnectionMap; EventLoop* loop_; // the acceptor loop + string name_; boost::scoped_ptr acceptor_; // avoid revealing Acceptor boost::scoped_ptr threadModel_; ConnectionCallback connectionCallback_; diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 3172457fa..0c358e55e 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -22,6 +22,7 @@ class EchoServer boost::bind(&EchoServer::onConnection, this, _1)); server_.setMessageCallback( boost::bind(&EchoServer::onMessage, this, _1, _2)); + server_.setThreadNum(0); } void start() @@ -31,16 +32,34 @@ class EchoServer // void stop(); private: + TcpConnectionPtr first; + TcpConnectionPtr second; void onConnection(const TcpConnectionPtr& conn) { - printf("conn %s -> %s\n", conn->peerAddr().toHostPort().c_str(), - conn->localAddr().toHostPort().c_str()); + printf("conn %s -> %s %s\n", + conn->peerAddress().toHostPort().c_str(), + conn->localAddress().toHostPort().c_str(), + conn->connected() ? "UP" : "DOWN"); + if (!first) + first = conn; + else if (!second) + second = conn; } - void onMessage(const TcpConnectionPtr&, ChannelBuffer* buf) + void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf) { string msg(buf->retrieveAsString()); printf("recv %zu bytes '%s'", msg.size(), msg.c_str()); + // conn->send(buf); + // conn->shutdown(); + // loop_->quit(); + if (second && conn == first) + { + second->shutdown(); + second.reset(); + first.reset(); + loop_->quit(); + } } EventLoop* loop_; From e0073df29db1a1d44083f859f5bf1f39bbdc7d42 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 16 Mar 2010 16:55:07 +0000 Subject: [PATCH 019/371] Shrink buffer, no reinterpret_cast. --- muduo/net/ChannelBuffer.h | 29 +++++++++++++++++++++--- muduo/net/EventLoop.cc | 31 +++++++++++++++++++++++--- muduo/net/EventLoop.h | 7 +++++- muduo/net/PollPoller.cc | 1 + muduo/net/SocketsOps.cc | 21 ++++++++++++----- muduo/net/TcpConnection.cc | 8 +++++-- muduo/net/TcpConnection.h | 2 +- muduo/net/TcpServer.cc | 14 +++++++++++- muduo/net/TcpServer.h | 2 +- muduo/net/tests/EchoServer_unittest.cc | 16 ++++++++++--- 10 files changed, 111 insertions(+), 20 deletions(-) diff --git a/muduo/net/ChannelBuffer.h b/muduo/net/ChannelBuffer.h index af563b08a..78d6c8d4e 100644 --- a/muduo/net/ChannelBuffer.h +++ b/muduo/net/ChannelBuffer.h @@ -74,6 +74,15 @@ class ChannelBuffer : public muduo::copyable assert(prependableBytes() == kCheapPrepend); } + // default copy-ctor, dtor and assignment are fine + + void swap(ChannelBuffer& rhs) + { + buffer_.swap(rhs.buffer_); + std::swap(readerIndex_, rhs.readerIndex_); + std::swap(writerIndex_, rhs.writerIndex_); + } + size_t readableBytes() { return writerIndex_ - readerIndex_; } @@ -86,12 +95,19 @@ class ChannelBuffer : public muduo::copyable const char* peek() const { return begin() + readerIndex_; } - char* retrieve(size_t len) + // retrieve returns void, to prevent + // string str(retrieve(readableBytes()), readableBytes()); + // the evaluation of two functions are unspecified + void retrieve(size_t len) { assert(len <= readableBytes()); - char* p = begin() + readerIndex_; readerIndex_ += len; - return p; + } + + void retrieveAll() + { + readerIndex_ = kCheapPrepend; + writerIndex_ = kCheapPrepend; } string retrieveAsString() @@ -120,6 +136,13 @@ class ChannelBuffer : public muduo::copyable std::copy(data, data+len, begin()+readerIndex_); } + void shrink(size_t reserve) + { + std::vector buf(kCheapPrepend+readableBytes()+reserve); + std::copy(peek(), peek()+readableBytes(), buf.begin()+kCheapPrepend); + buf.swap(buffer_); + } + /// Read data directly into buffer. /// /// It may implement with readv(2) diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 2d9d53db4..29b904927 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -65,6 +65,7 @@ int createEventfd() EventLoop::EventLoop() : looping_(false), quit_(false), + eventHandling_(false), threadId_(CurrentThread::tid()), poller_(Poller::newDefaultPoller()), timerQueue_(new TimerQueue(this)), @@ -104,13 +105,16 @@ void EventLoop::loop() { activeChannels_.clear(); poller_->poll(kPollTimeMs, &activeChannels_); + // TODO sort channel by priority + eventHandling_ = true; for (ChannelList::iterator it = activeChannels_.begin(); it != activeChannels_.end(); ++it) { (*it)->handleEvent(); // FIXME if one handleEvent() destroys XXX HACK } - //pendingDestructs(); + eventHandling_ = false; + doPendingFunctors(); } looping_ = false; } @@ -138,12 +142,14 @@ void EventLoop::runInLoop(const Functor& cb) } else { - abort(); + queueInLoop(cb); } } -void EventLoop::runDelayDestruct(const Functor& cb) +void EventLoop::queueInLoop(const Functor& cb) { + MutexLockGuard lock(mutex_); + pendingFunctors_.push_back(cb); } TimerId EventLoop::runAt(const UtcTime& time, const TimerCallback& cb) @@ -186,3 +192,22 @@ void EventLoop::wakedup() // what's up } +void EventLoop::doPendingFunctors() +{ + std::vector functors; + do + { + functors.clear(); + + { + MutexLockGuard lock(mutex_); + functors.swap(pendingFunctors_); + } + + for (size_t i = 0; i < functors.size(); ++i) + { + functors[i](); + } + } while (!functors.empty()); +} + diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 2850d9a41..0fb6eceb1 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -86,7 +87,7 @@ class EventLoop : boost::noncopyable /// Queues callback in the loop thread. /// Runs after finish pooling. /// Safe to call from other threads. - void runDelayDestruct(const Functor& cb); + void queueInLoop(const Functor& cb); /// TimerId runAt(const UtcTime& time, const TimerCallback& cb); /// @@ -109,11 +110,13 @@ class EventLoop : boost::noncopyable private: void wakedup(); + void doPendingFunctors(); typedef std::vector ChannelList; bool looping_; /* atomic */ bool quit_; /* atomic */ + bool eventHandling_; const pid_t threadId_; boost::scoped_ptr poller_; boost::scoped_ptr timerQueue_; @@ -122,6 +125,8 @@ class EventLoop : boost::noncopyable // we don't expose Channel to client. boost::scoped_ptr wakeupChannel_; ChannelList activeChannels_; + MutexLock mutex_; + std::vector pendingFunctors_; // @BuardedBy mutex_ }; } diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index a469f8ab2..03cef3cac 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -50,6 +50,7 @@ void PollPoller::poll(int timeoutMs, ChannelList* activeChannels) if (numEvents > 0) { fillActiveChannels(numEvents, activeChannels); + printf("%d events\n", numEvents); } else if (numEvents == 0) { diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index 35e920ee6..831c5b32b 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -29,6 +29,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include #include #include @@ -42,6 +43,16 @@ using namespace muduo::net; typedef struct sockaddr SA; +const SA* sockaddr_cast(const struct sockaddr_in* addr) +{ + return static_cast(implicit_cast(addr)); +} + +SA* sockaddr_cast(struct sockaddr_in* addr) +{ + return static_cast(implicit_cast(addr)); +} + int sockets::createNonblockingOrDie() { // socket @@ -65,7 +76,7 @@ int sockets::createNonblockingOrDie() void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) { - int ret = ::bind(sockfd, reinterpret_cast(&addr), sizeof addr); + int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); if (ret) { perror("sockets::bindOrDie"); @@ -86,9 +97,8 @@ void sockets::listenOrDie(int sockfd) int sockets::accept(int sockfd, struct sockaddr_in* addr) { socklen_t addrlen = sizeof *addr; - int connfd = ::accept(sockfd, reinterpret_cast(addr), - &addrlen);//, SOCK_NONBLOCK | SOCK_CLOEXEC); - // int connfd = ::accept4(sockfd, reinterpret_cast(addr), + int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); + // int connfd = ::accept4(sockfd, sockaddr_cast(addr), // &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); if (connfd == -1) { @@ -150,7 +160,8 @@ struct sockaddr_in sockets::getLocalAddr(int sockfd) { struct sockaddr_in localaddr; socklen_t addrlen = sizeof(localaddr); - ::getsockname(sockfd, reinterpret_cast(&localaddr), &addrlen); + ::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen); // FIXME check return localaddr; } + diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index a0c3ff756..4b7665ce5 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -75,8 +75,12 @@ TcpConnection::~TcpConnection() void TcpConnection::shutdown() { - sockets::shutdown(channel_->fd()); - loop_->runInLoop(boost::bind(&TcpConnection::handleClose, this)); + if (state_ == kConnected) + { + state_ = kDisconnecting; + sockets::shutdown(channel_->fd()); + loop_->runInLoop(boost::bind(&TcpConnection::handleClose, this)); + } } void TcpConnection::connectEstablished() diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index eb3727a09..a96a2e2a5 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -95,7 +95,7 @@ class TcpConnection : public boost::enable_shared_from_this, void connectDestroyed(); private: - enum States { kDisconnected, kConnecting, kConnected }; + enum States { kDisconnected, kConnecting, kConnected, kDisconnecting }; void handleRead(); void handleWrite(); void handleClose(); diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 99114dd60..8fae3fa76 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -56,6 +56,17 @@ TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr) TcpServer::~TcpServer() { + loop_->assertInLoopThread(); + + for (ConnectionMap::iterator it(connections_.begin()); + it != connections_.end(); ++it) + { + TcpConnectionPtr conn = it->second; + it->second.reset(); + conn->getLoop()->runInLoop( + boost::bind(&TcpConnection::connectDestroyed, conn)); + conn.reset(); + } } void TcpServer::setThreadNum(int numThreads) @@ -110,6 +121,7 @@ void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) size_t n = connections_.erase(conn->name()); assert(n == 1); EventLoop* ioLoop = conn->getLoop(); - ioLoop->runDelayDestruct(boost::bind(&TcpConnection::connectDestroyed, conn)); + ioLoop->queueInLoop( + boost::bind(&TcpConnection::connectDestroyed, conn)); } diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index cba66c2cb..59408e3fc 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -116,7 +116,7 @@ class TcpServer : boost::noncopyable const string serverName_; bool started_; // always in loop thread - int nextConnId_; + int nextConnId_; ConnectionMap connections_; }; diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 0c358e55e..e6abc0739 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -7,10 +7,13 @@ #include #include +#include using namespace muduo; using namespace muduo::net; +int numThreads = 0; + class EchoServer { public: @@ -22,7 +25,7 @@ class EchoServer boost::bind(&EchoServer::onConnection, this, _1)); server_.setMessageCallback( boost::bind(&EchoServer::onMessage, this, _1, _2)); - server_.setThreadNum(0); + server_.setThreadNum(numThreads); } void start() @@ -50,15 +53,21 @@ class EchoServer { string msg(buf->retrieveAsString()); printf("recv %zu bytes '%s'", msg.size(), msg.c_str()); + if (msg == "exit\n") + ::exit(0); // conn->send(buf); // conn->shutdown(); // loop_->quit(); + if (conn == second) + { + sleep(10); + } if (second && conn == first) { second->shutdown(); second.reset(); first.reset(); - loop_->quit(); + // loop_->quit(); } } @@ -70,9 +79,10 @@ void threadFunc(uint16_t port) { } -int main() +int main(int argc, char* argv[]) { printf("main(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + numThreads = argc - 1; EventLoop loop; InetAddress listenAddr(2000); EchoServer server(&loop, listenAddr); From eaf8dac5b062d5667f41ac5906a8f9f3d5f1ae8a Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Wed, 17 Mar 2010 16:56:20 +0000 Subject: [PATCH 020/371] Rename UtcTime to Timestamp. send works. --- muduo/base/CMakeLists.txt | 2 +- muduo/base/{UtcTime.cc => Timestamp.cc} | 18 +++---- muduo/base/{UtcTime.h => Timestamp.h} | 42 +++++++-------- muduo/base/tests/CMakeLists.txt | 4 +- ...Time_unittest.cc => Timestamp_unittest.cc} | 10 ++-- muduo/net/Callbacks.h | 4 +- muduo/net/Channel.cc | 10 ++-- muduo/net/Channel.h | 13 +++-- muduo/net/EPollPoller.cc | 4 +- muduo/net/EPollPoller.h | 2 +- muduo/net/EventLoop.cc | 10 ++-- muduo/net/EventLoop.h | 4 +- muduo/net/PollPoller.cc | 11 ++-- muduo/net/PollPoller.h | 2 +- muduo/net/Poller.h | 4 +- muduo/net/TcpConnection.cc | 52 +++++++++++++++++-- muduo/net/TcpConnection.h | 8 ++- muduo/net/Timer.cc | 4 +- muduo/net/Timer.h | 10 ++-- muduo/net/TimerQueue.cc | 18 +++---- muduo/net/TimerQueue.h | 4 +- muduo/net/tests/EchoServer_unittest.cc | 18 +++++-- muduo/net/tests/TimerQueue_unittest.cc | 2 +- 23 files changed, 165 insertions(+), 91 deletions(-) rename muduo/base/{UtcTime.cc => Timestamp.cc} (64%) rename muduo/base/{UtcTime.h => Timestamp.h} (59%) rename muduo/base/tests/{UtcTime_unittest.cc => Timestamp_unittest.cc} (56%) diff --git a/muduo/base/CMakeLists.txt b/muduo/base/CMakeLists.txt index 65ef86aa6..16c35aab7 100644 --- a/muduo/base/CMakeLists.txt +++ b/muduo/base/CMakeLists.txt @@ -1,6 +1,6 @@ set(base_SRCS + Timestamp.cc Thread.cc - UtcTime.cc ) add_library(muduo_base ${base_SRCS}) diff --git a/muduo/base/UtcTime.cc b/muduo/base/Timestamp.cc similarity index 64% rename from muduo/base/UtcTime.cc rename to muduo/base/Timestamp.cc index 4c7509e23..357aa1ba2 100644 --- a/muduo/base/UtcTime.cc +++ b/muduo/base/Timestamp.cc @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -10,19 +10,19 @@ using namespace muduo; -BOOST_STATIC_ASSERT(sizeof(UtcTime) == sizeof(int64_t)); +BOOST_STATIC_ASSERT(sizeof(Timestamp) == sizeof(int64_t)); -UtcTime::UtcTime() +Timestamp::Timestamp() : microSecondsSinceEpoch_(0) { } -UtcTime::UtcTime(int64_t microseconds) +Timestamp::Timestamp(int64_t microseconds) : microSecondsSinceEpoch_(microseconds) { } -string UtcTime::toString() const +string Timestamp::toString() const { char buf[32] = {0}; int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond; @@ -31,16 +31,16 @@ string UtcTime::toString() const return buf; } -UtcTime UtcTime::now() +Timestamp Timestamp::now() { struct timeval tv; gettimeofday(&tv, NULL); int64_t seconds = tv.tv_sec; - return UtcTime(seconds * kMicroSecondsPerSecond + tv.tv_usec); + return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec); } -UtcTime UtcTime::invalid() +Timestamp Timestamp::invalid() { - return UtcTime(); + return Timestamp(); } diff --git a/muduo/base/UtcTime.h b/muduo/base/Timestamp.h similarity index 59% rename from muduo/base/UtcTime.h rename to muduo/base/Timestamp.h index 23123f55d..285337053 100644 --- a/muduo/base/UtcTime.h +++ b/muduo/base/Timestamp.h @@ -1,5 +1,5 @@ -#ifndef MUDUO_BASE_UTCTIME_H -#define MUDUO_BASE_UTCTIME_H +#ifndef MUDUO_BASE_TIMESTAMP_H +#define MUDUO_BASE_TIMESTAMP_H #include #include @@ -13,19 +13,19 @@ namespace muduo /// This class is immutable. /// It's recommended to pass it by value, since it's passed in register on x64. /// -class UtcTime : public muduo::copyable +class Timestamp : public muduo::copyable { public: /// - /// Constucts an invalid UtcTime. + /// Constucts an invalid Timestamp. /// - UtcTime(); + Timestamp(); /// - /// Constucts a UtcTime at specific time + /// Constucts a Timestamp at specific time /// /// @param microSecondsSinceEpoch - explicit UtcTime(int64_t microSecondsSinceEpoch); + explicit Timestamp(int64_t microSecondsSinceEpoch); // default copy/assignment are Okay @@ -33,17 +33,17 @@ class UtcTime : public muduo::copyable bool valid() const { return microSecondsSinceEpoch_ > 0; } - bool before(UtcTime rhs) const + bool before(Timestamp rhs) const { return microSecondsSinceEpoch_ < rhs.microSecondsSinceEpoch_; } - bool after(UtcTime rhs) const + bool after(Timestamp rhs) const { return microSecondsSinceEpoch_ > rhs.microSecondsSinceEpoch_; } - bool equals(UtcTime rhs) const + bool equals(Timestamp rhs) const { return microSecondsSinceEpoch_ == rhs.microSecondsSinceEpoch_; } @@ -54,8 +54,8 @@ class UtcTime : public muduo::copyable /// /// Get time of now. /// - static UtcTime now(); - static UtcTime invalid(); + static Timestamp now(); + static Timestamp invalid(); static const int kMicroSecondsPerSecond = 1000 * 1000; @@ -63,12 +63,12 @@ class UtcTime : public muduo::copyable int64_t microSecondsSinceEpoch_; }; -inline bool operator<(UtcTime lhs, UtcTime rhs) +inline bool operator<(Timestamp lhs, Timestamp rhs) { return lhs.before(rhs); } -inline bool operator==(UtcTime lhs, UtcTime rhs) +inline bool operator==(Timestamp lhs, Timestamp rhs) { return lhs.equals(rhs); } @@ -80,22 +80,22 @@ inline bool operator==(UtcTime lhs, UtcTime rhs) /// @return (high-low) in seconds /// @c double has 52-bit precision, enough for one-microseciond /// resolution for next 100 years. -inline double timeDifference(UtcTime high, UtcTime low) +inline double timeDifference(Timestamp high, Timestamp low) { int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch(); - return static_cast(diff) / UtcTime::kMicroSecondsPerSecond; + return static_cast(diff) / Timestamp::kMicroSecondsPerSecond; } /// /// Add @c seconds to given timestamp. /// -/// @return timestamp+seconds as UtcTime +/// @return timestamp+seconds as Timestamp /// -inline UtcTime addTime(UtcTime timestamp, double seconds) +inline Timestamp addTime(Timestamp timestamp, double seconds) { - int64_t delta = static_cast(seconds * UtcTime::kMicroSecondsPerSecond); - return UtcTime(timestamp.microSecondsSinceEpoch() + delta); + int64_t delta = static_cast(seconds * Timestamp::kMicroSecondsPerSecond); + return Timestamp(timestamp.microSecondsSinceEpoch() + delta); } } -#endif +#endif // MUDUO_BASE_TIMESTAMP_H diff --git a/muduo/base/tests/CMakeLists.txt b/muduo/base/tests/CMakeLists.txt index 66cfe2ac2..ee40f42e5 100644 --- a/muduo/base/tests/CMakeLists.txt +++ b/muduo/base/tests/CMakeLists.txt @@ -1,3 +1,3 @@ -add_executable(utctime_unittest UtcTime_unittest.cc) -target_link_libraries(utctime_unittest muduo_base) +add_executable(timestamp_unittest Timestamp_unittest.cc) +target_link_libraries(timestamp_unittest muduo_base) diff --git a/muduo/base/tests/UtcTime_unittest.cc b/muduo/base/tests/Timestamp_unittest.cc similarity index 56% rename from muduo/base/tests/UtcTime_unittest.cc rename to muduo/base/tests/Timestamp_unittest.cc index 858ab42c9..92e63ecf9 100644 --- a/muduo/base/tests/UtcTime_unittest.cc +++ b/muduo/base/tests/Timestamp_unittest.cc @@ -1,21 +1,21 @@ -#include +#include #include -using muduo::UtcTime; +using muduo::Timestamp; -void passByConstReference(const UtcTime& x) +void passByConstReference(const Timestamp& x) { printf("%s\n", x.toString().c_str()); } -void passByValue(UtcTime x) +void passByValue(Timestamp x) { printf("%s\n", x.toString().c_str()); } int main() { - UtcTime now(UtcTime::now()); + Timestamp now(Timestamp::now()); printf("%s\n", now.toString().c_str()); passByValue(now); passByConstReference(now); diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index 6000c3aad..1e9df8f83 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -40,6 +40,7 @@ namespace muduo { +class Timestamp; namespace net { @@ -53,7 +54,8 @@ typedef boost::function ConnectionCallback; // the data has been read to (buf, len) typedef boost::function MessageCallback; + ChannelBuffer*, + Timestamp receiveTime)> MessageCallback; } } diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 7f1cb681a..beffdd1a9 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -60,7 +60,7 @@ void Channel::tie(const boost::shared_ptr& obj) tied_ = true; } -void Channel::handleEvent() +void Channel::handleEvent(Timestamp receiveTime) { boost::shared_ptr guard; if (tied_) @@ -68,16 +68,16 @@ void Channel::handleEvent() guard = tie_.lock(); if (guard) { - handleEventWithGuard(); + handleEventWithGuard(receiveTime); } } else { - handleEventWithGuard(); + handleEventWithGuard(receiveTime); } } -void Channel::handleEventWithGuard() +void Channel::handleEventWithGuard(Timestamp receiveTime) { if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) { @@ -96,7 +96,7 @@ void Channel::handleEventWithGuard() } if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) { - if (readCallback_) readCallback_(); + if (readCallback_) readCallback_(receiveTime); } if (revents_ & POLLOUT) { diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index c97225ace..c4ef4bd23 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -40,6 +40,8 @@ #include #include +#include + namespace muduo { namespace net @@ -57,16 +59,17 @@ class Channel : boost::noncopyable { public: typedef boost::function EventCallback; + typedef boost::function ReadEventCallback; static const int kNoneEvent; static const int kReadEvent; static const int kWriteEvent; - static const int kErrorvent; + // static const int kErrorvent; Channel(EventLoop* loop, int fd); ~Channel(); - void handleEvent(); - void setReadCallback(const EventCallback& cb) + void handleEvent(Timestamp receiveTime); + void setReadCallback(const ReadEventCallback& cb) { readCallback_ = cb; } void setWriteCallback(const EventCallback& cb) { writeCallback_ = cb; } @@ -92,7 +95,7 @@ class Channel : boost::noncopyable // void set_loop(EventLoop* loop) { loop_ = loop; } private: - void handleEventWithGuard(); + void handleEventWithGuard(Timestamp receiveTime); EventLoop* loop_; const int fd_; @@ -102,7 +105,7 @@ class Channel : boost::noncopyable boost::weak_ptr tie_; bool tied_; - EventCallback readCallback_; + ReadEventCallback readCallback_; EventCallback writeCallback_; EventCallback closeCallback_; EventCallback errorCallback_; diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc index f52493163..3628d3809 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/EPollPoller.cc @@ -53,7 +53,9 @@ EPollPoller::~EPollPoller() { } -void EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) +Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) { + Timestamp now(Timestamp::now()); + return now; } diff --git a/muduo/net/EPollPoller.h b/muduo/net/EPollPoller.h index ea711fed0..59de0b396 100644 --- a/muduo/net/EPollPoller.h +++ b/muduo/net/EPollPoller.h @@ -54,7 +54,7 @@ class EPollPoller : public Poller virtual ~EPollPoller(); - virtual void poll(int timeoutMs, ChannelList* activeChannels); + virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels); virtual void updateChannel(Channel* channel); private: diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 29b904927..867de3878 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -104,13 +104,13 @@ void EventLoop::loop() while (!quit_) { activeChannels_.clear(); - poller_->poll(kPollTimeMs, &activeChannels_); + Timestamp receiveTime = poller_->poll(kPollTimeMs, &activeChannels_); // TODO sort channel by priority eventHandling_ = true; for (ChannelList::iterator it = activeChannels_.begin(); it != activeChannels_.end(); ++it) { - (*it)->handleEvent(); + (*it)->handleEvent(receiveTime); // FIXME if one handleEvent() destroys XXX HACK } eventHandling_ = false; @@ -152,20 +152,20 @@ void EventLoop::queueInLoop(const Functor& cb) pendingFunctors_.push_back(cb); } -TimerId EventLoop::runAt(const UtcTime& time, const TimerCallback& cb) +TimerId EventLoop::runAt(const Timestamp& time, const TimerCallback& cb) { return timerQueue_->schedule(cb, time, 0.0); } TimerId EventLoop::runAfter(double delay, const TimerCallback& cb) { - UtcTime time(addTime(UtcTime::now(), delay)); + Timestamp time(addTime(Timestamp::now(), delay)); return runAt(time, cb); } TimerId EventLoop::runEvery(double interval, const TimerCallback& cb) { - UtcTime time(addTime(UtcTime::now(), interval)); + Timestamp time(addTime(Timestamp::now(), interval)); return timerQueue_->schedule(cb, time, interval); } diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 0fb6eceb1..5cd982da7 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include @@ -89,7 +89,7 @@ class EventLoop : boost::noncopyable /// Safe to call from other threads. void queueInLoop(const Functor& cb); /// - TimerId runAt(const UtcTime& time, const TimerCallback& cb); + TimerId runAt(const Timestamp& time, const TimerCallback& cb); /// /// Runs callback after @c delay seconds. /// Safe to call from other threads. diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index 03cef3cac..ac2cd1581 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -43,10 +43,11 @@ PollPoller::~PollPoller() { } -void PollPoller::poll(int timeoutMs, ChannelList* activeChannels) +Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels) { // XXX pollfds_ shouldn't change int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); + Timestamp now(Timestamp::now()); if (numEvents > 0) { fillActiveChannels(numEvents, activeChannels); @@ -60,7 +61,7 @@ void PollPoller::poll(int timeoutMs, ChannelList* activeChannels) { perror("PollPoller::poll"); } - + return now; } void PollPoller::fillActiveChannels(int numEvents, @@ -129,7 +130,7 @@ void PollPoller::removeChannel(Channel* channel) int idx = channel->index(); assert(0 <= idx && idx < static_cast(pollfds_.size())); const struct pollfd& pfd = pollfds_[idx]; - // assert(pfd.fd == -channel->fd()-1 && pfd.events == Channel::kNoneEvent); + assert(pfd.fd == -channel->fd()-1 && pfd.events == Channel::kNoneEvent); size_t n = channels_.erase(channel->fd()); assert(n == 1); if (implicit_cast(idx) == pollfds_.size()-1) @@ -140,6 +141,10 @@ void PollPoller::removeChannel(Channel* channel) { int channelAtEnd = pollfds_.back().fd; iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); + if (channelAtEnd < 0) + { + channelAtEnd = -channelAtEnd-1; + } channels_[channelAtEnd]->set_index(idx); pollfds_.pop_back(); } diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index 9222a93b1..486c1086a 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -56,7 +56,7 @@ class PollPoller : public Poller virtual ~PollPoller(); - virtual void poll(int timeoutMs, ChannelList* activeChannels); + virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels); virtual void updateChannel(Channel* channel); virtual void removeChannel(Channel* channel); diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index b597864c0..d5f05bf5a 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -38,6 +38,8 @@ #include #include +#include + namespace muduo { namespace net @@ -57,7 +59,7 @@ class Poller : boost::noncopyable /// Polls the I/O events. /// Must be called in the loop thread. - virtual void poll(int timeoutMs, ChannelList* activeChannels) = 0; + virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0; /// Changes the interested I/O events. /// Must be called in the loop thread. diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 4b7665ce5..33b0dc79a 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -56,7 +56,7 @@ TcpConnection::TcpConnection(EventLoop* loop, peerAddr_(peerAddr) { channel_->setReadCallback( - boost::bind(&TcpConnection::handleRead, this)); + boost::bind(&TcpConnection::handleRead, this, _1)); channel_->setWriteCallback( boost::bind(&TcpConnection::handleWrite, this)); channel_->setCloseCallback( @@ -67,10 +67,36 @@ TcpConnection::TcpConnection(EventLoop* loop, } TcpConnection::~TcpConnection() +{ +} + +void TcpConnection::send(const string& message) +{ + if (state_ == kConnected) + { + loop_->runInLoop( + boost::bind(&TcpConnection::sendInLoop, this, message)); + /* + { + MutexLockGuard lock(mutex_); + outputBuffer_.append(message.data(), message.size()); + } + channel_->set_events(Channel::kReadEvent | Channel::kWriteEvent); + loop_->runInLoop( + boost::bind(&EventLoop::updateChannel, loop_, get_pointer(channel_))); + */ + } +} + +void TcpConnection::sendInLoop(const string& message) { loop_->assertInLoopThread(); - loop_->removeChannel(get_pointer(channel_)); - printf("%p %s dtor\n", this, name_.c_str()); + outputBuffer_.append(message.data(), message.size()); + if ((channel_->events() & Channel::kWriteEvent) == 0) + { + channel_->set_events(Channel::kReadEvent | Channel::kWriteEvent); + loop_->updateChannel(get_pointer(channel_)); + } } void TcpConnection::shutdown() @@ -96,16 +122,19 @@ void TcpConnection::connectEstablished() void TcpConnection::connectDestroyed() { + loop_->assertInLoopThread(); + loop_->removeChannel(get_pointer(channel_)); + printf("%p %s dtor\n", this, name_.c_str()); } -void TcpConnection::handleRead() +void TcpConnection::handleRead(Timestamp receiveTime) { loop_->assertInLoopThread(); int savedErrno; ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno); if (n > 0) { - messageCallback_(shared_from_this(), &inputBuffer_); + messageCallback_(shared_from_this(), &inputBuffer_, receiveTime); } else if (n == 0) { @@ -119,6 +148,19 @@ void TcpConnection::handleRead() void TcpConnection::handleWrite() { + loop_->assertInLoopThread(); + + ssize_t n = ::write(channel_->fd(), outputBuffer_.peek(), outputBuffer_.readableBytes()); + //int savedErrno = errno; + if (n > 0) + { + outputBuffer_.retrieve(n); + if (outputBuffer_.readableBytes() == 0) + { + channel_->set_events(Channel::kReadEvent); + loop_->updateChannel(get_pointer(channel_)); + } + } } void TcpConnection::handleClose() diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index a96a2e2a5..d2b49bd8b 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -35,6 +35,7 @@ #ifndef MUDUO_NET_TCPCONNECTION_H #define MUDUO_NET_TCPCONNECTION_H +#include #include #include #include @@ -78,6 +79,9 @@ class TcpConnection : public boost::enable_shared_from_this, bool connected() const { return state_ == kConnected; } bool connecting() const { return state_ == kConnecting; } + void send(const string& message); + // void send(const ChannelBuffer& message); + void send(ChannelBuffer* message); // this one will retrieve data void shutdown(); void setConnectionCallback(ConnectionCallback cb) @@ -96,10 +100,11 @@ class TcpConnection : public boost::enable_shared_from_this, private: enum States { kDisconnected, kConnecting, kConnected, kDisconnecting }; - void handleRead(); + void handleRead(Timestamp receiveTime); void handleWrite(); void handleClose(); void handleError(); + void sendInLoop(const string& message); EventLoop* loop_; string name_; @@ -113,6 +118,7 @@ class TcpConnection : public boost::enable_shared_from_this, MessageCallback messageCallback_; ConnectionCallback closeCallback_; ChannelBuffer inputBuffer_; + // MutexLock mutex_; ChannelBuffer outputBuffer_; }; diff --git a/muduo/net/Timer.cc b/muduo/net/Timer.cc index 0c28c170a..e3ea1565d 100644 --- a/muduo/net/Timer.cc +++ b/muduo/net/Timer.cc @@ -33,7 +33,7 @@ using namespace muduo; using namespace muduo::net; -void Timer::restart(UtcTime now) +void Timer::restart(Timestamp now) { if (repeat_) { @@ -41,6 +41,6 @@ void Timer::restart(UtcTime now) } else { - expiration_ = UtcTime::invalid(); + expiration_ = Timestamp::invalid(); } } diff --git a/muduo/net/Timer.h b/muduo/net/Timer.h index f0c68ccf1..cbe0d5f6d 100644 --- a/muduo/net/Timer.h +++ b/muduo/net/Timer.h @@ -39,7 +39,7 @@ #include -#include +#include #include namespace muduo @@ -52,7 +52,7 @@ namespace net class Timer : boost::noncopyable { public: - Timer(const TimerCallback& cb, UtcTime when, double interval) + Timer(const TimerCallback& cb, Timestamp when, double interval) : cb_(cb), expiration_(when), interval_(interval), @@ -64,14 +64,14 @@ class Timer : boost::noncopyable cb_(); } - UtcTime expiration() const { return expiration_; } + Timestamp expiration() const { return expiration_; } bool repeat() const { return repeat_; } - void restart(UtcTime now); + void restart(Timestamp now); private: const TimerCallback cb_; - UtcTime expiration_; + Timestamp expiration_; const double interval_; const bool repeat_; }; diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index 85d699fb7..f9a5ac510 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -59,23 +59,23 @@ int createTimerfd() return timerfd; } -struct timespec howMuchTimeFromNow(UtcTime when) +struct timespec howMuchTimeFromNow(Timestamp when) { int64_t microseconds = when.microSecondsSinceEpoch() - - UtcTime::now().microSecondsSinceEpoch(); + - Timestamp::now().microSecondsSinceEpoch(); if (microseconds < 100) { microseconds = 100; } struct timespec ts; ts.tv_sec = static_cast( - microseconds / UtcTime::kMicroSecondsPerSecond); + microseconds / Timestamp::kMicroSecondsPerSecond); ts.tv_nsec = static_cast( - (microseconds % UtcTime::kMicroSecondsPerSecond) * 1000); + (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); return ts; } -void resetTimerfd(int timerfd, UtcTime when) +void resetTimerfd(int timerfd, Timestamp when) { // wake up loop by timerfd_settime() struct itimerspec newValue; @@ -119,7 +119,7 @@ TimerQueue::~TimerQueue() void TimerQueue::timeout() { loop_->assertInLoopThread(); - UtcTime now(UtcTime::now()); + Timestamp now(Timestamp::now()); uint64_t howmany; ssize_t n = ::read(timerfd_, &howmany, sizeof howmany); printf("TimerQueue::timeout() timeout %" PRIu64 " at %s\n", @@ -152,7 +152,7 @@ void TimerQueue::timeout() (*it)->run(); } - UtcTime nextExpire; + Timestamp nextExpire; { MutexLockGuard lock(mutex_); // shall never callback in critical section @@ -184,7 +184,7 @@ void TimerQueue::timeout() } TimerId TimerQueue::schedule(const TimerCallback& cb, - UtcTime when, + Timestamp when, double interval) { Timer* timer = new Timer(cb, when, interval); @@ -206,7 +206,7 @@ TimerId TimerQueue::schedule(const TimerCallback& cb, bool TimerQueue::insertWithLockHold(Timer* timer) { bool earliestChanged = false; - UtcTime when = timer->expiration(); + Timestamp when = timer->expiration(); TimerList::iterator it = timers_.begin(); if (it == timers_.end() || (*it)->expiration().after(when)) { diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index dec9a650f..6237ccb6d 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include @@ -69,7 +69,7 @@ class TimerQueue : boost::noncopyable /// /// Must be thread safe. Usually be called from other threads. TimerId schedule(const TimerCallback& cb, - UtcTime when, + Timestamp when, double interval); void cancel(TimerId timerId); diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index e6abc0739..44d0d3977 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -24,7 +24,7 @@ class EchoServer server_.setConnectionCallback( boost::bind(&EchoServer::onConnection, this, _1)); server_.setMessageCallback( - boost::bind(&EchoServer::onMessage, this, _1, _2)); + boost::bind(&EchoServer::onMessage, this, _1, _2, _3)); server_.setThreadNum(numThreads); } @@ -49,15 +49,26 @@ class EchoServer second = conn; } - void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf) + void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf, Timestamp time) { string msg(buf->retrieveAsString()); printf("recv %zu bytes '%s'", msg.size(), msg.c_str()); if (msg == "exit\n") - ::exit(0); + { + first->shutdown(); + first.reset(); + second->shutdown(); + second.reset(); + loop_->quit(); + } + if (conn != first && first) + first->send(msg); + if (conn != second && second) + second->send(msg); // conn->send(buf); // conn->shutdown(); // loop_->quit(); + /* if (conn == second) { sleep(10); @@ -69,6 +80,7 @@ class EchoServer first.reset(); // loop_->quit(); } + */ } EventLoop* loop_; diff --git a/muduo/net/tests/TimerQueue_unittest.cc b/muduo/net/tests/TimerQueue_unittest.cc index ed5c7e415..288073e53 100644 --- a/muduo/net/tests/TimerQueue_unittest.cc +++ b/muduo/net/tests/TimerQueue_unittest.cc @@ -14,7 +14,7 @@ EventLoop* g_loop; void print(const char* msg) { - printf("msg %s %s\n", UtcTime::now().toString().c_str(), msg); + printf("msg %s %s\n", Timestamp::now().toString().c_str(), msg); if (++cnt == 20) { g_loop->quit(); From 56991a0391f626298cdbd33294fbf6ca2f5c7657 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 18 Mar 2010 01:09:30 +0000 Subject: [PATCH 021/371] Still crash. --- muduo/net/CMakeLists.txt | 2 +- muduo/net/EventLoop.cc | 16 +++- .../net/{ThreadModel.cc => EventLoopPool.cc} | 14 ++-- muduo/net/EventLoopPool.h | 80 +++++++++++++++++++ muduo/net/TcpConnection.cc | 10 ++- muduo/net/TcpServer.cc | 10 +-- muduo/net/TcpServer.h | 4 +- muduo/net/{ThreadModel.h => ThreadLoopPool.h} | 0 muduo/net/TimerQueue.cc | 2 + muduo/net/tests/CMakeLists.txt | 4 +- ...del_unittest.cc => ThreadPool_unittest.cc} | 8 +- 11 files changed, 125 insertions(+), 25 deletions(-) rename muduo/net/{ThreadModel.cc => EventLoopPool.cc} (90%) create mode 100644 muduo/net/EventLoopPool.h rename muduo/net/{ThreadModel.h => ThreadLoopPool.h} (100%) rename muduo/net/tests/{ThreadModel_unittest.cc => ThreadPool_unittest.cc} (89%) diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 2ec10afdf..6d0fa7dd2 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -5,6 +5,7 @@ set(net_SRCS DefaultPoller.cc EPollPoller.cc EventLoop.cc + EventLoopPool.cc InetAddress.cc Poller.cc PollPoller.cc @@ -12,7 +13,6 @@ set(net_SRCS SocketsOps.cc TcpConnection.cc TcpServer.cc - ThreadModel.cc Timer.cc TimerQueue.cc ) diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 867de3878..f908b725a 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -85,7 +85,7 @@ EventLoop::EventLoop() } wakeupChannel_->setReadCallback( boost::bind(&EventLoop::wakedup, this)); - // we are always reading the wakeupfd, like the old pipe(2) way. + // we are always reading the wakeupfd wakeupChannel_->set_events(Channel::kReadEvent); updateChannel(get_pointer(wakeupChannel_)); } @@ -111,7 +111,6 @@ void EventLoop::loop() it != activeChannels_.end(); ++it) { (*it)->handleEvent(receiveTime); - // FIXME if one handleEvent() destroys XXX HACK } eventHandling_ = false; doPendingFunctors(); @@ -122,6 +121,10 @@ void EventLoop::loop() void EventLoop::quit() { quit_ = true; + if (threadId_ == CurrentThread::tid()) + { + wakeup(); + } } void EventLoop::wakeup() @@ -143,6 +146,7 @@ void EventLoop::runInLoop(const Functor& cb) else { queueInLoop(cb); + wakeup(); } } @@ -179,6 +183,7 @@ void EventLoop::updateChannel(Channel* channel) void EventLoop::removeChannel(Channel* channel) { assert(channel->getLoop() == this); + assertInLoopThread(); poller_->removeChannel(channel); } @@ -189,7 +194,12 @@ void EventLoop::assertInLoopThread() void EventLoop::wakedup() { - // what's up + uint64_t one = 1; + ssize_t n = ::read(wakeupFd_, &one, sizeof one); + if (n != sizeof one) + { + fprintf(stderr, "EventLoop::wakedup() write %zd bytes instead of 8\n", n); + } } void EventLoop::doPendingFunctors() diff --git a/muduo/net/ThreadModel.cc b/muduo/net/EventLoopPool.cc similarity index 90% rename from muduo/net/ThreadModel.cc rename to muduo/net/EventLoopPool.cc index 4000aa9c9..43a1f6a71 100644 --- a/muduo/net/ThreadModel.cc +++ b/muduo/net/EventLoopPool.cc @@ -28,7 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include +#include #include #include @@ -39,7 +39,7 @@ using namespace muduo; using namespace muduo::net; -ThreadModel::ThreadModel(EventLoop* baseLoop) +EventLoopPool::EventLoopPool(EventLoop* baseLoop) : baseLoop_(baseLoop), started_(false), exiting_(false), @@ -50,7 +50,7 @@ ThreadModel::ThreadModel(EventLoop* baseLoop) { } -ThreadModel::~ThreadModel() +EventLoopPool::~EventLoopPool() { exiting_ = true; for (size_t i = 0; i < loopPool_.size(); ++i) @@ -66,14 +66,14 @@ ThreadModel::~ThreadModel() } } -void ThreadModel::start() +void EventLoopPool::start() { assert(!started_); baseLoop_->assertInLoopThread(); started_ = true; - Thread::ThreadFunc func = boost::bind(&ThreadModel::threadFunc, this); + Thread::ThreadFunc func = boost::bind(&EventLoopPool::threadFunc, this); for (int i = 0; i < numThreads_; ++i) { @@ -91,7 +91,7 @@ void ThreadModel::start() } } -EventLoop* ThreadModel::getNextLoop() +EventLoop* EventLoopPool::getNextLoop() { baseLoop_->assertInLoopThread(); EventLoop* loop = baseLoop_; @@ -109,7 +109,7 @@ EventLoop* ThreadModel::getNextLoop() return loop; } -void ThreadModel::threadFunc() +void EventLoopPool::threadFunc() { EventLoop loop; diff --git a/muduo/net/EventLoopPool.h b/muduo/net/EventLoopPool.h new file mode 100644 index 000000000..73b463270 --- /dev/null +++ b/muduo/net/EventLoopPool.h @@ -0,0 +1,80 @@ +// Muduo - A lightwight C++ network library for Linux +// Copyright (c) 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Muduo team nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_THREADMODEL_H +#define MUDUO_NET_THREADMODEL_H + +#include +#include + +#include +#include + +namespace muduo +{ + +class Thread; + +namespace net +{ + +class EventLoop; + +class EventLoopPool : boost::noncopyable +{ + public: + EventLoopPool(EventLoop* baseLoop); + ~EventLoopPool(); + void setThreadNum(int numThreads) { numThreads_ = numThreads; } + void start(); + EventLoop* getNextLoop(); + + private: + void threadFunc(); + + EventLoop* baseLoop_; + bool started_; + bool exiting_; + int numThreads_; + int next_; + std::vector threads_; + MutexLock mutex_; + Condition cond_; + std::vector loopPool_; // @GuardedBy mutex_ +}; + +} +} + +#endif // MUDUO_NET_THREADMODEL_H diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 33b0dc79a..fd14f802a 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -68,6 +68,7 @@ TcpConnection::TcpConnection(EventLoop* loop, TcpConnection::~TcpConnection() { + printf("%p %s dtor\n", this, name_.c_str()); } void TcpConnection::send(const string& message) @@ -123,8 +124,15 @@ void TcpConnection::connectEstablished() void TcpConnection::connectDestroyed() { loop_->assertInLoopThread(); + if (state_ == kConnected) + { + state_ = kDisconnected; + sockets::shutdown(channel_->fd()); + channel_->set_events(Channel::kNoneEvent); + loop_->updateChannel(get_pointer(channel_)); + connectionCallback_(shared_from_this()); + } loop_->removeChannel(get_pointer(channel_)); - printf("%p %s dtor\n", this, name_.c_str()); } void TcpConnection::handleRead(Timestamp receiveTime) diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 8fae3fa76..f3198ee17 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -32,8 +32,8 @@ #include #include +#include #include -#include #include @@ -46,7 +46,7 @@ TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr) : loop_(loop), name_(listenAddr.toHostPort()), acceptor_(new Acceptor(loop, listenAddr)), - threadModel_(new ThreadModel(loop)), + threadPool_(new EventLoopPool(loop)), started_(false), nextConnId_(1) { @@ -72,7 +72,7 @@ TcpServer::~TcpServer() void TcpServer::setThreadNum(int numThreads) { assert(0 <= numThreads); - threadModel_->setThreadNum(numThreads); + threadPool_->setThreadNum(numThreads); } void TcpServer::start() @@ -80,7 +80,7 @@ void TcpServer::start() if (!started_) { started_ = true; - threadModel_->start(); + threadPool_->start(); } if (!acceptor_->listenning()) @@ -92,7 +92,7 @@ void TcpServer::start() void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) { loop_->assertInLoopThread(); - EventLoop* ioLoop = threadModel_->getNextLoop(); + EventLoop* ioLoop = threadPool_->getNextLoop(); char buf[32]; snprintf(buf, sizeof buf, "%s#%d", name_.c_str(), nextConnId_); ++nextConnId_; diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index 59408e3fc..4f0b6533c 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -51,7 +51,7 @@ namespace net class Acceptor; class EventLoop; class InetAddress; -class ThreadModel; +class EventLoopPool; /// /// TCP server, supports single-threaded and thread-pool models. @@ -110,7 +110,7 @@ class TcpServer : boost::noncopyable EventLoop* loop_; // the acceptor loop string name_; boost::scoped_ptr acceptor_; // avoid revealing Acceptor - boost::scoped_ptr threadModel_; + boost::scoped_ptr threadPool_; ConnectionCallback connectionCallback_; MessageCallback messageCallback_; const string serverName_; diff --git a/muduo/net/ThreadModel.h b/muduo/net/ThreadLoopPool.h similarity index 100% rename from muduo/net/ThreadModel.h rename to muduo/net/ThreadLoopPool.h diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index f9a5ac510..558e4508e 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -47,6 +47,7 @@ using namespace muduo::net; namespace { + int createTimerfd() { int timerfd = ::timerfd_create(CLOCK_MONOTONIC, @@ -89,6 +90,7 @@ void resetTimerfd(int timerfd, Timestamp when) perror("Error in timerfd_settime"); } } + } TimerQueue::TimerQueue(EventLoop* loop) diff --git a/muduo/net/tests/CMakeLists.txt b/muduo/net/tests/CMakeLists.txt index f45d65f1b..f02063597 100644 --- a/muduo/net/tests/CMakeLists.txt +++ b/muduo/net/tests/CMakeLists.txt @@ -4,8 +4,8 @@ target_link_libraries(echoserver_unittest muduo_net) add_executable(eventloop_unittest EventLoop_unittest.cc) target_link_libraries(eventloop_unittest muduo_net) -add_executable(threadmodel_unittest ThreadModel_unittest.cc) -target_link_libraries(threadmodel_unittest muduo_net) +add_executable(threadpool_unittest ThreadPool_unittest.cc) +target_link_libraries(threadpool_unittest muduo_net) add_executable(timerqueue_unittest TimerQueue_unittest.cc) target_link_libraries(timerqueue_unittest muduo_net) diff --git a/muduo/net/tests/ThreadModel_unittest.cc b/muduo/net/tests/ThreadPool_unittest.cc similarity index 89% rename from muduo/net/tests/ThreadModel_unittest.cc rename to muduo/net/tests/ThreadPool_unittest.cc index 56eca7f3c..dea0f1999 100644 --- a/muduo/net/tests/ThreadModel_unittest.cc +++ b/muduo/net/tests/ThreadPool_unittest.cc @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -23,7 +23,7 @@ int main() { printf("Single thread:\n"); - ThreadModel model(&loop); + EventLoopPool model(&loop); model.setThreadNum(0); model.start(); assert(model.getNextLoop() == &loop); @@ -33,7 +33,7 @@ int main() { printf("Another thread:\n"); - ThreadModel model(&loop); + EventLoopPool model(&loop); model.setThreadNum(1); model.start(); EventLoop* nextLoop = model.getNextLoop(); @@ -44,7 +44,7 @@ int main() { printf("Three threads:\n"); - ThreadModel model(&loop); + EventLoopPool model(&loop); model.setThreadNum(3); model.start(); EventLoop* nextLoop = model.getNextLoop(); From 2137de7b11a8ae2f505badfe77faf9416eafeba3 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 18 Mar 2010 01:10:55 +0000 Subject: [PATCH 022/371] Fix typo. --- muduo/net/EventLoopPool.h | 6 +-- muduo/net/ThreadLoopPool.h | 80 -------------------------------------- 2 files changed, 3 insertions(+), 83 deletions(-) delete mode 100644 muduo/net/ThreadLoopPool.h diff --git a/muduo/net/EventLoopPool.h b/muduo/net/EventLoopPool.h index 73b463270..86e2fa465 100644 --- a/muduo/net/EventLoopPool.h +++ b/muduo/net/EventLoopPool.h @@ -32,8 +32,8 @@ // // This is an internal header file, you should not include this. -#ifndef MUDUO_NET_THREADMODEL_H -#define MUDUO_NET_THREADMODEL_H +#ifndef MUDUO_NET_EVENTLOOPPOOL_H +#define MUDUO_NET_EVENTLOOPPOOL_H #include #include @@ -77,4 +77,4 @@ class EventLoopPool : boost::noncopyable } } -#endif // MUDUO_NET_THREADMODEL_H +#endif // MUDUO_NET_EVENTLOOPPOOL_H diff --git a/muduo/net/ThreadLoopPool.h b/muduo/net/ThreadLoopPool.h deleted file mode 100644 index 46328c192..000000000 --- a/muduo/net/ThreadLoopPool.h +++ /dev/null @@ -1,80 +0,0 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_THREADMODEL_H -#define MUDUO_NET_THREADMODEL_H - -#include -#include - -#include -#include - -namespace muduo -{ - -class Thread; - -namespace net -{ - -class EventLoop; - -class ThreadModel : boost::noncopyable -{ - public: - ThreadModel(EventLoop* baseLoop); - ~ThreadModel(); - void setThreadNum(int numThreads) { numThreads_ = numThreads; } - void start(); - EventLoop* getNextLoop(); - - private: - void threadFunc(); - - EventLoop* baseLoop_; - bool started_; - bool exiting_; - int numThreads_; - int next_; - std::vector threads_; - MutexLock mutex_; - Condition cond_; - std::vector loopPool_; // @GuardedBy mutex_ -}; - -} -} - -#endif // MUDUO_NET_THREADMODEL_H From 7373683b1f38f5532e879128baaaed8c9513cc35 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 18 Mar 2010 14:04:43 +0000 Subject: [PATCH 023/371] Add logging. --- CMakeLists.txt | 2 + muduo/base/CMakeLists.txt | 1 + muduo/base/Logging.cc | 102 +++++++++++++++++++++++++ muduo/base/Logging.h | 48 ++++++++++++ muduo/base/Timestamp.cc | 15 ++++ muduo/base/Timestamp.h | 1 + muduo/net/EventLoop.cc | 14 ++-- muduo/net/tests/EchoServer_unittest.cc | 3 +- 8 files changed, 178 insertions(+), 8 deletions(-) create mode 100644 muduo/base/Logging.cc create mode 100644 muduo/base/Logging.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 818c3a525..b4e6d321d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,8 @@ set(CXX_FLAGS -Wwrite-strings -rdynamic -lpthread + -lglog + -L/usr/local/lib ) string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") diff --git a/muduo/base/CMakeLists.txt b/muduo/base/CMakeLists.txt index 16c35aab7..71f89efa8 100644 --- a/muduo/base/CMakeLists.txt +++ b/muduo/base/CMakeLists.txt @@ -1,4 +1,5 @@ set(base_SRCS + Logging.cc Timestamp.cc Thread.cc ) diff --git a/muduo/base/Logging.cc b/muduo/base/Logging.cc new file mode 100644 index 000000000..5825dc365 --- /dev/null +++ b/muduo/base/Logging.cc @@ -0,0 +1,102 @@ +#include + +#include +#include + +#include // for errno +#include +#include + +#include + +namespace muduo +{ +class LoggerImpl +{ + public: + typedef Logger::LogLevel LogLevel; + LoggerImpl(LogLevel level, int old_errno, const char* file, int line); + + Timestamp time_; + std::ostringstream stream_; + LogLevel level_; + const char* fullname_; + int line_; + const char* basename_; + const char* function_; + + static const char* LogLevelName[]; +}; +} + +using namespace muduo; + +const char* LoggerImpl::LogLevelName[Logger::NUM_LOG_LEVELS] = +{ + "TRACE", + "DEBUG", + "INFO", + "WARN", + "ERROR", + "FATAL", +}; + +LoggerImpl::LoggerImpl(LogLevel level, int savedErrno, const char* file, int line) + : time_(Timestamp::now()), + stream_(), + level_(level), + fullname_(file), + line_(line), + basename_(NULL), + function_(NULL) +{ + const char* path_sep_pos = strrchr(fullname_, '/'); + basename_ = (path_sep_pos != NULL) ? path_sep_pos + 1 : fullname_; + char message_head[512]; + snprintf(message_head, sizeof(message_head), "%s %5d %s:%d %s ", + time_.toFormattedString().c_str(), CurrentThread::tid(), + basename_, line_, LogLevelName[level]); + stream_ << message_head; + if (savedErrno != 0) + { + stream_ << strerror(savedErrno); + } +} + +std::ostream& Logger::stream() +{ + return impl_->stream_; +} + +Logger::Logger(const char* file, int line) + : impl_(new LoggerImpl(INFO, 0, file, line)) +{ +} + +Logger::Logger(const char* file, int line, LogLevel level, const char* func) + : impl_(new LoggerImpl(level, 0, file, line)) +{ + impl_->stream_ << func << ' '; +} + +Logger::Logger(const char* file, int line, LogLevel level) + : impl_(new LoggerImpl(level, 0, file, line)) +{ +} + +Logger::Logger(const char* file, int line, bool toAbort) + : impl_(new LoggerImpl(toAbort?FATAL:ERROR, errno, file, line)) +{ +} + +Logger::~Logger() +{ + impl_->stream_ << '\n'; + std::string buf(impl_->stream_.str()); + ssize_t n = ::write(1, buf.data(), buf.size()); + if (impl_->level_ == FATAL) + { + abort(); + } +} + diff --git a/muduo/base/Logging.h b/muduo/base/Logging.h new file mode 100644 index 000000000..dad7dbbc2 --- /dev/null +++ b/muduo/base/Logging.h @@ -0,0 +1,48 @@ +#ifndef MUDUO_LOG_LOGGING_H +#define MUDUO_LOG_LOGGING_H + +#include +#include + +namespace muduo +{ + +class LoggerImpl; +class Logger +{ + public: + enum LogLevel + { + TRACE, + DEBUG, + INFO, + WARN, + ERROR, + FATAL, + NUM_LOG_LEVELS, + }; + + Logger(const char* file, int line); + Logger(const char* file, int line, LogLevel level); + Logger(const char* file, int line, LogLevel level, const char* func); + Logger(const char* file, int line, bool toAbort); + ~Logger(); + + std::ostream& stream(); + + private: + boost::scoped_ptr impl_; +}; + +#define LOG_TRACE Logger(__FILE__, __LINE__, Logger::TRACE, __PRETTY_FUNCTION__).stream() +#define LOG_DEBUG Logger(__FILE__, __LINE__, Logger::DEBUG, __PRETTY_FUNCTION__).stream() +#define LOG_INFO Logger(__FILE__, __LINE__).stream() +#define LOG_WARN Logger(__FILE__, __LINE__, Logger::WARN).stream() +#define LOG_ERROR Logger(__FILE__, __LINE__, Logger::ERROR).stream() +#define LOG_FATAL Logger(__FILE__, __LINE__, Logger::FATAL).stream() +#define LOG_SYSERR Logger(__FILE__, __LINE__, false).stream() +#define LOG_SYSFATAL Logger(__FILE__, __LINE__, true).stream() + +} + +#endif // MUDUO_LOG_LOGGING_H diff --git a/muduo/base/Timestamp.cc b/muduo/base/Timestamp.cc index 357aa1ba2..9839d136f 100644 --- a/muduo/base/Timestamp.cc +++ b/muduo/base/Timestamp.cc @@ -31,6 +31,21 @@ string Timestamp::toString() const return buf; } +string Timestamp::toFormattedString() const +{ + char buf[32] = {0}; + time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); + int microseconds = static_cast(microSecondsSinceEpoch_ % kMicroSecondsPerSecond); + struct tm tm_time; + gmtime_r(&seconds, &tm_time); + + snprintf(buf, sizeof(buf), "%4d-%02d-%02d %02d:%02d:%02d.%06d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, + microseconds); + return buf; +} + Timestamp Timestamp::now() { struct timeval tv; diff --git a/muduo/base/Timestamp.h b/muduo/base/Timestamp.h index 285337053..f1a5d66ac 100644 --- a/muduo/base/Timestamp.h +++ b/muduo/base/Timestamp.h @@ -30,6 +30,7 @@ class Timestamp : public muduo::copyable // default copy/assignment are Okay string toString() const; + string toFormattedString() const; bool valid() const { return microSecondsSinceEpoch_ > 0; } diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index f908b725a..52ad9bed1 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -30,6 +30,7 @@ #include +#include #include #include #include @@ -38,7 +39,6 @@ #include -#include // FIXME #include using namespace muduo; @@ -55,7 +55,7 @@ int createEventfd() int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); if (evtfd < 0) { - perror("Failed in eventfd"); + LOG_SYSERR << "Failed in eventfd"; abort(); } return evtfd; @@ -72,11 +72,11 @@ EventLoop::EventLoop() wakeupFd_(createEventfd()), wakeupChannel_(new Channel(this, wakeupFd_)) { - printf("EventLoop created in thread %d\n", threadId_); + LOG_TRACE << "EventLoop created " << this << " in thread " << threadId_; if (t_loopInThisThread) { - fprintf(stderr, "Another EventLoop %p exists in this thread %d\n", - t_loopInThisThread, threadId_); + LOG_FATAL << "Another EventLoop " << t_loopInThisThread + << " exists in this thread " << threadId_; abort(); } else @@ -133,7 +133,7 @@ void EventLoop::wakeup() ssize_t n = ::write(wakeupFd_, &one, sizeof one); if (n != sizeof one) { - fprintf(stderr, "EventLoop::wakeup() write %zd bytes instead of 8\n", n); + LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8"; } } @@ -198,7 +198,7 @@ void EventLoop::wakedup() ssize_t n = ::read(wakeupFd_, &one, sizeof one); if (n != sizeof one) { - fprintf(stderr, "EventLoop::wakedup() write %zd bytes instead of 8\n", n); + LOG_ERROR << "EventLoop::wakeup() reads " << n << " bytes instead of 8"; } } diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 44d0d3977..d1f2e1d61 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -93,7 +94,7 @@ void threadFunc(uint16_t port) int main(int argc, char* argv[]) { - printf("main(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); numThreads = argc - 1; EventLoop loop; InetAddress listenAddr(2000); From 2e5863cb5db470f577c1c28b76ddcef088dc40b9 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 18 Mar 2010 14:08:19 +0000 Subject: [PATCH 024/371] Removing glog. --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b4e6d321d..818c3a525 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,8 +16,6 @@ set(CXX_FLAGS -Wwrite-strings -rdynamic -lpthread - -lglog - -L/usr/local/lib ) string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") From 742ca0a8914f5e929e67cbfb187c9d6d15a3b810 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 18 Mar 2010 16:20:34 +0000 Subject: [PATCH 025/371] Replace printf with logging. --- muduo/base/Logging.h | 4 ++-- muduo/net/Acceptor.cc | 6 ++++-- muduo/net/DefaultPoller.cc | 4 ++-- muduo/net/EventLoop.cc | 4 ++-- muduo/net/PollPoller.cc | 24 ++++++++++++++---------- muduo/net/PollPoller.h | 1 + muduo/net/Poller.cc | 12 ++++++++++++ muduo/net/Poller.h | 10 +++++++++- muduo/net/TcpConnection.cc | 8 ++++---- muduo/net/TcpConnection.h | 2 +- muduo/net/TimerQueue.cc | 16 +++++----------- muduo/net/tests/EchoServer_unittest.cc | 9 ++++----- 12 files changed, 60 insertions(+), 40 deletions(-) diff --git a/muduo/base/Logging.h b/muduo/base/Logging.h index dad7dbbc2..7bcdf6b83 100644 --- a/muduo/base/Logging.h +++ b/muduo/base/Logging.h @@ -34,8 +34,8 @@ class Logger boost::scoped_ptr impl_; }; -#define LOG_TRACE Logger(__FILE__, __LINE__, Logger::TRACE, __PRETTY_FUNCTION__).stream() -#define LOG_DEBUG Logger(__FILE__, __LINE__, Logger::DEBUG, __PRETTY_FUNCTION__).stream() +#define LOG_TRACE Logger(__FILE__, __LINE__, Logger::TRACE, __func__).stream() +#define LOG_DEBUG Logger(__FILE__, __LINE__, Logger::DEBUG, __func__).stream() #define LOG_INFO Logger(__FILE__, __LINE__).stream() #define LOG_WARN Logger(__FILE__, __LINE__, Logger::WARN).stream() #define LOG_ERROR Logger(__FILE__, __LINE__, Logger::ERROR).stream() diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index df223e2a9..c88652348 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -30,6 +30,7 @@ #include +#include #include #include #include @@ -66,11 +67,12 @@ void Acceptor::accept() { loop_->assertInLoopThread(); InetAddress peerAddr(0); + //FIXME loop until no more int connfd = acceptSocket_.accept(&peerAddr); if (connfd >= 0) { string hostport = peerAddr.toHostPort(); - printf("Connecting from %s\n", hostport.c_str()); + LOG_INFO << "Accepts of " << hostport; if (newConnectionCallback_) { newConnectionCallback_(connfd, peerAddr); @@ -82,7 +84,7 @@ void Acceptor::accept() } else { - //FIXME log error + LOG_SYSERR << "accept"; } } diff --git a/muduo/net/DefaultPoller.cc b/muduo/net/DefaultPoller.cc index 9ae6fb0d3..891bf0a9a 100644 --- a/muduo/net/DefaultPoller.cc +++ b/muduo/net/DefaultPoller.cc @@ -34,7 +34,7 @@ using namespace muduo::net; -Poller* Poller::newDefaultPoller() +Poller* Poller::newDefaultPoller(EventLoop* loop) { - return new PollPoller; + return new PollPoller(loop); } diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 52ad9bed1..1abd0552c 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -48,7 +48,7 @@ namespace { __thread EventLoop* t_loopInThisThread = 0; -const int kPollTimeMs = 10000; +const int kPollTimeMs = 60000; int createEventfd() { @@ -67,7 +67,7 @@ EventLoop::EventLoop() quit_(false), eventHandling_(false), threadId_(CurrentThread::tid()), - poller_(Poller::newDefaultPoller()), + poller_(Poller::newDefaultPoller(this)), timerQueue_(new TimerQueue(this)), wakeupFd_(createEventfd()), wakeupChannel_(new Channel(this, wakeupFd_)) diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index ac2cd1581..2470f1361 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -30,15 +30,20 @@ #include +#include #include #include #include -#include using namespace muduo; using namespace muduo::net; +PollPoller::PollPoller(EventLoop* loop) + : Poller(loop) +{ +} + PollPoller::~PollPoller() { } @@ -50,16 +55,16 @@ Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels) Timestamp now(Timestamp::now()); if (numEvents > 0) { + LOG_TRACE << numEvents << " events happended"; fillActiveChannels(numEvents, activeChannels); - printf("%d events\n", numEvents); } else if (numEvents == 0) { - printf("nothing\n"); + LOG_TRACE << " nothing happended"; } else { - perror("PollPoller::poll"); + LOG_SYSERR << "PollPoller::poll()"; } return now; } @@ -86,9 +91,8 @@ void PollPoller::fillActiveChannels(int numEvents, void PollPoller::updateChannel(Channel* channel) { - // assert(channel->getLoop() - //assert in loop thread - + Poller::assertInLoopThread(); + LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); if (channel->index() < 0) { // a new one, add to pollfds_ @@ -116,17 +120,17 @@ void PollPoller::updateChannel(Channel* channel) { // ignore this pollfd pfd.fd = -channel->fd()-1; - printf("set pfd.fd=-fd-1 for fd=%d\n", channel->fd()); } } } void PollPoller::removeChannel(Channel* channel) { - //assert in loop thread + Poller::assertInLoopThread(); + LOG_TRACE << "fd = " << channel->fd(); assert(channels_.find(channel->fd()) != channels_.end()); assert(channels_[channel->fd()] == channel); - // assert(channel->events() == Channel::kNoneEvent); + assert(channel->events() == Channel::kNoneEvent); int idx = channel->index(); assert(0 <= idx && idx < static_cast(pollfds_.size())); const struct pollfd& pfd = pollfds_[idx]; diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index 486c1086a..8b2a31d1c 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -54,6 +54,7 @@ class PollPoller : public Poller { public: + PollPoller(EventLoop* loop); virtual ~PollPoller(); virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels); diff --git a/muduo/net/Poller.cc b/muduo/net/Poller.cc index 97afc120d..dd4005350 100644 --- a/muduo/net/Poller.cc +++ b/muduo/net/Poller.cc @@ -29,10 +29,22 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include using namespace muduo; using namespace muduo::net; +Poller::Poller(EventLoop* loop) + : loop_(loop) +{ +} + Poller::~Poller() { } + +void Poller::assertInLoopThread() +{ + loop_->assertInLoopThread(); +} + diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index d5f05bf5a..eb51aa498 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -46,6 +46,7 @@ namespace net { class Channel; +class EventLoop; /// /// Base class for IO Multiplexing /// @@ -55,6 +56,7 @@ class Poller : boost::noncopyable public: typedef std::vector ChannelList; + Poller(EventLoop* loop); virtual ~Poller(); /// Polls the I/O events. @@ -69,7 +71,13 @@ class Poller : boost::noncopyable /// Must be called in the loop thread. virtual void removeChannel(Channel* channel) = 0; - static Poller* newDefaultPoller(); + static Poller* newDefaultPoller(EventLoop* loop); + + protected: + void assertInLoopThread(); + + private: + EventLoop* loop_; }; } diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index fd14f802a..afce55f1f 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -104,7 +104,7 @@ void TcpConnection::shutdown() { if (state_ == kConnected) { - state_ = kDisconnecting; + setState(kDisconnecting); sockets::shutdown(channel_->fd()); loop_->runInLoop(boost::bind(&TcpConnection::handleClose, this)); } @@ -113,7 +113,7 @@ void TcpConnection::shutdown() void TcpConnection::connectEstablished() { loop_->assertInLoopThread(); - state_ = kConnected; + setState(kConnected); channel_->tie(shared_from_this()); channel_->set_events(Channel::kReadEvent); loop_->updateChannel(get_pointer(channel_)); @@ -126,7 +126,7 @@ void TcpConnection::connectDestroyed() loop_->assertInLoopThread(); if (state_ == kConnected) { - state_ = kDisconnected; + setState(kDisconnected); sockets::shutdown(channel_->fd()); channel_->set_events(Channel::kNoneEvent); loop_->updateChannel(get_pointer(channel_)); @@ -175,7 +175,7 @@ void TcpConnection::handleClose() { loop_->assertInLoopThread(); // we don't close fd, leave it to dtor, so we can find leaks easily. - state_ = kDisconnected; + setState(kDisconnected); channel_->set_events(Channel::kNoneEvent); loop_->updateChannel(get_pointer(channel_)); diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index d2b49bd8b..ee341bcd3 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -77,7 +77,6 @@ class TcpConnection : public boost::enable_shared_from_this, const InetAddress& localAddress() { return localAddr_; } const InetAddress& peerAddress() { return peerAddr_; } bool connected() const { return state_ == kConnected; } - bool connecting() const { return state_ == kConnecting; } void send(const string& message); // void send(const ChannelBuffer& message); @@ -105,6 +104,7 @@ class TcpConnection : public boost::enable_shared_from_this, void handleClose(); void handleError(); void sendInLoop(const string& message); + void setState(States s) { state_ = s; } EventLoop* loop_; string name_; diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index 558e4508e..c190217bb 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -30,16 +30,13 @@ #include +#include #include #include #include #include -#define __STDC_FORMAT_MACROS -#include // FIXME remove -#undef __STDC_FORMAT_MACROS -#include // FIXME perror #include using namespace muduo; @@ -54,8 +51,7 @@ int createTimerfd() TFD_NONBLOCK | TFD_CLOEXEC); if (timerfd < 0) { - perror("Failed in timerfd_create"); - abort(); + LOG_SYSFATAL << "Failed in timerfd_create"; } return timerfd; } @@ -87,7 +83,7 @@ void resetTimerfd(int timerfd, Timestamp when) int ret = timerfd_settime(timerfd, 0, &newValue, &oldValue); if (ret) { - perror("Error in timerfd_settime"); + LOG_SYSERR << "timerfd_settime()"; } } @@ -124,12 +120,10 @@ void TimerQueue::timeout() Timestamp now(Timestamp::now()); uint64_t howmany; ssize_t n = ::read(timerfd_, &howmany, sizeof howmany); - printf("TimerQueue::timeout() timeout %" PRIu64 " at %s\n", - howmany, now.toString().c_str()); + LOG_DEBUG << "TimerQueue::timeout() " << howmany << " at " << now.toString(); if (n != sizeof howmany) { - fprintf(stderr, "TimerQueue::timeout() " - "reads %zd bytes instead of 8\n", n); + LOG_ERROR << "TimerQueue::timeout() reads " << n << " bytes instead of 8"; } TimerList expired; diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index d1f2e1d61..68eae6bd8 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -40,10 +40,9 @@ class EchoServer TcpConnectionPtr second; void onConnection(const TcpConnectionPtr& conn) { - printf("conn %s -> %s %s\n", - conn->peerAddress().toHostPort().c_str(), - conn->localAddress().toHostPort().c_str(), - conn->connected() ? "UP" : "DOWN"); + LOG_TRACE << conn->peerAddress().toHostPort() << " -> " + << conn->localAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); if (!first) first = conn; else if (!second) @@ -53,7 +52,7 @@ class EchoServer void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf, Timestamp time) { string msg(buf->retrieveAsString()); - printf("recv %zu bytes '%s'", msg.size(), msg.c_str()); + LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes"; if (msg == "exit\n") { first->shutdown(); From d35d0e6f7abf112c875c87edbed31368d6250160 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 19 Mar 2010 15:18:24 +0000 Subject: [PATCH 026/371] Update License. --- License | 21 ++++++++--------- muduo/net/Acceptor.cc | 30 +----------------------- muduo/net/Acceptor.h | 30 ------------------------ muduo/net/Callbacks.h | 30 ------------------------ muduo/net/Channel.cc | 30 +----------------------- muduo/net/Channel.h | 30 ------------------------ muduo/net/ChannelBuffer.cc | 30 ------------------------ muduo/net/ChannelBuffer.h | 30 ------------------------ muduo/net/DefaultPoller.cc | 30 +----------------------- muduo/net/EPollPoller.cc | 30 +----------------------- muduo/net/EPollPoller.h | 30 ------------------------ muduo/net/EventLoop.cc | 32 ++------------------------ muduo/net/EventLoop.h | 30 ------------------------ muduo/net/EventLoopPool.cc | 30 +----------------------- muduo/net/EventLoopPool.h | 30 ------------------------ muduo/net/InetAddress.cc | 30 +----------------------- muduo/net/InetAddress.h | 30 ------------------------ muduo/net/PollPoller.cc | 30 +----------------------- muduo/net/PollPoller.h | 30 ------------------------ muduo/net/Poller.cc | 30 +----------------------- muduo/net/Poller.h | 30 ------------------------ muduo/net/Socket.cc | 30 +----------------------- muduo/net/Socket.h | 30 ------------------------ muduo/net/SocketsOps.cc | 30 +----------------------- muduo/net/SocketsOps.h | 30 ------------------------ muduo/net/TcpConnection.cc | 30 +----------------------- muduo/net/TcpConnection.h | 32 +------------------------- muduo/net/TcpServer.cc | 30 +----------------------- muduo/net/TcpServer.h | 30 ------------------------ muduo/net/Timer.cc | 30 +----------------------- muduo/net/Timer.h | 30 ------------------------ muduo/net/TimerId.h | 30 ------------------------ muduo/net/TimerQueue.cc | 30 +----------------------- muduo/net/TimerQueue.h | 30 ------------------------ muduo/net/boilerplate.cc | 30 ------------------------ muduo/net/boilerplate.h | 30 ------------------------ muduo/net/tests/EchoServer_unittest.cc | 7 ++++-- 37 files changed, 32 insertions(+), 1050 deletions(-) diff --git a/License b/License index 6847f52e0..a2ff61865 100644 --- a/License +++ b/License @@ -1,20 +1,19 @@ -// Muduo - A lightwight C++ network library for Linux +// Muduo - A reactor-based C++ network library for Linux // Copyright (c) 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: +// modification, are permitted provided that the following conditions +// are met: // -// * Redistributions of source code must retain the above copyright +// * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * The name of the author may not be used to endorse or promote +// products derived from this software without specific prior written +// permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index c88652348..1ee48d356 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/Acceptor.h b/muduo/net/Acceptor.h index f341e8f6a..fdf7d1641 100644 --- a/muduo/net/Acceptor.h +++ b/muduo/net/Acceptor.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index 1e9df8f83..8545bbea1 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index beffdd1a9..4cf9c71c9 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index c4ef4bd23..d91af67b6 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/ChannelBuffer.cc b/muduo/net/ChannelBuffer.cc index 75f23805e..382515020 100644 --- a/muduo/net/ChannelBuffer.cc +++ b/muduo/net/ChannelBuffer.cc @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // diff --git a/muduo/net/ChannelBuffer.h b/muduo/net/ChannelBuffer.h index 78d6c8d4e..0298e94e2 100644 --- a/muduo/net/ChannelBuffer.h +++ b/muduo/net/ChannelBuffer.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/DefaultPoller.cc b/muduo/net/DefaultPoller.cc index 891bf0a9a..e06b046f4 100644 --- a/muduo/net/DefaultPoller.cc +++ b/muduo/net/DefaultPoller.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include #include diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc index 3628d3809..aca3ee418 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/EPollPoller.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/EPollPoller.h b/muduo/net/EPollPoller.h index 59de0b396..7edc3fa17 100644 --- a/muduo/net/EPollPoller.h +++ b/muduo/net/EPollPoller.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 1abd0552c..b2aa0e116 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include @@ -48,7 +20,7 @@ namespace { __thread EventLoop* t_loopInThisThread = 0; -const int kPollTimeMs = 60000; +const int kPollTimeMs = 10000; int createEventfd() { diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 5cd982da7..f207db4ac 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/EventLoopPool.cc b/muduo/net/EventLoopPool.cc index 43a1f6a71..d0f5ff766 100644 --- a/muduo/net/EventLoopPool.cc +++ b/muduo/net/EventLoopPool.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/EventLoopPool.h b/muduo/net/EventLoopPool.h index 86e2fa465..4dddc3c5f 100644 --- a/muduo/net/EventLoopPool.h +++ b/muduo/net/EventLoopPool.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/InetAddress.cc b/muduo/net/InetAddress.cc index 38f150159..2c9218206 100644 --- a/muduo/net/InetAddress.cc +++ b/muduo/net/InetAddress.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/InetAddress.h b/muduo/net/InetAddress.h index bdc99285e..73061d66c 100644 --- a/muduo/net/InetAddress.h +++ b/muduo/net/InetAddress.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index 2470f1361..ed63ed877 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index 8b2a31d1c..57f10a2b7 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/Poller.cc b/muduo/net/Poller.cc index dd4005350..ce09c912b 100644 --- a/muduo/net/Poller.cc +++ b/muduo/net/Poller.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include #include diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index eb51aa498..9d6a0deac 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/Socket.cc b/muduo/net/Socket.cc index eaa16d53c..05b8a5248 100644 --- a/muduo/net/Socket.cc +++ b/muduo/net/Socket.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/Socket.h b/muduo/net/Socket.h index 15d9c61ab..d7c5bdf7d 100644 --- a/muduo/net/Socket.h +++ b/muduo/net/Socket.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index 831c5b32b..aa42c53ce 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include #include diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h index 3077a17d6..c83dcff37 100644 --- a/muduo/net/SocketsOps.h +++ b/muduo/net/SocketsOps.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index afce55f1f..1607724bd 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index ee341bcd3..0f961744d 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. @@ -80,7 +50,7 @@ class TcpConnection : public boost::enable_shared_from_this, void send(const string& message); // void send(const ChannelBuffer& message); - void send(ChannelBuffer* message); // this one will retrieve data + void send(ChannelBuffer* message); // this one will swap data void shutdown(); void setConnectionCallback(ConnectionCallback cb) diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index f3198ee17..8f6f46a61 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index 4f0b6533c..98ffeef72 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/Timer.cc b/muduo/net/Timer.cc index e3ea1565d..72299b3f2 100644 --- a/muduo/net/Timer.cc +++ b/muduo/net/Timer.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/Timer.h b/muduo/net/Timer.h index cbe0d5f6d..3606aa55d 100644 --- a/muduo/net/Timer.h +++ b/muduo/net/Timer.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/TimerId.h b/muduo/net/TimerId.h index 0e8f2af9a..aabf9db01 100644 --- a/muduo/net/TimerId.h +++ b/muduo/net/TimerId.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index c190217bb..88ee610e8 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -1,32 +1,4 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index 6237ccb6d..df6de07ea 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/boilerplate.cc b/muduo/net/boilerplate.cc index 3d761a595..62ccbed54 100644 --- a/muduo/net/boilerplate.cc +++ b/muduo/net/boilerplate.cc @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // diff --git a/muduo/net/boilerplate.h b/muduo/net/boilerplate.h index 98da03554..213d31178 100644 --- a/muduo/net/boilerplate.h +++ b/muduo/net/boilerplate.h @@ -1,33 +1,3 @@ -// Muduo - A lightwight C++ network library for Linux -// Copyright (c) 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Muduo team nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 68eae6bd8..9a59f2aee 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -7,6 +7,7 @@ #include +#include #include #include @@ -55,9 +56,9 @@ class EchoServer LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes"; if (msg == "exit\n") { - first->shutdown(); + // first->shutdown(); first.reset(); - second->shutdown(); + // second->shutdown(); second.reset(); loop_->quit(); } @@ -93,7 +94,9 @@ void threadFunc(uint16_t port) int main(int argc, char* argv[]) { + mtrace(); LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + LOG_INFO << "sizeof TcpConnection = " << sizeof(TcpConnection); numThreads = argc - 1; EventLoop loop; InetAddress listenAddr(2000); From cb8bcffc0a9c3b3a54745f91aefff4aee119f84a Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Wed, 31 Mar 2010 14:57:19 +0000 Subject: [PATCH 027/371] Add Copyright. --- muduo/net/Acceptor.cc | 6 ++++++ muduo/net/Acceptor.h | 6 ++++++ muduo/net/Callbacks.h | 6 ++++++ muduo/net/Channel.cc | 6 ++++++ muduo/net/Channel.h | 6 ++++++ muduo/net/ChannelBuffer.cc | 6 ++++++ muduo/net/ChannelBuffer.h | 6 ++++++ muduo/net/DefaultPoller.cc | 6 ++++++ muduo/net/EPollPoller.cc | 6 ++++++ muduo/net/EPollPoller.h | 6 ++++++ muduo/net/EventLoop.cc | 6 ++++++ muduo/net/EventLoop.h | 6 ++++++ muduo/net/EventLoopPool.cc | 6 ++++++ muduo/net/EventLoopPool.h | 6 ++++++ muduo/net/InetAddress.cc | 6 ++++++ muduo/net/InetAddress.h | 6 ++++++ muduo/net/PollPoller.cc | 6 ++++++ muduo/net/PollPoller.h | 6 ++++++ muduo/net/Poller.cc | 6 ++++++ muduo/net/Poller.h | 6 ++++++ muduo/net/Socket.cc | 6 ++++++ muduo/net/Socket.h | 6 ++++++ muduo/net/SocketsOps.cc | 6 ++++++ muduo/net/SocketsOps.h | 6 ++++++ muduo/net/TcpConnection.cc | 6 ++++++ muduo/net/TcpConnection.h | 6 ++++++ muduo/net/TcpServer.cc | 6 ++++++ muduo/net/TcpServer.h | 6 ++++++ muduo/net/Timer.cc | 6 ++++++ muduo/net/Timer.h | 6 ++++++ muduo/net/TimerId.h | 6 ++++++ muduo/net/TimerQueue.cc | 6 ++++++ muduo/net/TimerQueue.h | 6 ++++++ muduo/net/boilerplate.cc | 6 ++++++ muduo/net/boilerplate.h | 6 ++++++ 35 files changed, 210 insertions(+) diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index 1ee48d356..e1029e445 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/Acceptor.h b/muduo/net/Acceptor.h index fdf7d1641..866e2b25d 100644 --- a/muduo/net/Acceptor.h +++ b/muduo/net/Acceptor.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index 8545bbea1..b8df847ca 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 4cf9c71c9..cfecc187d 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index d91af67b6..9f3a86c63 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/ChannelBuffer.cc b/muduo/net/ChannelBuffer.cc index 382515020..14eea3ac6 100644 --- a/muduo/net/ChannelBuffer.cc +++ b/muduo/net/ChannelBuffer.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // diff --git a/muduo/net/ChannelBuffer.h b/muduo/net/ChannelBuffer.h index 0298e94e2..58d4304aa 100644 --- a/muduo/net/ChannelBuffer.h +++ b/muduo/net/ChannelBuffer.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/DefaultPoller.cc b/muduo/net/DefaultPoller.cc index e06b046f4..7b8e21735 100644 --- a/muduo/net/DefaultPoller.cc +++ b/muduo/net/DefaultPoller.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc index aca3ee418..a11c6d8a8 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/EPollPoller.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/EPollPoller.h b/muduo/net/EPollPoller.h index 7edc3fa17..e184fa544 100644 --- a/muduo/net/EPollPoller.h +++ b/muduo/net/EPollPoller.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index b2aa0e116..2af970251 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index f207db4ac..fb64af125 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/EventLoopPool.cc b/muduo/net/EventLoopPool.cc index d0f5ff766..2d78abf85 100644 --- a/muduo/net/EventLoopPool.cc +++ b/muduo/net/EventLoopPool.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/EventLoopPool.h b/muduo/net/EventLoopPool.h index 4dddc3c5f..c83e3a373 100644 --- a/muduo/net/EventLoopPool.h +++ b/muduo/net/EventLoopPool.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/InetAddress.cc b/muduo/net/InetAddress.cc index 2c9218206..a3535a854 100644 --- a/muduo/net/InetAddress.cc +++ b/muduo/net/InetAddress.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/InetAddress.h b/muduo/net/InetAddress.h index 73061d66c..ccebb8286 100644 --- a/muduo/net/InetAddress.h +++ b/muduo/net/InetAddress.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/PollPoller.cc b/muduo/net/PollPoller.cc index ed63ed877..a5fac978b 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/PollPoller.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/PollPoller.h b/muduo/net/PollPoller.h index 57f10a2b7..3a0fad988 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/PollPoller.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/Poller.cc b/muduo/net/Poller.cc index ce09c912b..23ead15a9 100644 --- a/muduo/net/Poller.cc +++ b/muduo/net/Poller.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index 9d6a0deac..b05daa1bb 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/Socket.cc b/muduo/net/Socket.cc index 05b8a5248..b834a0448 100644 --- a/muduo/net/Socket.cc +++ b/muduo/net/Socket.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/Socket.h b/muduo/net/Socket.h index d7c5bdf7d..6396d719e 100644 --- a/muduo/net/Socket.h +++ b/muduo/net/Socket.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index aa42c53ce..b0aa320a6 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h index c83dcff37..c066f9927 100644 --- a/muduo/net/SocketsOps.h +++ b/muduo/net/SocketsOps.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 1607724bd..b726693a7 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index 0f961744d..516097ce8 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 8f6f46a61..89285df94 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index 98ffeef72..b71cbe80e 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/Timer.cc b/muduo/net/Timer.cc index 72299b3f2..843352f3f 100644 --- a/muduo/net/Timer.cc +++ b/muduo/net/Timer.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/Timer.h b/muduo/net/Timer.h index 3606aa55d..36a1fad5b 100644 --- a/muduo/net/Timer.h +++ b/muduo/net/Timer.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/TimerId.h b/muduo/net/TimerId.h index aabf9db01..e93c64c9b 100644 --- a/muduo/net/TimerId.h +++ b/muduo/net/TimerId.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index 88ee610e8..2ec723788 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) #include diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index df6de07ea..cc3cf4918 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. diff --git a/muduo/net/boilerplate.cc b/muduo/net/boilerplate.cc index 62ccbed54..417905e71 100644 --- a/muduo/net/boilerplate.cc +++ b/muduo/net/boilerplate.cc @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // diff --git a/muduo/net/boilerplate.h b/muduo/net/boilerplate.h index 213d31178..f75ad50d3 100644 --- a/muduo/net/boilerplate.h +++ b/muduo/net/boilerplate.h @@ -1,3 +1,9 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. From 59692abeb3c9f997b4e57e7b86e4f0bb2c9f5ca1 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 2 Apr 2010 02:37:41 +0000 Subject: [PATCH 028/371] Safe close tcp connection. --- build.sh | 2 +- muduo/net/Channel.h | 4 ++-- muduo/net/EventLoop.cc | 4 +++- muduo/net/SocketsOps.cc | 4 ++-- muduo/net/SocketsOps.h | 2 +- muduo/net/TcpConnection.cc | 29 ++++++++++++++++++++++---- muduo/net/TcpConnection.h | 3 ++- muduo/net/TcpServer.cc | 2 ++ muduo/net/tests/EchoServer_unittest.cc | 15 +++++++++++++ 9 files changed, 53 insertions(+), 12 deletions(-) diff --git a/build.sh b/build.sh index 97478709d..c30e4ba0b 100755 --- a/build.sh +++ b/build.sh @@ -4,7 +4,7 @@ set -x SOURCE_DIR=`pwd` BUILD_DIR=${BUILD_DIR:-../build} -BUILD_TYPE=${BUILD_TYPE:-Debug} +BUILD_TYPE=${BUILD_TYPE:-debug} mkdir -p $BUILD_DIR/$BUILD_TYPE \ && cd $BUILD_DIR/$BUILD_TYPE \ diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 9f3a86c63..01975f71d 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -58,8 +58,8 @@ class Channel : boost::noncopyable /// prevent the owner object being destroyed in handleEvent. void tie(const boost::shared_ptr&); - int fd() { return fd_; } - int events() { return events_; } + int fd() const { return fd_; } + int events() const { return events_; } void set_events(int evt) { events_ = evt; } void set_revents(int revt) { revents_ = revt; } diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 2af970251..f8873c3be 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -79,6 +79,7 @@ void EventLoop::loop() assert(!looping_); assertInLoopThread(); looping_ = true; + LOG_TRACE << "EventLoop " << this << " start looping"; while (!quit_) { activeChannels_.clear(); @@ -93,13 +94,14 @@ void EventLoop::loop() eventHandling_ = false; doPendingFunctors(); } + LOG_TRACE << "EventLoop " << this << " stop looping"; looping_ = false; } void EventLoop::quit() { quit_ = true; - if (threadId_ == CurrentThread::tid()) + if (threadId_ != CurrentThread::tid()) { wakeup(); } diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index b0aa320a6..5bc8f98a5 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -119,9 +119,9 @@ void sockets::close(int sockfd) // FIXME EINTR } -void sockets::shutdown(int sockfd) +void sockets::shutdownWrite(int sockfd) { - ::shutdown(sockfd, SHUT_RDWR); + ::shutdown(sockfd, SHUT_WR); // FIXME EINTR } diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h index c066f9927..8ec6104ed 100644 --- a/muduo/net/SocketsOps.h +++ b/muduo/net/SocketsOps.h @@ -53,7 +53,7 @@ void bindOrDie(int sockfd, const struct sockaddr_in& addr); void listenOrDie(int sockfd); int accept(int sockfd, struct sockaddr_in* addr); void close(int sockfd); -void shutdown(int sockfd); +void shutdownWrite(int sockfd); void toHostPort(char* buf, size_t size, const struct sockaddr_in& addr); diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index b726693a7..904e8aaf9 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -15,6 +16,7 @@ #include +#include #include using namespace muduo; @@ -71,6 +73,7 @@ void TcpConnection::sendInLoop(const string& message) { loop_->assertInLoopThread(); outputBuffer_.append(message.data(), message.size()); + // enableWriting if ((channel_->events() & Channel::kWriteEvent) == 0) { channel_->set_events(Channel::kReadEvent | Channel::kWriteEvent); @@ -83,8 +86,18 @@ void TcpConnection::shutdown() if (state_ == kConnected) { setState(kDisconnecting); - sockets::shutdown(channel_->fd()); - loop_->runInLoop(boost::bind(&TcpConnection::handleClose, this)); + loop_->runInLoop( + boost::bind(&TcpConnection::shutdownInLoop, this)); + } +} + +void TcpConnection::shutdownInLoop() +{ + loop_->assertInLoopThread(); + if ((channel_->events() & Channel::kWriteEvent) == 0) + { + // we are not writing + sockets::shutdownWrite(channel_->fd()); } } @@ -105,7 +118,7 @@ void TcpConnection::connectDestroyed() if (state_ == kConnected) { setState(kDisconnected); - sockets::shutdown(channel_->fd()); + //sockets::shutdown(channel_->fd()); channel_->set_events(Channel::kNoneEvent); loop_->updateChannel(get_pointer(channel_)); connectionCallback_(shared_from_this()); @@ -137,7 +150,7 @@ void TcpConnection::handleWrite() loop_->assertInLoopThread(); ssize_t n = ::write(channel_->fd(), outputBuffer_.peek(), outputBuffer_.readableBytes()); - //int savedErrno = errno; + int savedErrno = errno; if (n > 0) { outputBuffer_.retrieve(n); @@ -145,8 +158,16 @@ void TcpConnection::handleWrite() { channel_->set_events(Channel::kReadEvent); loop_->updateChannel(get_pointer(channel_)); + if (state_ == kDisconnecting) + { + shutdownInLoop(); + } } } + else + { + LOG_SYSERR << "TcpConnection::handleWrite"; + } } void TcpConnection::handleClose() diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index 516097ce8..5e3262b6a 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -57,7 +57,7 @@ class TcpConnection : public boost::enable_shared_from_this, void send(const string& message); // void send(const ChannelBuffer& message); void send(ChannelBuffer* message); // this one will swap data - void shutdown(); + void shutdown(); // not thread safe, no simultaneous calling void setConnectionCallback(ConnectionCallback cb) { connectionCallback_ = cb; } @@ -80,6 +80,7 @@ class TcpConnection : public boost::enable_shared_from_this, void handleClose(); void handleError(); void sendInLoop(const string& message); + void shutdownInLoop(); void setState(States s) { state_ = s; } EventLoop* loop_; diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 89285df94..fdad6763d 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -35,6 +36,7 @@ TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr) TcpServer::~TcpServer() { loop_->assertInLoopThread(); + LOG_TRACE << "TcpServer::~TcpServer " << this << " destructing"; for (ConnectionMap::iterator it(connections_.begin()); it != connections_.end(); ++it) diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 9a59f2aee..e75683029 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -44,10 +44,20 @@ class EchoServer LOG_TRACE << conn->peerAddress().toHostPort() << " -> " << conn->localAddress().toHostPort() << " is " << (conn->connected() ? "UP" : "DOWN"); + if (conn->connected()) + { if (!first) first = conn; else if (!second) second = conn; + } + else + { + if (first == conn) + first.reset(); + else if (second == conn) + second.reset(); + } } void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf, Timestamp time) @@ -55,6 +65,11 @@ class EchoServer string msg(buf->retrieveAsString()); LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes"; if (msg == "exit\n") + { + conn->send("bye\n"); + conn->shutdown(); + } + if (msg == "quit\n") { // first->shutdown(); first.reset(); From e4bb7ce56722dd9d28b112e02643fbb5af2f9efc Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 2 Apr 2010 02:57:17 +0000 Subject: [PATCH 029/371] Add comment for future improvement. --- muduo/net/TcpConnection.cc | 16 ++++------------ muduo/net/TcpConnection.h | 1 + 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 904e8aaf9..79986cd9d 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -29,7 +29,7 @@ TcpConnection::TcpConnection(EventLoop* loop, const InetAddress& peerAddr) : loop_(loop), name_(name__), - state_(kDisconnected), + state_(kConnecting), socket_(new Socket(fd)), channel_(new Channel(loop, fd)), localAddr_(localAddr), @@ -57,15 +57,7 @@ void TcpConnection::send(const string& message) { loop_->runInLoop( boost::bind(&TcpConnection::sendInLoop, this, message)); - /* - { - MutexLockGuard lock(mutex_); - outputBuffer_.append(message.data(), message.size()); - } - channel_->set_events(Channel::kReadEvent | Channel::kWriteEvent); - loop_->runInLoop( - boost::bind(&EventLoop::updateChannel, loop_, get_pointer(channel_))); - */ + // FIXME: as an optimization, send message here } } @@ -86,8 +78,7 @@ void TcpConnection::shutdown() if (state_ == kConnected) { setState(kDisconnecting); - loop_->runInLoop( - boost::bind(&TcpConnection::shutdownInLoop, this)); + loop_->runInLoop(boost::bind(&TcpConnection::shutdownInLoop, this)); } } @@ -104,6 +95,7 @@ void TcpConnection::shutdownInLoop() void TcpConnection::connectEstablished() { loop_->assertInLoopThread(); + assert(state_ == kConnecting); setState(kConnected); channel_->tie(shared_from_this()); channel_->set_events(Channel::kReadEvent); diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index 5e3262b6a..15376cf8a 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -71,6 +71,7 @@ class TcpConnection : public boost::enable_shared_from_this, // called when TcpServer accepts a new connection void connectEstablished(); + // called when TcpServer has removed me from its map void connectDestroyed(); private: From 00938cc0b2085f9fb6cd715963a187936eaaebf3 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 2 Apr 2010 16:42:19 +0000 Subject: [PATCH 030/371] Use rvalue reference. --- CMakeLists.txt | 3 +- muduo/base/Types.h | 9 +++- muduo/net/Acceptor.cc | 3 +- muduo/net/Channel.cc | 7 +++- muduo/net/Channel.h | 17 +++++--- muduo/net/ChannelBuffer.cc | 1 + muduo/net/EventLoop.cc | 7 ++-- muduo/net/EventLoop.h | 3 +- muduo/net/TcpConnection.cc | 58 ++++++++++++++------------ muduo/net/TcpConnection.h | 12 +++--- muduo/net/TimerQueue.cc | 3 +- muduo/net/tests/EchoServer_unittest.cc | 46 +++----------------- 12 files changed, 79 insertions(+), 90 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 818c3a525..66711659e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,10 +10,11 @@ set(CXX_FLAGS -Wconversion -Wunused-parameter -Wold-style-cast - -MMD -Wpointer-arith -Wshadow -Wwrite-strings + -MMD + -std=c++0x -rdynamic -lpthread ) diff --git a/muduo/base/Types.h b/muduo/base/Types.h index d3b766855..bb378de43 100644 --- a/muduo/base/Types.h +++ b/muduo/base/Types.h @@ -2,8 +2,12 @@ #define MUDUO_BASE_TYPES_H #include +#ifdef MUDUO_STD_STRING +#include +#else // !MUDUO_STD_STRING #include #include +#endif /// /// The most common stuffs. @@ -11,9 +15,12 @@ namespace muduo { +#ifdef MUDUO_STD_STRING +using std::string; +#else // !MUDUO_STD_STRING // typedef __gnu_cxx::__versa_string, std::allocator > string; typedef __gnu_cxx::__sso_string string; - +#endif // Taken from google-protobuf stubs/common.h // // Use implicit_cast as a safe version of static_cast or const_cast diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index e1029e445..86846a773 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -37,8 +37,7 @@ void Acceptor::listen() loop_->assertInLoopThread(); listenning_ = true; acceptSocket_.listen(); - acceptChannel_.set_events(Channel::kReadEvent); - loop_->updateChannel(&acceptChannel_); + acceptChannel_.enableReading(); } void Acceptor::accept() diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index cfecc187d..8428ad547 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -7,9 +7,9 @@ // Author: Shuo Chen (chenshuo at chenshuo dot com) #include +#include #include -#include // FIXME using namespace muduo; using namespace muduo::net; @@ -38,6 +38,11 @@ void Channel::tie(const boost::shared_ptr& obj) tied_ = true; } +void Channel::update() +{ + loop_->updateChannel(this); +} + void Channel::handleEvent(Timestamp receiveTime) { boost::shared_ptr guard; diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 01975f71d..c4ef21d83 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -37,9 +37,6 @@ class Channel : boost::noncopyable typedef boost::function EventCallback; typedef boost::function ReadEventCallback; static const int kNoneEvent; - static const int kReadEvent; - static const int kWriteEvent; - // static const int kErrorvent; Channel(EventLoop* loop, int fd); ~Channel(); @@ -60,19 +57,27 @@ class Channel : boost::noncopyable int fd() const { return fd_; } int events() const { return events_; } - void set_events(int evt) { events_ = evt; } void set_revents(int revt) { revents_ = revt; } + void enableReading() { events_ |= kReadEvent; update(); } + void enableWriting() { events_ |= kWriteEvent; update(); } + void disableWriting() { events_ &= ~kWriteEvent; update(); } + void disableAll() { events_ = kNoneEvent; update(); } + bool isWriting() const { return events_ & kWriteEvent; } + + // for PollPoller int index() { return index_; } void set_index(int idx) { index_ = idx; } EventLoop* getLoop() { return loop_; } - // void set_loop(EventLoop* loop) { loop_ = loop; } - private: + void update(); void handleEventWithGuard(Timestamp receiveTime); + static const int kReadEvent; + static const int kWriteEvent; + EventLoop* loop_; const int fd_; int events_; diff --git a/muduo/net/ChannelBuffer.cc b/muduo/net/ChannelBuffer.cc index 14eea3ac6..445065285 100644 --- a/muduo/net/ChannelBuffer.cc +++ b/muduo/net/ChannelBuffer.cc @@ -19,6 +19,7 @@ using namespace muduo::net; ssize_t ChannelBuffer::readFd(int fd, int* savedErrno) { + // FIXME use ioctl/FIONREAD to tell how much to read char extrabuf[65536]; struct iovec vec[2]; size_t writable = writableBytes(); diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index f8873c3be..8349a5b81 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -64,8 +64,7 @@ EventLoop::EventLoop() wakeupChannel_->setReadCallback( boost::bind(&EventLoop::wakedup, this)); // we are always reading the wakeupfd - wakeupChannel_->set_events(Channel::kReadEvent); - updateChannel(get_pointer(wakeupChannel_)); + wakeupChannel_->enableReading(); } EventLoop::~EventLoop() @@ -83,13 +82,13 @@ void EventLoop::loop() while (!quit_) { activeChannels_.clear(); - Timestamp receiveTime = poller_->poll(kPollTimeMs, &activeChannels_); + happenTime_ = poller_->poll(kPollTimeMs, &activeChannels_); // TODO sort channel by priority eventHandling_ = true; for (ChannelList::iterator it = activeChannels_.begin(); it != activeChannels_.end(); ++it) { - (*it)->handleEvent(receiveTime); + (*it)->handleEvent(happenTime_); } eventHandling_ = false; doPendingFunctors(); diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index fb64af125..c317f074a 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -92,7 +92,8 @@ class EventLoop : boost::noncopyable bool looping_; /* atomic */ bool quit_; /* atomic */ - bool eventHandling_; + bool eventHandling_; /* atomic */ + Timestamp happenTime_; const pid_t threadId_; boost::scoped_ptr poller_; boost::scoped_ptr timerQueue_; diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 79986cd9d..8ed524ab8 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -51,25 +51,26 @@ TcpConnection::~TcpConnection() printf("%p %s dtor\n", this, name_.c_str()); } -void TcpConnection::send(const string& message) +void TcpConnection::send(string&& message) { if (state_ == kConnected) { loop_->runInLoop( - boost::bind(&TcpConnection::sendInLoop, this, message)); + boost::bind(&TcpConnection::sendInLoop, + this, + std::forward(message))); // FIXME: as an optimization, send message here } } -void TcpConnection::sendInLoop(const string& message) +void TcpConnection::sendInLoop(string&& message) { loop_->assertInLoopThread(); + // FIXME: try writing here, until EWOULDBLOCK outputBuffer_.append(message.data(), message.size()); - // enableWriting - if ((channel_->events() & Channel::kWriteEvent) == 0) + if (!channel_->isWriting()) { - channel_->set_events(Channel::kReadEvent | Channel::kWriteEvent); - loop_->updateChannel(get_pointer(channel_)); + channel_->enableWriting(); } } @@ -85,7 +86,7 @@ void TcpConnection::shutdown() void TcpConnection::shutdownInLoop() { loop_->assertInLoopThread(); - if ((channel_->events() & Channel::kWriteEvent) == 0) + if (!channel_->isWriting()) { // we are not writing sockets::shutdownWrite(channel_->fd()); @@ -98,8 +99,7 @@ void TcpConnection::connectEstablished() assert(state_ == kConnecting); setState(kConnected); channel_->tie(shared_from_this()); - channel_->set_events(Channel::kReadEvent); - loop_->updateChannel(get_pointer(channel_)); + channel_->enableReading(); connectionCallback_(shared_from_this()); } @@ -110,9 +110,8 @@ void TcpConnection::connectDestroyed() if (state_ == kConnected) { setState(kDisconnected); - //sockets::shutdown(channel_->fd()); - channel_->set_events(Channel::kNoneEvent); - loop_->updateChannel(get_pointer(channel_)); + channel_->disableAll(); + connectionCallback_(shared_from_this()); } loop_->removeChannel(get_pointer(channel_)); @@ -140,25 +139,33 @@ void TcpConnection::handleRead(Timestamp receiveTime) void TcpConnection::handleWrite() { loop_->assertInLoopThread(); - - ssize_t n = ::write(channel_->fd(), outputBuffer_.peek(), outputBuffer_.readableBytes()); - int savedErrno = errno; - if (n > 0) + if (channel_->isWriting()) { - outputBuffer_.retrieve(n); - if (outputBuffer_.readableBytes() == 0) + ssize_t n = ::write(channel_->fd(), outputBuffer_.peek(), outputBuffer_.readableBytes()); + if (n > 0) { - channel_->set_events(Channel::kReadEvent); - loop_->updateChannel(get_pointer(channel_)); - if (state_ == kDisconnecting) + outputBuffer_.retrieve(n); + if (outputBuffer_.readableBytes() == 0) { - shutdownInLoop(); + channel_->disableWriting(); + if (state_ == kDisconnecting) + { + shutdownInLoop(); + } } + else + { + LOG_TRACE << "I am going to write more data"; + } + } + else + { + LOG_SYSERR << "TcpConnection::handleWrite"; } } else { - LOG_SYSERR << "TcpConnection::handleWrite"; + LOG_TRACE << "Connection is down, no more writing"; } } @@ -167,8 +174,7 @@ void TcpConnection::handleClose() loop_->assertInLoopThread(); // we don't close fd, leave it to dtor, so we can find leaks easily. setState(kDisconnected); - channel_->set_events(Channel::kNoneEvent); - loop_->updateChannel(get_pointer(channel_)); + channel_->disableAll(); TcpConnectionPtr guardThis(shared_from_this()); connectionCallback_(guardThis); diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index 15376cf8a..703e169e7 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -54,10 +54,10 @@ class TcpConnection : public boost::enable_shared_from_this, const InetAddress& peerAddress() { return peerAddr_; } bool connected() const { return state_ == kConnected; } - void send(const string& message); + void send(string&& message); // void send(const ChannelBuffer& message); void send(ChannelBuffer* message); // this one will swap data - void shutdown(); // not thread safe, no simultaneous calling + void shutdown(); // NOT thread safe, no simultaneous calling void setConnectionCallback(ConnectionCallback cb) { connectionCallback_ = cb; } @@ -70,9 +70,9 @@ class TcpConnection : public boost::enable_shared_from_this, { closeCallback_ = cb; } // called when TcpServer accepts a new connection - void connectEstablished(); + void connectEstablished(); // should be called only once // called when TcpServer has removed me from its map - void connectDestroyed(); + void connectDestroyed(); // should be called only once private: enum States { kDisconnected, kConnecting, kConnected, kDisconnecting }; @@ -80,13 +80,13 @@ class TcpConnection : public boost::enable_shared_from_this, void handleWrite(); void handleClose(); void handleError(); - void sendInLoop(const string& message); + void sendInLoop(string&& message); void shutdownInLoop(); void setState(States s) { state_ = s; } EventLoop* loop_; string name_; - States state_; + States state_; // FIXME: use atomic variable // we don't expose those classes to client. boost::scoped_ptr socket_; boost::scoped_ptr channel_; diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index 2ec723788..bbac8a054 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -76,8 +76,7 @@ TimerQueue::TimerQueue(EventLoop* loop) timerfdChannel_.setReadCallback( boost::bind(&TimerQueue::timeout, this)); // we are always reading the timerfd, we disarm it with timerfd_settime. - timerfdChannel_.set_events(Channel::kReadEvent); - loop_->updateChannel(&timerfdChannel_); + timerfdChannel_.enableReading(); } TimerQueue::~TimerQueue() diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index e75683029..defadf0d1 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -7,6 +7,8 @@ #include +#include + #include #include #include @@ -37,27 +39,13 @@ class EchoServer // void stop(); private: - TcpConnectionPtr first; - TcpConnectionPtr second; void onConnection(const TcpConnectionPtr& conn) { LOG_TRACE << conn->peerAddress().toHostPort() << " -> " << conn->localAddress().toHostPort() << " is " << (conn->connected() ? "UP" : "DOWN"); - if (conn->connected()) - { - if (!first) - first = conn; - else if (!second) - second = conn; - } - else - { - if (first == conn) - first.reset(); - else if (second == conn) - second.reset(); - } + + conn->send("hello\n"); } void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf, Timestamp time) @@ -71,32 +59,10 @@ class EchoServer } if (msg == "quit\n") { - // first->shutdown(); - first.reset(); - // second->shutdown(); - second.reset(); loop_->quit(); } - if (conn != first && first) - first->send(msg); - if (conn != second && second) - second->send(msg); - // conn->send(buf); - // conn->shutdown(); - // loop_->quit(); - /* - if (conn == second) - { - sleep(10); - } - if (second && conn == first) - { - second->shutdown(); - second.reset(); - first.reset(); - // loop_->quit(); - } - */ + sleep(2); + conn->send(std::move(msg)); } EventLoop* loop_; From 6c8d441e07daeecdcf3ae9688db049c6df55a2b0 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 3 Apr 2010 01:35:59 +0000 Subject: [PATCH 031/371] No C++0x. --- CMakeLists.txt | 2 +- muduo/net/Channel.cc | 5 +++-- muduo/net/TcpConnection.cc | 7 ++++--- muduo/net/TcpConnection.h | 6 ++++-- muduo/net/tests/EchoServer_unittest.cc | 2 +- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66711659e..0a4fc3320 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ set(CXX_FLAGS -Wshadow -Wwrite-strings -MMD - -std=c++0x + # -std=c++0x -rdynamic -lpthread ) diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 8428ad547..28028e98d 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -6,6 +6,7 @@ // Author: Shuo Chen (chenshuo at chenshuo dot com) +#include #include #include @@ -64,13 +65,13 @@ void Channel::handleEventWithGuard(Timestamp receiveTime) { if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) { - printf("Channel::handle_event() POLLHUP"); + LOG_WARN << "Channel::handle_event() POLLHUP"; if (closeCallback_) closeCallback_(); } if (revents_ & POLLNVAL) { - printf("Channel::handle_event() POLLNVAL"); + LOG_WARN << "Channel::handle_event() POLLNVAL"; } if (revents_ & (POLLERR | POLLNVAL)) diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 8ed524ab8..f7ed86ffd 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -51,19 +51,20 @@ TcpConnection::~TcpConnection() printf("%p %s dtor\n", this, name_.c_str()); } -void TcpConnection::send(string&& message) +void TcpConnection::send(const string& message) { if (state_ == kConnected) { loop_->runInLoop( boost::bind(&TcpConnection::sendInLoop, this, - std::forward(message))); + message)); + //std::forward(message))); // FIXME: as an optimization, send message here } } -void TcpConnection::sendInLoop(string&& message) +void TcpConnection::sendInLoop(const string& message) { loop_->assertInLoopThread(); // FIXME: try writing here, until EWOULDBLOCK diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index 703e169e7..834d7360a 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -54,7 +54,8 @@ class TcpConnection : public boost::enable_shared_from_this, const InetAddress& peerAddress() { return peerAddr_; } bool connected() const { return state_ == kConnected; } - void send(string&& message); + // void send(string&& message); + void send(const string& message); // void send(const ChannelBuffer& message); void send(ChannelBuffer* message); // this one will swap data void shutdown(); // NOT thread safe, no simultaneous calling @@ -80,7 +81,8 @@ class TcpConnection : public boost::enable_shared_from_this, void handleWrite(); void handleClose(); void handleError(); - void sendInLoop(string&& message); + //void sendInLoop(string&& message); + void sendInLoop(const string& message); void shutdownInLoop(); void setState(States s) { state_ = s; } diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index defadf0d1..e24f4242a 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -62,7 +62,7 @@ class EchoServer loop_->quit(); } sleep(2); - conn->send(std::move(msg)); + conn->send(msg); } EventLoop* loop_; From d211a57475b81f750b51340b6e6e122eb70256bd Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 3 Apr 2010 01:37:42 +0000 Subject: [PATCH 032/371] Add TcpClient. --- muduo/base/Types.h | 2 +- muduo/net/CMakeLists.txt | 1 + muduo/net/EventLoop.cc | 9 ++++----- muduo/net/EventLoop.h | 11 ++++++++++- muduo/net/TcpClient.cc | 15 +++++++++++++++ muduo/net/TcpClient.h | 31 +++++++++++++++++++++++++++++++ muduo/net/TcpConnection.cc | 16 +++++++++++----- 7 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 muduo/net/TcpClient.cc create mode 100644 muduo/net/TcpClient.h diff --git a/muduo/base/Types.h b/muduo/base/Types.h index bb378de43..28c816986 100644 --- a/muduo/base/Types.h +++ b/muduo/base/Types.h @@ -18,9 +18,9 @@ namespace muduo #ifdef MUDUO_STD_STRING using std::string; #else // !MUDUO_STD_STRING -// typedef __gnu_cxx::__versa_string, std::allocator > string; typedef __gnu_cxx::__sso_string string; #endif + // Taken from google-protobuf stubs/common.h // // Use implicit_cast as a safe version of static_cast or const_cast diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 6d0fa7dd2..06080f3ea 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -11,6 +11,7 @@ set(net_SRCS PollPoller.cc Socket.cc SocketsOps.cc + TcpClient.cc TcpConnection.cc TcpServer.cc Timer.cc diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 8349a5b81..d582581f0 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -100,7 +99,7 @@ void EventLoop::loop() void EventLoop::quit() { quit_ = true; - if (threadId_ != CurrentThread::tid()) + if (!isInLoopThread()) { wakeup(); } @@ -118,7 +117,7 @@ void EventLoop::wakeup() void EventLoop::runInLoop(const Functor& cb) { - if (threadId_ == CurrentThread::tid()) + if (isInLoopThread()) { cb(); } @@ -166,9 +165,9 @@ void EventLoop::removeChannel(Channel* channel) poller_->removeChannel(channel); } -void EventLoop::assertInLoopThread() +void EventLoop::abortNotInLoopThread() { - assert(threadId_ == CurrentThread::tid()); + LOG_FATAL << "threadId_=" << threadId_; } void EventLoop::wakedup() diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index c317f074a..006b9a556 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -82,9 +83,17 @@ class EventLoop : boost::noncopyable void removeChannel(Channel* channel); pid_t threadId() { return threadId_; } - void assertInLoopThread(); + void assertInLoopThread() + { + if (!isInLoopThread()) + { + abortNotInLoopThread(); + } + } + bool isInLoopThread() { return threadId_ == CurrentThread::tid(); } private: + void abortNotInLoopThread(); void wakedup(); void doPendingFunctors(); diff --git a/muduo/net/TcpClient.cc b/muduo/net/TcpClient.cc new file mode 100644 index 000000000..6b16b7df8 --- /dev/null +++ b/muduo/net/TcpClient.cc @@ -0,0 +1,15 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include + +using namespace muduo; +using namespace muduo::net; + + diff --git a/muduo/net/TcpClient.h b/muduo/net/TcpClient.h new file mode 100644 index 000000000..4f7d1ce1b --- /dev/null +++ b/muduo/net/TcpClient.h @@ -0,0 +1,31 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TCPCLIENT_H +#define MUDUO_NET_TCPCLIENT_H + +#include + +namespace muduo +{ +namespace net +{ + +class TcpClient : boost::noncopyable +{ + public: + + private: +}; + +} +} + +#endif // MUDUO_NET_TCPCLIENT_H diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index f7ed86ffd..4e6662ea6 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -55,12 +55,18 @@ void TcpConnection::send(const string& message) { if (state_ == kConnected) { - loop_->runInLoop( - boost::bind(&TcpConnection::sendInLoop, - this, - message)); + if (loop_->isInLoopThread()) + { + sendInLoop(message); + } + else + { + loop_->runInLoop( + boost::bind(&TcpConnection::sendInLoop, + this, + message)); //std::forward(message))); - // FIXME: as an optimization, send message here + } } } From 6ae53c2ff2b7c5585a62a7e66de213fcead45d1a Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 9 Apr 2010 17:49:27 +0000 Subject: [PATCH 033/371] Add Connector. --- ChangeLog | 4 ++ muduo/net/CMakeLists.txt | 1 + muduo/net/Connector.cc | 15 +++++ muduo/net/Connector.h | 31 +++++++++ muduo/net/InetAddress.cc | 5 ++ muduo/net/InetAddress.h | 2 +- muduo/net/SocketsOps.cc | 11 ++-- muduo/net/TcpClient.cc | 20 ++++++ muduo/net/TcpClient.h | 27 ++++++++ muduo/net/TcpServer.h | 1 - muduo/net/tests/CMakeLists.txt | 3 + muduo/net/tests/EchoClient_unittest.cc | 89 ++++++++++++++++++++++++++ 12 files changed, 203 insertions(+), 6 deletions(-) create mode 100644 muduo/net/Connector.cc create mode 100644 muduo/net/Connector.h create mode 100644 muduo/net/tests/EchoClient_unittest.cc diff --git a/ChangeLog b/ChangeLog index 7ce60b924..064f96a45 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ * First alpha release, version 0.1.0 +2010-04-03 Shuo Chen + + * TcpServer works. + 2010-03-15 Shuo Chen * TcpConnection at server side works. diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 06080f3ea..b3f704723 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -2,6 +2,7 @@ set(net_SRCS Acceptor.cc Channel.cc ChannelBuffer.cc + Connector.cc DefaultPoller.cc EPollPoller.cc EventLoop.cc diff --git a/muduo/net/Connector.cc b/muduo/net/Connector.cc new file mode 100644 index 000000000..239a1c9b8 --- /dev/null +++ b/muduo/net/Connector.cc @@ -0,0 +1,15 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include + +using namespace muduo; +using namespace muduo::net; + + diff --git a/muduo/net/Connector.h b/muduo/net/Connector.h new file mode 100644 index 000000000..82a5c2146 --- /dev/null +++ b/muduo/net/Connector.h @@ -0,0 +1,31 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_CONNECTOR_H +#define MUDUO_NET_CONNECTOR_H + +#include + +namespace muduo +{ +namespace net +{ + +class Connector : boost::noncopyable +{ + public: + + private: +}; + +} +} + +#endif // MUDUO_NET_CONNECTOR_H diff --git a/muduo/net/InetAddress.cc b/muduo/net/InetAddress.cc index a3535a854..e6b870a6f 100644 --- a/muduo/net/InetAddress.cc +++ b/muduo/net/InetAddress.cc @@ -46,6 +46,11 @@ InetAddress::InetAddress(uint16_t port) addr_.sin_port = sockets::hostToNetwork16(port); } +InetAddress::InetAddress(const string& host, uint16_t port) +{ + bzero(&addr_, sizeof addr_); +} + string InetAddress::toHostPort() const { char buf[32]; diff --git a/muduo/net/InetAddress.h b/muduo/net/InetAddress.h index ccebb8286..5e4588dd9 100644 --- a/muduo/net/InetAddress.h +++ b/muduo/net/InetAddress.h @@ -34,7 +34,7 @@ class InetAddress : public muduo::copyable /// Constructs an endpoint with given host and port. /// @c host could either be "1.2.3.4" or "example.com" - InetAddress(string host, uint16_t port); + InetAddress(const string& host, uint16_t port); /// Constructs an endpoint with given struct @c sockaddr_in /// Mostly used when accepting new connections diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index 5bc8f98a5..82e84aa24 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -34,7 +34,7 @@ SA* sockaddr_cast(struct sockaddr_in* addr) int sockets::createNonblockingOrDie() { // socket - int sockfd = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // FIXME check // non-block @@ -75,9 +75,12 @@ void sockets::listenOrDie(int sockfd) int sockets::accept(int sockfd, struct sockaddr_in* addr) { socklen_t addrlen = sizeof *addr; +#if VALGRIND int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); - // int connfd = ::accept4(sockfd, sockaddr_cast(addr), - // &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); +#else + int connfd = ::accept4(sockfd, sockaddr_cast(addr), + &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); +#endif if (connfd == -1) { int savedErrno = errno; @@ -129,7 +132,7 @@ void sockets::toHostPort(char* buf, size_t size, const struct sockaddr_in& addr) { char host[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); + ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); uint16_t port = sockets::networkToHost16(addr.sin_port); snprintf(buf, size, "%s:%u", host, port); } diff --git a/muduo/net/TcpClient.cc b/muduo/net/TcpClient.cc index 6b16b7df8..057004dec 100644 --- a/muduo/net/TcpClient.cc +++ b/muduo/net/TcpClient.cc @@ -8,8 +8,28 @@ // #include +#include using namespace muduo; using namespace muduo::net; +TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port) + : loop_(loop), + serverAddr_(host, port) +{ +} + +TcpClient::TcpClient(EventLoop* loop, const InetAddress& serverAddr) + : loop_(loop), + serverAddr_(serverAddr) +{ +} + +TcpClient::~TcpClient() +{ +} + +void TcpClient::connect() +{ +} diff --git a/muduo/net/TcpClient.h b/muduo/net/TcpClient.h index 4f7d1ce1b..ff7119f63 100644 --- a/muduo/net/TcpClient.h +++ b/muduo/net/TcpClient.h @@ -13,16 +13,43 @@ #include +#include + namespace muduo { namespace net { +class Connector; +class EventLoop; + class TcpClient : boost::noncopyable { public: + TcpClient(EventLoop* loop, const string& host, uint16_t port); + TcpClient(EventLoop* loop, const InetAddress& serverAddr); + ~TcpClient(); // force out-line dtor, for scoped_ptr members. + + void connect(); + void disconnect(); + + /// Set connection callback. + /// Not thread safe. + void setConnectionCallback(const ConnectionCallback& cb) + { connectionCallback_ = cb; } + + /// Set message callback. + /// Not thread safe. + void setMessageCallback(const MessageCallback& cb) + { messageCallback_ = cb; } private: + EventLoop* loop_; + InetAddress serverAddr_; + boost::scoped_ptr connector_; // avoid revealing Connector + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + TcpConnectionPtr connection_; }; } diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index b71cbe80e..24b4fd740 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -26,7 +26,6 @@ namespace net class Acceptor; class EventLoop; -class InetAddress; class EventLoopPool; /// diff --git a/muduo/net/tests/CMakeLists.txt b/muduo/net/tests/CMakeLists.txt index f02063597..cdaf193bb 100644 --- a/muduo/net/tests/CMakeLists.txt +++ b/muduo/net/tests/CMakeLists.txt @@ -1,6 +1,9 @@ add_executable(echoserver_unittest EchoServer_unittest.cc) target_link_libraries(echoserver_unittest muduo_net) +add_executable(echoclient_unittest EchoClient_unittest.cc) +target_link_libraries(echoclient_unittest muduo_net) + add_executable(eventloop_unittest EventLoop_unittest.cc) target_link_libraries(eventloop_unittest muduo_net) diff --git a/muduo/net/tests/EchoClient_unittest.cc b/muduo/net/tests/EchoClient_unittest.cc new file mode 100644 index 000000000..f49830d2e --- /dev/null +++ b/muduo/net/tests/EchoClient_unittest.cc @@ -0,0 +1,89 @@ +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int numThreads = 0; + +class EchoClient +{ + public: + EchoClient(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + client_(loop, listenAddr) + { + client_.setConnectionCallback( + boost::bind(&EchoClient::onConnection, this, _1)); + client_.setMessageCallback( + boost::bind(&EchoClient::onMessage, this, _1, _2, _3)); + } + + void connect() + { + client_.connect(); + } + // void stop(); + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->peerAddress().toHostPort() << " -> " + << conn->localAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + + conn->send("hello\n"); + } + + void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf, Timestamp time) + { + string msg(buf->retrieveAsString()); + LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes"; + if (msg == "exit\n") + { + conn->send("bye\n"); + conn->shutdown(); + } + if (msg == "quit\n") + { + loop_->quit(); + } + sleep(2); + conn->send(msg); + } + + EventLoop* loop_; + TcpClient client_; +}; + +void threadFunc(uint16_t port) +{ +} + +int main(int argc, char* argv[]) +{ + mtrace(); + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + LOG_INFO << "sizeof TcpConnection = " << sizeof(TcpConnection); + numThreads = argc - 1; + EventLoop loop; + InetAddress serverAddr("127.0.0.1", 2000); + EchoClient client(&loop, serverAddr); + + client.connect(); + + loop.loop(); +} + From 1929efa22ee432f2d1b55be0ea1fa1a36a4f64bc Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 11 Apr 2010 13:20:39 +0000 Subject: [PATCH 034/371] TcpClient works. --- muduo/base/Logging.cc | 10 +- muduo/base/Logging.h | 19 ++++ muduo/net/Acceptor.cc | 8 +- muduo/net/Acceptor.h | 4 +- muduo/net/Channel.cc | 6 +- muduo/net/Channel.h | 1 + muduo/net/Connector.cc | 128 +++++++++++++++++++++++++ muduo/net/Connector.h | 38 ++++++++ muduo/net/EventLoop.cc | 5 +- muduo/net/EventLoop.h | 2 +- muduo/net/InetAddress.cc | 3 +- muduo/net/InetAddress.h | 6 +- muduo/net/Socket.cc | 4 +- muduo/net/Socket.h | 3 +- muduo/net/SocketsOps.cc | 98 ++++++++++++++----- muduo/net/SocketsOps.h | 7 ++ muduo/net/TcpClient.cc | 83 ++++++++++++++-- muduo/net/TcpClient.h | 22 ++++- muduo/net/TcpConnection.cc | 5 +- muduo/net/TcpServer.cc | 11 ++- muduo/net/TcpServer.h | 10 +- muduo/net/Timer.h | 6 +- muduo/net/TimerQueue.cc | 8 +- muduo/net/TimerQueue.h | 2 +- muduo/net/tests/EchoClient_unittest.cc | 13 +-- 25 files changed, 422 insertions(+), 80 deletions(-) diff --git a/muduo/base/Logging.cc b/muduo/base/Logging.cc index 5825dc365..114207901 100644 --- a/muduo/base/Logging.cc +++ b/muduo/base/Logging.cc @@ -27,6 +27,14 @@ class LoggerImpl static const char* LogLevelName[]; }; + +__thread char t_errnobuf[512]; + +const char* strerror_tl(int savedErrno) +{ + return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf); +} + } using namespace muduo; @@ -59,7 +67,7 @@ LoggerImpl::LoggerImpl(LogLevel level, int savedErrno, const char* file, int lin stream_ << message_head; if (savedErrno != 0) { - stream_ << strerror(savedErrno); + stream_ << strerror_tl(savedErrno) << " "; } } diff --git a/muduo/base/Logging.h b/muduo/base/Logging.h index 7bcdf6b83..7adc9a490 100644 --- a/muduo/base/Logging.h +++ b/muduo/base/Logging.h @@ -43,6 +43,25 @@ class Logger #define LOG_SYSERR Logger(__FILE__, __LINE__, false).stream() #define LOG_SYSFATAL Logger(__FILE__, __LINE__, true).stream() +const char* strerror_tl(int savedErrno); + +// Taken from glog/logging.h +// +// Check that the input is non NULL. This very useful in constructor +// initializer lists. + +#define CHECK_NOTNULL(val) \ + ::muduo::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) + +// A small helper for CHECK_NOTNULL(). +template +T* CheckNotNull(const char *file, int line, const char *names, T* ptr) { + if (ptr == NULL) { + Logger(file, line, Logger::FATAL).stream() << names; + } + return ptr; +} + } #endif // MUDUO_LOG_LOGGING_H diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index 86846a773..ef2658f6d 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -29,7 +29,7 @@ Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr) acceptSocket_.setReuseAddr(true); acceptSocket_.bindAddress(listenAddr); acceptChannel_.setReadCallback( - boost::bind(&Acceptor::accept, this)); + boost::bind(&Acceptor::handleRead, this)); } void Acceptor::listen() @@ -40,7 +40,7 @@ void Acceptor::listen() acceptChannel_.enableReading(); } -void Acceptor::accept() +void Acceptor::handleRead() { loop_->assertInLoopThread(); InetAddress peerAddr(0); @@ -59,9 +59,5 @@ void Acceptor::accept() sockets::close(connfd); } } - else - { - LOG_SYSERR << "accept"; - } } diff --git a/muduo/net/Acceptor.h b/muduo/net/Acceptor.h index 866e2b25d..e486b6506 100644 --- a/muduo/net/Acceptor.h +++ b/muduo/net/Acceptor.h @@ -31,7 +31,7 @@ class InetAddress; class Acceptor : boost::noncopyable { public: - typedef boost::function + typedef boost::function NewConnectionCallback; Acceptor(EventLoop* loop, const InetAddress& listenAddr); @@ -43,7 +43,7 @@ class Acceptor : boost::noncopyable void listen(); private: - void accept(); + void handleRead(); EventLoop* loop_; Socket acceptSocket_; diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 28028e98d..7ac17e34e 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -25,12 +25,14 @@ Channel::Channel(EventLoop* loop, int fd__) events_(0), revents_(0), index_(-1), - tied_(false) + tied_(false), + eventHandling_(false) { } Channel::~Channel() { + assert(!eventHandling_); } void Channel::tie(const boost::shared_ptr& obj) @@ -63,6 +65,7 @@ void Channel::handleEvent(Timestamp receiveTime) void Channel::handleEventWithGuard(Timestamp receiveTime) { + eventHandling_ = true; if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) { LOG_WARN << "Channel::handle_event() POLLHUP"; @@ -86,5 +89,6 @@ void Channel::handleEventWithGuard(Timestamp receiveTime) { if (writeCallback_) writeCallback_(); } + eventHandling_ = false; } diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index c4ef21d83..21f715ba4 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -86,6 +86,7 @@ class Channel : boost::noncopyable boost::weak_ptr tie_; bool tied_; + bool eventHandling_; ReadEventCallback readCallback_; EventCallback writeCallback_; EventCallback closeCallback_; diff --git a/muduo/net/Connector.cc b/muduo/net/Connector.cc index 239a1c9b8..af5c20cde 100644 --- a/muduo/net/Connector.cc +++ b/muduo/net/Connector.cc @@ -9,7 +9,135 @@ #include +#include +#include +#include +#include + +#include + +#include + using namespace muduo; using namespace muduo::net; +const int Connector::kMaxRetryDelayMs; + +Connector::Connector(EventLoop* loop, const InetAddress& serverAddr) + : loop_(loop), + serverAddr_(serverAddr), + state_(kDisconnected), + retryDelayMs_(kInitRetryDelayMs) +{ +} + +Connector::~Connector() +{ +} + +void Connector::start() +{ + loop_->runInLoop(boost::bind(&Connector::startInLoop, this)); +} + +void Connector::startInLoop() +{ + loop_->assertInLoopThread(); + assert(state_ == kDisconnected); + int sockfd = sockets::createNonblockingOrDie(); + int ret = sockets::connect(sockfd, serverAddr_.getSockAddrInet()); + int savedErrno = (ret == 0) ? 0 : errno; + LOG_TRACE << strerror_tl(savedErrno); + switch (savedErrno) + { + case 0: + case EINPROGRESS: + connecting(sockfd); + break; + + case EAGAIN: + case ECONNREFUSED: + retry(sockfd); + break; + + default: + retry(sockfd); + break; + } +} + +void Connector::restart() +{ + setState(kDisconnected); + retryDelayMs_ = kInitRetryDelayMs; + startInLoop(); +} + +void Connector::connecting(int sockfd) +{ + setState(kConnecting); + assert(!channel_); + channel_.reset(new Channel(loop_, sockfd)); + channel_->setWriteCallback( + boost::bind(&Connector::handleWrite, this)); + channel_->setErrorCallback( + boost::bind(&Connector::handleError, this)); + channel_->enableWriting(); +} + +int Connector::removeAndResetChannel() +{ + channel_->disableAll(); + loop_->removeChannel(get_pointer(channel_)); + int sockfd = channel_->fd(); + // Can't reset channel_ here, because we are inside Channel::handleEvent + loop_->queueInLoop(boost::bind(&Connector::resetChannel, this)); + return sockfd; +} + +void Connector::resetChannel() +{ + channel_.reset(); +} + +void Connector::handleWrite() +{ + LOG_TRACE << "Connector::handleWrite"; + + assert(state_ == kConnecting); + int sockfd = removeAndResetChannel(); + if (sockets::isSelfConnect(sockfd)) + { + LOG_WARN << "Connector::handleWrite - Self connect"; + abort(); + retry(sockfd); + } + else + { + setState(kConnected); + newConnectionCallback_(sockfd); + } +} + +void Connector::handleError() +{ + LOG_ERROR << "Connector::handleError"; + assert(state_ == kConnecting); + + int sockfd = removeAndResetChannel(); + int err = sockets::getSocketError(sockfd); + LOG_INFO << "SO_ERROR = " << err << " " << strerror_tl(err); + retry(sockfd); +} + +void Connector::retry(int sockfd) +{ + InetAddress addr(sockets::getLocalAddr(sockfd)); + sockets::close(sockfd); + setState(kDisconnected); + LOG_INFO << "Connector::retry - Retry connecting to " << serverAddr_.toHostPort() + << " in " << retryDelayMs_ << " milliseconds. " << addr.toHostPort(); + loop_->runAfter(retryDelayMs_/1000.0, boost::bind(&Connector::startInLoop, this)); + retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs); +} diff --git a/muduo/net/Connector.h b/muduo/net/Connector.h index 82a5c2146..d547857a5 100644 --- a/muduo/net/Connector.h +++ b/muduo/net/Connector.h @@ -11,18 +11,56 @@ #ifndef MUDUO_NET_CONNECTOR_H #define MUDUO_NET_CONNECTOR_H +#include + +#include #include +#include namespace muduo { namespace net { +class Channel; +class EventLoop; + class Connector : boost::noncopyable { public: + typedef boost::function NewConnectionCallback; + + Connector(EventLoop* loop, const InetAddress& serverAddr); + ~Connector(); + + void setNewConnectionCallback(const NewConnectionCallback& cb) + { newConnectionCallback_ = cb; } + + void start(); + void restart(); + + const InetAddress& serverAddress() const { return serverAddr_; } private: + enum States { kDisconnected, kConnecting, kConnected }; + static const int kMaxRetryDelayMs = 30*1000; + static const int kInitRetryDelayMs = 500; + + void setState(States s) { state_ = s; } + void startInLoop(); + void connecting(int sockfd); + void handleWrite(); + void handleError(); + void retry(int sockfd); + int removeAndResetChannel(); + void resetChannel(); + + EventLoop* loop_; + InetAddress serverAddr_; + States state_; // FIXME: use atomic variable + boost::scoped_ptr channel_; + NewConnectionCallback newConnectionCallback_; + int retryDelayMs_; }; } diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index d582581f0..3f37bfc0e 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -54,14 +54,13 @@ EventLoop::EventLoop() { LOG_FATAL << "Another EventLoop " << t_loopInThisThread << " exists in this thread " << threadId_; - abort(); } else { t_loopInThisThread = this; } wakeupChannel_->setReadCallback( - boost::bind(&EventLoop::wakedup, this)); + boost::bind(&EventLoop::handleRead, this)); // we are always reading the wakeupfd wakeupChannel_->enableReading(); } @@ -170,7 +169,7 @@ void EventLoop::abortNotInLoopThread() LOG_FATAL << "threadId_=" << threadId_; } -void EventLoop::wakedup() +void EventLoop::handleRead() { uint64_t one = 1; ssize_t n = ::read(wakeupFd_, &one, sizeof one); diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 006b9a556..2e0e846fe 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -94,7 +94,7 @@ class EventLoop : boost::noncopyable private: void abortNotInLoopThread(); - void wakedup(); + void handleRead(); // waked up void doPendingFunctors(); typedef std::vector ChannelList; diff --git a/muduo/net/InetAddress.cc b/muduo/net/InetAddress.cc index e6b870a6f..16657a9ae 100644 --- a/muduo/net/InetAddress.cc +++ b/muduo/net/InetAddress.cc @@ -46,9 +46,10 @@ InetAddress::InetAddress(uint16_t port) addr_.sin_port = sockets::hostToNetwork16(port); } -InetAddress::InetAddress(const string& host, uint16_t port) +InetAddress::InetAddress(const string& ip, uint16_t port) { bzero(&addr_, sizeof addr_); + sockets::fromHostPort(ip.c_str(), port, &addr_); } string InetAddress::toHostPort() const diff --git a/muduo/net/InetAddress.h b/muduo/net/InetAddress.h index 5e4588dd9..360cdba14 100644 --- a/muduo/net/InetAddress.h +++ b/muduo/net/InetAddress.h @@ -32,9 +32,9 @@ class InetAddress : public muduo::copyable /// Mostly used in TcpServer listening. explicit InetAddress(uint16_t port); - /// Constructs an endpoint with given host and port. - /// @c host could either be "1.2.3.4" or "example.com" - InetAddress(const string& host, uint16_t port); + /// Constructs an endpoint with given ip and port. + /// @c ip should be "1.2.3.4" + InetAddress(const string& ip, uint16_t port); /// Constructs an endpoint with given struct @c sockaddr_in /// Mostly used when accepting new connections diff --git a/muduo/net/Socket.cc b/muduo/net/Socket.cc index b834a0448..d1c711ebe 100644 --- a/muduo/net/Socket.cc +++ b/muduo/net/Socket.cc @@ -45,9 +45,9 @@ int Socket::accept(InetAddress* peeraddr) return connfd; } -void Socket::shutdown() +void Socket::shutdownWrite() { - // ::shutdown(sockfd_); + sockets::shutdownWrite(sockfd_); } void Socket::setTcpNoDelay(bool on) diff --git a/muduo/net/Socket.h b/muduo/net/Socket.h index 6396d719e..3184c2ad2 100644 --- a/muduo/net/Socket.h +++ b/muduo/net/Socket.h @@ -49,7 +49,8 @@ class Socket : boost::noncopyable /// set to non-blocking and close-on-exec. *peeraddr is assigned. /// On error, -1 is returned, and *peeraddr is untouched. int accept(InetAddress* peeraddr); - void shutdown(); + + void shutdownWrite(); /// /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index 82e84aa24..cabc080e4 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -7,12 +7,13 @@ // Author: Shuo Chen (chenshuo at chenshuo dot com) #include +#include #include #include #include -#include // FIXME -#include // FIXME +#include // snprintf +#include // bzero #include #include @@ -35,7 +36,10 @@ int sockets::createNonblockingOrDie() { // socket int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - // FIXME check + if (sockfd < 0) + { + LOG_SYSFATAL << "sockets::createNonblockingOrDie"; + } // non-block int flags = ::fcntl(sockfd, F_GETFL, 0); @@ -55,20 +59,18 @@ int sockets::createNonblockingOrDie() void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) { int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); - if (ret) + if (ret < 0) { - perror("sockets::bindOrDie"); - abort(); + LOG_SYSFATAL << "sockets::bindOrDie"; } } void sockets::listenOrDie(int sockfd) { int ret = ::listen(sockfd, SOMAXCONN); - if (ret) + if (ret < 0) { - perror("sockets::listenOrDie"); - abort(); + LOG_SYSFATAL << "sockets::listenOrDie"; } } @@ -81,10 +83,10 @@ int sockets::accept(int sockfd, struct sockaddr_in* addr) int connfd = ::accept4(sockfd, sockaddr_cast(addr), &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); #endif - if (connfd == -1) + if (connfd < 0) { int savedErrno = errno; - perror("Socket::accept"); + LOG_SYSERR << "Socket::accept"; switch (savedErrno) { case EAGAIN: @@ -104,45 +106,97 @@ int sockets::accept(int sockfd, struct sockaddr_in* addr) case ENOTSOCK: case EOPNOTSUPP: // unexpected errors - abort(); + LOG_FATAL << "unexpected error of ::accept"; break; default: - // unknown errors - fprintf(stderr, "errno = %d\n", savedErrno); - abort(); + LOG_FATAL << "unknown error of ::accept " << savedErrno; break; } } return connfd; } +int sockets::connect(int sockfd, const struct sockaddr_in& addr) +{ + return ::connect(sockfd, sockaddr_cast(&addr), sizeof addr); +} + void sockets::close(int sockfd) { - ::close(sockfd); - // FIXME EINTR + if (::close(sockfd) < 0) + { + LOG_SYSERR << "sockets::close"; + } } void sockets::shutdownWrite(int sockfd) { - ::shutdown(sockfd, SHUT_WR); - // FIXME EINTR + if (::shutdown(sockfd, SHUT_WR) < 0) + { + LOG_SYSERR << "sockets::shutdownWrite"; + } } void sockets::toHostPort(char* buf, size_t size, const struct sockaddr_in& addr) { - char host[INET_ADDRSTRLEN]; + char host[INET_ADDRSTRLEN] = "INVALID"; ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); uint16_t port = sockets::networkToHost16(addr.sin_port); snprintf(buf, size, "%s:%u", host, port); } +void sockets::fromHostPort(const char* ip, uint16_t port, + struct sockaddr_in* addr) +{ + addr->sin_family = AF_INET; + addr->sin_port = hostToNetwork16(port); + if (inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) + { + LOG_SYSERR << "sockets::fromHostPort"; + } +} + +int sockets::getSocketError(int sockfd) +{ + int optval; + socklen_t optlen = sizeof optval; + + if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) + { + return errno; + } + else + { + return optval; + } +} + struct sockaddr_in sockets::getLocalAddr(int sockfd) { struct sockaddr_in localaddr; + bzero(&localaddr, sizeof localaddr); socklen_t addrlen = sizeof(localaddr); - ::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen); - // FIXME check + if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) + { + LOG_SYSERR << "sockets::getLocalAddr"; + } return localaddr; } +struct sockaddr_in sockets::getPeerAddr(int sockfd) +{ + struct sockaddr_in peeraddr; + bzero(&peeraddr, sizeof peeraddr); + socklen_t addrlen = sizeof(peeraddr); + if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) + { + LOG_SYSERR << "sockets::getPeerAddr"; + } + return peeraddr; +} + +bool sockets::isSelfConnect(int sockfd) +{ + return false; +} diff --git a/muduo/net/SocketsOps.h b/muduo/net/SocketsOps.h index 8ec6104ed..95680a715 100644 --- a/muduo/net/SocketsOps.h +++ b/muduo/net/SocketsOps.h @@ -49,6 +49,7 @@ inline uint16_t networkToHost16(uint16_t netshort) /// abort if any error. int createNonblockingOrDie(); +int connect(int sockfd, const struct sockaddr_in& addr); void bindOrDie(int sockfd, const struct sockaddr_in& addr); void listenOrDie(int sockfd); int accept(int sockfd, struct sockaddr_in* addr); @@ -57,8 +58,14 @@ void shutdownWrite(int sockfd); void toHostPort(char* buf, size_t size, const struct sockaddr_in& addr); +void fromHostPort(const char* ip, uint16_t port, + struct sockaddr_in* addr); + +int getSocketError(int sockfd); struct sockaddr_in getLocalAddr(int sockfd); +struct sockaddr_in getPeerAddr(int sockfd); +bool isSelfConnect(int sockfd); } } diff --git a/muduo/net/TcpClient.cc b/muduo/net/TcpClient.cc index 057004dec..ce59efb89 100644 --- a/muduo/net/TcpClient.cc +++ b/muduo/net/TcpClient.cc @@ -8,22 +8,40 @@ // #include + +#include #include +#include +#include + +#include + +#include // snprintf using namespace muduo; using namespace muduo::net; -TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port) - : loop_(loop), - serverAddr_(host, port) -{ -} +// TcpClient::TcpClient(EventLoop* loop) +// : loop_(loop) +// { +// } + +// TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port) +// : loop_(CHECK_NOTNULL(loop)), +// serverAddr_(host, port) +// { +// } TcpClient::TcpClient(EventLoop* loop, const InetAddress& serverAddr) - : loop_(loop), - serverAddr_(serverAddr) + : loop_(CHECK_NOTNULL(loop)), + connector_(new Connector(loop, serverAddr)), + retry_(false), + nextConnId_(1) { + connector_->setNewConnectionCallback( + boost::bind(&TcpClient::newConnection, this, _1)); + // FIXME setConnectFailedCallback } TcpClient::~TcpClient() @@ -32,4 +50,55 @@ TcpClient::~TcpClient() void TcpClient::connect() { + // FIXME: check state + LOG_INFO << "TcpClient::connect[" << name_ << "] - connecting to " + << connector_->serverAddress().toHostPort(); + connector_->start(); } + +void TcpClient::newConnection(int sockfd) +{ + loop_->assertInLoopThread(); + InetAddress peerAddr(sockets::getPeerAddr(sockfd)); + char buf[32]; + snprintf(buf, sizeof buf, ":%s#%d", peerAddr.toHostPort().c_str(), nextConnId_); + ++nextConnId_; + string connName = name_ + buf; + + InetAddress localAddr(sockets::getLocalAddr(sockfd)); + // FIXME poll with zero timeout to double confirm the new connection + TcpConnectionPtr conn( + new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr)); + + conn->setConnectionCallback(connectionCallback_); + conn->setMessageCallback(messageCallback_); + conn->setCloseCallback( + boost::bind(&TcpClient::removeConnection, this, _1)); + { + MutexLockGuard lock(mutex_); + connection_ = conn; + } + conn->connectEstablished(); +} + +void TcpClient::removeConnection(const TcpConnectionPtr& conn) +{ + loop_->assertInLoopThread(); + assert(loop_ == conn->getLoop()); + + { + MutexLockGuard lock(mutex_); + assert(connection_ == conn); + connection_.reset(); + } + + loop_->queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn)); + // FIXME wake up ? + if (retry_) + { + LOG_INFO << "TcpClient::connect[" << name_ << "] - Reconnecting to " + << connector_->serverAddress().toHostPort(); + connector_->restart(); + } +} + diff --git a/muduo/net/TcpClient.h b/muduo/net/TcpClient.h index ff7119f63..835fbce2f 100644 --- a/muduo/net/TcpClient.h +++ b/muduo/net/TcpClient.h @@ -13,6 +13,7 @@ #include +#include #include namespace muduo @@ -26,12 +27,16 @@ class EventLoop; class TcpClient : boost::noncopyable { public: - TcpClient(EventLoop* loop, const string& host, uint16_t port); + // TcpClient(EventLoop* loop); + // TcpClient(EventLoop* loop, const string& host, uint16_t port); TcpClient(EventLoop* loop, const InetAddress& serverAddr); ~TcpClient(); // force out-line dtor, for scoped_ptr members. void connect(); - void disconnect(); + // void disconnect(); + + bool retry() const; + void setRetry(bool on) { retry_ = on; } /// Set connection callback. /// Not thread safe. @@ -44,12 +49,21 @@ class TcpClient : boost::noncopyable { messageCallback_ = cb; } private: + /// Not thread safe, but in loop + void newConnection(int sockfd); + /// Not thread safe, but in loop + void removeConnection(const TcpConnectionPtr& conn); + EventLoop* loop_; - InetAddress serverAddr_; boost::scoped_ptr connector_; // avoid revealing Connector + const string name_; ConnectionCallback connectionCallback_; MessageCallback messageCallback_; - TcpConnectionPtr connection_; + bool retry_; // atmoic + // always in loop thread + int nextConnId_; + MutexLock mutex_; + TcpConnectionPtr connection_; // @BuardedBy mutex_ }; } diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 4e6662ea6..7cfc835a8 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -27,7 +27,7 @@ TcpConnection::TcpConnection(EventLoop* loop, int fd, const InetAddress& localAddr, const InetAddress& peerAddr) - : loop_(loop), + : loop_(CHECK_NOTNULL(loop)), name_(name__), state_(kConnecting), socket_(new Socket(fd)), @@ -96,7 +96,7 @@ void TcpConnection::shutdownInLoop() if (!channel_->isWriting()) { // we are not writing - sockets::shutdownWrite(channel_->fd()); + socket_->shutdownWrite(); } } @@ -191,5 +191,6 @@ void TcpConnection::handleClose() void TcpConnection::handleError() { + LOG_ERROR << "TcpConnection::handleError"; } diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index fdad6763d..72e7270ab 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -16,14 +16,14 @@ #include -#include +#include // snprintf using namespace muduo; using namespace muduo::net; TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr) - : loop_(loop), - name_(listenAddr.toHostPort()), + : loop_(CHECK_NOTNULL(loop)), + hostport_(listenAddr.toHostPort()), acceptor_(new Acceptor(loop, listenAddr)), threadPool_(new EventLoopPool(loop)), started_(false), @@ -74,9 +74,9 @@ void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) loop_->assertInLoopThread(); EventLoop* ioLoop = threadPool_->getNextLoop(); char buf[32]; - snprintf(buf, sizeof buf, "%s#%d", name_.c_str(), nextConnId_); + snprintf(buf, sizeof buf, ":%s#%d", hostport_.c_str(), nextConnId_); ++nextConnId_; - string connName = serverName_ + buf; + string connName = name_ + buf; InetAddress localAddr(sockets::getLocalAddr(sockfd)); // FIXME poll with zero timeout to double confirm the new connection @@ -103,5 +103,6 @@ void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) EventLoop* ioLoop = conn->getLoop(); ioLoop->queueInLoop( boost::bind(&TcpConnection::connectDestroyed, conn)); + // FIXME wake up ? } diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index 24b4fd740..d5c4aa495 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -42,7 +42,7 @@ class TcpServer : boost::noncopyable const string& name); ~TcpServer(); // force out-line dtor, for scoped_ptr members. - const string& name() const { return name_; } + // const string& hostport() const { return hostport_; } /// Set the number of threads for handling input. /// @@ -73,22 +73,22 @@ class TcpServer : boost::noncopyable { messageCallback_ = cb; } private: - /// Not thread safe. + /// Not thread safe, but in loop void newConnection(int sockfd, const InetAddress& peerAddr); /// Thread safe. void removeConnection(const TcpConnectionPtr& conn); - /// Not thread safe. + /// Not thread safe, but in loop void removeConnectionInLoop(const TcpConnectionPtr& conn); typedef std::map ConnectionMap; EventLoop* loop_; // the acceptor loop - string name_; + const string hostport_; + const string name_; boost::scoped_ptr acceptor_; // avoid revealing Acceptor boost::scoped_ptr threadPool_; ConnectionCallback connectionCallback_; MessageCallback messageCallback_; - const string serverName_; bool started_; // always in loop thread int nextConnId_; diff --git a/muduo/net/Timer.h b/muduo/net/Timer.h index 36a1fad5b..1d12d0f3e 100644 --- a/muduo/net/Timer.h +++ b/muduo/net/Timer.h @@ -29,7 +29,7 @@ class Timer : boost::noncopyable { public: Timer(const TimerCallback& cb, Timestamp when, double interval) - : cb_(cb), + : callback_(cb), expiration_(when), interval_(interval), repeat_(interval > 0.0) @@ -37,7 +37,7 @@ class Timer : boost::noncopyable void run() const { - cb_(); + callback_(); } Timestamp expiration() const { return expiration_; } @@ -46,7 +46,7 @@ class Timer : boost::noncopyable void restart(Timestamp now); private: - const TimerCallback cb_; + const TimerCallback callback_; Timestamp expiration_; const double interval_; const bool repeat_; diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index bbac8a054..156861fc1 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -74,7 +74,7 @@ TimerQueue::TimerQueue(EventLoop* loop) timers_() { timerfdChannel_.setReadCallback( - boost::bind(&TimerQueue::timeout, this)); + boost::bind(&TimerQueue::handleRead, this)); // we are always reading the timerfd, we disarm it with timerfd_settime. timerfdChannel_.enableReading(); } @@ -91,16 +91,16 @@ TimerQueue::~TimerQueue() } // FIXME replace linked-list operations with binary-heap. -void TimerQueue::timeout() +void TimerQueue::handleRead() { loop_->assertInLoopThread(); Timestamp now(Timestamp::now()); uint64_t howmany; ssize_t n = ::read(timerfd_, &howmany, sizeof howmany); - LOG_DEBUG << "TimerQueue::timeout() " << howmany << " at " << now.toString(); + LOG_DEBUG << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); if (n != sizeof howmany) { - LOG_ERROR << "TimerQueue::timeout() reads " << n << " bytes instead of 8"; + LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; } TimerList expired; diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index cc3cf4918..676fa335c 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -52,7 +52,7 @@ class TimerQueue : boost::noncopyable private: // called when timerfd arms - void timeout(); + void handleRead(); // insert timer in sorted list. bool insertWithLockHold(Timer* timer); diff --git a/muduo/net/tests/EchoClient_unittest.cc b/muduo/net/tests/EchoClient_unittest.cc index f49830d2e..b2ed31016 100644 --- a/muduo/net/tests/EchoClient_unittest.cc +++ b/muduo/net/tests/EchoClient_unittest.cc @@ -29,6 +29,7 @@ class EchoClient boost::bind(&EchoClient::onConnection, this, _1)); client_.setMessageCallback( boost::bind(&EchoClient::onMessage, this, _1, _2, _3)); + client_.setRetry(true); } void connect() @@ -40,11 +41,14 @@ class EchoClient private: void onConnection(const TcpConnectionPtr& conn) { - LOG_TRACE << conn->peerAddress().toHostPort() << " -> " - << conn->localAddress().toHostPort() << " is " + LOG_TRACE << conn->localAddress().toHostPort() << " -> " + << conn->peerAddress().toHostPort() << " is " << (conn->connected() ? "UP" : "DOWN"); - conn->send("hello\n"); + conn->send("world\n"); + if (!conn->connected()) + { + } } void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf, Timestamp time) @@ -74,10 +78,7 @@ void threadFunc(uint16_t port) int main(int argc, char* argv[]) { - mtrace(); LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); - LOG_INFO << "sizeof TcpConnection = " << sizeof(TcpConnection); - numThreads = argc - 1; EventLoop loop; InetAddress serverAddr("127.0.0.1", 2000); EchoClient client(&loop, serverAddr); From 3fc9dd12c4a1a6a16b46eac79f21abfc68b4ad6b Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Mon, 12 Apr 2010 02:03:54 +0000 Subject: [PATCH 035/371] Finish EPollPoller. --- muduo/net/Connector.cc | 26 +++++-- muduo/net/DefaultPoller.cc | 2 +- muduo/net/EPollPoller.cc | 104 ++++++++++++++++++++++++- muduo/net/EPollPoller.h | 18 ++++- muduo/net/Poller.h | 2 +- muduo/net/SocketsOps.cc | 6 +- muduo/net/tests/EchoClient_unittest.cc | 2 +- 7 files changed, 147 insertions(+), 13 deletions(-) diff --git a/muduo/net/Connector.cc b/muduo/net/Connector.cc index af5c20cde..d5d259c21 100644 --- a/muduo/net/Connector.cc +++ b/muduo/net/Connector.cc @@ -47,21 +47,37 @@ void Connector::startInLoop() int sockfd = sockets::createNonblockingOrDie(); int ret = sockets::connect(sockfd, serverAddr_.getSockAddrInet()); int savedErrno = (ret == 0) ? 0 : errno; - LOG_TRACE << strerror_tl(savedErrno); switch (savedErrno) { case 0: case EINPROGRESS: + case EINTR: + case EISCONN: connecting(sockfd); break; case EAGAIN: + case EADDRINUSE: case ECONNREFUSED: + case ENETUNREACH: retry(sockfd); break; + case EACCES: + case EPERM: + case EAFNOSUPPORT: + case EALREADY: + case EBADF: + case EFAULT: + case ENOTSOCK: + LOG_SYSERR << "connect error in Connector::startInLoop."; + sockets::close(sockfd); + break; + default: - retry(sockfd); + LOG_SYSERR << "Unexpected error in Connector::startInLoop."; + sockets::close(sockfd); + // connectErrorCallback_(); break; } } @@ -109,7 +125,6 @@ void Connector::handleWrite() if (sockets::isSelfConnect(sockfd)) { LOG_WARN << "Connector::handleWrite - Self connect"; - abort(); retry(sockfd); } else @@ -126,17 +141,16 @@ void Connector::handleError() int sockfd = removeAndResetChannel(); int err = sockets::getSocketError(sockfd); - LOG_INFO << "SO_ERROR = " << err << " " << strerror_tl(err); + LOG_TRACE << "SO_ERROR = " << err << " " << strerror_tl(err); retry(sockfd); } void Connector::retry(int sockfd) { - InetAddress addr(sockets::getLocalAddr(sockfd)); sockets::close(sockfd); setState(kDisconnected); LOG_INFO << "Connector::retry - Retry connecting to " << serverAddr_.toHostPort() - << " in " << retryDelayMs_ << " milliseconds. " << addr.toHostPort(); + << " in " << retryDelayMs_ << " milliseconds. "; loop_->runAfter(retryDelayMs_/1000.0, boost::bind(&Connector::startInLoop, this)); retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs); } diff --git a/muduo/net/DefaultPoller.cc b/muduo/net/DefaultPoller.cc index 7b8e21735..dd92c5cb5 100644 --- a/muduo/net/DefaultPoller.cc +++ b/muduo/net/DefaultPoller.cc @@ -14,5 +14,5 @@ using namespace muduo::net; Poller* Poller::newDefaultPoller(EventLoop* loop) { - return new PollPoller(loop); + return new EPollPoller(loop); } diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc index a11c6d8a8..831277466 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/EPollPoller.cc @@ -8,13 +8,16 @@ #include +#include #include +#include + #include +#include #include #include -#include using namespace muduo; using namespace muduo::net; @@ -27,13 +30,112 @@ BOOST_STATIC_ASSERT(EPOLLRDHUP == POLLRDHUP); BOOST_STATIC_ASSERT(EPOLLERR == POLLERR); BOOST_STATIC_ASSERT(EPOLLHUP == POLLHUP); +EPollPoller::EPollPoller(EventLoop* loop) + : Poller(loop), + epollfd_(::epoll_create1(EPOLL_CLOEXEC)), + events_(kInitEventListSize) +{ + if (epollfd_ < 0) + { + LOG_SYSFATAL << "EPollPoller::EPollPoller"; + } +} + EPollPoller::~EPollPoller() { + ::close(epollfd_); } Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) { + int numEvents = ::epoll_wait(epollfd_, + &*events_.begin(), + static_cast(events_.size()), + timeoutMs); Timestamp now(Timestamp::now()); + if (numEvents > 0) + { + LOG_TRACE << numEvents << " events happended"; + fillActiveChannels(numEvents, activeChannels); + if (implicit_cast(numEvents) == events_.size()) + { + events_.resize(events_.size()+1); + } + } + else if (numEvents == 0) + { + LOG_TRACE << " nothing happended"; + } + else + { + LOG_SYSERR << "PollPoller::poll()"; + } return now; } +void EPollPoller::fillActiveChannels(int numEvents, + ChannelList* activeChannels) const +{ + assert(implicit_cast(numEvents) <= events_.size()); + for (int i = 0; i < numEvents; ++i) + { + Channel* channel = static_cast(events_[i].data.ptr); + int fd = channel->fd(); + ChannelMap::const_iterator it = channels_.find(fd); + assert(it != channels_.end()); + assert(it->second == channel); + channel->set_revents(events_[i].events); + activeChannels->push_back(channel); + } +} + +void EPollPoller::updateChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); + if (channel->index() < 0) + { + // a new one, add with EPOLL_CTL_ADD + int fd = channel->fd(); + assert(channels_.find(fd) == channels_.end()); + channel->set_index(1); + channels_[fd] = channel; + update(EPOLL_CTL_ADD, channel); + } + else + { + // update existing one with EPOLL_CTL_MOD + int fd = channel->fd(); + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + assert(channel->index() == 1); + update(EPOLL_CTL_MOD, channel); + } +} + +void EPollPoller::removeChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + int fd = channel->fd(); + LOG_TRACE << "fd = " << fd; + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + assert(channel->events() == Channel::kNoneEvent); + assert(channel->index() == 1); + size_t n = channels_.erase(fd); + assert(n == 1); + + update(EPOLL_CTL_DEL, channel); +} + +void EPollPoller::update(int operation, Channel* channel) +{ + struct epoll_event event; + event.events = channel->events(); + event.data.ptr = channel; + if (::epoll_ctl(epollfd_, operation, channel->fd(), &event) < 0) + { + LOG_SYSFATAL << "epoll_ctl op=" << operation; + } +} + diff --git a/muduo/net/EPollPoller.h b/muduo/net/EPollPoller.h index e184fa544..8062f7d6e 100644 --- a/muduo/net/EPollPoller.h +++ b/muduo/net/EPollPoller.h @@ -16,6 +16,8 @@ #include #include +#include + namespace muduo { namespace net @@ -27,14 +29,26 @@ namespace net class EPollPoller : public Poller { public: - + EPollPoller(EventLoop* loop); virtual ~EPollPoller(); virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels); virtual void updateChannel(Channel* channel); + virtual void removeChannel(Channel* channel); private: - std::map channels_; + static const int kInitEventListSize = 16; + + void fillActiveChannels(int numEvents, + ChannelList* activeChannels) const; + void update(int operation, Channel* channel); + + typedef std::vector EventList; + typedef std::map ChannelMap; + + int epollfd_; + EventList events_; + ChannelMap channels_; }; } diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index b05daa1bb..846c1e75c 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -23,6 +23,7 @@ namespace net class Channel; class EventLoop; + /// /// Base class for IO Multiplexing /// @@ -49,7 +50,6 @@ class Poller : boost::noncopyable static Poller* newDefaultPoller(EventLoop* loop); - protected: void assertInLoopThread(); private: diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index cabc080e4..0a05a09f6 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -198,5 +198,9 @@ struct sockaddr_in sockets::getPeerAddr(int sockfd) bool sockets::isSelfConnect(int sockfd) { - return false; + struct sockaddr_in localaddr = getLocalAddr(sockfd); + struct sockaddr_in peeraddr = getPeerAddr(sockfd); + return localaddr.sin_port == peeraddr.sin_port + && localaddr.sin_addr.s_addr == peeraddr.sin_addr.s_addr; } + diff --git a/muduo/net/tests/EchoClient_unittest.cc b/muduo/net/tests/EchoClient_unittest.cc index b2ed31016..19a0bcbdf 100644 --- a/muduo/net/tests/EchoClient_unittest.cc +++ b/muduo/net/tests/EchoClient_unittest.cc @@ -80,7 +80,7 @@ int main(int argc, char* argv[]) { LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); EventLoop loop; - InetAddress serverAddr("127.0.0.1", 2000); + InetAddress serverAddr(argv[1], 2000); EchoClient client(&loop, serverAddr); client.connect(); From 738a9b47ef103b11b169bce91bda01ea4e3c8a22 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Mon, 12 Apr 2010 17:18:19 +0000 Subject: [PATCH 036/371] Add name to TcpClient and TcpServer. --- ChangeLog | 4 ++++ README | 9 ++++++++ TODO | 5 ++++ muduo/net/ChannelBuffer.h | 2 +- muduo/net/Connector.cc | 1 + muduo/net/EPollPoller.cc | 2 +- muduo/net/TcpClient.cc | 5 +++- muduo/net/TcpClient.h | 6 +++-- muduo/net/TcpConnection.h | 1 + muduo/net/TcpServer.cc | 5 +++- muduo/net/TcpServer.h | 2 +- muduo/net/tests/EchoClient_unittest.cc | 32 ++++++++++++-------------- muduo/net/tests/EchoServer_unittest.cc | 14 +++++------ 13 files changed, 56 insertions(+), 32 deletions(-) create mode 100644 README create mode 100644 TODO diff --git a/ChangeLog b/ChangeLog index 064f96a45..ffa3f2503 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ * First alpha release, version 0.1.0 +2010-04-11 Shuo Chen + + * TcpClient works. + 2010-04-03 Shuo Chen * TcpServer works. diff --git a/README b/README new file mode 100644 index 000000000..2cc806e4e --- /dev/null +++ b/README @@ -0,0 +1,9 @@ +Muduo is a multithreaded C++ network library based on +the reactor pattern. +http://code.google.com/p/muduo/ + +Copyright (c) 2010, Shuo Chen. All rights reserved. + +Use of this source code is governed by a BSD-style +license that can be found in the License file. + diff --git a/TODO b/TODO new file mode 100644 index 000000000..c78e9cff9 --- /dev/null +++ b/TODO @@ -0,0 +1,5 @@ +Always processing timer before IO +Support string and line protocol +Add Resolver +Add Benchmark + diff --git a/muduo/net/ChannelBuffer.h b/muduo/net/ChannelBuffer.h index 58d4304aa..bfba9140b 100644 --- a/muduo/net/ChannelBuffer.h +++ b/muduo/net/ChannelBuffer.h @@ -147,7 +147,7 @@ class ChannelBuffer : public muduo::copyable begin()+kCheapPrepend); readerIndex_ = kCheapPrepend; writerIndex_ = readerIndex_ + used; - assert(used = readableBytes()); + assert(used == readableBytes()); } } diff --git a/muduo/net/Connector.cc b/muduo/net/Connector.cc index d5d259c21..cf57b0f00 100644 --- a/muduo/net/Connector.cc +++ b/muduo/net/Connector.cc @@ -33,6 +33,7 @@ Connector::Connector(EventLoop* loop, const InetAddress& serverAddr) Connector::~Connector() { + assert(!channel_); } void Connector::start() diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc index 831277466..1871dd2ae 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/EPollPoller.cc @@ -68,7 +68,7 @@ Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) } else { - LOG_SYSERR << "PollPoller::poll()"; + LOG_SYSERR << "EPollPoller::poll()"; } return now; } diff --git a/muduo/net/TcpClient.cc b/muduo/net/TcpClient.cc index ce59efb89..783f19c1a 100644 --- a/muduo/net/TcpClient.cc +++ b/muduo/net/TcpClient.cc @@ -33,9 +33,12 @@ using namespace muduo::net; // { // } -TcpClient::TcpClient(EventLoop* loop, const InetAddress& serverAddr) +TcpClient::TcpClient(EventLoop* loop, + const InetAddress& serverAddr, + const string& name) : loop_(CHECK_NOTNULL(loop)), connector_(new Connector(loop, serverAddr)), + name_(name), retry_(false), nextConnId_(1) { diff --git a/muduo/net/TcpClient.h b/muduo/net/TcpClient.h index 835fbce2f..1fe6becca 100644 --- a/muduo/net/TcpClient.h +++ b/muduo/net/TcpClient.h @@ -29,14 +29,16 @@ class TcpClient : boost::noncopyable public: // TcpClient(EventLoop* loop); // TcpClient(EventLoop* loop, const string& host, uint16_t port); - TcpClient(EventLoop* loop, const InetAddress& serverAddr); + TcpClient(EventLoop* loop, + const InetAddress& serverAddr, + const string& name); ~TcpClient(); // force out-line dtor, for scoped_ptr members. void connect(); // void disconnect(); bool retry() const; - void setRetry(bool on) { retry_ = on; } + void enableRetry() { retry_ = true; } /// Set connection callback. /// Not thread safe. diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index 834d7360a..b2a5726ff 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -41,6 +41,7 @@ class TcpConnection : public boost::enable_shared_from_this, public: /// Constructs a TcpConnection with a connected sockfd /// + /// User should not create this object. TcpConnection(EventLoop* loop, const string& name, int sockfd, diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 72e7270ab..7a8113315 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -21,9 +21,12 @@ using namespace muduo; using namespace muduo::net; -TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr) +TcpServer::TcpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name) : loop_(CHECK_NOTNULL(loop)), hostport_(listenAddr.toHostPort()), + name_(name), acceptor_(new Acceptor(loop, listenAddr)), threadPool_(new EventLoopPool(loop)), started_(false), diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index d5c4aa495..6039b42f1 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -36,7 +36,7 @@ class TcpServer : boost::noncopyable { public: - TcpServer(EventLoop* loop, const InetAddress& listenAddr); + //TcpServer(EventLoop* loop, const InetAddress& listenAddr); TcpServer(EventLoop* loop, const InetAddress& listenAddr, const string& name); diff --git a/muduo/net/tests/EchoClient_unittest.cc b/muduo/net/tests/EchoClient_unittest.cc index 19a0bcbdf..29661f96f 100644 --- a/muduo/net/tests/EchoClient_unittest.cc +++ b/muduo/net/tests/EchoClient_unittest.cc @@ -23,13 +23,13 @@ class EchoClient public: EchoClient(EventLoop* loop, const InetAddress& listenAddr) : loop_(loop), - client_(loop, listenAddr) + client_(loop, listenAddr, "EchoClient") { client_.setConnectionCallback( boost::bind(&EchoClient::onConnection, this, _1)); client_.setMessageCallback( boost::bind(&EchoClient::onMessage, this, _1, _2, _3)); - client_.setRetry(true); + client_.enableRetry(); } void connect() @@ -46,15 +46,12 @@ class EchoClient << (conn->connected() ? "UP" : "DOWN"); conn->send("world\n"); - if (!conn->connected()) - { - } } void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf, Timestamp time) { string msg(buf->retrieveAsString()); - LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes"; + LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); if (msg == "exit\n") { conn->send("bye\n"); @@ -64,7 +61,6 @@ class EchoClient { loop_->quit(); } - sleep(2); conn->send(msg); } @@ -72,19 +68,21 @@ class EchoClient TcpClient client_; }; -void threadFunc(uint16_t port) -{ -} - int main(int argc, char* argv[]) { LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); - EventLoop loop; - InetAddress serverAddr(argv[1], 2000); - EchoClient client(&loop, serverAddr); - - client.connect(); + if (argc > 1) + { + EventLoop loop; + InetAddress serverAddr(argv[1], 2000); + EchoClient client(&loop, serverAddr); - loop.loop(); + client.connect(); + loop.loop(); + } + else + { + printf("Usage: %s host_ip\n", argv[0]); + } } diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index e24f4242a..937c15757 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -23,7 +23,7 @@ class EchoServer public: EchoServer(EventLoop* loop, const InetAddress& listenAddr) : loop_(loop), - server_(loop, listenAddr) + server_(loop, listenAddr, "EchoServer") { server_.setConnectionCallback( boost::bind(&EchoServer::onConnection, this, _1)); @@ -51,7 +51,7 @@ class EchoServer void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf, Timestamp time) { string msg(buf->retrieveAsString()); - LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes"; + LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); if (msg == "exit\n") { conn->send("bye\n"); @@ -61,7 +61,6 @@ class EchoServer { loop_->quit(); } - sleep(2); conn->send(msg); } @@ -69,16 +68,15 @@ class EchoServer TcpServer server_; }; -void threadFunc(uint16_t port) -{ -} - int main(int argc, char* argv[]) { mtrace(); LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); LOG_INFO << "sizeof TcpConnection = " << sizeof(TcpConnection); - numThreads = argc - 1; + if (argc > 1) + { + numThreads = atoi(argv[1]); + } EventLoop loop; InetAddress listenAddr(2000); EchoServer server(&loop, listenAddr); From 4939882d276ca2857eb44332d2a27c02f89b403c Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 13 Apr 2010 15:27:54 +0000 Subject: [PATCH 037/371] Ignore SIGPIPE. Rename ChannelBuffer to Buffer. --- muduo/base/Singleton.h | 39 +++++++++++++++++++++++ muduo/net/{ChannelBuffer.cc => Buffer.cc} | 4 +-- muduo/net/{ChannelBuffer.h => Buffer.h} | 12 +++---- muduo/net/CMakeLists.txt | 2 +- muduo/net/Callbacks.h | 4 +-- muduo/net/DefaultPoller.cc | 11 ++++++- muduo/net/EventLoop.cc | 15 +++++++++ muduo/net/EventLoop.h | 2 +- muduo/net/TcpConnection.h | 10 +++--- muduo/net/tests/EchoClient_unittest.cc | 2 +- muduo/net/tests/EchoServer_unittest.cc | 2 +- 11 files changed, 83 insertions(+), 20 deletions(-) create mode 100644 muduo/base/Singleton.h rename muduo/net/{ChannelBuffer.cc => Buffer.cc} (91%) rename muduo/net/{ChannelBuffer.h => Buffer.h} (95%) diff --git a/muduo/base/Singleton.h b/muduo/base/Singleton.h new file mode 100644 index 000000000..4bf236987 --- /dev/null +++ b/muduo/base/Singleton.h @@ -0,0 +1,39 @@ +#ifndef MUDUO_BASE_SINGLETON_H +#define MUDUO_BASE_SINGLETON_H + +#include + +template +class Singleton +{ + public: + static T& instance() + { + pthread_once(&ponce_, &Singleton::init); + return *value_; + } + + private: + Singleton(); + Singleton(const Singleton&); + Singleton& operator=(const Singleton&); + ~Singleton(); + + static void init() + { + value_ = new T(); + } + + private: + static pthread_once_t ponce_; + static T* value_; +}; + +template +pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT; + +template +T* Singleton::value_ = NULL; + +#endif + diff --git a/muduo/net/ChannelBuffer.cc b/muduo/net/Buffer.cc similarity index 91% rename from muduo/net/ChannelBuffer.cc rename to muduo/net/Buffer.cc index 445065285..eba643669 100644 --- a/muduo/net/ChannelBuffer.cc +++ b/muduo/net/Buffer.cc @@ -7,7 +7,7 @@ // Author: Shuo Chen (chenshuo at chenshuo dot com) // -#include +#include #include // implicit_cast @@ -17,7 +17,7 @@ using namespace muduo; using namespace muduo::net; -ssize_t ChannelBuffer::readFd(int fd, int* savedErrno) +ssize_t Buffer::readFd(int fd, int* savedErrno) { // FIXME use ioctl/FIONREAD to tell how much to read char extrabuf[65536]; diff --git a/muduo/net/ChannelBuffer.h b/muduo/net/Buffer.h similarity index 95% rename from muduo/net/ChannelBuffer.h rename to muduo/net/Buffer.h index bfba9140b..efff3ecf3 100644 --- a/muduo/net/ChannelBuffer.h +++ b/muduo/net/Buffer.h @@ -8,8 +8,8 @@ // // This is a public header file, it must only include public header files. -#ifndef MUDUO_NET_CHANNELBUFFER_H -#define MUDUO_NET_CHANNELBUFFER_H +#ifndef MUDUO_NET_BUFFER_H +#define MUDUO_NET_BUFFER_H #include #include @@ -34,13 +34,13 @@ namespace net /// | | | | /// 0 <= readerIndex <= writerIndex <= size /// @endcode -class ChannelBuffer : public muduo::copyable +class Buffer : public muduo::copyable { public: static const size_t kCheapPrepend = 8; static const size_t kInitialSize = 1024; - ChannelBuffer() + Buffer() : buffer_(kCheapPrepend + kInitialSize), readerIndex_(kCheapPrepend), writerIndex_(kCheapPrepend) @@ -52,7 +52,7 @@ class ChannelBuffer : public muduo::copyable // default copy-ctor, dtor and assignment are fine - void swap(ChannelBuffer& rhs) + void swap(Buffer& rhs) { buffer_.swap(rhs.buffer_); std::swap(readerIndex_, rhs.readerIndex_); @@ -160,4 +160,4 @@ class ChannelBuffer : public muduo::copyable } } -#endif // MUDUO_NET_CHANNELBUFFER_H +#endif // MUDUO_NET_BUFFER_H diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index b3f704723..fbbd43e81 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -1,7 +1,7 @@ set(net_SRCS Acceptor.cc + Buffer.cc Channel.cc - ChannelBuffer.cc Connector.cc DefaultPoller.cc EPollPoller.cc diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index b8df847ca..c1a6b809f 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -22,7 +22,7 @@ namespace net // All client visible callbacks go here. -class ChannelBuffer; +class Buffer; class TcpConnection; typedef boost::shared_ptr TcpConnectionPtr; typedef boost::function TimerCallback; @@ -30,7 +30,7 @@ typedef boost::function ConnectionCallback; // the data has been read to (buf, len) typedef boost::function MessageCallback; } diff --git a/muduo/net/DefaultPoller.cc b/muduo/net/DefaultPoller.cc index dd92c5cb5..c729047c7 100644 --- a/muduo/net/DefaultPoller.cc +++ b/muduo/net/DefaultPoller.cc @@ -10,9 +10,18 @@ #include #include +#include + using namespace muduo::net; Poller* Poller::newDefaultPoller(EventLoop* loop) { - return new EPollPoller(loop); + if (::getenv("MUDUO_USE_POLL")) + { + return new PollPoller(loop); + } + else + { + return new EPollPoller(loop); + } } diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 3f37bfc0e..497dc93fa 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -10,12 +10,14 @@ #include #include +#include #include #include #include #include +#include #include using namespace muduo; @@ -37,6 +39,18 @@ int createEventfd() } return evtfd; } + +#pragma GCC diagnostic ignored "-Wold-style-cast" +class IgnoreSigPipe +{ + public: + IgnoreSigPipe() + { + ::signal(SIGPIPE, SIG_IGN); + LOG_TRACE << "Ignore SIGPIPE"; + } +}; +#pragma GCC diagnostic error "-Wold-style-cast" } EventLoop::EventLoop() @@ -49,6 +63,7 @@ EventLoop::EventLoop() wakeupFd_(createEventfd()), wakeupChannel_(new Channel(this, wakeupFd_)) { + Singleton::instance(); LOG_TRACE << "EventLoop created " << this << " in thread " << threadId_; if (t_loopInThisThread) { diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 2e0e846fe..d3335f530 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -107,7 +107,7 @@ class EventLoop : boost::noncopyable boost::scoped_ptr poller_; boost::scoped_ptr timerQueue_; int wakeupFd_; - // unlink in TimerQueue, which is an internal class, + // unlike in TimerQueue, which is an internal class, // we don't expose Channel to client. boost::scoped_ptr wakeupChannel_; ChannelList activeChannels_; diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index b2a5726ff..f5977d421 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -57,8 +57,8 @@ class TcpConnection : public boost::enable_shared_from_this, // void send(string&& message); void send(const string& message); - // void send(const ChannelBuffer& message); - void send(ChannelBuffer* message); // this one will swap data + // void send(const Buffer& message); + void send(Buffer* message); // this one will swap data void shutdown(); // NOT thread safe, no simultaneous calling void setConnectionCallback(ConnectionCallback cb) @@ -98,9 +98,9 @@ class TcpConnection : public boost::enable_shared_from_this, ConnectionCallback connectionCallback_; MessageCallback messageCallback_; ConnectionCallback closeCallback_; - ChannelBuffer inputBuffer_; + Buffer inputBuffer_; // MutexLock mutex_; - ChannelBuffer outputBuffer_; + Buffer outputBuffer_; }; typedef boost::shared_ptr TcpConnectionPtr; diff --git a/muduo/net/tests/EchoClient_unittest.cc b/muduo/net/tests/EchoClient_unittest.cc index 29661f96f..f5e2487ec 100644 --- a/muduo/net/tests/EchoClient_unittest.cc +++ b/muduo/net/tests/EchoClient_unittest.cc @@ -48,7 +48,7 @@ class EchoClient conn->send("world\n"); } - void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf, Timestamp time) + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) { string msg(buf->retrieveAsString()); LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); diff --git a/muduo/net/tests/EchoServer_unittest.cc b/muduo/net/tests/EchoServer_unittest.cc index 937c15757..9db2828dd 100644 --- a/muduo/net/tests/EchoServer_unittest.cc +++ b/muduo/net/tests/EchoServer_unittest.cc @@ -48,7 +48,7 @@ class EchoServer conn->send("hello\n"); } - void onMessage(const TcpConnectionPtr& conn, ChannelBuffer* buf, Timestamp time) + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) { string msg(buf->retrieveAsString()); LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); From 3a6365c4bb1ba769b519c03e8250b4c6714b5cd1 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 13 Apr 2010 16:56:13 +0000 Subject: [PATCH 038/371] Log errors. --- CMakeLists.txt | 8 +++++- examples/CMakeLists.txt | 2 ++ examples/clockerror/CMakeLists.txt | 3 +++ examples/clockerror/clockerror.cc | 8 ++++++ muduo/base/Singleton.h | 7 ++++++ muduo/net/Connector.cc | 5 ++-- muduo/net/EPollPoller.cc | 1 + muduo/net/TcpConnection.cc | 4 ++- muduo/net/tests/EchoClient_unittest.cc | 35 ++++++++++++++++++++------ 9 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 examples/CMakeLists.txt create mode 100644 examples/clockerror/CMakeLists.txt create mode 100644 examples/clockerror/clockerror.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a4fc3320..c916556c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ project(muduo CXX) set(CXX_FLAGS -g + -DVALGRIND -Wall -Wextra # -Werror @@ -13,7 +14,7 @@ set(CXX_FLAGS -Wpointer-arith -Wshadow -Wwrite-strings - -MMD + # -MMD # -std=c++0x -rdynamic -lpthread @@ -22,8 +23,13 @@ string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "-O0") set(CMAKE_CXX_FLAGS_RELEASE "-O2") # no NDEBUG in Release, keep asserting. +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) +set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) include_directories(${PROJECT_SOURCE_DIR}) + add_subdirectory(muduo/base) add_subdirectory(muduo/net) +add_subdirectory(examples) + diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 000000000..5b09ece1d --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(clockerror) + diff --git a/examples/clockerror/CMakeLists.txt b/examples/clockerror/CMakeLists.txt new file mode 100644 index 000000000..28cc009aa --- /dev/null +++ b/examples/clockerror/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(clockerror clockerror.cc) +target_link_libraries(clockerror muduo_net) + diff --git a/examples/clockerror/clockerror.cc b/examples/clockerror/clockerror.cc new file mode 100644 index 000000000..c6db2a199 --- /dev/null +++ b/examples/clockerror/clockerror.cc @@ -0,0 +1,8 @@ +#include +#include +#include + +int main(int argc, char* argv) +{ +} + diff --git a/muduo/base/Singleton.h b/muduo/base/Singleton.h index 4bf236987..3f8130054 100644 --- a/muduo/base/Singleton.h +++ b/muduo/base/Singleton.h @@ -2,6 +2,7 @@ #define MUDUO_BASE_SINGLETON_H #include +#include // atexit template class Singleton @@ -22,6 +23,12 @@ class Singleton static void init() { value_ = new T(); + atexit(destroy); + } + + static void destroy() + { + delete value_; } private: diff --git a/muduo/net/Connector.cc b/muduo/net/Connector.cc index cf57b0f00..831fec53a 100644 --- a/muduo/net/Connector.cc +++ b/muduo/net/Connector.cc @@ -59,6 +59,7 @@ void Connector::startInLoop() case EAGAIN: case EADDRINUSE: + case EADDRNOTAVAIL: case ECONNREFUSED: case ENETUNREACH: retry(sockfd); @@ -71,12 +72,12 @@ void Connector::startInLoop() case EBADF: case EFAULT: case ENOTSOCK: - LOG_SYSERR << "connect error in Connector::startInLoop."; + LOG_SYSERR << "connect error in Connector::startInLoop " << savedErrno; sockets::close(sockfd); break; default: - LOG_SYSERR << "Unexpected error in Connector::startInLoop."; + LOG_SYSERR << "Unexpected error in Connector::startInLoop " << savedErrno; sockets::close(sockfd); // connectErrorCallback_(); break; diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc index 1871dd2ae..33ed78ba5 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/EPollPoller.cc @@ -131,6 +131,7 @@ void EPollPoller::removeChannel(Channel* channel) void EPollPoller::update(int operation, Channel* channel) { struct epoll_event event; + bzero(&event, sizeof event); event.events = channel->events(); event.data.ptr = channel; if (::epoll_ctl(epollfd_, operation, channel->fd(), &event) < 0) diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 7cfc835a8..1a0212171 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -191,6 +191,8 @@ void TcpConnection::handleClose() void TcpConnection::handleError() { - LOG_ERROR << "TcpConnection::handleError"; + int err = sockets::getSocketError(channel_->fd()); + LOG_ERROR << "TcpConnection::handleError [" << name_ + << "] - SO_ERROR = " << err << " " << strerror_tl(err); } diff --git a/muduo/net/tests/EchoClient_unittest.cc b/muduo/net/tests/EchoClient_unittest.cc index f5e2487ec..8909b99b7 100644 --- a/muduo/net/tests/EchoClient_unittest.cc +++ b/muduo/net/tests/EchoClient_unittest.cc @@ -18,18 +18,18 @@ using namespace muduo::net; int numThreads = 0; -class EchoClient +class EchoClient : boost::noncopyable { public: - EchoClient(EventLoop* loop, const InetAddress& listenAddr) + EchoClient(EventLoop* loop, const InetAddress& listenAddr, const string& id) : loop_(loop), - client_(loop, listenAddr, "EchoClient") + client_(loop, listenAddr, "EchoClient"+id) { client_.setConnectionCallback( boost::bind(&EchoClient::onConnection, this, _1)); client_.setMessageCallback( boost::bind(&EchoClient::onMessage, this, _1, _2, _3)); - client_.enableRetry(); + //client_.enableRetry(); } void connect() @@ -52,6 +52,7 @@ class EchoClient { string msg(buf->retrieveAsString()); LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); + /* if (msg == "exit\n") { conn->send("bye\n"); @@ -62,6 +63,7 @@ class EchoClient loop_->quit(); } conn->send(msg); + */ } EventLoop* loop_; @@ -75,14 +77,33 @@ int main(int argc, char* argv[]) { EventLoop loop; InetAddress serverAddr(argv[1], 2000); - EchoClient client(&loop, serverAddr); - client.connect(); + int n = 1; + if (argc > 2) + { + n = atoi(argv[2]); + } + + std::vector clients; + clients.reserve(n); + for (int i = 0; i < n; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "%d", i+1); + clients.push_back(new EchoClient(&loop, serverAddr, buf)); + clients.back()->connect(); + } + loop.loop(); + while (!clients.empty()) + { + delete clients.back(); + clients.pop_back(); + } } else { - printf("Usage: %s host_ip\n", argv[0]); + printf("Usage: %s host_ip [current#]\n", argv[0]); } } From 9d8de05174874e313e1e87a82cc7ef2186312259 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Wed, 14 Apr 2010 00:48:56 +0000 Subject: [PATCH 039/371] Clock error works. Set default message & connection callbacks for client and server. Send immediately if output buffer is empty. --- examples/clockerror/clockerror.cc | 106 +++++++++++++++++++++++++++++- muduo/net/Callbacks.h | 7 +- muduo/net/EventLoop.h | 4 ++ muduo/net/TcpClient.cc | 2 + muduo/net/TcpConnection.cc | 66 +++++++++++++++++-- muduo/net/TcpConnection.h | 2 + muduo/net/TcpServer.cc | 2 + 7 files changed, 183 insertions(+), 6 deletions(-) diff --git a/examples/clockerror/clockerror.cc b/examples/clockerror/clockerror.cc index c6db2a199..4e2a8e9d1 100644 --- a/examples/clockerror/clockerror.cc +++ b/examples/clockerror/clockerror.cc @@ -1,8 +1,112 @@ +#include #include #include #include -int main(int argc, char* argv) +#include + +using namespace muduo; +using namespace muduo::net; + +const size_t frameLen = 2*sizeof(int64_t); + +void serverMessageCallback(const TcpConnectionPtr& conn, + Buffer* buffer, + muduo::Timestamp receiveTime) +{ + int64_t message[2]; + if (buffer->readableBytes() >= frameLen) + { + memcpy(message, buffer->peek(), frameLen); + buffer->retrieve(frameLen); + message[1] = receiveTime.microSecondsSinceEpoch(); + conn->send(message, sizeof message); + } +} + +void runServer(uint16_t port) +{ + EventLoop loop; + TcpServer server(&loop, InetAddress(port), "ClockServer"); + server.setMessageCallback(serverMessageCallback); + server.start(); + loop.loop(); +} + +TcpConnectionPtr clientConnection; + +void clientConnectionCallback(const TcpConnectionPtr& conn) +{ + LOG_TRACE << conn->localAddress().toHostPort() << " -> " + << conn->peerAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + if (conn->connected()) + { + clientConnection = conn; + } + else + { + clientConnection.reset(); + } +} + +void clientMessageCallback(const TcpConnectionPtr&, + Buffer* buffer, + muduo::Timestamp receiveTime) +{ + int64_t message[2]; + if (buffer->readableBytes() >= frameLen) + { + memcpy(message, buffer->peek(), frameLen); + buffer->retrieve(frameLen); + int64_t send = message[0]; + int64_t their = message[1]; + int64_t back = receiveTime.microSecondsSinceEpoch(); + int64_t mine = (back+send)/2; + LOG_INFO << "round trip " << back - send + << " clock error " << their - mine; + } +} + +void sendMyTime() +{ + if (clientConnection) + { + int64_t message[2] = { 0, 0 }; + message[0] = Timestamp::now().microSecondsSinceEpoch(); + clientConnection->send(message, sizeof message); + } +} + +void runClient(const char* ip, uint16_t port) +{ + EventLoop loop; + TcpClient client(&loop, InetAddress(ip, port), "ClockClient"); + client.enableRetry(); + client.setConnectionCallback(clientConnectionCallback); + client.setMessageCallback(clientMessageCallback); + client.connect(); + loop.runEvery(0.1, sendMyTime); + loop.loop(); +} + +int main(int argc, char* argv[]) { + if (argc > 2) + { + uint16_t port = static_cast(atoi(argv[2])); + if (strcmp(argv[1], "-s") == 0) + { + runServer(port); + } + else + { + runClient(argv[1], port); + } + } + else + { + printf("Usage:\n%s -s port\n%s ip port\n", argv[0], argv[0]); + } } diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index c1a6b809f..c14991150 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -31,7 +31,12 @@ typedef boost::function ConnectionCallback; // the data has been read to (buf, len) typedef boost::function MessageCallback; + Timestamp)> MessageCallback; + +void defaultConnectionCallback(const TcpConnectionPtr& conn); +void defaultMessageCallback(const TcpConnectionPtr& conn, + Buffer* buffer, + Timestamp receiveTime); } } diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index d3335f530..5dc80a727 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -54,6 +54,10 @@ class EventLoop : boost::noncopyable void quit(); void wakeup(); + /// Time when poll returns, usually means data arrivial. + /// + Timestamp receiveTime(); + // timers /// Runs callback immediately in the loop thread. diff --git a/muduo/net/TcpClient.cc b/muduo/net/TcpClient.cc index 783f19c1a..1dd03b1e0 100644 --- a/muduo/net/TcpClient.cc +++ b/muduo/net/TcpClient.cc @@ -39,6 +39,8 @@ TcpClient::TcpClient(EventLoop* loop, : loop_(CHECK_NOTNULL(loop)), connector_(new Connector(loop, serverAddr)), name_(name), + connectionCallback_(defaultConnectionCallback), + messageCallback_(defaultMessageCallback), retry_(false), nextConnId_(1) { diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 1a0212171..60f50045f 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -22,6 +22,19 @@ using namespace muduo; using namespace muduo::net; +void muduo::net::defaultConnectionCallback(const TcpConnectionPtr& conn) +{ + LOG_TRACE << conn->localAddress().toHostPort() << " -> " + << conn->peerAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); +} + +void muduo::net::defaultMessageCallback(const TcpConnectionPtr&, + Buffer*, + Timestamp) +{ +} + TcpConnection::TcpConnection(EventLoop* loop, const string& name__, int fd, @@ -51,6 +64,25 @@ TcpConnection::~TcpConnection() printf("%p %s dtor\n", this, name_.c_str()); } +void TcpConnection::send(const void* data, size_t len) +{ + if (state_ == kConnected) + { + if (loop_->isInLoopThread()) + { + sendInLoop(data, len); + } + else + { + string message(static_cast(data), len); + loop_->runInLoop( + boost::bind(&TcpConnection::sendInLoop, + this, + message)); + } + } +} + void TcpConnection::send(const string& message) { if (state_ == kConnected) @@ -71,13 +103,39 @@ void TcpConnection::send(const string& message) } void TcpConnection::sendInLoop(const string& message) +{ + sendInLoop(message.data(), message.size()); +} + +void TcpConnection::sendInLoop(const void* data, size_t len) { loop_->assertInLoopThread(); - // FIXME: try writing here, until EWOULDBLOCK - outputBuffer_.append(message.data(), message.size()); - if (!channel_->isWriting()) + ssize_t nwrote = 0; + if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0) { - channel_->enableWriting(); + nwrote = ::write(channel_->fd(), data, len); + if (nwrote >= 0) + { + if (implicit_cast(nwrote) < len) + { + LOG_TRACE << "I am going to write more data"; + } + } + else// if (errno != EWOULDBLOCK) + { + nwrote = 0; + LOG_SYSERR << "TcpConnection::handleWrite"; + } + } + + assert(nwrote >= 0); + if (implicit_cast(nwrote) < len) + { + outputBuffer_.append(static_cast(data)+nwrote, len); + if (!channel_->isWriting()) + { + channel_->enableWriting(); + } } } diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index f5977d421..dc08a64dc 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -56,6 +56,7 @@ class TcpConnection : public boost::enable_shared_from_this, bool connected() const { return state_ == kConnected; } // void send(string&& message); + void send(const void* message, size_t len); void send(const string& message); // void send(const Buffer& message); void send(Buffer* message); // this one will swap data @@ -84,6 +85,7 @@ class TcpConnection : public boost::enable_shared_from_this, void handleError(); //void sendInLoop(string&& message); void sendInLoop(const string& message); + void sendInLoop(const void* message, size_t len); void shutdownInLoop(); void setState(States s) { state_ = s; } diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 7a8113315..403fbbd66 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -29,6 +29,8 @@ TcpServer::TcpServer(EventLoop* loop, name_(name), acceptor_(new Acceptor(loop, listenAddr)), threadPool_(new EventLoopPool(loop)), + connectionCallback_(defaultConnectionCallback), + messageCallback_(defaultMessageCallback), started_(false), nextConnId_(1) { From 786613061fae56100dc35eab95af3a69e82d37fb Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Wed, 14 Apr 2010 16:48:02 +0000 Subject: [PATCH 040/371] Connects gracefully. --- muduo/base/Logging.cc | 14 ++++++++++---- muduo/net/EPollPoller.cc | 2 +- muduo/net/SocketsOps.cc | 26 ++++++++++++++++++-------- muduo/net/tests/EchoClient_unittest.cc | 15 +++++++++++++-- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/muduo/base/Logging.cc b/muduo/base/Logging.cc index 114207901..d2c487ebf 100644 --- a/muduo/base/Logging.cc +++ b/muduo/base/Logging.cc @@ -16,6 +16,7 @@ class LoggerImpl public: typedef Logger::LogLevel LogLevel; LoggerImpl(LogLevel level, int old_errno, const char* file, int line); + void finish(); Timestamp time_; std::ostringstream stream_; @@ -61,16 +62,21 @@ LoggerImpl::LoggerImpl(LogLevel level, int savedErrno, const char* file, int lin const char* path_sep_pos = strrchr(fullname_, '/'); basename_ = (path_sep_pos != NULL) ? path_sep_pos + 1 : fullname_; char message_head[512]; - snprintf(message_head, sizeof(message_head), "%s %5d %s:%d %s ", + snprintf(message_head, sizeof(message_head), "%s %5d %s ", time_.toFormattedString().c_str(), CurrentThread::tid(), - basename_, line_, LogLevelName[level]); + LogLevelName[level]); stream_ << message_head; if (savedErrno != 0) { - stream_ << strerror_tl(savedErrno) << " "; + stream_ << strerror_tl(savedErrno) << " (" << savedErrno << ")"; } } +void LoggerImpl::finish() +{ + stream_ << " - " << basename_ << ":" << line_ << '\n'; +} + std::ostream& Logger::stream() { return impl_->stream_; @@ -99,7 +105,7 @@ Logger::Logger(const char* file, int line, bool toAbort) Logger::~Logger() { - impl_->stream_ << '\n'; + impl_->finish(); std::string buf(impl_->stream_.str()); ssize_t n = ::write(1, buf.data(), buf.size()); if (impl_->level_ == FATAL) diff --git a/muduo/net/EPollPoller.cc b/muduo/net/EPollPoller.cc index 33ed78ba5..4e427665c 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/EPollPoller.cc @@ -59,7 +59,7 @@ Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) fillActiveChannels(numEvents, activeChannels); if (implicit_cast(numEvents) == events_.size()) { - events_.resize(events_.size()+1); + events_.resize(events_.size()*2); } } else if (numEvents == 0) diff --git a/muduo/net/SocketsOps.cc b/muduo/net/SocketsOps.cc index 0a05a09f6..d9c2fe84a 100644 --- a/muduo/net/SocketsOps.cc +++ b/muduo/net/SocketsOps.cc @@ -20,6 +20,9 @@ using namespace muduo; using namespace muduo::net; +namespace +{ + typedef struct sockaddr SA; const SA* sockaddr_cast(const struct sockaddr_in* addr) @@ -32,15 +35,8 @@ SA* sockaddr_cast(struct sockaddr_in* addr) return static_cast(implicit_cast(addr)); } -int sockets::createNonblockingOrDie() +void setNonBlockAndCloseOnExec(int sockfd) { - // socket - int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sockfd < 0) - { - LOG_SYSFATAL << "sockets::createNonblockingOrDie"; - } - // non-block int flags = ::fcntl(sockfd, F_GETFL, 0); flags |= O_NONBLOCK; @@ -52,7 +48,20 @@ int sockets::createNonblockingOrDie() flags |= FD_CLOEXEC; ret = ::fcntl(sockfd, F_SETFD, flags); // FIXME check +} + +} + +int sockets::createNonblockingOrDie() +{ + // socket + int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd < 0) + { + LOG_SYSFATAL << "sockets::createNonblockingOrDie"; + } + setNonBlockAndCloseOnExec(sockfd); return sockfd; } @@ -79,6 +88,7 @@ int sockets::accept(int sockfd, struct sockaddr_in* addr) socklen_t addrlen = sizeof *addr; #if VALGRIND int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); + setNonBlockAndCloseOnExec(connfd); #else int connfd = ::accept4(sockfd, sockaddr_cast(addr), &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); diff --git a/muduo/net/tests/EchoClient_unittest.cc b/muduo/net/tests/EchoClient_unittest.cc index 8909b99b7..3d1a51d14 100644 --- a/muduo/net/tests/EchoClient_unittest.cc +++ b/muduo/net/tests/EchoClient_unittest.cc @@ -17,6 +17,9 @@ using namespace muduo; using namespace muduo::net; int numThreads = 0; +class EchoClient; +std::vector clients; +int current = 0; class EchoClient : boost::noncopyable { @@ -45,6 +48,15 @@ class EchoClient : boost::noncopyable << conn->peerAddress().toHostPort() << " is " << (conn->connected() ? "UP" : "DOWN"); + if (conn->connected()) + { + ++current; + if (current < clients.size()) + { + clients[current]->connect(); + } + LOG_INFO << "*** connected " << current; + } conn->send("world\n"); } @@ -84,16 +96,15 @@ int main(int argc, char* argv[]) n = atoi(argv[2]); } - std::vector clients; clients.reserve(n); for (int i = 0; i < n; ++i) { char buf[32]; snprintf(buf, sizeof buf, "%d", i+1); clients.push_back(new EchoClient(&loop, serverAddr, buf)); - clients.back()->connect(); } + clients[current]->connect(); loop.loop(); while (!clients.empty()) { From a06e91bf158d199eb532bd3e8b5ae11f32670008 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 16 Apr 2010 02:22:35 +0000 Subject: [PATCH 041/371] Add EventLoopThread. --- muduo/net/CMakeLists.txt | 1 + muduo/net/EventLoopThread.cc | 64 ++++++++++++++++++++++++++++++++++++ muduo/net/EventLoopThread.h | 51 ++++++++++++++++++++++++++++ muduo/net/TcpConnection.cc | 2 ++ 4 files changed, 118 insertions(+) create mode 100644 muduo/net/EventLoopThread.cc create mode 100644 muduo/net/EventLoopThread.h diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index fbbd43e81..1606f0531 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -7,6 +7,7 @@ set(net_SRCS EPollPoller.cc EventLoop.cc EventLoopPool.cc + EventLoopThread.cc InetAddress.cc Poller.cc PollPoller.cc diff --git a/muduo/net/EventLoopThread.cc b/muduo/net/EventLoopThread.cc new file mode 100644 index 000000000..c708b413f --- /dev/null +++ b/muduo/net/EventLoopThread.cc @@ -0,0 +1,64 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include + +#include + +#include + +using namespace muduo; +using namespace muduo::net; + + +EventLoopThread::EventLoopThread() + : loop_(NULL), + exiting_(false), + thread_(boost::bind(&EventLoopThread::threadFunc, this)), + mutex_(), + cond_(mutex_) +{ +} + +EventLoopThread::~EventLoopThread() +{ + exiting_ = true; + loop_->quit(); + thread_.join(); +} + +EventLoop* EventLoopThread::startLoop() +{ + assert(!thread_.started()); + thread_.start(); + + { + MutexLockGuard lock(mutex_); + while (loop_ == NULL) + { + cond_.wait(); + } + } + + return loop_; +} + +void EventLoopThread::threadFunc() +{ + EventLoop loop; + + { + MutexLockGuard lock(mutex_); + loop_ = &loop; + cond_.notify(); + } + + loop.loop(); + assert(exiting_); +} + diff --git a/muduo/net/EventLoopThread.h b/muduo/net/EventLoopThread.h new file mode 100644 index 000000000..f1d4d35a1 --- /dev/null +++ b/muduo/net/EventLoopThread.h @@ -0,0 +1,51 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_EVENTLOOPTHREAD_H +#define MUDUO_NET_EVENTLOOPTHREAD_H + +#include +#include +#include + +#include + +namespace muduo +{ + +class Thread; + +namespace net +{ + +class EventLoop; + +class EventLoopThread : boost::noncopyable +{ + public: + EventLoopThread(); + ~EventLoopThread(); + EventLoop* startLoop(); + + private: + void threadFunc(); + + EventLoop* loop_; + bool exiting_; + Thread thread_; + MutexLock mutex_; + Condition cond_; +}; + +} +} + +#endif // MUDUO_NET_EVENTLOOPTHREAD_H + diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 60f50045f..1609b9450 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -226,6 +226,7 @@ void TcpConnection::handleWrite() else { LOG_SYSERR << "TcpConnection::handleWrite"; + abort(); // FIXME } } else @@ -252,5 +253,6 @@ void TcpConnection::handleError() int err = sockets::getSocketError(channel_->fd()); LOG_ERROR << "TcpConnection::handleError [" << name_ << "] - SO_ERROR = " << err << " " << strerror_tl(err); + abort(); // FIXME } From 9626660b349743e1f6717886d7d928805a7cdea2 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 16 Apr 2010 02:23:22 +0000 Subject: [PATCH 042/371] rename clockerror to roundtrip. --- CMakeLists.txt | 4 ++++ examples/CMakeLists.txt | 2 +- examples/clockerror/CMakeLists.txt | 3 --- examples/roundtrip/CMakeLists.txt | 3 +++ examples/{clockerror/clockerror.cc => roundtrip/roundtrip.cc} | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) delete mode 100644 examples/clockerror/CMakeLists.txt create mode 100644 examples/roundtrip/CMakeLists.txt rename examples/{clockerror/clockerror.cc => roundtrip/roundtrip.cc} (98%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c916556c9..f479ea5c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,10 @@ project(muduo CXX) set(CXX_FLAGS -g -DVALGRIND + # -DMUDUO_STD_STRING -Wall -Wextra + # -m32 # -Werror -Wconversion -Wunused-parameter @@ -21,6 +23,8 @@ set(CXX_FLAGS ) string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") +set(CMAKE_CXX_COMPILER "g++") +#set(CMAKE_CXX_COMPILER "icpc") set(CMAKE_CXX_FLAGS_DEBUG "-O0") set(CMAKE_CXX_FLAGS_RELEASE "-O2") # no NDEBUG in Release, keep asserting. set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5b09ece1d..56a132266 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(clockerror) +add_subdirectory(roundtrip) diff --git a/examples/clockerror/CMakeLists.txt b/examples/clockerror/CMakeLists.txt deleted file mode 100644 index 28cc009aa..000000000 --- a/examples/clockerror/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_executable(clockerror clockerror.cc) -target_link_libraries(clockerror muduo_net) - diff --git a/examples/roundtrip/CMakeLists.txt b/examples/roundtrip/CMakeLists.txt new file mode 100644 index 000000000..5b60e36c5 --- /dev/null +++ b/examples/roundtrip/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(roundtrip roundtrip.cc) +target_link_libraries(roundtrip muduo_net) + diff --git a/examples/clockerror/clockerror.cc b/examples/roundtrip/roundtrip.cc similarity index 98% rename from examples/clockerror/clockerror.cc rename to examples/roundtrip/roundtrip.cc index 4e2a8e9d1..14acddec8 100644 --- a/examples/clockerror/clockerror.cc +++ b/examples/roundtrip/roundtrip.cc @@ -86,7 +86,7 @@ void runClient(const char* ip, uint16_t port) client.setConnectionCallback(clientConnectionCallback); client.setMessageCallback(clientMessageCallback); client.connect(); - loop.runEvery(0.1, sendMyTime); + loop.runEvery(0.2, sendMyTime); loop.loop(); } From 738d2dd66308794861609cff08c8b8b77512486f Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 16 Apr 2010 16:14:32 +0000 Subject: [PATCH 043/371] Implements EventLoopThreadPool with EventLoopThread. --- muduo/net/EventLoopPool.cc | 61 ++++++-------------------- muduo/net/EventLoopPool.h | 15 +++---- muduo/net/TcpServer.cc | 2 +- muduo/net/TcpServer.h | 4 +- muduo/net/tests/ThreadPool_unittest.cc | 6 +-- 5 files changed, 26 insertions(+), 62 deletions(-) diff --git a/muduo/net/EventLoopPool.cc b/muduo/net/EventLoopPool.cc index 2d78abf85..895f83489 100644 --- a/muduo/net/EventLoopPool.cc +++ b/muduo/net/EventLoopPool.cc @@ -8,8 +8,8 @@ #include -#include #include +#include #include @@ -17,69 +17,50 @@ using namespace muduo; using namespace muduo::net; -EventLoopPool::EventLoopPool(EventLoop* baseLoop) +EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop) : baseLoop_(baseLoop), started_(false), - exiting_(false), numThreads_(0), - next_(0), - mutex_(), - cond_(mutex_) + next_(0) { } -EventLoopPool::~EventLoopPool() +EventLoopThreadPool::~EventLoopThreadPool() { - exiting_ = true; - for (size_t i = 0; i < loopPool_.size(); ++i) - { - loopPool_[i]->quit(); - // Don't delete loop, it's stack variable - } + // Don't delete loop, it's stack variable + for (size_t i = 0; i < threads_.size(); ++i) { - Thread* t = threads_[i]; - t->join(); - delete t; + delete threads_[i]; } } -void EventLoopPool::start() +void EventLoopThreadPool::start() { assert(!started_); baseLoop_->assertInLoopThread(); started_ = true; - Thread::ThreadFunc func = boost::bind(&EventLoopPool::threadFunc, this); - for (int i = 0; i < numThreads_; ++i) { - Thread* t = new Thread(func); - t->start(); + EventLoopThread* t = new EventLoopThread; threads_.push_back(t); - } - - { - MutexLockGuard lock(mutex_); - while (static_cast(loopPool_.size()) != numThreads_) - { - cond_.wait(); - } + loops_.push_back(t->startLoop()); } } -EventLoop* EventLoopPool::getNextLoop() +EventLoop* EventLoopThreadPool::getNextLoop() { baseLoop_->assertInLoopThread(); EventLoop* loop = baseLoop_; - if (!loopPool_.empty()) + if (!loops_.empty()) { // round-robin - loop = loopPool_[next_]; + loop = loops_[next_]; ++next_; - if (next_ >= static_cast(loopPool_.size())) + if (implicit_cast(next_) >= loops_.size()) { next_ = 0; } @@ -87,17 +68,3 @@ EventLoop* EventLoopPool::getNextLoop() return loop; } -void EventLoopPool::threadFunc() -{ - EventLoop loop; - - { - MutexLockGuard lock(mutex_); - loopPool_.push_back(&loop); - cond_.notify(); - } - - loop.loop(); - assert(exiting_); -} - diff --git a/muduo/net/EventLoopPool.h b/muduo/net/EventLoopPool.h index c83e3a373..88ac2c2cb 100644 --- a/muduo/net/EventLoopPool.h +++ b/muduo/net/EventLoopPool.h @@ -26,28 +26,25 @@ namespace net { class EventLoop; +class EventLoopThread; -class EventLoopPool : boost::noncopyable +class EventLoopThreadPool : boost::noncopyable { public: - EventLoopPool(EventLoop* baseLoop); - ~EventLoopPool(); + EventLoopThreadPool(EventLoop* baseLoop); + ~EventLoopThreadPool(); void setThreadNum(int numThreads) { numThreads_ = numThreads; } void start(); EventLoop* getNextLoop(); private: - void threadFunc(); EventLoop* baseLoop_; bool started_; - bool exiting_; int numThreads_; int next_; - std::vector threads_; - MutexLock mutex_; - Condition cond_; - std::vector loopPool_; // @GuardedBy mutex_ + std::vector threads_; // FIXME: use unique_ptr + std::vector loops_; }; } diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 403fbbd66..4aa7b42d7 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -28,7 +28,7 @@ TcpServer::TcpServer(EventLoop* loop, hostport_(listenAddr.toHostPort()), name_(name), acceptor_(new Acceptor(loop, listenAddr)), - threadPool_(new EventLoopPool(loop)), + threadPool_(new EventLoopThreadPool(loop)), connectionCallback_(defaultConnectionCallback), messageCallback_(defaultMessageCallback), started_(false), diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index 6039b42f1..b0d629ccb 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -26,7 +26,7 @@ namespace net class Acceptor; class EventLoop; -class EventLoopPool; +class EventLoopThreadPool; /// /// TCP server, supports single-threaded and thread-pool models. @@ -86,7 +86,7 @@ class TcpServer : boost::noncopyable const string hostport_; const string name_; boost::scoped_ptr acceptor_; // avoid revealing Acceptor - boost::scoped_ptr threadPool_; + boost::scoped_ptr threadPool_; ConnectionCallback connectionCallback_; MessageCallback messageCallback_; bool started_; diff --git a/muduo/net/tests/ThreadPool_unittest.cc b/muduo/net/tests/ThreadPool_unittest.cc index dea0f1999..89ec0ebc5 100644 --- a/muduo/net/tests/ThreadPool_unittest.cc +++ b/muduo/net/tests/ThreadPool_unittest.cc @@ -23,7 +23,7 @@ int main() { printf("Single thread:\n"); - EventLoopPool model(&loop); + EventLoopThreadPool model(&loop); model.setThreadNum(0); model.start(); assert(model.getNextLoop() == &loop); @@ -33,7 +33,7 @@ int main() { printf("Another thread:\n"); - EventLoopPool model(&loop); + EventLoopThreadPool model(&loop); model.setThreadNum(1); model.start(); EventLoop* nextLoop = model.getNextLoop(); @@ -44,7 +44,7 @@ int main() { printf("Three threads:\n"); - EventLoopPool model(&loop); + EventLoopThreadPool model(&loop); model.setThreadNum(3); model.start(); EventLoop* nextLoop = model.getNextLoop(); From 2ad537148e15a460c01d87ba5b6d562bfd5cc90b Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 16 Apr 2010 16:20:52 +0000 Subject: [PATCH 044/371] Move pollers to net/poller. --- muduo/net/CMakeLists.txt | 8 ++++---- muduo/net/Channel.h | 4 ++-- muduo/net/{EventLoopPool.cc => EventLoopThreadPool.cc} | 2 +- muduo/net/{EventLoopPool.h => EventLoopThreadPool.h} | 6 +++--- muduo/net/TcpServer.cc | 2 +- muduo/net/{ => poller}/DefaultPoller.cc | 4 ++-- muduo/net/{ => poller}/EPollPoller.cc | 2 +- muduo/net/{ => poller}/EPollPoller.h | 6 +++--- muduo/net/{ => poller}/PollPoller.cc | 2 +- muduo/net/{ => poller}/PollPoller.h | 6 +++--- muduo/net/tests/ThreadPool_unittest.cc | 2 +- 11 files changed, 22 insertions(+), 22 deletions(-) rename muduo/net/{EventLoopPool.cc => EventLoopThreadPool.cc} (96%) rename muduo/net/{EventLoopPool.h => EventLoopThreadPool.h} (88%) rename muduo/net/{ => poller}/DefaultPoller.cc (85%) rename muduo/net/{ => poller}/EPollPoller.cc (98%) rename muduo/net/{ => poller}/EPollPoller.h (90%) rename muduo/net/{ => poller}/PollPoller.cc (98%) rename muduo/net/{ => poller}/PollPoller.h (89%) diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 1606f0531..5d00874e4 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -3,14 +3,14 @@ set(net_SRCS Buffer.cc Channel.cc Connector.cc - DefaultPoller.cc - EPollPoller.cc EventLoop.cc - EventLoopPool.cc EventLoopThread.cc + EventLoopThreadPool.cc InetAddress.cc Poller.cc - PollPoller.cc + poller/DefaultPoller.cc + poller/EPollPoller.cc + poller/PollPoller.cc Socket.cc SocketsOps.cc TcpClient.cc diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 21f715ba4..79ac3a2c9 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -65,7 +65,7 @@ class Channel : boost::noncopyable void disableAll() { events_ = kNoneEvent; update(); } bool isWriting() const { return events_ & kWriteEvent; } - // for PollPoller + // for Poller int index() { return index_; } void set_index(int idx) { index_ = idx; } @@ -82,7 +82,7 @@ class Channel : boost::noncopyable const int fd_; int events_; int revents_; - int index_; // used by PollPoller. + int index_; // used by Poller. boost::weak_ptr tie_; bool tied_; diff --git a/muduo/net/EventLoopPool.cc b/muduo/net/EventLoopThreadPool.cc similarity index 96% rename from muduo/net/EventLoopPool.cc rename to muduo/net/EventLoopThreadPool.cc index 895f83489..06aecfa05 100644 --- a/muduo/net/EventLoopPool.cc +++ b/muduo/net/EventLoopThreadPool.cc @@ -6,7 +6,7 @@ // Author: Shuo Chen (chenshuo at chenshuo dot com) -#include +#include #include #include diff --git a/muduo/net/EventLoopPool.h b/muduo/net/EventLoopThreadPool.h similarity index 88% rename from muduo/net/EventLoopPool.h rename to muduo/net/EventLoopThreadPool.h index 88ac2c2cb..1ad975def 100644 --- a/muduo/net/EventLoopPool.h +++ b/muduo/net/EventLoopThreadPool.h @@ -8,8 +8,8 @@ // // This is an internal header file, you should not include this. -#ifndef MUDUO_NET_EVENTLOOPPOOL_H -#define MUDUO_NET_EVENTLOOPPOOL_H +#ifndef MUDUO_NET_EVENTLOOPTHREADPOOL_H +#define MUDUO_NET_EVENTLOOPTHREADPOOL_H #include #include @@ -50,4 +50,4 @@ class EventLoopThreadPool : boost::noncopyable } } -#endif // MUDUO_NET_EVENTLOOPPOOL_H +#endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 4aa7b42d7..20f6d186c 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/muduo/net/DefaultPoller.cc b/muduo/net/poller/DefaultPoller.cc similarity index 85% rename from muduo/net/DefaultPoller.cc rename to muduo/net/poller/DefaultPoller.cc index c729047c7..f42f5a48d 100644 --- a/muduo/net/DefaultPoller.cc +++ b/muduo/net/poller/DefaultPoller.cc @@ -7,8 +7,8 @@ // Author: Shuo Chen (chenshuo at chenshuo dot com) #include -#include -#include +#include +#include #include diff --git a/muduo/net/EPollPoller.cc b/muduo/net/poller/EPollPoller.cc similarity index 98% rename from muduo/net/EPollPoller.cc rename to muduo/net/poller/EPollPoller.cc index 4e427665c..56d92f9cf 100644 --- a/muduo/net/EPollPoller.cc +++ b/muduo/net/poller/EPollPoller.cc @@ -6,7 +6,7 @@ // Author: Shuo Chen (chenshuo at chenshuo dot com) -#include +#include #include #include diff --git a/muduo/net/EPollPoller.h b/muduo/net/poller/EPollPoller.h similarity index 90% rename from muduo/net/EPollPoller.h rename to muduo/net/poller/EPollPoller.h index 8062f7d6e..9b7742791 100644 --- a/muduo/net/EPollPoller.h +++ b/muduo/net/poller/EPollPoller.h @@ -8,8 +8,8 @@ // // This is an internal header file, you should not include this. -#ifndef MUDUO_NET_EPOLLPOLLER_H -#define MUDUO_NET_EPOLLPOLLER_H +#ifndef MUDUO_NET_POLLER_EPOLLPOLLER_H +#define MUDUO_NET_POLLER_EPOLLPOLLER_H #include @@ -53,4 +53,4 @@ class EPollPoller : public Poller } } -#endif // MUDUO_NET_EPOLLPOLLER_H +#endif // MUDUO_NET_POLLER_EPOLLPOLLER_H diff --git a/muduo/net/PollPoller.cc b/muduo/net/poller/PollPoller.cc similarity index 98% rename from muduo/net/PollPoller.cc rename to muduo/net/poller/PollPoller.cc index a5fac978b..3989b88c1 100644 --- a/muduo/net/PollPoller.cc +++ b/muduo/net/poller/PollPoller.cc @@ -6,7 +6,7 @@ // Author: Shuo Chen (chenshuo at chenshuo dot com) -#include +#include #include #include diff --git a/muduo/net/PollPoller.h b/muduo/net/poller/PollPoller.h similarity index 89% rename from muduo/net/PollPoller.h rename to muduo/net/poller/PollPoller.h index 3a0fad988..e6ca2f103 100644 --- a/muduo/net/PollPoller.h +++ b/muduo/net/poller/PollPoller.h @@ -8,8 +8,8 @@ // // This is an internal header file, you should not include this. -#ifndef MUDUO_NET_POLLPOLLER_H -#define MUDUO_NET_POLLPOLLER_H +#ifndef MUDUO_NET_POLLER_POLLPOLLER_H +#define MUDUO_NET_POLLER_POLLPOLLER_H #include @@ -49,4 +49,4 @@ class PollPoller : public Poller } } -#endif // MUDUO_NET_POLLPOLLER_H +#endif // MUDUO_NET_POLLER_POLLPOLLER_H diff --git a/muduo/net/tests/ThreadPool_unittest.cc b/muduo/net/tests/ThreadPool_unittest.cc index 89ec0ebc5..7f098100a 100644 --- a/muduo/net/tests/ThreadPool_unittest.cc +++ b/muduo/net/tests/ThreadPool_unittest.cc @@ -1,4 +1,4 @@ -#include +#include #include #include From 8f2995349173b600b8e5b14625f8b674261df012 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 17 Apr 2010 15:18:56 +0000 Subject: [PATCH 045/371] Condition log. --- muduo/base/Logging.cc | 4 ++++ muduo/base/Logging.h | 4 +++- muduo/net/TimerQueue.cc | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/muduo/base/Logging.cc b/muduo/base/Logging.cc index d2c487ebf..7d791548d 100644 --- a/muduo/base/Logging.cc +++ b/muduo/base/Logging.cc @@ -114,3 +114,7 @@ Logger::~Logger() } } +Logger::LogLevel Logger::logLevel() +{ + return INFO; +} diff --git a/muduo/base/Logging.h b/muduo/base/Logging.h index 7adc9a490..60f38e6ae 100644 --- a/muduo/base/Logging.h +++ b/muduo/base/Logging.h @@ -30,11 +30,13 @@ class Logger std::ostream& stream(); + static LogLevel logLevel(); + private: boost::scoped_ptr impl_; }; -#define LOG_TRACE Logger(__FILE__, __LINE__, Logger::TRACE, __func__).stream() +#define LOG_TRACE if (Logger::logLevel() <= Logger::TRACE) Logger(__FILE__, __LINE__, Logger::TRACE, __func__).stream() #define LOG_DEBUG Logger(__FILE__, __LINE__, Logger::DEBUG, __func__).stream() #define LOG_INFO Logger(__FILE__, __LINE__).stream() #define LOG_WARN Logger(__FILE__, __LINE__, Logger::WARN).stream() diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index 156861fc1..23e167b52 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -97,7 +97,7 @@ void TimerQueue::handleRead() Timestamp now(Timestamp::now()); uint64_t howmany; ssize_t n = ::read(timerfd_, &howmany, sizeof howmany); - LOG_DEBUG << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); + LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); if (n != sizeof howmany) { LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; From 30386401a92a1b4fcaa82d80071b980266df66f2 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 17 Apr 2010 16:41:06 +0000 Subject: [PATCH 046/371] Add simple examples. --- examples/CMakeLists.txt | 1 + examples/simple/CMakeLists.txt | 23 +++++++ examples/simple/allinone/allinone.cc | 33 +++++++++ examples/simple/daytime/daytime.cc | 43 ++++++++++++ examples/simple/daytime/daytime.h | 26 ++++++++ examples/simple/daytime/main.cc | 18 +++++ examples/simple/discard/discard.cc | 40 +++++++++++ examples/simple/discard/discard.h | 25 +++++++ examples/simple/discard/main.cc | 18 +++++ examples/simple/echo/echo.cc | 41 ++++++++++++ examples/simple/echo/echo.h | 25 +++++++ examples/simple/echo/main.cc | 18 +++++ examples/simple/time/main.cc | 18 +++++ examples/simple/time/time.cc | 44 ++++++++++++ examples/simple/time/time.h | 26 ++++++++ examples/simple/timeclient/timeclient.cc | 85 ++++++++++++++++++++++++ muduo/base/Logging.cc | 4 +- muduo/net/Callbacks.h | 3 +- muduo/net/tests/EchoClient_unittest.cc | 2 +- 19 files changed, 489 insertions(+), 4 deletions(-) create mode 100644 examples/simple/CMakeLists.txt create mode 100644 examples/simple/allinone/allinone.cc create mode 100644 examples/simple/daytime/daytime.cc create mode 100644 examples/simple/daytime/daytime.h create mode 100644 examples/simple/daytime/main.cc create mode 100644 examples/simple/discard/discard.cc create mode 100644 examples/simple/discard/discard.h create mode 100644 examples/simple/discard/main.cc create mode 100644 examples/simple/echo/echo.cc create mode 100644 examples/simple/echo/echo.h create mode 100644 examples/simple/echo/main.cc create mode 100644 examples/simple/time/main.cc create mode 100644 examples/simple/time/time.cc create mode 100644 examples/simple/time/time.h create mode 100644 examples/simple/timeclient/timeclient.cc diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 56a132266..587bb00dd 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(roundtrip) +add_subdirectory(simple) diff --git a/examples/simple/CMakeLists.txt b/examples/simple/CMakeLists.txt new file mode 100644 index 000000000..2bfa8518c --- /dev/null +++ b/examples/simple/CMakeLists.txt @@ -0,0 +1,23 @@ +add_executable(simple_discard discard/discard.cc discard/main.cc) +target_link_libraries(simple_discard muduo_net) + +add_executable(simple_daytime daytime/daytime.cc daytime/main.cc) +target_link_libraries(simple_daytime muduo_net) + +add_executable(simple_time time/time.cc time/main.cc) +target_link_libraries(simple_time muduo_net) + +add_executable(simple_echo echo/echo.cc echo/main.cc) +target_link_libraries(simple_echo muduo_net) + +add_executable(simple_allinone + discard/discard.cc + daytime/daytime.cc + time/time.cc + echo/echo.cc + allinone/allinone.cc) +target_link_libraries(simple_allinone muduo_net) + +add_executable(simple_timeclient timeclient/timeclient.cc) +target_link_libraries(simple_timeclient muduo_net) + diff --git a/examples/simple/allinone/allinone.cc b/examples/simple/allinone/allinone.cc new file mode 100644 index 000000000..9f72fcd48 --- /dev/null +++ b/examples/simple/allinone/allinone.cc @@ -0,0 +1,33 @@ +#include "../daytime/daytime.h" +#include "../discard/discard.h" +#include "../echo/echo.h" +#include "../time/time.h" + +#include +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + LOG_INFO << "pid = " << getpid(); + EventLoop loop; + + DaytimeServer daytimeServer(&loop, InetAddress(2013)); + daytimeServer.start(); + + DiscardServer discardServer(&loop, InetAddress(2009)); + discardServer.start(); + + EchoServer echoServer(&loop, InetAddress(2007)); + echoServer.start(); + + TimeServer timeServer(&loop, InetAddress(2037)); + timeServer.start(); + + loop.loop(); +} + diff --git a/examples/simple/daytime/daytime.cc b/examples/simple/daytime/daytime.cc new file mode 100644 index 000000000..80387a225 --- /dev/null +++ b/examples/simple/daytime/daytime.cc @@ -0,0 +1,43 @@ +#include "daytime.h" + +#include +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +DaytimeServer::DaytimeServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "DaytimeServer") +{ + server_.setConnectionCallback( + boost::bind(&DaytimeServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&DaytimeServer::onMessage, this, _1, _2, _3)); +} + +void DaytimeServer::start() +{ + server_.start(); +} + +void DaytimeServer::onConnection(const muduo::net::TcpConnectionPtr& conn) +{ + LOG_INFO << "DaytimeServer - " << conn->peerAddress().toHostPort() << " -> " + << conn->localAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + conn->send(Timestamp::now().toFormattedString() + "\n"); + conn->shutdown(); +} + +void DaytimeServer::onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time) +{ + string msg(buf->retrieveAsString()); + LOG_INFO << conn->name() << " discards " << msg.size() << " bytes at " << time.toString(); +} + diff --git a/examples/simple/daytime/daytime.h b/examples/simple/daytime/daytime.h new file mode 100644 index 000000000..cf0fc1bea --- /dev/null +++ b/examples/simple/daytime/daytime.h @@ -0,0 +1,26 @@ +#ifndef MUDUO_EXAMPLES_SIMPLE_DAYTIME_DAYTIME_H +#define MUDUO_EXAMPLES_SIMPLE_DAYTIME_DAYTIME_H + +#include + +// RFC 867 +class DaytimeServer +{ + public: + DaytimeServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr); + + void start(); + + private: + void onConnection(const muduo::net::TcpConnectionPtr& conn); + + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time); + + muduo::net::EventLoop* loop_; + muduo::net::TcpServer server_; +}; + +#endif // MUDUO_EXAMPLES_SIMPLE_DAYTIME_DAYTIME_H diff --git a/examples/simple/daytime/main.cc b/examples/simple/daytime/main.cc new file mode 100644 index 000000000..061a7b95e --- /dev/null +++ b/examples/simple/daytime/main.cc @@ -0,0 +1,18 @@ +#include "daytime.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + LOG_INFO << "pid = " << getpid(); + EventLoop loop; + InetAddress listenAddr(2013); + DaytimeServer server(&loop, listenAddr); + server.start(); + loop.loop(); +} + diff --git a/examples/simple/discard/discard.cc b/examples/simple/discard/discard.cc new file mode 100644 index 000000000..427d1c0c0 --- /dev/null +++ b/examples/simple/discard/discard.cc @@ -0,0 +1,40 @@ +#include "discard.h" + +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +DiscardServer::DiscardServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "DiscardServer") +{ + server_.setConnectionCallback( + boost::bind(&DiscardServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&DiscardServer::onMessage, this, _1, _2, _3)); +} + +void DiscardServer::start() +{ + server_.start(); +} + +void DiscardServer::onConnection(const muduo::net::TcpConnectionPtr& conn) +{ + LOG_INFO << "DiscardServer - " << conn->peerAddress().toHostPort() << " -> " + << conn->localAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); +} + +void DiscardServer::onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time) +{ + string msg(buf->retrieveAsString()); + LOG_INFO << conn->name() << " discards " << msg.size() << " bytes at " << time.toString(); +} + diff --git a/examples/simple/discard/discard.h b/examples/simple/discard/discard.h new file mode 100644 index 000000000..45f78d348 --- /dev/null +++ b/examples/simple/discard/discard.h @@ -0,0 +1,25 @@ +#ifndef MUDUO_EXAMPLES_SIMPLE_DISCARD_DISCARD_H +#define MUDUO_EXAMPLES_SIMPLE_DISCARD_DISCARD_H + +#include + +class DiscardServer +{ + public: + DiscardServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr); + + void start(); + + private: + void onConnection(const muduo::net::TcpConnectionPtr& conn); + + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time); + + muduo::net::EventLoop* loop_; + muduo::net::TcpServer server_; +}; + +#endif // MUDUO_EXAMPLES_SIMPLE_DISCARD_DISCARD_H diff --git a/examples/simple/discard/main.cc b/examples/simple/discard/main.cc new file mode 100644 index 000000000..b7da9e2a1 --- /dev/null +++ b/examples/simple/discard/main.cc @@ -0,0 +1,18 @@ +#include "discard.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + LOG_INFO << "pid = " << getpid(); + EventLoop loop; + InetAddress listenAddr(2009); + DiscardServer server(&loop, listenAddr); + server.start(); + loop.loop(); +} + diff --git a/examples/simple/echo/echo.cc b/examples/simple/echo/echo.cc new file mode 100644 index 000000000..68f44b727 --- /dev/null +++ b/examples/simple/echo/echo.cc @@ -0,0 +1,41 @@ +#include "echo.h" + +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +EchoServer::EchoServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "EchoServer") +{ + server_.setConnectionCallback( + boost::bind(&EchoServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&EchoServer::onMessage, this, _1, _2, _3)); +} + +void EchoServer::start() +{ + server_.start(); +} + +void EchoServer::onConnection(const muduo::net::TcpConnectionPtr& conn) +{ + LOG_INFO << "EchoServer - " << conn->peerAddress().toHostPort() << " -> " + << conn->localAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); +} + +void EchoServer::onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time) +{ + string msg(buf->retrieveAsString()); + LOG_INFO << conn->name() << " echo " << msg.size() << " bytes at " << time.toString(); + conn->send(msg); +} + diff --git a/examples/simple/echo/echo.h b/examples/simple/echo/echo.h new file mode 100644 index 000000000..8a2a1268f --- /dev/null +++ b/examples/simple/echo/echo.h @@ -0,0 +1,25 @@ +#ifndef MUDUO_EXAMPLES_SIMPLE_ECHO_ECHO_H +#define MUDUO_EXAMPLES_SIMPLE_ECHO_ECHO_H + +#include + +class EchoServer +{ + public: + EchoServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr); + + void start(); + + private: + void onConnection(const muduo::net::TcpConnectionPtr& conn); + + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time); + + muduo::net::EventLoop* loop_; + muduo::net::TcpServer server_; +}; + +#endif // MUDUO_EXAMPLES_SIMPLE_ECHO_ECHO_H diff --git a/examples/simple/echo/main.cc b/examples/simple/echo/main.cc new file mode 100644 index 000000000..306ee311a --- /dev/null +++ b/examples/simple/echo/main.cc @@ -0,0 +1,18 @@ +#include "echo.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + LOG_INFO << "pid = " << getpid(); + EventLoop loop; + InetAddress listenAddr(2007); + EchoServer server(&loop, listenAddr); + server.start(); + loop.loop(); +} + diff --git a/examples/simple/time/main.cc b/examples/simple/time/main.cc new file mode 100644 index 000000000..1e1a1f6dc --- /dev/null +++ b/examples/simple/time/main.cc @@ -0,0 +1,18 @@ +#include "time.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + LOG_INFO << "pid = " << getpid(); + EventLoop loop; + InetAddress listenAddr(2037); + TimeServer server(&loop, listenAddr); + server.start(); + loop.loop(); +} + diff --git a/examples/simple/time/time.cc b/examples/simple/time/time.cc new file mode 100644 index 000000000..6bf124baa --- /dev/null +++ b/examples/simple/time/time.cc @@ -0,0 +1,44 @@ +#include "time.h" + +#include +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +TimeServer::TimeServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "TimeServer") +{ + server_.setConnectionCallback( + boost::bind(&TimeServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&TimeServer::onMessage, this, _1, _2, _3)); +} + +void TimeServer::start() +{ + server_.start(); +} + +void TimeServer::onConnection(const muduo::net::TcpConnectionPtr& conn) +{ + LOG_INFO << "TimeServer - " << conn->peerAddress().toHostPort() << " -> " + << conn->localAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + int32_t now = sockets::hostToNetwork32(static_cast(::time(NULL))); + conn->send(&now, sizeof now); + conn->shutdown(); +} + +void TimeServer::onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time) +{ + string msg(buf->retrieveAsString()); + LOG_INFO << conn->name() << " discards " << msg.size() << " bytes at " << time.toString(); +} + diff --git a/examples/simple/time/time.h b/examples/simple/time/time.h new file mode 100644 index 000000000..c67b51b48 --- /dev/null +++ b/examples/simple/time/time.h @@ -0,0 +1,26 @@ +#ifndef MUDUO_EXAMPLES_SIMPLE_TIME_TIME_H +#define MUDUO_EXAMPLES_SIMPLE_TIME_TIME_H + +#include + +// RFC 868 +class TimeServer +{ + public: + TimeServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr); + + void start(); + + private: + void onConnection(const muduo::net::TcpConnectionPtr& conn); + + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time); + + muduo::net::EventLoop* loop_; + muduo::net::TcpServer server_; +}; + +#endif // MUDUO_EXAMPLES_SIMPLE_TIME_TIME_H diff --git a/examples/simple/timeclient/timeclient.cc b/examples/simple/timeclient/timeclient.cc new file mode 100644 index 000000000..2b44dd9e9 --- /dev/null +++ b/examples/simple/timeclient/timeclient.cc @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +class TimeClient : boost::noncopyable +{ + public: + TimeClient(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + client_(loop, listenAddr, "TimeClient") + { + client_.setConnectionCallback( + boost::bind(&TimeClient::onConnection, this, _1)); + client_.setMessageCallback( + boost::bind(&TimeClient::onMessage, this, _1, _2, _3)); + client_.enableRetry(); + } + + void connect() + { + client_.connect(); + } + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_INFO << conn->localAddress().toHostPort() << " -> " + << conn->peerAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + + if (!conn->connected()) + loop_->quit(); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime) + { + if (buf->readableBytes() >= sizeof(int32_t)) + { + const void* data = buf->peek(); + int32_t time = *static_cast(data); + time_t servertime = sockets::networkToHost32(time); + Timestamp t(servertime * Timestamp::kMicroSecondsPerSecond); + LOG_INFO << "Server time = " << servertime << ", " << t.toFormattedString(); + } + else + { + LOG_INFO << conn->name() << " no enough data " << buf->readableBytes() + << " at " << receiveTime.toFormattedString(); + } + } + + EventLoop* loop_; + TcpClient client_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid(); + if (argc > 1) + { + EventLoop loop; + InetAddress serverAddr(argv[1], 2037); + + TimeClient timeClient(&loop, serverAddr); + timeClient.connect(); + loop.loop(); + } + else + { + printf("Usage: %s host_ip\n", argv[0]); + } +} + diff --git a/muduo/base/Logging.cc b/muduo/base/Logging.cc index 7d791548d..54b4ae493 100644 --- a/muduo/base/Logging.cc +++ b/muduo/base/Logging.cc @@ -3,7 +3,7 @@ #include #include -#include // for errno +#include #include #include @@ -68,7 +68,7 @@ LoggerImpl::LoggerImpl(LogLevel level, int savedErrno, const char* file, int lin stream_ << message_head; if (savedErrno != 0) { - stream_ << strerror_tl(savedErrno) << " (" << savedErrno << ")"; + stream_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") "; } } diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index c14991150..170777031 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -14,9 +14,10 @@ #include #include +#include + namespace muduo { -class Timestamp; namespace net { diff --git a/muduo/net/tests/EchoClient_unittest.cc b/muduo/net/tests/EchoClient_unittest.cc index 3d1a51d14..74ba5f35c 100644 --- a/muduo/net/tests/EchoClient_unittest.cc +++ b/muduo/net/tests/EchoClient_unittest.cc @@ -51,7 +51,7 @@ class EchoClient : boost::noncopyable if (conn->connected()) { ++current; - if (current < clients.size()) + if (implicit_cast(current) < clients.size()) { clients[current]->connect(); } From e0ccd19c821df9898aaafd9416c45a0b1cbb7c40 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 18 Apr 2010 03:18:43 +0000 Subject: [PATCH 047/371] Better logging. --- muduo/base/Logging.cc | 2 +- muduo/net/Acceptor.cc | 4 ++-- muduo/net/Channel.cc | 23 +++++++++++++++++++++++ muduo/net/Channel.h | 4 ++++ muduo/net/EventLoop.cc | 14 ++++++++++++++ muduo/net/EventLoop.h | 2 ++ muduo/net/Poller.cc | 4 ++-- muduo/net/Poller.h | 2 +- muduo/net/TcpConnection.cc | 9 +++++---- muduo/net/TcpServer.cc | 7 ++++++- 10 files changed, 60 insertions(+), 11 deletions(-) diff --git a/muduo/base/Logging.cc b/muduo/base/Logging.cc index 54b4ae493..e9e293d47 100644 --- a/muduo/base/Logging.cc +++ b/muduo/base/Logging.cc @@ -116,5 +116,5 @@ Logger::~Logger() Logger::LogLevel Logger::logLevel() { - return INFO; + return TRACE; } diff --git a/muduo/net/Acceptor.cc b/muduo/net/Acceptor.cc index ef2658f6d..046ed3ab1 100644 --- a/muduo/net/Acceptor.cc +++ b/muduo/net/Acceptor.cc @@ -48,8 +48,8 @@ void Acceptor::handleRead() int connfd = acceptSocket_.accept(&peerAddr); if (connfd >= 0) { - string hostport = peerAddr.toHostPort(); - LOG_INFO << "Accepts of " << hostport; + // string hostport = peerAddr.toHostPort(); + // LOG_TRACE << "Accepts of " << hostport; if (newConnectionCallback_) { newConnectionCallback_(connfd, peerAddr); diff --git a/muduo/net/Channel.cc b/muduo/net/Channel.cc index 7ac17e34e..b9e9ecc3d 100644 --- a/muduo/net/Channel.cc +++ b/muduo/net/Channel.cc @@ -10,6 +10,8 @@ #include #include +#include + #include using namespace muduo; @@ -92,3 +94,24 @@ void Channel::handleEventWithGuard(Timestamp receiveTime) eventHandling_ = false; } +string Channel::reventsToString() const +{ + std::ostringstream oss; + oss << fd_ << ": "; + if (revents_ & POLLIN) + oss << "IN "; + if (revents_ & POLLPRI) + oss << "PRI "; + if (revents_ & POLLOUT) + oss << "OUT "; + if (revents_ & POLLHUP) + oss << "HUP "; + if (revents_ & POLLRDHUP) + oss << "RDHUP "; + if (revents_ & POLLERR) + oss << "ERR "; + if (revents_ & POLLNVAL) + oss << "NVAL "; + + return oss.str().c_str(); +} diff --git a/muduo/net/Channel.h b/muduo/net/Channel.h index 79ac3a2c9..d67ae0606 100644 --- a/muduo/net/Channel.h +++ b/muduo/net/Channel.h @@ -58,6 +58,7 @@ class Channel : boost::noncopyable int fd() const { return fd_; } int events() const { return events_; } void set_revents(int revt) { revents_ = revt; } + // int revents() const { return revents_; } void enableReading() { events_ |= kReadEvent; update(); } void enableWriting() { events_ |= kWriteEvent; update(); } @@ -69,6 +70,9 @@ class Channel : boost::noncopyable int index() { return index_; } void set_index(int idx) { index_ = idx; } + // for debug + string reventsToString() const; + EventLoop* getLoop() { return loop_; } private: diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 497dc93fa..743bcbb9a 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -96,6 +96,10 @@ void EventLoop::loop() { activeChannels_.clear(); happenTime_ = poller_->poll(kPollTimeMs, &activeChannels_); + if (Logger::logLevel() <= Logger::TRACE) + { + printActiveChannels(); + } // TODO sort channel by priority eventHandling_ = true; for (ChannelList::iterator it = activeChannels_.begin(); @@ -213,3 +217,13 @@ void EventLoop::doPendingFunctors() } while (!functors.empty()); } +void EventLoop::printActiveChannels() const +{ + for (ChannelList::const_iterator it = activeChannels_.begin(); + it != activeChannels_.end(); ++it) + { + const Channel* ch = *it; + LOG_TRACE << "{" << ch->reventsToString() << "} "; + } +} + diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 5dc80a727..3223e72a1 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -101,6 +101,8 @@ class EventLoop : boost::noncopyable void handleRead(); // waked up void doPendingFunctors(); + void printActiveChannels() const; // DEBUG + typedef std::vector ChannelList; bool looping_; /* atomic */ diff --git a/muduo/net/Poller.cc b/muduo/net/Poller.cc index 23ead15a9..2cf0e5897 100644 --- a/muduo/net/Poller.cc +++ b/muduo/net/Poller.cc @@ -13,7 +13,7 @@ using namespace muduo; using namespace muduo::net; Poller::Poller(EventLoop* loop) - : loop_(loop) + : ownerLoop_(loop) { } @@ -23,6 +23,6 @@ Poller::~Poller() void Poller::assertInLoopThread() { - loop_->assertInLoopThread(); + ownerLoop_->assertInLoopThread(); } diff --git a/muduo/net/Poller.h b/muduo/net/Poller.h index 846c1e75c..523ff08fd 100644 --- a/muduo/net/Poller.h +++ b/muduo/net/Poller.h @@ -53,7 +53,7 @@ class Poller : boost::noncopyable void assertInLoopThread(); private: - EventLoop* loop_; + EventLoop* ownerLoop_; }; } diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 1609b9450..293ca9528 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -30,9 +30,10 @@ void muduo::net::defaultConnectionCallback(const TcpConnectionPtr& conn) } void muduo::net::defaultMessageCallback(const TcpConnectionPtr&, - Buffer*, + Buffer* buf, Timestamp) { + buf->retrieveAll(); } TcpConnection::TcpConnection(EventLoop* loop, @@ -56,12 +57,12 @@ TcpConnection::TcpConnection(EventLoop* loop, boost::bind(&TcpConnection::handleClose, this)); channel_->setErrorCallback( boost::bind(&TcpConnection::handleError, this)); - printf("%p %s ctor\n", this, name_.c_str()); + LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this; } TcpConnection::~TcpConnection() { - printf("%p %s dtor\n", this, name_.c_str()); + LOG_DEBUG << "TcpConnection::dtor[" << name_ << "] at " << this; } void TcpConnection::send(const void* data, size_t len) @@ -253,6 +254,6 @@ void TcpConnection::handleError() int err = sockets::getSocketError(channel_->fd()); LOG_ERROR << "TcpConnection::handleError [" << name_ << "] - SO_ERROR = " << err << " " << strerror_tl(err); - abort(); // FIXME + //handleClose(); } diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 20f6d186c..f64db3ee5 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -41,7 +41,7 @@ TcpServer::TcpServer(EventLoop* loop, TcpServer::~TcpServer() { loop_->assertInLoopThread(); - LOG_TRACE << "TcpServer::~TcpServer " << this << " destructing"; + LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing"; for (ConnectionMap::iterator it(connections_.begin()); it != connections_.end(); ++it) @@ -83,6 +83,9 @@ void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) ++nextConnId_; string connName = name_ + buf; + LOG_INFO << "TcpServer::newConnection [" << name_ + << "] - new connection [" << connName + << "] from " << peerAddr.toHostPort(); InetAddress localAddr(sockets::getLocalAddr(sockfd)); // FIXME poll with zero timeout to double confirm the new connection TcpConnectionPtr conn( @@ -103,6 +106,8 @@ void TcpServer::removeConnection(const TcpConnectionPtr& conn) void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) { loop_->assertInLoopThread(); + LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_ + << "] - connection " << conn->name(); size_t n = connections_.erase(conn->name()); assert(n == 1); EventLoop* ioLoop = conn->getLoop(); From 4e9e61d7d5504a73cd7ab2e294b41cba0cf81d89 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 18 Apr 2010 03:29:58 +0000 Subject: [PATCH 048/371] Control log level by environment variable. --- muduo/base/Logging.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/muduo/base/Logging.cc b/muduo/base/Logging.cc index e9e293d47..b71759c24 100644 --- a/muduo/base/Logging.cc +++ b/muduo/base/Logging.cc @@ -36,6 +36,16 @@ const char* strerror_tl(int savedErrno) return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf); } +Logger::LogLevel initLogLevel() +{ + if (::getenv("MUDUO_LOG_TRACE")) + return Logger::TRACE; + else + return Logger::DEBUG; +} + +Logger::LogLevel g_logLevel = initLogLevel(); + } using namespace muduo; @@ -116,5 +126,6 @@ Logger::~Logger() Logger::LogLevel Logger::logLevel() { - return TRACE; + return g_logLevel; } + From 7d023d7d55ef96b20ea50e3f69c9b06c2c28401a Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 18 Apr 2010 04:25:46 +0000 Subject: [PATCH 049/371] Add examples of asio tutorial timers. --- examples/CMakeLists.txt | 4 +- examples/asio/tutorial/CMakeLists.txt | 15 +++ examples/asio/tutorial/there_is_no_timer1 | 0 examples/asio/tutorial/timer2/timer.cc | 16 ++++ examples/asio/tutorial/timer3/timer.cc | 29 ++++++ examples/asio/tutorial/timer4/timer.cc | 48 ++++++++++ examples/asio/tutorial/timer5/timer.cc | 74 +++++++++++++++ examples/asio/tutorial/timer6/timer.cc | 106 ++++++++++++++++++++++ muduo/net/EventLoop.h | 4 +- muduo/net/EventLoopThread.cc | 2 +- 10 files changed, 294 insertions(+), 4 deletions(-) create mode 100644 examples/asio/tutorial/CMakeLists.txt create mode 100644 examples/asio/tutorial/there_is_no_timer1 create mode 100644 examples/asio/tutorial/timer2/timer.cc create mode 100644 examples/asio/tutorial/timer3/timer.cc create mode 100644 examples/asio/tutorial/timer4/timer.cc create mode 100644 examples/asio/tutorial/timer5/timer.cc create mode 100644 examples/asio/tutorial/timer6/timer.cc diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 587bb00dd..e25ef5a40 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,5 @@ -add_subdirectory(roundtrip) add_subdirectory(simple) +add_subdirectory(roundtrip) + +add_subdirectory(asio/tutorial) diff --git a/examples/asio/tutorial/CMakeLists.txt b/examples/asio/tutorial/CMakeLists.txt new file mode 100644 index 000000000..e4d304113 --- /dev/null +++ b/examples/asio/tutorial/CMakeLists.txt @@ -0,0 +1,15 @@ +add_executable(asio_tutorial_timer2 timer2/timer.cc) +target_link_libraries(asio_tutorial_timer2 muduo_net) + +add_executable(asio_tutorial_timer3 timer3/timer.cc) +target_link_libraries(asio_tutorial_timer3 muduo_net) + +add_executable(asio_tutorial_timer4 timer4/timer.cc) +target_link_libraries(asio_tutorial_timer4 muduo_net) + +add_executable(asio_tutorial_timer5 timer5/timer.cc) +target_link_libraries(asio_tutorial_timer5 muduo_net) + +add_executable(asio_tutorial_timer6 timer6/timer.cc) +target_link_libraries(asio_tutorial_timer6 muduo_net) + diff --git a/examples/asio/tutorial/there_is_no_timer1 b/examples/asio/tutorial/there_is_no_timer1 new file mode 100644 index 000000000..e69de29bb diff --git a/examples/asio/tutorial/timer2/timer.cc b/examples/asio/tutorial/timer2/timer.cc new file mode 100644 index 000000000..2376b8d36 --- /dev/null +++ b/examples/asio/tutorial/timer2/timer.cc @@ -0,0 +1,16 @@ +#include + +#include + +void print() +{ + std::cout << "Hello, world!\n"; +} + +int main() +{ + muduo::net::EventLoop loop; + loop.runAfter(5, print); + loop.loop(); +} + diff --git a/examples/asio/tutorial/timer3/timer.cc b/examples/asio/tutorial/timer3/timer.cc new file mode 100644 index 000000000..98d609300 --- /dev/null +++ b/examples/asio/tutorial/timer3/timer.cc @@ -0,0 +1,29 @@ +#include + +#include +#include + +void print(muduo::net::EventLoop* loop, int* count) +{ + if (*count < 5) + { + std::cout << *count << "\n"; + ++(*count); + + loop->runAfter(1, boost::bind(print, loop, count)); + } + else + { + loop->quit(); + } +} + +int main() +{ + muduo::net::EventLoop loop; + int count = 0; + loop.runAfter(1, boost::bind(print, &loop, &count)); + loop.loop(); + std::cout << "Final count is " << count << "\n"; +} + diff --git a/examples/asio/tutorial/timer4/timer.cc b/examples/asio/tutorial/timer4/timer.cc new file mode 100644 index 000000000..2a2d8c329 --- /dev/null +++ b/examples/asio/tutorial/timer4/timer.cc @@ -0,0 +1,48 @@ +#include + +#include +#include +#include + +class Printer : boost::noncopyable +{ + public: + Printer(muduo::net::EventLoop* loop) + : loop_(loop), + count_(0) + { + loop_->runAfter(1, boost::bind(&Printer::print, this)); + } + + ~Printer() + { + std::cout << "Final count is " << count_ << "\n"; + } + + void print() + { + if (count_ < 5) + { + std::cout << count_ << "\n"; + ++count_; + + loop_->runAfter(1, boost::bind(&Printer::print, this)); + } + else + { + loop_->quit(); + } + } + +private: + muduo::net::EventLoop* loop_; + int count_; +}; + +int main() +{ + muduo::net::EventLoop loop; + Printer printer(&loop); + loop.loop(); +} + diff --git a/examples/asio/tutorial/timer5/timer.cc b/examples/asio/tutorial/timer5/timer.cc new file mode 100644 index 000000000..8e345c98e --- /dev/null +++ b/examples/asio/tutorial/timer5/timer.cc @@ -0,0 +1,74 @@ +#include +#include +#include + +#include +#include +#include + +class Printer : boost::noncopyable +{ + public: + Printer(muduo::net::EventLoop* loop1, muduo::net::EventLoop* loop2) + : loop1_(loop1), + loop2_(loop2), + count_(0) + { + loop1_->runAfter(1, boost::bind(&Printer::print1, this)); + loop2_->runAfter(1, boost::bind(&Printer::print2, this)); + } + + ~Printer() + { + std::cout << "Final count is " << count_ << "\n"; + } + + void print1() + { + muduo::MutexLockGuard lock(mutex_); + if (count_ < 10) + { + std::cout << "Timer 1: " << count_ << "\n"; + ++count_; + + loop1_->runAfter(1, boost::bind(&Printer::print1, this)); + } + else + { + loop1_->quit(); + } + } + + void print2() + { + muduo::MutexLockGuard lock(mutex_); + if (count_ < 10) + { + std::cout << "Timer 2: " << count_ << "\n"; + ++count_; + + loop2_->runAfter(1, boost::bind(&Printer::print2, this)); + } + else + { + loop2_->quit(); + } + } + +private: + + muduo::MutexLock mutex_; + muduo::net::EventLoop* loop1_; + muduo::net::EventLoop* loop2_; + int count_; +}; + +int main() +{ + muduo::net::EventLoop loop; + muduo::net::EventLoopThread loopThread; + muduo::net::EventLoop* loopInAnotherThread = loopThread.startLoop(); + Printer printer(&loop, loopInAnotherThread); + loop.loop(); +} + diff --git a/examples/asio/tutorial/timer6/timer.cc b/examples/asio/tutorial/timer6/timer.cc new file mode 100644 index 000000000..73a1a4f6c --- /dev/null +++ b/examples/asio/tutorial/timer6/timer.cc @@ -0,0 +1,106 @@ +#include +#include +#include + +#include +#include +#include + +// +// Minimize locking +// + +class Printer : boost::noncopyable +{ + public: + Printer(muduo::net::EventLoop* loop1, muduo::net::EventLoop* loop2) + : loop1_(loop1), + loop2_(loop2), + count_(0) + { + loop1_->runAfter(1, boost::bind(&Printer::print1, this)); + loop2_->runAfter(1, boost::bind(&Printer::print2, this)); + } + + ~Printer() + { + std::cout << "Final count is " << count_ << "\n"; + } + + void print1() + { + bool shouldQuit = false; + int count = 0; + + { + muduo::MutexLockGuard lock(mutex_); + if (count_ < 10) + { + count = count_; + ++count_; + } + else + { + shouldQuit = true; + } + } + + // out of lock + if (shouldQuit) + { + loop1_->quit(); + } + else + { + std::cout << "Timer 1: " << count << "\n"; + loop1_->runAfter(1, boost::bind(&Printer::print1, this)); + } + } + + void print2() + { + bool shouldQuit = false; + int count = 0; + + { + muduo::MutexLockGuard lock(mutex_); + if (count_ < 10) + { + count = count_; + ++count_; + } + else + { + shouldQuit = true; + } + } + + // out of lock + if (shouldQuit) + { + loop2_->quit(); + } + else + { + std::cout << "Timer 2: " << count << "\n"; + loop2_->runAfter(1, boost::bind(&Printer::print2, this)); + } + } + +private: + + muduo::MutexLock mutex_; + muduo::net::EventLoop* loop1_; + muduo::net::EventLoop* loop2_; + int count_; +}; + +int main() +{ + muduo::net::EventLoop loop; + muduo::net::EventLoopThread loopThread; + muduo::net::EventLoop* loopInAnotherThread = loopThread.startLoop(); + Printer printer(&loop, loopInAnotherThread); + loop.loop(); +} + diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 3223e72a1..3c3eb9f17 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -52,7 +52,6 @@ class EventLoop : boost::noncopyable void loop(); void quit(); - void wakeup(); /// Time when poll returns, usually means data arrivial. /// @@ -81,8 +80,9 @@ class EventLoop : boost::noncopyable TimerId runEvery(double interval, const TimerCallback& cb); /// Cancels the timer. /// Safe to call from other threads. - void cancel(TimerId timerId); + // void cancel(TimerId timerId); + void wakeup(); void updateChannel(Channel* channel); void removeChannel(Channel* channel); diff --git a/muduo/net/EventLoopThread.cc b/muduo/net/EventLoopThread.cc index c708b413f..bbaf6b8a8 100644 --- a/muduo/net/EventLoopThread.cc +++ b/muduo/net/EventLoopThread.cc @@ -59,6 +59,6 @@ void EventLoopThread::threadFunc() } loop.loop(); - assert(exiting_); + //assert(exiting_); } From 74acba2efcdc95bdc5ea773082035f1fa8eba3a2 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 18 Apr 2010 04:34:56 +0000 Subject: [PATCH 050/371] std::cout is not thread safe. --- examples/asio/tutorial/timer6/timer.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/asio/tutorial/timer6/timer.cc b/examples/asio/tutorial/timer6/timer.cc index 73a1a4f6c..95c4721d4 100644 --- a/examples/asio/tutorial/timer6/timer.cc +++ b/examples/asio/tutorial/timer6/timer.cc @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -24,7 +24,9 @@ class Printer : boost::noncopyable ~Printer() { - std::cout << "Final count is " << count_ << "\n"; + // cout is not thread safe + //std::cout << "Final count is " << count_ << "\n"; + printf("Final count is %d\n", count_); } void print1() @@ -52,7 +54,9 @@ class Printer : boost::noncopyable } else { - std::cout << "Timer 1: " << count << "\n"; + // cout is not thread safe + //std::cout << "Timer 1: " << count << "\n"; + printf("Timer 1: %d\n", count); loop1_->runAfter(1, boost::bind(&Printer::print1, this)); } } @@ -82,7 +86,9 @@ class Printer : boost::noncopyable } else { - std::cout << "Timer 2: " << count << "\n"; + // cout is not thread safe + //std::cout << "Timer 2: " << count << "\n"; + printf("Timer 2: %d\n", count); loop2_->runAfter(1, boost::bind(&Printer::print2, this)); } } From f88fbe99068f406e43471aaec6eb4348496e233e Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 18 Apr 2010 16:16:51 +0000 Subject: [PATCH 051/371] Add asio chat client. --- examples/CMakeLists.txt | 1 + examples/asio/chat/CMakeLists.txt | 3 + examples/asio/chat/client.cc | 132 ++++++++++++++++++++++ examples/asio/echo/echo_see_simple | 0 examples/asio/tutorial/daytime_see_simple | 0 examples/simple/timeclient/timeclient.cc | 3 +- muduo/net/Buffer.h | 5 +- muduo/net/TcpConnection.cc | 20 ++++ 8 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 examples/asio/chat/CMakeLists.txt create mode 100644 examples/asio/chat/client.cc create mode 100644 examples/asio/echo/echo_see_simple create mode 100644 examples/asio/tutorial/daytime_see_simple diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e25ef5a40..5f649e377 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,4 +2,5 @@ add_subdirectory(simple) add_subdirectory(roundtrip) add_subdirectory(asio/tutorial) +add_subdirectory(asio/chat) diff --git a/examples/asio/chat/CMakeLists.txt b/examples/asio/chat/CMakeLists.txt new file mode 100644 index 000000000..46f4304ce --- /dev/null +++ b/examples/asio/chat/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(asio_chat_client client.cc) +target_link_libraries(asio_chat_client muduo_net) + diff --git a/examples/asio/chat/client.cc b/examples/asio/chat/client.cc new file mode 100644 index 000000000..e8639faaf --- /dev/null +++ b/examples/asio/chat/client.cc @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +class ChatClient : boost::noncopyable +{ + public: + ChatClient(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + client_(loop, listenAddr, "ChatClient") + { + client_.setConnectionCallback( + boost::bind(&ChatClient::onConnection, this, _1)); + client_.setMessageCallback( + boost::bind(&ChatClient::onMessage, this, _1, _2, _3)); + client_.enableRetry(); + } + + void connect() + { + client_.connect(); + } + + void disconnect() + { + // client_.disconnect(); + } + + void write(const string& message) + { + MutexLockGuard lock(mutex_); + if (connection_) + { + Buffer buf; + buf.append(message.data(), message.size()); + int32_t len = sockets::hostToNetwork32(static_cast(message.size())); + buf.prepend(&len, sizeof len); + connection_->send(&buf); + } + } + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_INFO << conn->localAddress().toHostPort() << " -> " + << conn->peerAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + + MutexLockGuard lock(mutex_); + if (conn->connected()) + { + connection_ = conn; + } + else + { + connection_.reset(); + } + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime) + { + if (buf->readableBytes() >= kHeaderLen) + { + const void* data = buf->peek(); + int32_t tmp = *static_cast(data); + int32_t len = sockets::networkToHost32(tmp); + if (len > 65536 || len < 0) + { + LOG_ERROR << "Invalid length " << len; + conn->shutdown(); + } + else + { + if (buf->readableBytes() >= len + kHeaderLen) + { + buf->retrieve(kHeaderLen); + string message(buf->peek(), len); + buf->retrieve(len); + printf("<<< %s\n", message.c_str()); + } + } + } + else + { + LOG_INFO << conn->name() << " no enough data " << buf->readableBytes() + << " at " << receiveTime.toFormattedString(); + } + } + + EventLoop* loop_; + TcpClient client_; + MutexLock mutex_; + TcpConnectionPtr connection_; + const static size_t kHeaderLen = 4; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid(); + if (argc > 2) + { + EventLoopThread loopThread; + uint16_t port = static_cast(atoi(argv[2])); + InetAddress serverAddr(argv[1], port); + + ChatClient client(loopThread.startLoop(), serverAddr); + client.connect(); + std::string line; + while (std::getline(std::cin, line)) + { + string message(line.c_str()); + client.write(message); + } + client.disconnect(); + } + else + { + printf("Usage: %s host_ip port\n", argv[0]); + } +} + diff --git a/examples/asio/echo/echo_see_simple b/examples/asio/echo/echo_see_simple new file mode 100644 index 000000000..e69de29bb diff --git a/examples/asio/tutorial/daytime_see_simple b/examples/asio/tutorial/daytime_see_simple new file mode 100644 index 000000000..e69de29bb diff --git a/examples/simple/timeclient/timeclient.cc b/examples/simple/timeclient/timeclient.cc index 2b44dd9e9..0d680e4f0 100644 --- a/examples/simple/timeclient/timeclient.cc +++ b/examples/simple/timeclient/timeclient.cc @@ -25,7 +25,7 @@ class TimeClient : boost::noncopyable boost::bind(&TimeClient::onConnection, this, _1)); client_.setMessageCallback( boost::bind(&TimeClient::onMessage, this, _1, _2, _3)); - client_.enableRetry(); + // client_.enableRetry(); } void connect() @@ -50,6 +50,7 @@ class TimeClient : boost::noncopyable { const void* data = buf->peek(); int32_t time = *static_cast(data); + buf->retrieve(sizeof(int32_t)); time_t servertime = sockets::networkToHost32(time); Timestamp t(servertime * Timestamp::kMicroSecondsPerSecond); LOG_INFO << "Server time = " << servertime << ", " << t.toFormattedString(); diff --git a/muduo/net/Buffer.h b/muduo/net/Buffer.h index efff3ecf3..906d0d619 100644 --- a/muduo/net/Buffer.h +++ b/muduo/net/Buffer.h @@ -105,11 +105,12 @@ class Buffer : public muduo::copyable writerIndex_ += len; } - void prepend(const char* /*restrict*/ data, size_t len) + void prepend(const void* /*restrict*/ data, size_t len) { assert(len <= prependableBytes()); readerIndex_ -= len; - std::copy(data, data+len, begin()+readerIndex_); + const char* d = static_cast(data); + std::copy(d, d+len, begin()+readerIndex_); } void shrink(size_t reserve) diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 293ca9528..f0fbfda77 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -103,6 +103,26 @@ void TcpConnection::send(const string& message) } } +// FIXME efficiency!!! +void TcpConnection::send(Buffer* buf) +{ + if (state_ == kConnected) + { + if (loop_->isInLoopThread()) + { + sendInLoop(buf->retrieveAsString()); + } + else + { + loop_->runInLoop( + boost::bind(&TcpConnection::sendInLoop, + this, + buf->retrieveAsString())); + //std::forward(message))); + } + } +} + void TcpConnection::sendInLoop(const string& message) { sendInLoop(message.data(), message.size()); From a6958555412cb06ae3f6cbd18349244eaca5304e Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 20 Apr 2010 01:40:59 +0000 Subject: [PATCH 052/371] Extra codec class for asio chat. --- examples/asio/chat/CMakeLists.txt | 3 ++ examples/asio/chat/client.cc | 47 ++++++---------------- examples/asio/chat/codec.h | 66 +++++++++++++++++++++++++++++++ examples/asio/chat/server.cc | 63 +++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 36 deletions(-) create mode 100644 examples/asio/chat/codec.h create mode 100644 examples/asio/chat/server.cc diff --git a/examples/asio/chat/CMakeLists.txt b/examples/asio/chat/CMakeLists.txt index 46f4304ce..3da45287d 100644 --- a/examples/asio/chat/CMakeLists.txt +++ b/examples/asio/chat/CMakeLists.txt @@ -1,3 +1,6 @@ add_executable(asio_chat_client client.cc) target_link_libraries(asio_chat_client muduo_net) +add_executable(asio_chat_server server.cc) +target_link_libraries(asio_chat_server muduo_net) + diff --git a/examples/asio/chat/client.cc b/examples/asio/chat/client.cc index e8639faaf..d7ac13073 100644 --- a/examples/asio/chat/client.cc +++ b/examples/asio/chat/client.cc @@ -1,7 +1,8 @@ +#include "codec.h" + #include #include #include -#include #include #include @@ -18,12 +19,13 @@ class ChatClient : boost::noncopyable public: ChatClient(EventLoop* loop, const InetAddress& listenAddr) : loop_(loop), - client_(loop, listenAddr, "ChatClient") + client_(loop, listenAddr, "ChatClient"), + codec_(boost::bind(&ChatClient::onStringMessage, this, _1, _2, _3)) { client_.setConnectionCallback( boost::bind(&ChatClient::onConnection, this, _1)); client_.setMessageCallback( - boost::bind(&ChatClient::onMessage, this, _1, _2, _3)); + boost::bind(&LengthHeaderCodec::onMessage, &codec_, _1, _2, _3)); client_.enableRetry(); } @@ -42,11 +44,7 @@ class ChatClient : boost::noncopyable MutexLockGuard lock(mutex_); if (connection_) { - Buffer buf; - buf.append(message.data(), message.size()); - int32_t len = sockets::hostToNetwork32(static_cast(message.size())); - buf.prepend(&len, sizeof len); - connection_->send(&buf); + codec_.send(get_pointer(connection_), message); } } @@ -68,41 +66,18 @@ class ChatClient : boost::noncopyable } } - void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime) + void onStringMessage(const TcpConnectionPtr& conn, + const string& message, + Timestamp receiveTime) { - if (buf->readableBytes() >= kHeaderLen) - { - const void* data = buf->peek(); - int32_t tmp = *static_cast(data); - int32_t len = sockets::networkToHost32(tmp); - if (len > 65536 || len < 0) - { - LOG_ERROR << "Invalid length " << len; - conn->shutdown(); - } - else - { - if (buf->readableBytes() >= len + kHeaderLen) - { - buf->retrieve(kHeaderLen); - string message(buf->peek(), len); - buf->retrieve(len); - printf("<<< %s\n", message.c_str()); - } - } - } - else - { - LOG_INFO << conn->name() << " no enough data " << buf->readableBytes() - << " at " << receiveTime.toFormattedString(); - } + printf("<<< %s\n", message.c_str()); } EventLoop* loop_; TcpClient client_; + LengthHeaderCodec codec_; MutexLock mutex_; TcpConnectionPtr connection_; - const static size_t kHeaderLen = 4; }; int main(int argc, char* argv[]) diff --git a/examples/asio/chat/codec.h b/examples/asio/chat/codec.h new file mode 100644 index 000000000..fb9d7aef9 --- /dev/null +++ b/examples/asio/chat/codec.h @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +#include + +using muduo::Logger; + +class LengthHeaderCodec +{ + public: + typedef boost::function StringMessageCallback; + + explicit LengthHeaderCodec(const StringMessageCallback& cb) + : messageCallback_(cb) + { + } + + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp receiveTime) + { + if (!receiveTime_.valid()) + { + receiveTime_ = receiveTime; + } + + if (buf->readableBytes() >= kHeaderLen) + { + const void* data = buf->peek(); + int32_t tmp = *static_cast(data); + int32_t len = muduo::net::sockets::networkToHost32(tmp); + if (len > 65536 || len < 0) + { + LOG_ERROR << "Invalid length " << len; + conn->shutdown(); + } + else if (buf->readableBytes() >= len + kHeaderLen) + { + buf->retrieve(kHeaderLen); + muduo::string message(buf->peek(), len); + buf->retrieve(len); + messageCallback_(conn, message, receiveTime_); + receiveTime_ = muduo::Timestamp::invalid(); + } + } + } + + void send(muduo::net::TcpConnection* conn, const muduo::string& message) + { + muduo::net::Buffer buf; + buf.append(message.data(), message.size()); + int32_t len = muduo::net::sockets::hostToNetwork32(static_cast(message.size())); + buf.prepend(&len, sizeof len); + conn->send(&buf); + } + + private: + StringMessageCallback messageCallback_; + muduo::Timestamp receiveTime_; + const static size_t kHeaderLen = sizeof(int32_t); +}; + diff --git a/examples/asio/chat/server.cc b/examples/asio/chat/server.cc new file mode 100644 index 000000000..181892ef4 --- /dev/null +++ b/examples/asio/chat/server.cc @@ -0,0 +1,63 @@ +#include "codec.h" + +#include +#include +#include +#include +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +class ChatServer : boost::noncopyable +{ + public: + ChatServer(EventLoop* loop, + const InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "ChatServer"), + codec_(boost::bind(&ChatServer::onStringMessage, this, _1, _2, _3)) + { + server_.setConnectionCallback( + boost::bind(&ChatServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&LengthHeaderCodec::onMessage, &codec_, _1, _2, _3)); + } + + void start() + { + server_.start(); + } + + private: + void onConnection(const TcpConnectionPtr& conn) + { + } + + void onStringMessage(const TcpConnectionPtr& conn, + const string& message, + Timestamp time) + { + } + + EventLoop* loop_; + TcpServer server_; + LengthHeaderCodec codec_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid(); + if (argc > 1) + { + EventLoop loop; + uint16_t port = static_cast(atoi(argv[1])); + InetAddress serverAddr(port); + ChatServer server(&loop, serverAddr); + server.start(); + loop.loop(); + } +} + From ceef30b2b8394f180daaa0a67644ea4535c99239 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 20 Apr 2010 14:43:26 +0000 Subject: [PATCH 053/371] Finish asio chat server example. --- examples/asio/chat/server.cc | 30 ++++++++++++++++++++++++++++++ examples/simple/echo/echo.cc | 20 ++++++++++---------- examples/simple/echo/echo.h | 2 +- muduo/net/Callbacks.h | 1 + muduo/net/TcpConnection.cc | 6 ++++-- muduo/net/TcpConnection.h | 6 +++--- 6 files changed, 49 insertions(+), 16 deletions(-) diff --git a/examples/asio/chat/server.cc b/examples/asio/chat/server.cc index 181892ef4..9c6db178e 100644 --- a/examples/asio/chat/server.cc +++ b/examples/asio/chat/server.cc @@ -8,6 +8,9 @@ #include +#include +#include + using namespace muduo; using namespace muduo::net; @@ -34,17 +37,40 @@ class ChatServer : boost::noncopyable private: void onConnection(const TcpConnectionPtr& conn) { + LOG_INFO << conn->localAddress().toHostPort() << " -> " + << conn->peerAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + + MutexLockGuard lock(mutex_); + if (conn->connected()) + { + connections_.insert(conn); + } + else + { + connections_.erase(conn); + } } void onStringMessage(const TcpConnectionPtr& conn, const string& message, Timestamp time) { + MutexLockGuard lock(mutex_); + for (ConnectionList::iterator it = connections_.begin(); + it != connections_.end(); + ++it) + { + codec_.send(get_pointer(*it), message); + } } + typedef std::set ConnectionList; EventLoop* loop_; TcpServer server_; LengthHeaderCodec codec_; + MutexLock mutex_; + ConnectionList connections_; }; int main(int argc, char* argv[]) @@ -59,5 +85,9 @@ int main(int argc, char* argv[]) server.start(); loop.loop(); } + else + { + printf("Usage: %s port\n", argv[0]); + } } diff --git a/examples/simple/echo/echo.cc b/examples/simple/echo/echo.cc index 68f44b727..576f23ce7 100644 --- a/examples/simple/echo/echo.cc +++ b/examples/simple/echo/echo.cc @@ -7,15 +7,15 @@ using namespace muduo; using namespace muduo::net; -EchoServer::EchoServer(muduo::net::EventLoop* loop, - const muduo::net::InetAddress& listenAddr) +EchoServer::EchoServer(EventLoop* loop, + const InetAddress& listenAddr) : loop_(loop), server_(loop, listenAddr, "EchoServer") { - server_.setConnectionCallback( - boost::bind(&EchoServer::onConnection, this, _1)); - server_.setMessageCallback( - boost::bind(&EchoServer::onMessage, this, _1, _2, _3)); + server_.setConnectionCallback( + boost::bind(&EchoServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&EchoServer::onMessage, this, _1, _2, _3)); } void EchoServer::start() @@ -23,16 +23,16 @@ void EchoServer::start() server_.start(); } -void EchoServer::onConnection(const muduo::net::TcpConnectionPtr& conn) +void EchoServer::onConnection(const TcpConnectionPtr& conn) { LOG_INFO << "EchoServer - " << conn->peerAddress().toHostPort() << " -> " << conn->localAddress().toHostPort() << " is " << (conn->connected() ? "UP" : "DOWN"); } -void EchoServer::onMessage(const muduo::net::TcpConnectionPtr& conn, - muduo::net::Buffer* buf, - muduo::Timestamp time) +void EchoServer::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp time) { string msg(buf->retrieveAsString()); LOG_INFO << conn->name() << " echo " << msg.size() << " bytes at " << time.toString(); diff --git a/examples/simple/echo/echo.h b/examples/simple/echo/echo.h index 8a2a1268f..f10aee89e 100644 --- a/examples/simple/echo/echo.h +++ b/examples/simple/echo/echo.h @@ -7,7 +7,7 @@ class EchoServer { public: EchoServer(muduo::net::EventLoop* loop, - const muduo::net::InetAddress& listenAddr); + const muduo::net::InetAddress& listenAddr); void start(); diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index 170777031..542722c7d 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -28,6 +28,7 @@ class TcpConnection; typedef boost::shared_ptr TcpConnectionPtr; typedef boost::function TimerCallback; typedef boost::function ConnectionCallback; +typedef boost::function CloseCallback; // the data has been read to (buf, len) typedef boost::functionsetErrorCallback( boost::bind(&TcpConnection::handleError, this)); - LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this; + LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this + << " fd=" << fd; } TcpConnection::~TcpConnection() { - LOG_DEBUG << "TcpConnection::dtor[" << name_ << "] at " << this; + LOG_DEBUG << "TcpConnection::dtor[" << name_ << "] at " << this + << " fd=" << fd; } void TcpConnection::send(const void* data, size_t len) diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index dc08a64dc..b63e1262b 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -62,14 +62,14 @@ class TcpConnection : public boost::enable_shared_from_this, void send(Buffer* message); // this one will swap data void shutdown(); // NOT thread safe, no simultaneous calling - void setConnectionCallback(ConnectionCallback cb) + void setConnectionCallback(const ConnectionCallback& cb) { connectionCallback_ = cb; } - void setMessageCallback(MessageCallback cb) + void setMessageCallback(const MessageCallback& cb) { messageCallback_ = cb; } /// Internal use only. - void setCloseCallback(ConnectionCallback cb) + void setCloseCallback(const CloseCallback& cb) { closeCallback_ = cb; } // called when TcpServer accepts a new connection From cc7aa30869f59ec9a649441dea9d23cb1403bbcc Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 20 Apr 2010 14:49:35 +0000 Subject: [PATCH 054/371] Fix typos and compile warnings. --- examples/asio/chat/client.cc | 4 ++-- examples/asio/chat/codec.h | 3 ++- examples/asio/chat/server.cc | 4 ++-- muduo/net/TcpConnection.cc | 10 +++++----- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/asio/chat/client.cc b/examples/asio/chat/client.cc index d7ac13073..31b61434c 100644 --- a/examples/asio/chat/client.cc +++ b/examples/asio/chat/client.cc @@ -66,9 +66,9 @@ class ChatClient : boost::noncopyable } } - void onStringMessage(const TcpConnectionPtr& conn, + void onStringMessage(const TcpConnectionPtr&, const string& message, - Timestamp receiveTime) + Timestamp) { printf("<<< %s\n", message.c_str()); } diff --git a/examples/asio/chat/codec.h b/examples/asio/chat/codec.h index fb9d7aef9..b57366917 100644 --- a/examples/asio/chat/codec.h +++ b/examples/asio/chat/codec.h @@ -4,10 +4,11 @@ #include #include +#include using muduo::Logger; -class LengthHeaderCodec +class LengthHeaderCodec : boost::noncopyable { public: typedef boost::functionsetErrorCallback( boost::bind(&TcpConnection::handleError, this)); LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this - << " fd=" << fd; + << " fd=" << sockfd; } TcpConnection::~TcpConnection() { LOG_DEBUG << "TcpConnection::dtor[" << name_ << "] at " << this - << " fd=" << fd; + << " fd=" << channel_->fd(); } void TcpConnection::send(const void* data, size_t len) From c550b4f75d364f8596f8a5f31f486c1e944f03cc Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Wed, 21 Apr 2010 16:14:22 +0000 Subject: [PATCH 055/371] Allow setting log level. --- muduo/base/Logging.cc | 5 +++++ muduo/base/Logging.h | 1 + 2 files changed, 6 insertions(+) diff --git a/muduo/base/Logging.cc b/muduo/base/Logging.cc index b71759c24..c131a5504 100644 --- a/muduo/base/Logging.cc +++ b/muduo/base/Logging.cc @@ -129,3 +129,8 @@ Logger::LogLevel Logger::logLevel() return g_logLevel; } +void Logger::setLogLevel(Logger::LogLevel level) +{ + g_logLevel = level; +} + diff --git a/muduo/base/Logging.h b/muduo/base/Logging.h index 60f38e6ae..8e228b20d 100644 --- a/muduo/base/Logging.h +++ b/muduo/base/Logging.h @@ -31,6 +31,7 @@ class Logger std::ostream& stream(); static LogLevel logLevel(); + static void setLogLevel(LogLevel level); private: boost::scoped_ptr impl_; From e5fd5b4cd9ed885134d3756cc149257ca19fdb98 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 22 Apr 2010 15:12:39 +0000 Subject: [PATCH 056/371] Add netty echo example. --- examples/CMakeLists.txt | 1 + examples/asio/{echo => }/echo_see_simple | 0 examples/netty/echo/CMakeLists.txt | 6 ++ examples/netty/echo/client.cc | 87 ++++++++++++++++++++++ examples/netty/echo/server.cc | 95 ++++++++++++++++++++++++ muduo/base/Atomic.h | 33 ++++++++ muduo/net/CMakeLists.txt | 1 + muduo/net/http/CMakeLists.txt | 8 ++ muduo/net/http/HttpServer.cc | 15 ++++ muduo/net/http/HttpServer.h | 31 ++++++++ 10 files changed, 277 insertions(+) rename examples/asio/{echo => }/echo_see_simple (100%) create mode 100644 examples/netty/echo/CMakeLists.txt create mode 100644 examples/netty/echo/client.cc create mode 100644 examples/netty/echo/server.cc create mode 100644 muduo/base/Atomic.h create mode 100644 muduo/net/http/CMakeLists.txt create mode 100644 muduo/net/http/HttpServer.cc create mode 100644 muduo/net/http/HttpServer.h diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5f649e377..731f1a4a8 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -4,3 +4,4 @@ add_subdirectory(roundtrip) add_subdirectory(asio/tutorial) add_subdirectory(asio/chat) +add_subdirectory(netty/echo) diff --git a/examples/asio/echo/echo_see_simple b/examples/asio/echo_see_simple similarity index 100% rename from examples/asio/echo/echo_see_simple rename to examples/asio/echo_see_simple diff --git a/examples/netty/echo/CMakeLists.txt b/examples/netty/echo/CMakeLists.txt new file mode 100644 index 000000000..b387037bf --- /dev/null +++ b/examples/netty/echo/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(netty_echo_client client.cc) +target_link_libraries(netty_echo_client muduo_net) + +add_executable(netty_echo_server server.cc) +target_link_libraries(netty_echo_server muduo_net) + diff --git a/examples/netty/echo/client.cc b/examples/netty/echo/client.cc new file mode 100644 index 000000000..0d7da4f9d --- /dev/null +++ b/examples/netty/echo/client.cc @@ -0,0 +1,87 @@ +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int numThreads = 0; +class EchoClient; +std::vector clients; +int current = 0; + +class EchoClient : boost::noncopyable +{ + public: + EchoClient(EventLoop* loop, const InetAddress& listenAddr, int size) + : loop_(loop), + client_(loop, listenAddr, "EchoClient"), + message_(size, 'H') + { + client_.setConnectionCallback( + boost::bind(&EchoClient::onConnection, this, _1)); + client_.setMessageCallback( + boost::bind(&EchoClient::onMessage, this, _1, _2, _3)); + //client_.enableRetry(); + } + + void connect() + { + client_.connect(); + } + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->localAddress().toHostPort() << " -> " + << conn->peerAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + + conn->send(message_); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) + { + conn->send(buf); + } + + EventLoop* loop_; + TcpClient client_; + string message_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + if (argc > 1) + { + EventLoop loop; + InetAddress serverAddr(argv[1], 2007); + + int size = 256; + if (argc > 2) + { + size = atoi(argv[2]); + } + + EchoClient client(&loop, serverAddr, size); + client.connect(); + loop.loop(); + } + else + { + printf("Usage: %s host_ip [msg_size]\n", argv[0]); + } +} + diff --git a/examples/netty/echo/server.cc b/examples/netty/echo/server.cc new file mode 100644 index 000000000..858676dca --- /dev/null +++ b/examples/netty/echo/server.cc @@ -0,0 +1,95 @@ +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int numThreads = 0; + +class EchoServer +{ + public: + EchoServer(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "EchoServer"), + oldCounter_(0), + startTime_(Timestamp::now()) + { + server_.setConnectionCallback( + boost::bind(&EchoServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&EchoServer::onMessage, this, _1, _2, _3)); + server_.setThreadNum(numThreads); + loop->runEvery(3.0, boost::bind(&EchoServer::printThroughput, this)); + } + + void start() + { + LOG_INFO << "starting " << numThreads << " threads."; + server_.start(); + } + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->peerAddress().toHostPort() << " -> " + << conn->localAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp) + { + size_t len = buf->readableBytes(); + transferred_.addAndGet(len); + conn->send(buf); + } + + void printThroughput() + { + Timestamp endTime = Timestamp::now(); + int64_t newCounter = transferred_.get(); + int64_t bytes = newCounter - oldCounter_; + double time = timeDifference(endTime, startTime_); + printf("%4.3f MiB/s\n", static_cast(bytes)/time/1024/1024); + + oldCounter_ = newCounter; + startTime_ = endTime; + } + + EventLoop* loop_; + TcpServer server_; + AtomicInt64 transferred_; + int64_t oldCounter_; + Timestamp startTime_; +}; + +int main(int argc, char* argv[]) +{ + mtrace(); + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + if (argc > 1) + { + numThreads = atoi(argv[1]); + } + EventLoop loop; + InetAddress listenAddr(2007); + EchoServer server(&loop, listenAddr); + + server.start(); + + loop.loop(); +} + diff --git a/muduo/base/Atomic.h b/muduo/base/Atomic.h new file mode 100644 index 000000000..097593b0f --- /dev/null +++ b/muduo/base/Atomic.h @@ -0,0 +1,33 @@ +#ifndef MUDUO_BASE_ATOMIC_H +#define MUDUO_BASE_ATOMIC_H + +#include + +namespace muduo +{ + +class AtomicInt64 : boost::noncopyable +{ + public: + AtomicInt64() + : value_(0) + { + } + + int64_t get() + { + return value_; + } + + int64_t addAndGet(int64_t x) + { + value_ += x; + return value_; + } + + private: + int64_t value_; +}; + +} +#endif // MUDUO_BASE_ATOMIC_H diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 5d00874e4..74fdda4ba 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -23,4 +23,5 @@ set(net_SRCS add_library(muduo_net ${net_SRCS}) target_link_libraries(muduo_net muduo_base) +add_subdirectory(http) add_subdirectory(tests) diff --git a/muduo/net/http/CMakeLists.txt b/muduo/net/http/CMakeLists.txt new file mode 100644 index 000000000..a68044dd9 --- /dev/null +++ b/muduo/net/http/CMakeLists.txt @@ -0,0 +1,8 @@ +set(http_SRCS + HttpServer.cc + ) + +add_library(muduo_http ${http_SRCS}) +target_link_libraries(muduo_http muduo_net) + +# add_subdirectory(tests) diff --git a/muduo/net/http/HttpServer.cc b/muduo/net/http/HttpServer.cc new file mode 100644 index 000000000..3e084f44c --- /dev/null +++ b/muduo/net/http/HttpServer.cc @@ -0,0 +1,15 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include + +using namespace muduo; +using namespace muduo::net; + + diff --git a/muduo/net/http/HttpServer.h b/muduo/net/http/HttpServer.h new file mode 100644 index 000000000..2a21486be --- /dev/null +++ b/muduo/net/http/HttpServer.h @@ -0,0 +1,31 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPSERVER_H +#define MUDUO_NET_HTTP_HTTPSERVER_H + +#include + +namespace muduo +{ +namespace net +{ + +class HttpServer : boost::noncopyable +{ + public: + + private: +}; + +} +} + +#endif // MUDUO_NET_HTTP_HTTPSERVER_H From 8cf007bb1ea6544af86c185490754a36f2db3036 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 22 Apr 2010 15:57:18 +0000 Subject: [PATCH 057/371] Fix sending bug. --- muduo/net/TcpConnection.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 57225136a..9c118935c 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -112,7 +112,8 @@ void TcpConnection::send(Buffer* buf) { if (loop_->isInLoopThread()) { - sendInLoop(buf->retrieveAsString()); + sendInLoop(buf->peek(), buf->readableBytes()); + buf->retrieveAll(); } else { @@ -154,7 +155,7 @@ void TcpConnection::sendInLoop(const void* data, size_t len) assert(nwrote >= 0); if (implicit_cast(nwrote) < len) { - outputBuffer_.append(static_cast(data)+nwrote, len); + outputBuffer_.append(static_cast(data)+nwrote, len-nwrote); if (!channel_->isWriting()) { channel_->enableWriting(); From 1007a253379484707780112edc0ac21d79a43220 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 23 Apr 2010 17:51:02 +0000 Subject: [PATCH 058/371] Add WriteCompleteCallback. Add netty discard example. --- examples/CMakeLists.txt | 1 + examples/netty/discard/CMakeLists.txt | 6 ++ examples/netty/discard/client.cc | 89 +++++++++++++++++++++++ examples/netty/discard/server.cc | 101 ++++++++++++++++++++++++++ examples/netty/echo/client.cc | 5 -- examples/netty/echo/server.cc | 8 +- muduo/base/Atomic.h | 12 +++ muduo/net/Callbacks.h | 1 + muduo/net/TcpClient.cc | 1 + muduo/net/TcpClient.h | 6 ++ muduo/net/TcpConnection.cc | 16 +++- muduo/net/TcpConnection.h | 4 + muduo/net/TcpServer.cc | 4 +- muduo/net/TcpServer.h | 6 ++ 14 files changed, 250 insertions(+), 10 deletions(-) create mode 100644 examples/netty/discard/CMakeLists.txt create mode 100644 examples/netty/discard/client.cc create mode 100644 examples/netty/discard/server.cc diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 731f1a4a8..82002baf4 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -4,4 +4,5 @@ add_subdirectory(roundtrip) add_subdirectory(asio/tutorial) add_subdirectory(asio/chat) +add_subdirectory(netty/discard) add_subdirectory(netty/echo) diff --git a/examples/netty/discard/CMakeLists.txt b/examples/netty/discard/CMakeLists.txt new file mode 100644 index 000000000..830f7e470 --- /dev/null +++ b/examples/netty/discard/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(netty_discard_client client.cc) +target_link_libraries(netty_discard_client muduo_net) + +add_executable(netty_discard_server server.cc) +target_link_libraries(netty_discard_server muduo_net) + diff --git a/examples/netty/discard/client.cc b/examples/netty/discard/client.cc new file mode 100644 index 000000000..491cbab4b --- /dev/null +++ b/examples/netty/discard/client.cc @@ -0,0 +1,89 @@ +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +class DiscardClient : boost::noncopyable +{ + public: + DiscardClient(EventLoop* loop, const InetAddress& listenAddr, int size) + : loop_(loop), + client_(loop, listenAddr, "DiscardClient"), + message_(size, 'H') + { + client_.setConnectionCallback( + boost::bind(&DiscardClient::onConnection, this, _1)); + client_.setMessageCallback( + boost::bind(&DiscardClient::onMessage, this, _1, _2, _3)); + client_.setWriteCompleteCallback( + boost::bind(&DiscardClient::onWriteComplete, this, _1)); + //client_.enableRetry(); + } + + void connect() + { + client_.connect(); + } + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->localAddress().toHostPort() << " -> " + << conn->peerAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + + conn->send(message_); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) + { + buf->retrieveAll(); + } + + void onWriteComplete(const TcpConnectionPtr& conn) + { + conn->send(message_); + } + + EventLoop* loop_; + TcpClient client_; + string message_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + if (argc > 1) + { + EventLoop loop; + InetAddress serverAddr(argv[1], 2007); + + int size = 256; + if (argc > 2) + { + size = atoi(argv[2]); + } + + DiscardClient client(&loop, serverAddr, size); + client.connect(); + loop.loop(); + } + else + { + printf("Usage: %s host_ip [msg_size]\n", argv[0]); + } +} + diff --git a/examples/netty/discard/server.cc b/examples/netty/discard/server.cc new file mode 100644 index 000000000..e7c293a5a --- /dev/null +++ b/examples/netty/discard/server.cc @@ -0,0 +1,101 @@ +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int numThreads = 0; + +class DiscardServer +{ + public: + DiscardServer(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "DiscardServer"), + oldCounter_(0), + startTime_(Timestamp::now()) + { + server_.setConnectionCallback( + boost::bind(&DiscardServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&DiscardServer::onMessage, this, _1, _2, _3)); + server_.setThreadNum(numThreads); + loop->runEvery(3.0, boost::bind(&DiscardServer::printThroughput, this)); + } + + void start() + { + LOG_INFO << "starting " << numThreads << " threads."; + server_.start(); + } + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->peerAddress().toHostPort() << " -> " + << conn->localAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp) + { + size_t len = buf->readableBytes(); + transferred_.addAndGet(len); + receivedMessages_.incrementAndGet(); + buf->retrieveAll(); + } + + void printThroughput() + { + Timestamp endTime = Timestamp::now(); + int64_t newCounter = transferred_.get(); + int64_t bytes = newCounter - oldCounter_; + int64_t msgs = receivedMessages_.getAndSet(0); + double time = timeDifference(endTime, startTime_); + printf("%4.3f MiB/s %4.3f Ki Msgs/s %6.2f bytes per msg\n", + static_cast(bytes)/time/1024/1024, + static_cast(msgs)/time/1024, + static_cast(bytes)/static_cast(msgs)); + + oldCounter_ = newCounter; + startTime_ = endTime; + } + + EventLoop* loop_; + TcpServer server_; + AtomicInt64 transferred_; + AtomicInt64 receivedMessages_; + int64_t oldCounter_; + Timestamp startTime_; +}; + +int main(int argc, char* argv[]) +{ + mtrace(); + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + if (argc > 1) + { + numThreads = atoi(argv[1]); + } + EventLoop loop; + InetAddress listenAddr(2007); + DiscardServer server(&loop, listenAddr); + + server.start(); + + loop.loop(); +} + diff --git a/examples/netty/echo/client.cc b/examples/netty/echo/client.cc index 0d7da4f9d..3956eb126 100644 --- a/examples/netty/echo/client.cc +++ b/examples/netty/echo/client.cc @@ -16,11 +16,6 @@ using namespace muduo; using namespace muduo::net; -int numThreads = 0; -class EchoClient; -std::vector clients; -int current = 0; - class EchoClient : boost::noncopyable { public: diff --git a/examples/netty/echo/server.cc b/examples/netty/echo/server.cc index 858676dca..3b28eaa03 100644 --- a/examples/netty/echo/server.cc +++ b/examples/netty/echo/server.cc @@ -54,6 +54,7 @@ class EchoServer { size_t len = buf->readableBytes(); transferred_.addAndGet(len); + receivedMessages_.incrementAndGet(); conn->send(buf); } @@ -62,8 +63,12 @@ class EchoServer Timestamp endTime = Timestamp::now(); int64_t newCounter = transferred_.get(); int64_t bytes = newCounter - oldCounter_; + int64_t msgs = receivedMessages_.getAndSet(0); double time = timeDifference(endTime, startTime_); - printf("%4.3f MiB/s\n", static_cast(bytes)/time/1024/1024); + printf("%4.3f MiB/s %4.3f Ki Msgs/s %6.2f bytes per msg\n", + static_cast(bytes)/time/1024/1024, + static_cast(msgs)/time/1024, + static_cast(bytes)/static_cast(msgs)); oldCounter_ = newCounter; startTime_ = endTime; @@ -72,6 +77,7 @@ class EchoServer EventLoop* loop_; TcpServer server_; AtomicInt64 transferred_; + AtomicInt64 receivedMessages_; int64_t oldCounter_; Timestamp startTime_; }; diff --git a/muduo/base/Atomic.h b/muduo/base/Atomic.h index 097593b0f..889e02ff2 100644 --- a/muduo/base/Atomic.h +++ b/muduo/base/Atomic.h @@ -25,6 +25,18 @@ class AtomicInt64 : boost::noncopyable return value_; } + int64_t incrementAndGet() + { + return addAndGet(1); + } + + int64_t getAndSet(int64_t newValue) + { + int64_t old = value_; + value_ = newValue; + return old; + } + private: int64_t value_; }; diff --git a/muduo/net/Callbacks.h b/muduo/net/Callbacks.h index 542722c7d..14a5ce53a 100644 --- a/muduo/net/Callbacks.h +++ b/muduo/net/Callbacks.h @@ -29,6 +29,7 @@ typedef boost::shared_ptr TcpConnectionPtr; typedef boost::function TimerCallback; typedef boost::function ConnectionCallback; typedef boost::function CloseCallback; +typedef boost::function WriteCompleteCallback; // the data has been read to (buf, len) typedef boost::functionsetConnectionCallback(connectionCallback_); conn->setMessageCallback(messageCallback_); + conn->setWriteCompleteCallback(writeCompleteCallback_); conn->setCloseCallback( boost::bind(&TcpClient::removeConnection, this, _1)); { diff --git a/muduo/net/TcpClient.h b/muduo/net/TcpClient.h index 1fe6becca..5e8c727bc 100644 --- a/muduo/net/TcpClient.h +++ b/muduo/net/TcpClient.h @@ -50,6 +50,11 @@ class TcpClient : boost::noncopyable void setMessageCallback(const MessageCallback& cb) { messageCallback_ = cb; } + /// Set write complete callback. + /// Not thread safe. + void setWriteCompleteCallback(const WriteCompleteCallback& cb) + { writeCompleteCallback_ = cb; } + private: /// Not thread safe, but in loop void newConnection(int sockfd); @@ -61,6 +66,7 @@ class TcpClient : boost::noncopyable const string name_; ConnectionCallback connectionCallback_; MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; bool retry_; // atmoic // always in loop thread int nextConnId_; diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 9c118935c..df81fabf2 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -144,11 +144,18 @@ void TcpConnection::sendInLoop(const void* data, size_t len) { LOG_TRACE << "I am going to write more data"; } + else if (writeCompleteCallback_) + { + loop_->queueInLoop(boost::bind(writeCompleteCallback_, shared_from_this())); + } } - else// if (errno != EWOULDBLOCK) + else // nwrote < 0 { nwrote = 0; - LOG_SYSERR << "TcpConnection::handleWrite"; + if (errno != EWOULDBLOCK) + { + LOG_SYSERR << "TcpConnection::sendInLoop"; + } } } @@ -237,6 +244,10 @@ void TcpConnection::handleWrite() if (outputBuffer_.readableBytes() == 0) { channel_->disableWriting(); + if (writeCompleteCallback_) + { + loop_->queueInLoop(boost::bind(writeCompleteCallback_, shared_from_this())); + } if (state_ == kDisconnecting) { shutdownInLoop(); @@ -277,6 +288,5 @@ void TcpConnection::handleError() int err = sockets::getSocketError(channel_->fd()); LOG_ERROR << "TcpConnection::handleError [" << name_ << "] - SO_ERROR = " << err << " " << strerror_tl(err); - //handleClose(); } diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index b63e1262b..61f12b0d3 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -68,6 +68,9 @@ class TcpConnection : public boost::enable_shared_from_this, void setMessageCallback(const MessageCallback& cb) { messageCallback_ = cb; } + void setWriteCompleteCallback(const WriteCompleteCallback& cb) + { writeCompleteCallback_ = cb; } + /// Internal use only. void setCloseCallback(const CloseCallback& cb) { closeCallback_ = cb; } @@ -99,6 +102,7 @@ class TcpConnection : public boost::enable_shared_from_this, InetAddress peerAddr_; ConnectionCallback connectionCallback_; MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; ConnectionCallback closeCallback_; Buffer inputBuffer_; // MutexLock mutex_; diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index f64db3ee5..2d153c3c8 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -70,7 +70,8 @@ void TcpServer::start() if (!acceptor_->listenning()) { - acceptor_->listen(); + loop_->runInLoop( + boost::bind(&Acceptor::listen, get_pointer(acceptor_))); } } @@ -93,6 +94,7 @@ void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) connections_[connName] = conn; conn->setConnectionCallback(connectionCallback_); conn->setMessageCallback(messageCallback_); + conn->setWriteCompleteCallback(writeCompleteCallback_); conn->setCloseCallback( boost::bind(&TcpServer::removeConnection, this, _1)); ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn)); diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index b0d629ccb..8d1118e60 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -72,6 +72,11 @@ class TcpServer : boost::noncopyable void setMessageCallback(const MessageCallback& cb) { messageCallback_ = cb; } + /// Set write complete callback. + /// Not thread safe. + void setWriteCompleteCallback(const WriteCompleteCallback& cb) + { writeCompleteCallback_ = cb; } + private: /// Not thread safe, but in loop void newConnection(int sockfd, const InetAddress& peerAddr); @@ -89,6 +94,7 @@ class TcpServer : boost::noncopyable boost::scoped_ptr threadPool_; ConnectionCallback connectionCallback_; MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; bool started_; // always in loop thread int nextConnId_; From ed015807610f0240c3c5935a0f0c4690c0f2a441 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 24 Apr 2010 16:01:32 +0000 Subject: [PATCH 059/371] Add netty uptime example, not finish yet. --- examples/CMakeLists.txt | 1 + examples/netty/discard/client.cc | 2 +- examples/netty/discard/server.cc | 2 +- examples/netty/uptime/CMakeLists.txt | 3 ++ examples/netty/uptime/uptime.cc | 71 ++++++++++++++++++++++++++++ muduo/net/CMakeLists.txt | 1 + 6 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 examples/netty/uptime/CMakeLists.txt create mode 100644 examples/netty/uptime/uptime.cc diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 82002baf4..2f232c970 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,3 +6,4 @@ add_subdirectory(asio/chat) add_subdirectory(netty/discard) add_subdirectory(netty/echo) +add_subdirectory(netty/uptime) diff --git a/examples/netty/discard/client.cc b/examples/netty/discard/client.cc index 491cbab4b..b6daaba6b 100644 --- a/examples/netty/discard/client.cc +++ b/examples/netty/discard/client.cc @@ -69,7 +69,7 @@ int main(int argc, char* argv[]) if (argc > 1) { EventLoop loop; - InetAddress serverAddr(argv[1], 2007); + InetAddress serverAddr(argv[1], 2009); int size = 256; if (argc > 2) diff --git a/examples/netty/discard/server.cc b/examples/netty/discard/server.cc index e7c293a5a..565aa630e 100644 --- a/examples/netty/discard/server.cc +++ b/examples/netty/discard/server.cc @@ -91,7 +91,7 @@ int main(int argc, char* argv[]) numThreads = atoi(argv[1]); } EventLoop loop; - InetAddress listenAddr(2007); + InetAddress listenAddr(2009); DiscardServer server(&loop, listenAddr); server.start(); diff --git a/examples/netty/uptime/CMakeLists.txt b/examples/netty/uptime/CMakeLists.txt new file mode 100644 index 000000000..415458c8d --- /dev/null +++ b/examples/netty/uptime/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(netty_uptime uptime.cc) +target_link_libraries(netty_uptime muduo_net) + diff --git a/examples/netty/uptime/uptime.cc b/examples/netty/uptime/uptime.cc new file mode 100644 index 000000000..8016f0865 --- /dev/null +++ b/examples/netty/uptime/uptime.cc @@ -0,0 +1,71 @@ +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +class UptimeClient : boost::noncopyable +{ + public: + UptimeClient(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + client_(loop, listenAddr, "UptimeClient") + { + client_.setConnectionCallback( + boost::bind(&UptimeClient::onConnection, this, _1)); + client_.setMessageCallback( + boost::bind(&UptimeClient::onMessage, this, _1, _2, _3)); + //client_.enableRetry(); + } + + void connect() + { + client_.connect(); + } + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->localAddress().toHostPort() << " -> " + << conn->peerAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) + { + } + + EventLoop* loop_; + TcpClient client_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + if (argc > 2) + { + EventLoop loop; + InetAddress serverAddr(argv[1], atoi(argv[2])); + + UptimeClient client(&loop, serverAddr); + client.connect(); + loop.loop(); + } + else + { + printf("Usage: %s host_ip port\n", argv[0]); + } +} + diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 74fdda4ba..96e694058 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -25,3 +25,4 @@ target_link_libraries(muduo_net muduo_base) add_subdirectory(http) add_subdirectory(tests) + From ddef9adba3dc2a1d2e588839bb18f16e68693247 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 25 Apr 2010 03:37:58 +0000 Subject: [PATCH 060/371] Add empty inspector. --- ChangeLog | 4 ++++ muduo/net/CMakeLists.txt | 1 + muduo/net/http/HttpServer.cc | 12 ++++++++++++ muduo/net/http/HttpServer.h | 7 +++++++ muduo/net/inspect/CMakeLists.txt | 8 ++++++++ muduo/net/inspect/Inspector.cc | 15 +++++++++++++++ muduo/net/inspect/Inspector.h | 31 +++++++++++++++++++++++++++++++ 7 files changed, 78 insertions(+) create mode 100644 muduo/net/inspect/CMakeLists.txt create mode 100644 muduo/net/inspect/Inspector.cc create mode 100644 muduo/net/inspect/Inspector.h diff --git a/ChangeLog b/ChangeLog index ffa3f2503..0b29b4549 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ * First alpha release, version 0.1.0 +2010-04-25 Shuo Chen + + * Add examples. + 2010-04-11 Shuo Chen * TcpClient works. diff --git a/muduo/net/CMakeLists.txt b/muduo/net/CMakeLists.txt index 96e694058..b1627ab84 100644 --- a/muduo/net/CMakeLists.txt +++ b/muduo/net/CMakeLists.txt @@ -24,5 +24,6 @@ add_library(muduo_net ${net_SRCS}) target_link_libraries(muduo_net muduo_base) add_subdirectory(http) +add_subdirectory(inspect) add_subdirectory(tests) diff --git a/muduo/net/http/HttpServer.cc b/muduo/net/http/HttpServer.cc index 3e084f44c..5d585efd1 100644 --- a/muduo/net/http/HttpServer.cc +++ b/muduo/net/http/HttpServer.cc @@ -13,3 +13,15 @@ using namespace muduo; using namespace muduo::net; +HttpServer::HttpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name) + : server_(loop, listenAddr, name) +{ +} + +void HttpServer::start() +{ + server_.start(); +} + diff --git a/muduo/net/http/HttpServer.h b/muduo/net/http/HttpServer.h index 2a21486be..8ebbb571e 100644 --- a/muduo/net/http/HttpServer.h +++ b/muduo/net/http/HttpServer.h @@ -12,6 +12,7 @@ #define MUDUO_NET_HTTP_HTTPSERVER_H #include +#include namespace muduo { @@ -21,8 +22,14 @@ namespace net class HttpServer : boost::noncopyable { public: + HttpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name); + + void start(); private: + TcpServer server_; }; } diff --git a/muduo/net/inspect/CMakeLists.txt b/muduo/net/inspect/CMakeLists.txt new file mode 100644 index 000000000..3f49e412c --- /dev/null +++ b/muduo/net/inspect/CMakeLists.txt @@ -0,0 +1,8 @@ +set(inspect_SRCS + Inspector.cc + ) + +add_library(muduo_inspect ${inspect_SRCS}) +target_link_libraries(muduo_inspect muduo_net) + +# add_subdirectory(tests) diff --git a/muduo/net/inspect/Inspector.cc b/muduo/net/inspect/Inspector.cc new file mode 100644 index 000000000..84e173536 --- /dev/null +++ b/muduo/net/inspect/Inspector.cc @@ -0,0 +1,15 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include + +using namespace muduo; +using namespace muduo::net; + + diff --git a/muduo/net/inspect/Inspector.h b/muduo/net/inspect/Inspector.h new file mode 100644 index 000000000..0758561de --- /dev/null +++ b/muduo/net/inspect/Inspector.h @@ -0,0 +1,31 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_INSPECT_INSPECTOR_H +#define MUDUO_NET_INSPECT_INSPECTOR_H + +#include + +namespace muduo +{ +namespace net +{ + +class Inspector : boost::noncopyable +{ + public: + + private: +}; + +} +} + +#endif // MUDUO_NET_INSPECT_INSPECTOR_H From 1d6e54c49babe1975a1b6285e8b7f039c04b3ab3 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 25 Apr 2010 03:46:35 +0000 Subject: [PATCH 061/371] Implement atomic integer with gcc builtins. --- muduo/base/Atomic.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/muduo/base/Atomic.h b/muduo/base/Atomic.h index 889e02ff2..f8c522574 100644 --- a/muduo/base/Atomic.h +++ b/muduo/base/Atomic.h @@ -21,8 +21,7 @@ class AtomicInt64 : boost::noncopyable int64_t addAndGet(int64_t x) { - value_ += x; - return value_; + return __sync_add_and_fetch(&value_, x); } int64_t incrementAndGet() @@ -32,13 +31,11 @@ class AtomicInt64 : boost::noncopyable int64_t getAndSet(int64_t newValue) { - int64_t old = value_; - value_ = newValue; - return old; + return __sync_lock_test_and_set(&value_, newValue); } private: - int64_t value_; + volatile int64_t value_; }; } From 8eb65c4c7b1c173e3c880b7dc33a9c8e666845b6 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 29 Apr 2010 16:32:08 +0000 Subject: [PATCH 062/371] A dummy http server works. --- examples/asio/chat/codec.h | 2 +- muduo/net/Buffer.cc | 2 + muduo/net/Buffer.h | 8 ++ muduo/net/TcpConnection.h | 11 +++ muduo/net/http/CMakeLists.txt | 4 + muduo/net/http/HttpCodec.cc | 100 +++++++++++++++++++++++ muduo/net/http/HttpCodec.h | 48 +++++++++++ muduo/net/http/HttpContext.h | 76 +++++++++++++++++ muduo/net/http/HttpRequest.h | 103 ++++++++++++++++++++++++ muduo/net/http/HttpServer.cc | 45 ++++++++++- muduo/net/http/HttpServer.h | 22 ++++- muduo/net/http/tests/httpserver_test.cc | 12 +++ 12 files changed, 430 insertions(+), 3 deletions(-) create mode 100644 muduo/net/http/HttpCodec.cc create mode 100644 muduo/net/http/HttpCodec.h create mode 100644 muduo/net/http/HttpContext.h create mode 100644 muduo/net/http/HttpRequest.h create mode 100644 muduo/net/http/tests/httpserver_test.cc diff --git a/examples/asio/chat/codec.h b/examples/asio/chat/codec.h index b57366917..2bd502264 100644 --- a/examples/asio/chat/codec.h +++ b/examples/asio/chat/codec.h @@ -61,7 +61,7 @@ class LengthHeaderCodec : boost::noncopyable private: StringMessageCallback messageCallback_; - muduo::Timestamp receiveTime_; + muduo::Timestamp receiveTime_; // FIXME: this should be per connection, not per server. const static size_t kHeaderLen = sizeof(int32_t); }; diff --git a/muduo/net/Buffer.cc b/muduo/net/Buffer.cc index eba643669..68e69478c 100644 --- a/muduo/net/Buffer.cc +++ b/muduo/net/Buffer.cc @@ -17,6 +17,8 @@ using namespace muduo; using namespace muduo::net; +const char Buffer::kCRLF[] = "\r\n"; + ssize_t Buffer::readFd(int fd, int* savedErrno) { // FIXME use ioctl/FIONREAD to tell how much to read diff --git a/muduo/net/Buffer.h b/muduo/net/Buffer.h index 906d0d619..7a5c9d914 100644 --- a/muduo/net/Buffer.h +++ b/muduo/net/Buffer.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -71,6 +72,12 @@ class Buffer : public muduo::copyable const char* peek() const { return begin() + readerIndex_; } + const char* findCRLF() const + { + const char* crlf = std::search(peek(), begin()+writerIndex_, kCRLF, kCRLF+2); + return crlf == begin()+writerIndex_ ? NULL : crlf; + } + // retrieve returns void, to prevent // string str(retrieve(readableBytes()), readableBytes()); // the evaluation of two functions are unspecified @@ -156,6 +163,7 @@ class Buffer : public muduo::copyable std::vector buffer_; size_t readerIndex_; size_t writerIndex_; + static const char kCRLF[]; }; } diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index 61f12b0d3..c359e7fb3 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -62,6 +63,15 @@ class TcpConnection : public boost::enable_shared_from_this, void send(Buffer* message); // this one will swap data void shutdown(); // NOT thread safe, no simultaneous calling + void setContext(const boost::any& context) + { context_ = context; } + + boost::any& getContext() + { return context_; } + + const boost::any& getContext() const + { return context_; } + void setConnectionCallback(const ConnectionCallback& cb) { connectionCallback_ = cb; } @@ -107,6 +117,7 @@ class TcpConnection : public boost::enable_shared_from_this, Buffer inputBuffer_; // MutexLock mutex_; Buffer outputBuffer_; + boost::any context_; }; typedef boost::shared_ptr TcpConnectionPtr; diff --git a/muduo/net/http/CMakeLists.txt b/muduo/net/http/CMakeLists.txt index a68044dd9..68dd2354a 100644 --- a/muduo/net/http/CMakeLists.txt +++ b/muduo/net/http/CMakeLists.txt @@ -1,8 +1,12 @@ set(http_SRCS + HttpCodec.cc HttpServer.cc ) add_library(muduo_http ${http_SRCS}) target_link_libraries(muduo_http muduo_net) +add_executable(httpserver_test tests/httpserver_test.cc) +target_link_libraries(httpserver_test muduo_http) + # add_subdirectory(tests) diff --git a/muduo/net/http/HttpCodec.cc b/muduo/net/http/HttpCodec.cc new file mode 100644 index 000000000..f06bcedcb --- /dev/null +++ b/muduo/net/http/HttpCodec.cc @@ -0,0 +1,100 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ + bool processRequestLine(const char* begin, const char* end, HttpContext* context) + { + bool succeed = false; + const char* start = begin; + const char* space = std::find(start, end, ' '); + if (space != end && context->request().setMethod(start, space)) + { + start = space+1; + space = std::find(start, end, ' '); + if (space != end) + { + context->request().setUri(start, space); + start = space+1; + succeed = end-start == 8 && std::equal(start, end, "HTTP/1.1"); + } + } + return succeed; + } + +} + +void HttpCodec::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + HttpContext& context = boost::any_cast(conn->getContext()); + bool hasMore = true; + while (hasMore) + { + if (context.expectRequestLine()) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + if (processRequestLine(buf->peek(), crlf, &context)) + { + buf->retrieve(crlf - buf->peek() + 2); + context.receiveRequestLine(); + } + else + { + conn->shutdown(); + } + } + else + { + hasMore = false; + } + } + else if (context.expectHeaders()) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + const char* colon = std::find(buf->peek(), crlf, ':'); + if (colon != crlf) + { + context.request().addHeader(buf->peek(), colon, crlf); + } + else + { + context.receiveHeaders(); + hasMore = !context.gotAll(); + } + buf->retrieve(crlf - buf->peek() + 2); + } + else + { + hasMore = false; + } + } + else if (context.expectBody()) + { + } + } + + if (context.gotAll()) + { + requestCallback_(conn, context.request()); + context.reset(); + } +} + diff --git a/muduo/net/http/HttpCodec.h b/muduo/net/http/HttpCodec.h new file mode 100644 index 000000000..3d67b4dfa --- /dev/null +++ b/muduo/net/http/HttpCodec.h @@ -0,0 +1,48 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_HTTP_HTTPCODEC_H +#define MUDUO_NET_HTTP_HTTPCODEC_H + +#include + +#include +#include + +namespace muduo +{ +namespace net +{ + +class HttpRequest; + +class HttpCodec : boost::noncopyable +{ + public: + typedef boost::function HttpRequestCallback; + + explicit HttpCodec(const HttpRequestCallback& cb) + : requestCallback_(cb) + { + } + + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); + + private: + HttpRequestCallback requestCallback_; +}; + +} +} + +#endif // MUDUO_NET_HTTP_HTTPCODEC_H diff --git a/muduo/net/http/HttpContext.h b/muduo/net/http/HttpContext.h new file mode 100644 index 000000000..d182fe561 --- /dev/null +++ b/muduo/net/http/HttpContext.h @@ -0,0 +1,76 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_HTTP_HTTPCONTEXT_H +#define MUDUO_NET_HTTP_HTTPCONTEXT_H + +#include + +#include + +namespace muduo +{ +namespace net +{ + +class HttpContext : public muduo::copyable +{ + public: + enum HttpRequestParseState + { + kExpectRequestLine, + kExpectHeaders, + kExpectBody, + kGotAll, + }; + + HttpContext() + : state_(kExpectRequestLine) + { + } + + // default copy-ctor, dtor and assignment are fine + + bool expectRequestLine() const + { return state_ == kExpectRequestLine; } + + bool expectHeaders() const + { return state_ == kExpectHeaders; } + + bool expectBody() const + { return state_ == kExpectBody; } + + bool gotAll() const + { return state_ == kGotAll; } + + void receiveRequestLine() + { state_ = kExpectHeaders; } + + void receiveHeaders() + { state_ = kGotAll; } // FIXME + + void reset() + { state_ = kExpectRequestLine; } + + const HttpRequest& request() const + { return request_; } + + HttpRequest& request() + { return request_; } + + private: + HttpRequestParseState state_; + HttpRequest request_; +}; + +} +} + +#endif // MUDUO_NET_HTTP_HTTPCONTEXT_H diff --git a/muduo/net/http/HttpRequest.h b/muduo/net/http/HttpRequest.h new file mode 100644 index 000000000..a1094ee1f --- /dev/null +++ b/muduo/net/http/HttpRequest.h @@ -0,0 +1,103 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPREQUEST_H +#define MUDUO_NET_HTTP_HTTPREQUEST_H + +#include + +#include + +namespace muduo +{ +namespace net +{ + +class HttpRequest +{ + public: + enum Method + { + kUnknown, kGet, kPost, kHead, kPut, kDelete + }; + + HttpRequest() + : method_(kUnknown) + { + } + + bool setMethod(const char* start, const char* end) + { + assert(method_ == kUnknown); + string method(start, end); + if (method == "GET") + { + method_ = kGet; + } + else if (method == "POST") + { + method_ = kPost; + } + else if (method == "HEAD") + { + method_ = kHead; + } + else if (method == "PUT") + { + method_ = kPut; + } + else if (method == "DELETE") + { + method_ = kDelete; + } + else + { + method_ = kUnknown; + } + return method_ != kUnknown; + } + + void setUri(const char* start, const char* end) + { + uri_.assign(start, end); + } + + const string& uri() const + { return uri_; } + + void addHeader(const char* start, const char* colon, const char* end) + { + string field(start, colon); + ++colon; + while (isspace(*colon)) + { + ++colon; + } + string value(colon, end); + while (!value.empty() && isspace(value[value.size()-1])) + { + value.resize(value.size()-1); + } + headers_[field] = value; + } + + const std::map& headers() const + { return headers_; } + + private: + Method method_; + string uri_; + std::map headers_; +}; + +} +} + +#endif // MUDUO_NET_HTTP_HTTPREQUEST_H diff --git a/muduo/net/http/HttpServer.cc b/muduo/net/http/HttpServer.cc index 5d585efd1..d559702b8 100644 --- a/muduo/net/http/HttpServer.cc +++ b/muduo/net/http/HttpServer.cc @@ -8,15 +8,32 @@ // #include +#include +#include + +#include +#include using namespace muduo; using namespace muduo::net; +namespace +{ +} HttpServer::HttpServer(EventLoop* loop, const InetAddress& listenAddr, const string& name) - : server_(loop, listenAddr, name) + : server_(loop, listenAddr, name), + codec_(new HttpCodec(boost::bind(&HttpServer::onRequest, this, _1, _2))) +{ + server_.setConnectionCallback( + boost::bind(&HttpServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&HttpCodec::onMessage, get_pointer(codec_), _1, _2, _3)); +} + +HttpServer::~HttpServer() { } @@ -25,3 +42,29 @@ void HttpServer::start() server_.start(); } +void HttpServer::onConnection(const TcpConnectionPtr& conn) +{ + if (conn->connected()) + { + conn->setContext(HttpContext()); + } +} + +void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req) +{ + std::cout << "Headers " << req.uri() << std::endl; + const std::map& headers = req.headers(); + for (std::map::const_iterator it = headers.begin(); + it != headers.end(); + ++it) + { + std::cout << it->first << ": " << it->second << std::endl; + } + + conn->send("HTTP/1.1 200 OK\r\n"); + conn->send("Connection: close\r\n"); + conn->send("\r\n"); + conn->send("Hello world.\r\n"); + conn->shutdown(); +} + diff --git a/muduo/net/http/HttpServer.h b/muduo/net/http/HttpServer.h index 8ebbb571e..e3bbf567b 100644 --- a/muduo/net/http/HttpServer.h +++ b/muduo/net/http/HttpServer.h @@ -11,25 +11,45 @@ #ifndef MUDUO_NET_HTTP_HTTPSERVER_H #define MUDUO_NET_HTTP_HTTPSERVER_H -#include #include +#include + +#include + namespace muduo { namespace net { +class HttpCodec; +class HttpRequest; +class HttpResponse; + class HttpServer : boost::noncopyable { public: + typedef boost::function HttpCallback; + HttpServer(EventLoop* loop, const InetAddress& listenAddr, const string& name); + ~HttpServer(); // force out-line dtor, for scoped_ptr members. + void start(); + void registerHttpCallback(const string& path, + const HttpCallback& cb); private: + void onConnection(const TcpConnectionPtr& conn); + void onRequest(const TcpConnectionPtr&, const HttpRequest&); + TcpServer server_; + boost::scoped_ptr codec_; + std::map callbacks_; }; } diff --git a/muduo/net/http/tests/httpserver_test.cc b/muduo/net/http/tests/httpserver_test.cc new file mode 100644 index 000000000..ec9e9ff05 --- /dev/null +++ b/muduo/net/http/tests/httpserver_test.cc @@ -0,0 +1,12 @@ +#include +#include + +using namespace muduo::net; + +int main() +{ + EventLoop loop; + HttpServer server(&loop, InetAddress(8000), "dummy"); + server.start(); + loop.loop(); +} From 797b489f0e5e82b37f20fc35e5ee0c86a48027df Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 4 May 2010 11:21:18 +0000 Subject: [PATCH 063/371] Move HttpCodec into HttpServer, and delete HttpCodec. --- muduo/net/http/CMakeLists.txt | 1 - muduo/net/http/HttpCodec.cc | 100 ---------------------------------- muduo/net/http/HttpCodec.h | 48 ---------------- muduo/net/http/HttpRequest.h | 4 ++ muduo/net/http/HttpServer.cc | 87 +++++++++++++++++++++++++++-- muduo/net/http/HttpServer.h | 5 +- 6 files changed, 90 insertions(+), 155 deletions(-) delete mode 100644 muduo/net/http/HttpCodec.cc delete mode 100644 muduo/net/http/HttpCodec.h diff --git a/muduo/net/http/CMakeLists.txt b/muduo/net/http/CMakeLists.txt index 68dd2354a..3f8fc3e97 100644 --- a/muduo/net/http/CMakeLists.txt +++ b/muduo/net/http/CMakeLists.txt @@ -1,5 +1,4 @@ set(http_SRCS - HttpCodec.cc HttpServer.cc ) diff --git a/muduo/net/http/HttpCodec.cc b/muduo/net/http/HttpCodec.cc deleted file mode 100644 index f06bcedcb..000000000 --- a/muduo/net/http/HttpCodec.cc +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -namespace -{ - bool processRequestLine(const char* begin, const char* end, HttpContext* context) - { - bool succeed = false; - const char* start = begin; - const char* space = std::find(start, end, ' '); - if (space != end && context->request().setMethod(start, space)) - { - start = space+1; - space = std::find(start, end, ' '); - if (space != end) - { - context->request().setUri(start, space); - start = space+1; - succeed = end-start == 8 && std::equal(start, end, "HTTP/1.1"); - } - } - return succeed; - } - -} - -void HttpCodec::onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime) -{ - HttpContext& context = boost::any_cast(conn->getContext()); - bool hasMore = true; - while (hasMore) - { - if (context.expectRequestLine()) - { - const char* crlf = buf->findCRLF(); - if (crlf) - { - if (processRequestLine(buf->peek(), crlf, &context)) - { - buf->retrieve(crlf - buf->peek() + 2); - context.receiveRequestLine(); - } - else - { - conn->shutdown(); - } - } - else - { - hasMore = false; - } - } - else if (context.expectHeaders()) - { - const char* crlf = buf->findCRLF(); - if (crlf) - { - const char* colon = std::find(buf->peek(), crlf, ':'); - if (colon != crlf) - { - context.request().addHeader(buf->peek(), colon, crlf); - } - else - { - context.receiveHeaders(); - hasMore = !context.gotAll(); - } - buf->retrieve(crlf - buf->peek() + 2); - } - else - { - hasMore = false; - } - } - else if (context.expectBody()) - { - } - } - - if (context.gotAll()) - { - requestCallback_(conn, context.request()); - context.reset(); - } -} - diff --git a/muduo/net/http/HttpCodec.h b/muduo/net/http/HttpCodec.h deleted file mode 100644 index 3d67b4dfa..000000000 --- a/muduo/net/http/HttpCodec.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_HTTP_HTTPCODEC_H -#define MUDUO_NET_HTTP_HTTPCODEC_H - -#include - -#include -#include - -namespace muduo -{ -namespace net -{ - -class HttpRequest; - -class HttpCodec : boost::noncopyable -{ - public: - typedef boost::function HttpRequestCallback; - - explicit HttpCodec(const HttpRequestCallback& cb) - : requestCallback_(cb) - { - } - - void onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime); - - private: - HttpRequestCallback requestCallback_; -}; - -} -} - -#endif // MUDUO_NET_HTTP_HTTPCODEC_H diff --git a/muduo/net/http/HttpRequest.h b/muduo/net/http/HttpRequest.h index a1094ee1f..772eb642a 100644 --- a/muduo/net/http/HttpRequest.h +++ b/muduo/net/http/HttpRequest.h @@ -72,6 +72,9 @@ class HttpRequest const string& uri() const { return uri_; } + void setReceiveTime(Timestamp t) + { receiveTime_ = t; } + void addHeader(const char* start, const char* colon, const char* end) { string field(start, colon); @@ -94,6 +97,7 @@ class HttpRequest private: Method method_; string uri_; + Timestamp receiveTime_; std::map headers_; }; diff --git a/muduo/net/http/HttpServer.cc b/muduo/net/http/HttpServer.cc index d559702b8..d64c5a8e9 100644 --- a/muduo/net/http/HttpServer.cc +++ b/muduo/net/http/HttpServer.cc @@ -8,7 +8,6 @@ // #include -#include #include #include @@ -19,18 +18,36 @@ using namespace muduo::net; namespace { + bool processRequestLine(const char* begin, const char* end, HttpContext* context) + { + bool succeed = false; + const char* start = begin; + const char* space = std::find(start, end, ' '); + if (space != end && context->request().setMethod(start, space)) + { + start = space+1; + space = std::find(start, end, ' '); + if (space != end) + { + context->request().setUri(start, space); + start = space+1; + succeed = end-start == 8 && std::equal(start, end, "HTTP/1.1"); + } + } + return succeed; + } + } HttpServer::HttpServer(EventLoop* loop, const InetAddress& listenAddr, const string& name) - : server_(loop, listenAddr, name), - codec_(new HttpCodec(boost::bind(&HttpServer::onRequest, this, _1, _2))) + : server_(loop, listenAddr, name) { server_.setConnectionCallback( boost::bind(&HttpServer::onConnection, this, _1)); server_.setMessageCallback( - boost::bind(&HttpCodec::onMessage, get_pointer(codec_), _1, _2, _3)); + boost::bind(&HttpServer::onMessage, this, _1, _2, _3)); } HttpServer::~HttpServer() @@ -50,6 +67,68 @@ void HttpServer::onConnection(const TcpConnectionPtr& conn) } } +void HttpServer::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + HttpContext& context = boost::any_cast(conn->getContext()); + bool hasMore = true; + while (hasMore) + { + if (context.expectRequestLine()) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + if (processRequestLine(buf->peek(), crlf, &context)) + { + context.request().setReceiveTime(receiveTime); + buf->retrieve(crlf - buf->peek() + 2); + context.receiveRequestLine(); + } + else + { + conn->shutdown(); + } + } + else + { + hasMore = false; + } + } + else if (context.expectHeaders()) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + const char* colon = std::find(buf->peek(), crlf, ':'); + if (colon != crlf) + { + context.request().addHeader(buf->peek(), colon, crlf); + } + else + { + context.receiveHeaders(); + hasMore = !context.gotAll(); + } + buf->retrieve(crlf - buf->peek() + 2); + } + else + { + hasMore = false; + } + } + else if (context.expectBody()) + { + } + } + if (context.gotAll()) + { + onRequest(conn, context.request()); + context.reset(); + } +} + void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req) { std::cout << "Headers " << req.uri() << std::endl; diff --git a/muduo/net/http/HttpServer.h b/muduo/net/http/HttpServer.h index e3bbf567b..c7f887dfe 100644 --- a/muduo/net/http/HttpServer.h +++ b/muduo/net/http/HttpServer.h @@ -22,7 +22,6 @@ namespace muduo namespace net { -class HttpCodec; class HttpRequest; class HttpResponse; @@ -45,10 +44,12 @@ class HttpServer : boost::noncopyable private: void onConnection(const TcpConnectionPtr& conn); + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); void onRequest(const TcpConnectionPtr&, const HttpRequest&); TcpServer server_; - boost::scoped_ptr codec_; std::map callbacks_; }; From f2749b67418999c295d6aa7d0b0c8552995f5bde Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 4 May 2010 11:21:23 +0000 Subject: [PATCH 064/371] Add HttpResponse. --- muduo/base/copyable.h | 1 + muduo/net/Buffer.h | 5 + muduo/net/http/CMakeLists.txt | 3 +- muduo/net/http/HttpRequest.h | 26 +++- muduo/net/http/HttpResponse.cc | 29 +++++ muduo/net/http/HttpResponse.h | 65 ++++++++++ muduo/net/http/HttpServer.cc | 163 +++++++++++++----------- muduo/net/http/HttpServer.h | 19 +-- muduo/net/http/tests/HttpServer_test.cc | 30 +++++ muduo/net/http/tests/httpserver_test.cc | 12 -- 10 files changed, 252 insertions(+), 101 deletions(-) create mode 100644 muduo/net/http/HttpResponse.cc create mode 100644 muduo/net/http/HttpResponse.h create mode 100644 muduo/net/http/tests/HttpServer_test.cc delete mode 100644 muduo/net/http/tests/httpserver_test.cc diff --git a/muduo/base/copyable.h b/muduo/base/copyable.h index f3259ec50..680278897 100644 --- a/muduo/base/copyable.h +++ b/muduo/base/copyable.h @@ -6,6 +6,7 @@ namespace muduo /// A tag class emphasises the objects are copyable. /// The empty base class optimization applies. +/// Any derived class of copyable should be a value type. class copyable { }; diff --git a/muduo/net/Buffer.h b/muduo/net/Buffer.h index 7a5c9d914..ea4cc98c5 100644 --- a/muduo/net/Buffer.h +++ b/muduo/net/Buffer.h @@ -101,6 +101,11 @@ class Buffer : public muduo::copyable return str; } + void append(const string& str) + { + append(str.data(), str.length()); + } + void append(const char* /*restrict*/ data, size_t len) { if (writableBytes() < len) diff --git a/muduo/net/http/CMakeLists.txt b/muduo/net/http/CMakeLists.txt index 3f8fc3e97..9badba823 100644 --- a/muduo/net/http/CMakeLists.txt +++ b/muduo/net/http/CMakeLists.txt @@ -1,11 +1,12 @@ set(http_SRCS HttpServer.cc + HttpResponse.cc ) add_library(muduo_http ${http_SRCS}) target_link_libraries(muduo_http muduo_net) -add_executable(httpserver_test tests/httpserver_test.cc) +add_executable(httpserver_test tests/HttpServer_test.cc) target_link_libraries(httpserver_test muduo_http) # add_subdirectory(tests) diff --git a/muduo/net/http/HttpRequest.h b/muduo/net/http/HttpRequest.h index 772eb642a..1513aaeb2 100644 --- a/muduo/net/http/HttpRequest.h +++ b/muduo/net/http/HttpRequest.h @@ -11,16 +11,17 @@ #ifndef MUDUO_NET_HTTP_HTTPREQUEST_H #define MUDUO_NET_HTTP_HTTPREQUEST_H -#include +#include #include +#include namespace muduo { namespace net { -class HttpRequest +class HttpRequest : public muduo::copyable { public: enum Method @@ -64,13 +65,13 @@ class HttpRequest return method_ != kUnknown; } - void setUri(const char* start, const char* end) + void setPath(const char* start, const char* end) { - uri_.assign(start, end); + path_.assign(start, end); } - const string& uri() const - { return uri_; } + const string& path() const + { return path_; } void setReceiveTime(Timestamp t) { receiveTime_ = t; } @@ -91,12 +92,23 @@ class HttpRequest headers_[field] = value; } + string getHeader(const string& field) const + { + string result; + std::map::const_iterator it = headers_.find(field); + if (it != headers_.end()) + { + result = it->second; + } + return result; + } + const std::map& headers() const { return headers_; } private: Method method_; - string uri_; + string path_; Timestamp receiveTime_; std::map headers_; }; diff --git a/muduo/net/http/HttpResponse.cc b/muduo/net/http/HttpResponse.cc new file mode 100644 index 000000000..a047d2539 --- /dev/null +++ b/muduo/net/http/HttpResponse.cc @@ -0,0 +1,29 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +void HttpResponse::appendToBuffer(Buffer* output) const +{ + char buf[32]; + snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_); + string statusLine(buf); + output->append(statusLine); + output->append(statusMessage_); + output->append("\r\n", 2); + + + output->append("\r\n", 2); +} diff --git a/muduo/net/http/HttpResponse.h b/muduo/net/http/HttpResponse.h new file mode 100644 index 000000000..3d3ef5d8f --- /dev/null +++ b/muduo/net/http/HttpResponse.h @@ -0,0 +1,65 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPRESPONSE_H +#define MUDUO_NET_HTTP_HTTPRESPONSE_H + +#include +#include + +#include + +namespace muduo +{ +namespace net +{ + +class Buffer; +class HttpResponse : public muduo::copyable +{ + public: + enum HttpStatusCode + { + kUnknown, + k200OK = 200, + k404NotFound = 404, + }; + + explicit HttpResponse(bool close) + : statusCode_(kUnknown), + closeConnection_(close) + { + } + + void setStatusCode(HttpStatusCode code) + { statusCode_ = code; } + + void setStatusMessage(const string& message) + { statusMessage_ = message; } + + void setCloseConnection(bool on) + { closeConnection_ = on; } + + bool closeConnection() const + { return closeConnection_; } + + void appendToBuffer(Buffer* output) const; + + private: + std::map headers_; + HttpStatusCode statusCode_; + string statusMessage_; + bool closeConnection_; +}; + +} +} + +#endif // MUDUO_NET_HTTP_HTTPRESPONSE_H diff --git a/muduo/net/http/HttpServer.cc b/muduo/net/http/HttpServer.cc index d64c5a8e9..0bafd13db 100644 --- a/muduo/net/http/HttpServer.cc +++ b/muduo/net/http/HttpServer.cc @@ -9,86 +9,57 @@ #include #include +#include +#include #include -#include using namespace muduo; using namespace muduo::net; namespace { - bool processRequestLine(const char* begin, const char* end, HttpContext* context) +bool processRequestLine(const char* begin, const char* end, HttpContext* context) +{ + bool succeed = false; + const char* start = begin; + const char* space = std::find(start, end, ' '); + if (space != end && context->request().setMethod(start, space)) { - bool succeed = false; - const char* start = begin; - const char* space = std::find(start, end, ' '); - if (space != end && context->request().setMethod(start, space)) + start = space+1; + space = std::find(start, end, ' '); + if (space != end) { + context->request().setPath(start, space); start = space+1; - space = std::find(start, end, ' '); - if (space != end) - { - context->request().setUri(start, space); - start = space+1; - succeed = end-start == 8 && std::equal(start, end, "HTTP/1.1"); - } + succeed = end-start == 8 && std::equal(start, end, "HTTP/1.1"); } - return succeed; } - -} - -HttpServer::HttpServer(EventLoop* loop, - const InetAddress& listenAddr, - const string& name) - : server_(loop, listenAddr, name) -{ - server_.setConnectionCallback( - boost::bind(&HttpServer::onConnection, this, _1)); - server_.setMessageCallback( - boost::bind(&HttpServer::onMessage, this, _1, _2, _3)); -} - -HttpServer::~HttpServer() -{ + return succeed; } -void HttpServer::start() +// return false if any error +bool parseRequest(Buffer* buf, HttpContext* context, Timestamp receiveTime) { - server_.start(); -} - -void HttpServer::onConnection(const TcpConnectionPtr& conn) -{ - if (conn->connected()) - { - conn->setContext(HttpContext()); - } -} - -void HttpServer::onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime) -{ - HttpContext& context = boost::any_cast(conn->getContext()); + bool ok = true; bool hasMore = true; while (hasMore) { - if (context.expectRequestLine()) + if (context->expectRequestLine()) { const char* crlf = buf->findCRLF(); if (crlf) { - if (processRequestLine(buf->peek(), crlf, &context)) + ok = processRequestLine(buf->peek(), crlf, context); + if (ok) { - context.request().setReceiveTime(receiveTime); + context->request().setReceiveTime(receiveTime); buf->retrieve(crlf - buf->peek() + 2); - context.receiveRequestLine(); + context->receiveRequestLine(); } else { - conn->shutdown(); + hasMore = false; } } else @@ -96,7 +67,7 @@ void HttpServer::onMessage(const TcpConnectionPtr& conn, hasMore = false; } } - else if (context.expectHeaders()) + else if (context->expectHeaders()) { const char* crlf = buf->findCRLF(); if (crlf) @@ -104,12 +75,12 @@ void HttpServer::onMessage(const TcpConnectionPtr& conn, const char* colon = std::find(buf->peek(), crlf, ':'); if (colon != crlf) { - context.request().addHeader(buf->peek(), colon, crlf); + context->request().addHeader(buf->peek(), colon, crlf); } else { - context.receiveHeaders(); - hasMore = !context.gotAll(); + context->receiveHeaders(); + hasMore = !context->gotAll(); } buf->retrieve(crlf - buf->peek() + 2); } @@ -118,32 +89,80 @@ void HttpServer::onMessage(const TcpConnectionPtr& conn, hasMore = false; } } - else if (context.expectBody()) + else if (context->expectBody()) { } } - if (context.gotAll()) + return ok; +} + +void defaultHttpCallback(const HttpRequest&, HttpResponse* resp) +{ + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + resp->setCloseConnection(true); +} + +} + +HttpServer::HttpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name) + : server_(loop, listenAddr, name), + httpCallback_(defaultHttpCallback) +{ + server_.setConnectionCallback( + boost::bind(&HttpServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&HttpServer::onMessage, this, _1, _2, _3)); +} + +HttpServer::~HttpServer() +{ +} + +void HttpServer::start() +{ + server_.start(); +} + +void HttpServer::onConnection(const TcpConnectionPtr& conn) +{ + if (conn->connected()) { - onRequest(conn, context.request()); - context.reset(); + conn->setContext(HttpContext()); } } -void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req) +void HttpServer::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) { - std::cout << "Headers " << req.uri() << std::endl; - const std::map& headers = req.headers(); - for (std::map::const_iterator it = headers.begin(); - it != headers.end(); - ++it) + HttpContext* context = &boost::any_cast(conn->getContext()); + + if (!parseRequest(buf, context, receiveTime)) { - std::cout << it->first << ": " << it->second << std::endl; + conn->send("HTTP/1.1 400 Bad Request\r\n\r\n"); + conn->shutdown(); } - conn->send("HTTP/1.1 200 OK\r\n"); - conn->send("Connection: close\r\n"); - conn->send("\r\n"); - conn->send("Hello world.\r\n"); - conn->shutdown(); + if (context->gotAll()) + { + onRequest(conn, context->request()); + context->reset(); + } +} + +void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req) +{ + HttpResponse response(req.getHeader("Connection") == "close"); + httpCallback_(req, &response); + Buffer buf; + response.appendToBuffer(&buf); + conn->send(&buf); + if (response.closeConnection()) + { + conn->shutdown(); + } } diff --git a/muduo/net/http/HttpServer.h b/muduo/net/http/HttpServer.h index c7f887dfe..c1e6a995e 100644 --- a/muduo/net/http/HttpServer.h +++ b/muduo/net/http/HttpServer.h @@ -13,10 +13,6 @@ #include -#include - -#include - namespace muduo { namespace net @@ -25,11 +21,14 @@ namespace net class HttpRequest; class HttpResponse; +/// A simple embeddable HTTP server designed for report status of a program. +/// It is not a fully HTTP 1.1 compliant server, but provides minimum features +/// that can communicate with HttpClient and Web browser. +/// It is synchronous, just like Java Servlet. class HttpServer : boost::noncopyable { public: - typedef boost::function HttpCallback; HttpServer(EventLoop* loop, @@ -39,8 +38,10 @@ class HttpServer : boost::noncopyable ~HttpServer(); // force out-line dtor, for scoped_ptr members. void start(); - void registerHttpCallback(const string& path, - const HttpCallback& cb); + + /// Not thread safe, callback be registered before calling start(). + void registerHttpCallback(const HttpCallback& cb) + { httpCallback_ = cb; } private: void onConnection(const TcpConnectionPtr& conn); @@ -50,7 +51,7 @@ class HttpServer : boost::noncopyable void onRequest(const TcpConnectionPtr&, const HttpRequest&); TcpServer server_; - std::map callbacks_; + HttpCallback httpCallback_; }; } diff --git a/muduo/net/http/tests/HttpServer_test.cc b/muduo/net/http/tests/HttpServer_test.cc new file mode 100644 index 000000000..988342641 --- /dev/null +++ b/muduo/net/http/tests/HttpServer_test.cc @@ -0,0 +1,30 @@ +#include +#include +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void onRequest(const HttpRequest& req, HttpResponse* resp) +{ + std::cout << "Headers " << req.path() << std::endl; + const std::map& headers = req.headers(); + for (std::map::const_iterator it = headers.begin(); + it != headers.end(); + ++it) + { + std::cout << it->first << ": " << it->second << std::endl; + } + +} + +int main() +{ + EventLoop loop; + HttpServer server(&loop, InetAddress(8000), "dummy"); + server.start(); + loop.loop(); +} diff --git a/muduo/net/http/tests/httpserver_test.cc b/muduo/net/http/tests/httpserver_test.cc deleted file mode 100644 index ec9e9ff05..000000000 --- a/muduo/net/http/tests/httpserver_test.cc +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include - -using namespace muduo::net; - -int main() -{ - EventLoop loop; - HttpServer server(&loop, InetAddress(8000), "dummy"); - server.start(); - loop.loop(); -} From 3a2a7e04526e625fc05f0728e1078a0d6a8d1c98 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 4 May 2010 11:21:27 +0000 Subject: [PATCH 065/371] Finish sample. --- muduo/net/http/HttpResponse.cc | 17 +++++++++++++---- muduo/net/http/HttpResponse.h | 6 +++++- muduo/net/http/HttpServer.h | 2 +- muduo/net/http/tests/HttpServer_test.cc | 15 +++++++++++++++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/muduo/net/http/HttpResponse.cc b/muduo/net/http/HttpResponse.cc index a047d2539..242b97578 100644 --- a/muduo/net/http/HttpResponse.cc +++ b/muduo/net/http/HttpResponse.cc @@ -19,11 +19,20 @@ void HttpResponse::appendToBuffer(Buffer* output) const { char buf[32]; snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_); - string statusLine(buf); - output->append(statusLine); + output->append(buf); output->append(statusMessage_); - output->append("\r\n", 2); + output->append("\r\n"); + if (closeConnection_) + { + output->append("Connection: close\r\n"); + } + else + { + snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", body_.size()); + output->append(buf); + } - output->append("\r\n", 2); + output->append("\r\n"); + output->append(body_); } diff --git a/muduo/net/http/HttpResponse.h b/muduo/net/http/HttpResponse.h index 3d3ef5d8f..455c48dc9 100644 --- a/muduo/net/http/HttpResponse.h +++ b/muduo/net/http/HttpResponse.h @@ -28,7 +28,7 @@ class HttpResponse : public muduo::copyable enum HttpStatusCode { kUnknown, - k200OK = 200, + k200Ok = 200, k404NotFound = 404, }; @@ -50,6 +50,9 @@ class HttpResponse : public muduo::copyable bool closeConnection() const { return closeConnection_; } + void setBody(const string& body) + { body_ = body; } + void appendToBuffer(Buffer* output) const; private: @@ -57,6 +60,7 @@ class HttpResponse : public muduo::copyable HttpStatusCode statusCode_; string statusMessage_; bool closeConnection_; + string body_; }; } diff --git a/muduo/net/http/HttpServer.h b/muduo/net/http/HttpServer.h index c1e6a995e..085f49004 100644 --- a/muduo/net/http/HttpServer.h +++ b/muduo/net/http/HttpServer.h @@ -40,7 +40,7 @@ class HttpServer : boost::noncopyable void start(); /// Not thread safe, callback be registered before calling start(). - void registerHttpCallback(const HttpCallback& cb) + void setHttpCallback(const HttpCallback& cb) { httpCallback_ = cb; } private: diff --git a/muduo/net/http/tests/HttpServer_test.cc b/muduo/net/http/tests/HttpServer_test.cc index 988342641..5ee19774a 100644 --- a/muduo/net/http/tests/HttpServer_test.cc +++ b/muduo/net/http/tests/HttpServer_test.cc @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -19,12 +20,26 @@ void onRequest(const HttpRequest& req, HttpResponse* resp) std::cout << it->first << ": " << it->second << std::endl; } + if (req.path() == "/") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setCloseConnection(true); + resp->setBody("hello"); + } + else + { + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + resp->setCloseConnection(true); + } } int main() { EventLoop loop; HttpServer server(&loop, InetAddress(8000), "dummy"); + server.setHttpCallback(onRequest); server.start(); loop.loop(); } From aa976ffb36c1cbc99f7151e6f4209c754101ef8b Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 4 May 2010 11:21:29 +0000 Subject: [PATCH 066/371] Add StringPiece from google pcre. --- muduo/base/StringPiece.h | 168 +++++++++++++++++++++++++++++++++++ muduo/base/Types.h | 35 ++++++++ muduo/net/TcpConnection.cc | 4 +- muduo/net/TcpConnection.h | 5 +- muduo/net/http/HttpRequest.h | 15 ++-- 5 files changed, 217 insertions(+), 10 deletions(-) create mode 100644 muduo/base/StringPiece.h diff --git a/muduo/base/StringPiece.h b/muduo/base/StringPiece.h new file mode 100644 index 000000000..d529b3f7a --- /dev/null +++ b/muduo/base/StringPiece.h @@ -0,0 +1,168 @@ +// Taken from PCRE pcre_stringpiece.h +// +// Copyright (c) 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Sanjay Ghemawat +// +// A string like object that points into another piece of memory. +// Useful for providing an interface that allows clients to easily +// pass in either a "const char*" or a "string". +// +// Arghh! I wish C++ literals were automatically of type "string". + +#ifndef MUDUO_BASE_STRINGPIECE_H +#define MUDUO_BASE_STRINGPIECE_H + +#include +#include // for ostream forward-declaration + +#include + +namespace muduo { + +class StringPiece { + private: + const char* ptr_; + int length_; + + public: + // We provide non-explicit singleton constructors so users can pass + // in a "const char*" or a "string" wherever a "StringPiece" is + // expected. + StringPiece() + : ptr_(NULL), length_(0) { } + StringPiece(const char* str) + : ptr_(str), length_(static_cast(strlen(ptr_))) { } + StringPiece(const unsigned char* str) + : ptr_(reinterpret_cast(str)), + length_(static_cast(strlen(ptr_))) { } + StringPiece(const string& str) + : ptr_(str.data()), length_(static_cast(str.size())) { } + StringPiece(const char* offset, int len) + : ptr_(offset), length_(len) { } + + // data() may return a pointer to a buffer with embedded NULs, and the + // returned buffer may or may not be null terminated. Therefore it is + // typically a mistake to pass data() to a routine that expects a NUL + // terminated string. Use "as_string().c_str()" if you really need to do + // this. Or better yet, change your routine so it does not rely on NUL + // termination. + const char* data() const { return ptr_; } + int size() const { return length_; } + bool empty() const { return length_ == 0; } + + void clear() { ptr_ = NULL; length_ = 0; } + void set(const char* buffer, int len) { ptr_ = buffer; length_ = len; } + void set(const char* str) { + ptr_ = str; + length_ = static_cast(strlen(str)); + } + void set(const void* buffer, int len) { + ptr_ = reinterpret_cast(buffer); + length_ = len; + } + + char operator[](int i) const { return ptr_[i]; } + + void remove_prefix(int n) { + ptr_ += n; + length_ -= n; + } + + void remove_suffix(int n) { + length_ -= n; + } + + bool operator==(const StringPiece& x) const { + return ((length_ == x.length_) && + (memcmp(ptr_, x.ptr_, length_) == 0)); + } + bool operator!=(const StringPiece& x) const { + return !(*this == x); + } + +#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \ + bool operator cmp (const StringPiece& x) const { \ + int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \ + return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \ + } + STRINGPIECE_BINARY_PREDICATE(<, <); + STRINGPIECE_BINARY_PREDICATE(<=, <); + STRINGPIECE_BINARY_PREDICATE(>=, >); + STRINGPIECE_BINARY_PREDICATE(>, >); +#undef STRINGPIECE_BINARY_PREDICATE + + int compare(const StringPiece& x) const { + int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); + if (r == 0) { + if (length_ < x.length_) r = -1; + else if (length_ > x.length_) r = +1; + } + return r; + } + + string as_string() const { + return string(data(), size()); + } + + void CopyToString(string* target) const { + target->assign(ptr_, length_); + } + + // Does "this" start with "x" + bool starts_with(const StringPiece& x) const { + return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0)); + } +}; + +} // namespace muduo + +// ------------------------------------------------------------------ +// Functions used to create STL containers that use StringPiece +// Remember that a StringPiece's lifetime had better be less than +// that of the underlying string or char*. If it is not, then you +// cannot safely store a StringPiece into an STL container +// ------------------------------------------------------------------ + +#ifdef HAVE_TYPE_TRAITS +// This makes vector really fast for some STL implementations +template<> struct __type_traits { + typedef __true_type has_trivial_default_constructor; + typedef __true_type has_trivial_copy_constructor; + typedef __true_type has_trivial_assignment_operator; + typedef __true_type has_trivial_destructor; + typedef __true_type is_POD_type; +}; +#endif + +// allow StringPiece to be logged +std::ostream& operator<<(std::ostream& o, const muduo::StringPiece& piece); + +#endif // MUDUO_BASE_STRINGPIECE_H diff --git a/muduo/base/Types.h b/muduo/base/Types.h index 28c816986..dc098a0da 100644 --- a/muduo/base/Types.h +++ b/muduo/base/Types.h @@ -22,6 +22,41 @@ typedef __gnu_cxx::__sso_string string; #endif // Taken from google-protobuf stubs/common.h +// +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) and others +// +// Contains basic types and utilities used by the rest of the library. + // // Use implicit_cast as a safe version of static_cast or const_cast // for upcasting in the type hierarchy (i.e. casting a pointer to Foo diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index df81fabf2..ab36c7cd0 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -86,7 +86,7 @@ void TcpConnection::send(const void* data, size_t len) } } -void TcpConnection::send(const string& message) +void TcpConnection::send(const StringPiece& message) { if (state_ == kConnected) { @@ -126,7 +126,7 @@ void TcpConnection::send(Buffer* buf) } } -void TcpConnection::sendInLoop(const string& message) +void TcpConnection::sendInLoop(const StringPiece& message) { sendInLoop(message.data(), message.size()); } diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index c359e7fb3..c47b0996b 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -12,6 +12,7 @@ #define MUDUO_NET_TCPCONNECTION_H #include +#include #include #include #include @@ -58,7 +59,7 @@ class TcpConnection : public boost::enable_shared_from_this, // void send(string&& message); void send(const void* message, size_t len); - void send(const string& message); + void send(const StringPiece& message); // void send(const Buffer& message); void send(Buffer* message); // this one will swap data void shutdown(); // NOT thread safe, no simultaneous calling @@ -97,7 +98,7 @@ class TcpConnection : public boost::enable_shared_from_this, void handleClose(); void handleError(); //void sendInLoop(string&& message); - void sendInLoop(const string& message); + void sendInLoop(const StringPiece& message); void sendInLoop(const void* message, size_t len); void shutdownInLoop(); void setState(States s) { state_ = s; } diff --git a/muduo/net/http/HttpRequest.h b/muduo/net/http/HttpRequest.h index 1513aaeb2..88c69b224 100644 --- a/muduo/net/http/HttpRequest.h +++ b/muduo/net/http/HttpRequest.h @@ -37,24 +37,24 @@ class HttpRequest : public muduo::copyable bool setMethod(const char* start, const char* end) { assert(method_ == kUnknown); - string method(start, end); - if (method == "GET") + string m(start, end); + if (m == "GET") { method_ = kGet; } - else if (method == "POST") + else if (m == "POST") { method_ = kPost; } - else if (method == "HEAD") + else if (m == "HEAD") { method_ = kHead; } - else if (method == "PUT") + else if (m == "PUT") { method_ = kPut; } - else if (method == "DELETE") + else if (m == "DELETE") { method_ = kDelete; } @@ -65,6 +65,9 @@ class HttpRequest : public muduo::copyable return method_ != kUnknown; } + Method method() const + { return method_; } + void setPath(const char* start, const char* end) { path_.assign(start, end); From bdc93403e29583747616a812e083003fdb6f624f Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 4 May 2010 11:21:30 +0000 Subject: [PATCH 067/371] Comment out TimerQueue::cancel. --- muduo/net/TimerQueue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/muduo/net/TimerQueue.h b/muduo/net/TimerQueue.h index 676fa335c..14a2dac13 100644 --- a/muduo/net/TimerQueue.h +++ b/muduo/net/TimerQueue.h @@ -48,7 +48,7 @@ class TimerQueue : boost::noncopyable Timestamp when, double interval); - void cancel(TimerId timerId); + // void cancel(TimerId timerId); private: // called when timerfd arms From 88ab6786c1ce4805bfe78652fe62b97912a71e5e Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 6 May 2010 19:16:32 +0800 Subject: [PATCH 068/371] Fix compile on 32-bit. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f479ea5c9..94cfeb26d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ set(CXX_FLAGS -Wpointer-arith -Wshadow -Wwrite-strings + -march=native # -MMD # -std=c++0x -rdynamic From 76ee66548907d538bda82ae455455941ad6509b0 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 7 May 2010 00:14:26 +0800 Subject: [PATCH 069/371] Reset after http request. --- muduo/base/Timestamp.h | 5 +++++ muduo/net/http/HttpContext.h | 6 +++++- muduo/net/http/HttpRequest.h | 8 ++++++++ muduo/net/http/tests/HttpServer_test.cc | 4 ++-- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/muduo/base/Timestamp.h b/muduo/base/Timestamp.h index f1a5d66ac..e0cbb34c0 100644 --- a/muduo/base/Timestamp.h +++ b/muduo/base/Timestamp.h @@ -27,6 +27,11 @@ class Timestamp : public muduo::copyable /// @param microSecondsSinceEpoch explicit Timestamp(int64_t microSecondsSinceEpoch); + void swap(Timestamp& that) + { + std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_); + } + // default copy/assignment are Okay string toString() const; diff --git a/muduo/net/http/HttpContext.h b/muduo/net/http/HttpContext.h index d182fe561..52c0213b5 100644 --- a/muduo/net/http/HttpContext.h +++ b/muduo/net/http/HttpContext.h @@ -57,7 +57,11 @@ class HttpContext : public muduo::copyable { state_ = kGotAll; } // FIXME void reset() - { state_ = kExpectRequestLine; } + { + state_ = kExpectRequestLine; + HttpRequest dummy; + request_.swap(dummy); + } const HttpRequest& request() const { return request_; } diff --git a/muduo/net/http/HttpRequest.h b/muduo/net/http/HttpRequest.h index 88c69b224..3ffb58ddd 100644 --- a/muduo/net/http/HttpRequest.h +++ b/muduo/net/http/HttpRequest.h @@ -109,6 +109,14 @@ class HttpRequest : public muduo::copyable const std::map& headers() const { return headers_; } + void swap(HttpRequest& that) + { + std::swap(method_, that.method_); + path_.swap(that.path_); + receiveTime_.swap(that.receiveTime_); + headers_.swap(that.headers_); + } + private: Method method_; string path_; diff --git a/muduo/net/http/tests/HttpServer_test.cc b/muduo/net/http/tests/HttpServer_test.cc index 5ee19774a..b2e833487 100644 --- a/muduo/net/http/tests/HttpServer_test.cc +++ b/muduo/net/http/tests/HttpServer_test.cc @@ -24,8 +24,8 @@ void onRequest(const HttpRequest& req, HttpResponse* resp) { resp->setStatusCode(HttpResponse::k200Ok); resp->setStatusMessage("OK"); - resp->setCloseConnection(true); - resp->setBody("hello"); + //resp->setCloseConnection(true); + resp->setBody("This is title

Hello

"); } else { From 563d6bdf44cda90f1cea7b6d2918acfb10d2877b Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 7 May 2010 23:09:52 +0800 Subject: [PATCH 070/371] Add favicon to dummy http server --- muduo/net/TcpServer.cc | 4 +- muduo/net/TcpServer.h | 5 +- muduo/net/http/HttpResponse.cc | 10 +++ muduo/net/http/HttpResponse.h | 3 + muduo/net/http/HttpServer.cc | 4 ++ muduo/net/http/tests/HttpServer_test.cc | 90 ++++++++++++++++++++++++- 6 files changed, 110 insertions(+), 6 deletions(-) diff --git a/muduo/net/TcpServer.cc b/muduo/net/TcpServer.cc index 2d153c3c8..6331b7b54 100644 --- a/muduo/net/TcpServer.cc +++ b/muduo/net/TcpServer.cc @@ -23,10 +23,10 @@ using namespace muduo::net; TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr, - const string& name) + const string& _name) : loop_(CHECK_NOTNULL(loop)), hostport_(listenAddr.toHostPort()), - name_(name), + name_(_name), acceptor_(new Acceptor(loop, listenAddr)), threadPool_(new EventLoopThreadPool(loop)), connectionCallback_(defaultConnectionCallback), diff --git a/muduo/net/TcpServer.h b/muduo/net/TcpServer.h index 8d1118e60..adb7fab92 100644 --- a/muduo/net/TcpServer.h +++ b/muduo/net/TcpServer.h @@ -39,10 +39,11 @@ class TcpServer : boost::noncopyable //TcpServer(EventLoop* loop, const InetAddress& listenAddr); TcpServer(EventLoop* loop, const InetAddress& listenAddr, - const string& name); + const string& _name); ~TcpServer(); // force out-line dtor, for scoped_ptr members. - // const string& hostport() const { return hostport_; } + const string& hostport() const { return hostport_; } + const string& name() const { return name_; } /// Set the number of threads for handling input. /// diff --git a/muduo/net/http/HttpResponse.cc b/muduo/net/http/HttpResponse.cc index 242b97578..63545a0db 100644 --- a/muduo/net/http/HttpResponse.cc +++ b/muduo/net/http/HttpResponse.cc @@ -33,6 +33,16 @@ void HttpResponse::appendToBuffer(Buffer* output) const output->append(buf); } + for (std::map::const_iterator it = headers_.begin(); + it != headers_.end(); + ++it) + { + output->append(it->first); + output->append(": "); + output->append(it->second); + output->append("\r\n"); + } + output->append("\r\n"); output->append(body_); } diff --git a/muduo/net/http/HttpResponse.h b/muduo/net/http/HttpResponse.h index 455c48dc9..f2c070634 100644 --- a/muduo/net/http/HttpResponse.h +++ b/muduo/net/http/HttpResponse.h @@ -50,6 +50,9 @@ class HttpResponse : public muduo::copyable bool closeConnection() const { return closeConnection_; } + void setContentType(const string& contentType) + { headers_["Content-Type"] = contentType; } + void setBody(const string& body) { body_ = body; } diff --git a/muduo/net/http/HttpServer.cc b/muduo/net/http/HttpServer.cc index 0bafd13db..4eeaa2caa 100644 --- a/muduo/net/http/HttpServer.cc +++ b/muduo/net/http/HttpServer.cc @@ -8,6 +8,8 @@ // #include + +#include #include #include #include @@ -123,6 +125,8 @@ HttpServer::~HttpServer() void HttpServer::start() { + LOG_INFO << "HttpServer[" << server_.name() + << "] starts listenning on " << server_.hostport(); server_.start(); } diff --git a/muduo/net/http/tests/HttpServer_test.cc b/muduo/net/http/tests/HttpServer_test.cc index b2e833487..59ab248ed 100644 --- a/muduo/net/http/tests/HttpServer_test.cc +++ b/muduo/net/http/tests/HttpServer_test.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -9,6 +10,8 @@ using namespace muduo; using namespace muduo::net; +extern char favicon[555]; + void onRequest(const HttpRequest& req, HttpResponse* resp) { std::cout << "Headers " << req.path() << std::endl; @@ -24,8 +27,18 @@ void onRequest(const HttpRequest& req, HttpResponse* resp) { resp->setStatusCode(HttpResponse::k200Ok); resp->setStatusMessage("OK"); - //resp->setCloseConnection(true); - resp->setBody("This is title

Hello

"); + resp->setContentType("text/html"); + string now = Timestamp::now().toFormattedString(); + resp->setBody("This is title" + "

Hello

Now is " + now + + ""); + } + else if (req.path() == "/favicon.ico") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("image/png"); + resp->setBody(string(favicon, sizeof favicon)); } else { @@ -43,3 +56,76 @@ int main() server.start(); loop.loop(); } + +char favicon[555] = { + '\x89', 'P', 'N', 'G', '\xD', '\xA', '\x1A', '\xA', + '\x0', '\x0', '\x0', '\xD', 'I', 'H', 'D', 'R', + '\x0', '\x0', '\x0', '\x10', '\x0', '\x0', '\x0', '\x10', + '\x8', '\x6', '\x0', '\x0', '\x0', '\x1F', '\xF3', '\xFF', + 'a', '\x0', '\x0', '\x0', '\x19', 't', 'E', 'X', + 't', 'S', 'o', 'f', 't', 'w', 'a', 'r', + 'e', '\x0', 'A', 'd', 'o', 'b', 'e', '\x20', + 'I', 'm', 'a', 'g', 'e', 'R', 'e', 'a', + 'd', 'y', 'q', '\xC9', 'e', '\x3C', '\x0', '\x0', + '\x1', '\xCD', 'I', 'D', 'A', 'T', 'x', '\xDA', + '\x94', '\x93', '9', 'H', '\x3', 'A', '\x14', '\x86', + '\xFF', '\x5D', 'b', '\xA7', '\x4', 'R', '\xC4', 'm', + '\x22', '\x1E', '\xA0', 'F', '\x24', '\x8', '\x16', '\x16', + 'v', '\xA', '6', '\xBA', 'J', '\x9A', '\x80', '\x8', + 'A', '\xB4', 'q', '\x85', 'X', '\x89', 'G', '\xB0', + 'I', '\xA9', 'Q', '\x24', '\xCD', '\xA6', '\x8', '\xA4', + 'H', 'c', '\x91', 'B', '\xB', '\xAF', 'V', '\xC1', + 'F', '\xB4', '\x15', '\xCF', '\x22', 'X', '\x98', '\xB', + 'T', 'H', '\x8A', 'd', '\x93', '\x8D', '\xFB', 'F', + 'g', '\xC9', '\x1A', '\x14', '\x7D', '\xF0', 'f', 'v', + 'f', '\xDF', '\x7C', '\xEF', '\xE7', 'g', 'F', '\xA8', + '\xD5', 'j', 'H', '\x24', '\x12', '\x2A', '\x0', '\x5', + '\xBF', 'G', '\xD4', '\xEF', '\xF7', '\x2F', '6', '\xEC', + '\x12', '\x20', '\x1E', '\x8F', '\xD7', '\xAA', '\xD5', '\xEA', + '\xAF', 'I', '5', 'F', '\xAA', 'T', '\x5F', '\x9F', + '\x22', 'A', '\x2A', '\x95', '\xA', '\x83', '\xE5', 'r', + '9', 'd', '\xB3', 'Y', '\x96', '\x99', 'L', '\x6', + '\xE9', 't', '\x9A', '\x25', '\x85', '\x2C', '\xCB', 'T', + '\xA7', '\xC4', 'b', '1', '\xB5', '\x5E', '\x0', '\x3', + 'h', '\x9A', '\xC6', '\x16', '\x82', '\x20', 'X', 'R', + '\x14', 'E', '6', 'S', '\x94', '\xCB', 'e', 'x', + '\xBD', '\x5E', '\xAA', 'U', 'T', '\x23', 'L', '\xC0', + '\xE0', '\xE2', '\xC1', '\x8F', '\x0', '\x9E', '\xBC', '\x9', + 'A', '\x7C', '\x3E', '\x1F', '\x83', 'D', '\x22', '\x11', + '\xD5', 'T', '\x40', '\x3F', '8', '\x80', 'w', '\xE5', + '3', '\x7', '\xB8', '\x5C', '\x2E', 'H', '\x92', '\x4', + '\x87', '\xC3', '\x81', '\x40', '\x20', '\x40', 'g', '\x98', + '\xE9', '6', '\x1A', '\xA6', 'g', '\x15', '\x4', '\xE3', + '\xD7', '\xC8', '\xBD', '\x15', '\xE1', 'i', '\xB7', 'C', + '\xAB', '\xEA', 'x', '\x2F', 'j', 'X', '\x92', '\xBB', + '\x18', '\x20', '\x9F', '\xCF', '3', '\xC3', '\xB8', '\xE9', + 'N', '\xA7', '\xD3', 'l', 'J', '\x0', 'i', '6', + '\x7C', '\x8E', '\xE1', '\xFE', 'V', '\x84', '\xE7', '\x3C', + '\x9F', 'r', '\x2B', '\x3A', 'B', '\x7B', '7', 'f', + 'w', '\xAE', '\x8E', '\xE', '\xF3', '\xBD', 'R', '\xA9', + 'd', '\x2', 'B', '\xAF', '\x85', '2', 'f', 'F', + '\xBA', '\xC', '\xD9', '\x9F', '\x1D', '\x9A', 'l', '\x22', + '\xE6', '\xC7', '\x3A', '\x2C', '\x80', '\xEF', '\xC1', '\x15', + '\x90', '\x7', '\x93', '\xA2', '\x28', '\xA0', 'S', 'j', + '\xB1', '\xB8', '\xDF', '\x29', '5', 'C', '\xE', '\x3F', + 'X', '\xFC', '\x98', '\xDA', 'y', 'j', 'P', '\x40', + '\x0', '\x87', '\xAE', '\x1B', '\x17', 'B', '\xB4', '\x3A', + '\x3F', '\xBE', 'y', '\xC7', '\xA', '\x26', '\xB6', '\xEE', + '\xD9', '\x9A', '\x60', '\x14', '\x93', '\xDB', '\x8F', '\xD', + '\xA', '\x2E', '\xE9', '\x23', '\x95', '\x29', 'X', '\x0', + '\x27', '\xEB', 'n', 'V', 'p', '\xBC', '\xD6', '\xCB', + '\xD6', 'G', '\xAB', '\x3D', 'l', '\x7D', '\xB8', '\xD2', + '\xDD', '\xA0', '\x60', '\x83', '\xBA', '\xEF', '\x5F', '\xA4', + '\xEA', '\xCC', '\x2', 'N', '\xAE', '\x5E', 'p', '\x1A', + '\xEC', '\xB3', '\x40', '9', '\xAC', '\xFE', '\xF2', '\x91', + '\x89', 'g', '\x91', '\x85', '\x21', '\xA8', '\x87', '\xB7', + 'X', '\x7E', '\x7E', '\x85', '\xBB', '\xCD', 'N', 'N', + 'b', 't', '\x40', '\xFA', '\x93', '\x89', '\xEC', '\x1E', + '\xEC', '\x86', '\x2', 'H', '\x26', '\x93', '\xD0', 'u', + '\x1D', '\x7F', '\x9', '2', '\x95', '\xBF', '\x1F', '\xDB', + '\xD7', 'c', '\x8A', '\x1A', '\xF7', '\x5C', '\xC1', '\xFF', + '\x22', 'J', '\xC3', '\x87', '\x0', '\x3', '\x0', 'K', + '\xBB', '\xF8', '\xD6', '\x2A', 'v', '\x98', 'I', '\x0', + '\x0', '\x0', '\x0', 'I', 'E', 'N', 'D', '\xAE', + 'B', '\x60', '\x82', +}; From a32e2f38cdffaab880b91433136f4a355584c896 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 8 May 2010 00:21:30 +0800 Subject: [PATCH 071/371] Inspector --- .gitignore | 1 + muduo/net/http/HttpServer.h | 1 + muduo/net/inspect/CMakeLists.txt | 6 ++++-- muduo/net/inspect/Inspector.cc | 14 ++++++++++++++ muduo/net/inspect/Inspector.h | 8 ++++++++ muduo/net/inspect/tests/Inspector_test.cc | 13 +++++++++++++ 6 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 muduo/net/inspect/tests/Inspector_test.cc diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..1377554eb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/muduo/net/http/HttpServer.h b/muduo/net/http/HttpServer.h index 085f49004..54d7364a5 100644 --- a/muduo/net/http/HttpServer.h +++ b/muduo/net/http/HttpServer.h @@ -12,6 +12,7 @@ #define MUDUO_NET_HTTP_HTTPSERVER_H #include +#include namespace muduo { diff --git a/muduo/net/inspect/CMakeLists.txt b/muduo/net/inspect/CMakeLists.txt index 3f49e412c..53b8f401f 100644 --- a/muduo/net/inspect/CMakeLists.txt +++ b/muduo/net/inspect/CMakeLists.txt @@ -3,6 +3,8 @@ set(inspect_SRCS ) add_library(muduo_inspect ${inspect_SRCS}) -target_link_libraries(muduo_inspect muduo_net) +target_link_libraries(muduo_inspect muduo_http) + +add_executable(inspector_test tests/Inspector_test.cc) +target_link_libraries(inspector_test muduo_inspect) -# add_subdirectory(tests) diff --git a/muduo/net/inspect/Inspector.cc b/muduo/net/inspect/Inspector.cc index 84e173536..5f515c055 100644 --- a/muduo/net/inspect/Inspector.cc +++ b/muduo/net/inspect/Inspector.cc @@ -8,8 +8,22 @@ // #include +#include + +#include using namespace muduo; using namespace muduo::net; +Inspector::Inspector(EventLoop* loop, + const InetAddress& httpAddr, + const string& name) + : server_(loop, httpAddr, "Inspector:"+name) +{ + loop->runAfter(0, boost::bind(&Inspector::start, this)); +} +void Inspector::start() +{ + server_.start(); +} diff --git a/muduo/net/inspect/Inspector.h b/muduo/net/inspect/Inspector.h index 0758561de..186b50eb1 100644 --- a/muduo/net/inspect/Inspector.h +++ b/muduo/net/inspect/Inspector.h @@ -11,6 +11,7 @@ #ifndef MUDUO_NET_INSPECT_INSPECTOR_H #define MUDUO_NET_INSPECT_INSPECTOR_H +#include #include namespace muduo @@ -18,11 +19,18 @@ namespace muduo namespace net { +// A internal inspector of the running process, usually a singleton. class Inspector : boost::noncopyable { public: + Inspector(EventLoop* loop, + const InetAddress& httpAddr, + const string& name); private: + void start(); + + HttpServer server_; }; } diff --git a/muduo/net/inspect/tests/Inspector_test.cc b/muduo/net/inspect/tests/Inspector_test.cc new file mode 100644 index 000000000..d665a82b7 --- /dev/null +++ b/muduo/net/inspect/tests/Inspector_test.cc @@ -0,0 +1,13 @@ +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + EventLoop loop; + Inspector ins(&loop, InetAddress(12345), "test"); + loop.loop(); +} + From 5957a9a33a8bac8fa76b61aafd1d1a689b6a881a Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 11 May 2010 01:29:04 +0800 Subject: [PATCH 072/371] Basic process info inspect command. --- muduo/net/http/HttpRequest.h | 3 + muduo/net/inspect/CMakeLists.txt | 1 + muduo/net/inspect/Inspector.cc | 137 ++++++++++++++++++++++++++++++- muduo/net/inspect/Inspector.h | 23 ++++++ muduo/net/inspect/ProcessInfo.cc | 36 ++++++++ muduo/net/inspect/ProcessInfo.h | 35 ++++++++ 6 files changed, 231 insertions(+), 4 deletions(-) create mode 100644 muduo/net/inspect/ProcessInfo.cc create mode 100644 muduo/net/inspect/ProcessInfo.h diff --git a/muduo/net/http/HttpRequest.h b/muduo/net/http/HttpRequest.h index 3ffb58ddd..6c31d6be2 100644 --- a/muduo/net/http/HttpRequest.h +++ b/muduo/net/http/HttpRequest.h @@ -79,6 +79,9 @@ class HttpRequest : public muduo::copyable void setReceiveTime(Timestamp t) { receiveTime_ = t; } + Timestamp receiveTime() const + { return receiveTime_; } + void addHeader(const char* start, const char* colon, const char* end) { string field(start, colon); diff --git a/muduo/net/inspect/CMakeLists.txt b/muduo/net/inspect/CMakeLists.txt index 53b8f401f..eba87fe04 100644 --- a/muduo/net/inspect/CMakeLists.txt +++ b/muduo/net/inspect/CMakeLists.txt @@ -1,5 +1,6 @@ set(inspect_SRCS Inspector.cc + ProcessInfo.cc ) add_library(muduo_inspect ${inspect_SRCS}) diff --git a/muduo/net/inspect/Inspector.cc b/muduo/net/inspect/Inspector.cc index 5f515c055..3cc004d5b 100644 --- a/muduo/net/inspect/Inspector.cc +++ b/muduo/net/inspect/Inspector.cc @@ -9,21 +9,150 @@ #include #include +#include +#include +#include +//#include +//#include +//#include #include +#include +#include using namespace muduo; using namespace muduo::net; -Inspector::Inspector(EventLoop* loop, - const InetAddress& httpAddr, - const string& name) - : server_(loop, httpAddr, "Inspector:"+name) +namespace { +std::vector split(const string& str) +{ + std::vector result; + size_t start = 0; + size_t pos = str.find('/'); + while (pos != string::npos) + { + if (pos > start) + { + result.push_back(str.substr(start, pos-start)); + } + start = pos+1; + pos = str.find('/', start); + } + + if (start < str.length()) + { + result.push_back(str.substr(start)); + } + + return result; +} +} + +Inspector::Inspector(EventLoop* loop, + const InetAddress& httpAddr, + const string& name) + : server_(loop, httpAddr, "Inspector:"+name), + processInfo_(new ProcessInfo) +{ + server_.setHttpCallback(boost::bind(&Inspector::onRequest, this, _1, _2)); + processInfo_->registerCommands(this); loop->runAfter(0, boost::bind(&Inspector::start, this)); } +Inspector::~Inspector() +{ +} + +void Inspector::add(const string& module, + const string& command, + const Callback& cb, + const string& help) +{ + MutexLockGuard lock(mutex_); + commands_[module][command] = cb; + helps_[module][command] = help; +} + void Inspector::start() { server_.start(); } + +void Inspector::onRequest(const HttpRequest& req, HttpResponse* resp) +{ + if (req.path() == "/") + { + string result; + MutexLockGuard lock(mutex_); + for (std::map::const_iterator helpListI = helps_.begin(); + helpListI != helps_.end(); + ++helpListI) + { + const HelpList& list = helpListI->second; + for (HelpList::const_iterator it = list.begin(); + it != list.end(); + ++it) + { + result += "/"; + result += helpListI->first; + result += "/"; + result += it->first; + result += "\t"; + result += it->second; + result += "\n"; + } + } + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + resp->setBody(result); + } + else + { + std::vector result = split(req.path()); + // boost::split(result, req.path(), boost::is_any_of("/")); + //std::copy(result.begin(), result.end(), std::ostream_iterator(std::cout, ", ")); + //std::cout << "\n"; + bool ok = false; + if (result.size() == 0) + { + } + else if (result.size() == 1) + { + string module = result[0]; + } + else + { + string module = result[0]; + std::map::const_iterator commListI = commands_.find(module); + if (commListI != commands_.end()) + { + string command = result[1]; + const CommandList& commList = commListI->second; + CommandList::const_iterator it = commList.find(command); + if (it != commList.end()) + { + ArgList args(result.begin()+2, result.end()); + if (it->second) + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + resp->setBody(it->second(args)); + ok = true; + } + } + } + + } + + if (!ok) + { + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + } + //resp->setCloseConnection(true); + } +} + diff --git a/muduo/net/inspect/Inspector.h b/muduo/net/inspect/Inspector.h index 186b50eb1..76c313dd9 100644 --- a/muduo/net/inspect/Inspector.h +++ b/muduo/net/inspect/Inspector.h @@ -11,26 +11,49 @@ #ifndef MUDUO_NET_INSPECT_INSPECTOR_H #define MUDUO_NET_INSPECT_INSPECTOR_H +#include #include + +#include +#include #include +#include namespace muduo { namespace net { +class ProcessInfo; + // A internal inspector of the running process, usually a singleton. class Inspector : boost::noncopyable { public: + typedef std::vector ArgList; + typedef boost::function Callback; Inspector(EventLoop* loop, const InetAddress& httpAddr, const string& name); + ~Inspector(); + + void add(const string& module, + const string& command, + const Callback& cb, + const string& help); private: + typedef std::map CommandList; + typedef std::map HelpList; + void start(); + void onRequest(const HttpRequest& req, HttpResponse* resp); HttpServer server_; + boost::scoped_ptr processInfo_; + MutexLock mutex_; + std::map commands_; + std::map helps_; }; } diff --git a/muduo/net/inspect/ProcessInfo.cc b/muduo/net/inspect/ProcessInfo.cc new file mode 100644 index 000000000..cc38543db --- /dev/null +++ b/muduo/net/inspect/ProcessInfo.cc @@ -0,0 +1,36 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void ProcessInfo::registerCommands(Inspector* ins) +{ + ins->add("proc", "status", ProcessInfo::procStatus, "print /proc/self/status"); +} + +string ProcessInfo::procStatus(const Inspector::ArgList& args) +{ + string result; + FILE* fp = fopen("/proc/self/status", "r"); + if (fp) + { + char buf[256] = {0}; + while (fgets(buf, sizeof(buf), fp) != NULL) + { + result += buf; + } + fclose(fp); + } + return result; +} + diff --git a/muduo/net/inspect/ProcessInfo.h b/muduo/net/inspect/ProcessInfo.h new file mode 100644 index 000000000..8783e6e35 --- /dev/null +++ b/muduo/net/inspect/ProcessInfo.h @@ -0,0 +1,35 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_INSPECT_PROCESSINFO_H +#define MUDUO_NET_INSPECT_PROCESSINFO_H + +#include +#include + +namespace muduo +{ +namespace net +{ + +class ProcessInfo : boost::noncopyable +{ + public: + void registerCommands(Inspector* ins); + + private: + static string procStatus(const Inspector::ArgList& args); + +}; + +} +} + +#endif // MUDUO_NET_INSPECT_PROCESSINFO_H From 26849463d8cae51e0e991108f88fbb5ef6a38a39 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Wed, 12 May 2010 00:14:28 +0800 Subject: [PATCH 073/371] add process inspector for opened files --- muduo/base/CMakeLists.txt | 1 + muduo/base/ProcessInfo.cc | 51 +++++++++++++++++++ muduo/base/ProcessInfo.h | 30 +++++++++++ muduo/net/inspect/CMakeLists.txt | 2 +- muduo/net/inspect/Inspector.cc | 6 +-- muduo/net/inspect/Inspector.h | 4 +- muduo/net/inspect/ProcessInfo.cc | 36 ------------- muduo/net/inspect/ProcessInspector.cc | 33 ++++++++++++ .../{ProcessInfo.h => ProcessInspector.h} | 9 ++-- 9 files changed, 126 insertions(+), 46 deletions(-) create mode 100644 muduo/base/ProcessInfo.cc create mode 100644 muduo/base/ProcessInfo.h delete mode 100644 muduo/net/inspect/ProcessInfo.cc create mode 100644 muduo/net/inspect/ProcessInspector.cc rename muduo/net/inspect/{ProcessInfo.h => ProcessInspector.h} (69%) diff --git a/muduo/base/CMakeLists.txt b/muduo/base/CMakeLists.txt index 71f89efa8..d2e23f349 100644 --- a/muduo/base/CMakeLists.txt +++ b/muduo/base/CMakeLists.txt @@ -1,5 +1,6 @@ set(base_SRCS Logging.cc + ProcessInfo.cc Timestamp.cc Thread.cc ) diff --git a/muduo/base/ProcessInfo.cc b/muduo/base/ProcessInfo.cc new file mode 100644 index 000000000..d6967e849 --- /dev/null +++ b/muduo/base/ProcessInfo.cc @@ -0,0 +1,51 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include +#include +#include + +using namespace muduo; + +namespace +{ + __thread int t_numOpenedFiles = 0; + int fdDirFilter(const struct dirent* d) + { + ++t_numOpenedFiles; + return 0; + } +} + +string ProcessInfo::procStatus() +{ + string result; + FILE* fp = fopen("/proc/self/status", "r"); + if (fp) + { + while (!feof(fp)) + { + char buf[8192]; + size_t n = fread(buf, 1, sizeof buf, fp); + result.append(buf, n); + } + fclose(fp); + } + return result; +} + +int ProcessInfo::openedFiles() +{ + t_numOpenedFiles = 0; + struct dirent** namelist; + scandir("/proc/self/fd", &namelist, fdDirFilter, alphasort); + + return t_numOpenedFiles-2; // "." and ".." +} + diff --git a/muduo/base/ProcessInfo.h b/muduo/base/ProcessInfo.h new file mode 100644 index 000000000..857c9c58a --- /dev/null +++ b/muduo/base/ProcessInfo.h @@ -0,0 +1,30 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_BASE_PROCESSINFO_H +#define MUDUO_BASE_PROCESSINFO_H + +#include + +namespace muduo +{ + +namespace ProcessInfo +{ + /// read /proc/self/status + string procStatus(); + + + int openedFiles(); +} + +} + +#endif // MUDUO_BASE_PROCESSINFO_H diff --git a/muduo/net/inspect/CMakeLists.txt b/muduo/net/inspect/CMakeLists.txt index eba87fe04..8ccab3434 100644 --- a/muduo/net/inspect/CMakeLists.txt +++ b/muduo/net/inspect/CMakeLists.txt @@ -1,6 +1,6 @@ set(inspect_SRCS Inspector.cc - ProcessInfo.cc + ProcessInspector.cc ) add_library(muduo_inspect ${inspect_SRCS}) diff --git a/muduo/net/inspect/Inspector.cc b/muduo/net/inspect/Inspector.cc index 3cc004d5b..1488a814e 100644 --- a/muduo/net/inspect/Inspector.cc +++ b/muduo/net/inspect/Inspector.cc @@ -11,7 +11,7 @@ #include #include #include -#include +#include //#include //#include @@ -53,10 +53,10 @@ Inspector::Inspector(EventLoop* loop, const InetAddress& httpAddr, const string& name) : server_(loop, httpAddr, "Inspector:"+name), - processInfo_(new ProcessInfo) + processInspector_(new ProcessInspector) { server_.setHttpCallback(boost::bind(&Inspector::onRequest, this, _1, _2)); - processInfo_->registerCommands(this); + processInspector_->registerCommands(this); loop->runAfter(0, boost::bind(&Inspector::start, this)); } diff --git a/muduo/net/inspect/Inspector.h b/muduo/net/inspect/Inspector.h index 76c313dd9..dc6ab98c5 100644 --- a/muduo/net/inspect/Inspector.h +++ b/muduo/net/inspect/Inspector.h @@ -24,7 +24,7 @@ namespace muduo namespace net { -class ProcessInfo; +class ProcessInspector; // A internal inspector of the running process, usually a singleton. class Inspector : boost::noncopyable @@ -50,7 +50,7 @@ class Inspector : boost::noncopyable void onRequest(const HttpRequest& req, HttpResponse* resp); HttpServer server_; - boost::scoped_ptr processInfo_; + boost::scoped_ptr processInspector_; MutexLock mutex_; std::map commands_; std::map helps_; diff --git a/muduo/net/inspect/ProcessInfo.cc b/muduo/net/inspect/ProcessInfo.cc deleted file mode 100644 index cc38543db..000000000 --- a/muduo/net/inspect/ProcessInfo.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -void ProcessInfo::registerCommands(Inspector* ins) -{ - ins->add("proc", "status", ProcessInfo::procStatus, "print /proc/self/status"); -} - -string ProcessInfo::procStatus(const Inspector::ArgList& args) -{ - string result; - FILE* fp = fopen("/proc/self/status", "r"); - if (fp) - { - char buf[256] = {0}; - while (fgets(buf, sizeof(buf), fp) != NULL) - { - result += buf; - } - fclose(fp); - } - return result; -} - diff --git a/muduo/net/inspect/ProcessInspector.cc b/muduo/net/inspect/ProcessInspector.cc new file mode 100644 index 000000000..c92891f4b --- /dev/null +++ b/muduo/net/inspect/ProcessInspector.cc @@ -0,0 +1,33 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void ProcessInspector::registerCommands(Inspector* ins) +{ + ins->add("proc", "status", ProcessInspector::procStatus, "print /proc/self/status"); + ins->add("proc", "opened_files", ProcessInspector::openedFiles, "count /proc/self/fd"); +} + +string ProcessInspector::procStatus(const Inspector::ArgList& args) +{ + return ProcessInfo::procStatus(); +} + +string ProcessInspector::openedFiles(const Inspector::ArgList& args) +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", ProcessInfo::openedFiles()); + return buf; +} diff --git a/muduo/net/inspect/ProcessInfo.h b/muduo/net/inspect/ProcessInspector.h similarity index 69% rename from muduo/net/inspect/ProcessInfo.h rename to muduo/net/inspect/ProcessInspector.h index 8783e6e35..2ce9a55d5 100644 --- a/muduo/net/inspect/ProcessInfo.h +++ b/muduo/net/inspect/ProcessInspector.h @@ -8,8 +8,8 @@ // // This is an internal header file, you should not include this. -#ifndef MUDUO_NET_INSPECT_PROCESSINFO_H -#define MUDUO_NET_INSPECT_PROCESSINFO_H +#ifndef MUDUO_NET_INSPECT_PROCESSINSPECTOR_H +#define MUDUO_NET_INSPECT_PROCESSINSPECTOR_H #include #include @@ -19,17 +19,18 @@ namespace muduo namespace net { -class ProcessInfo : boost::noncopyable +class ProcessInspector : boost::noncopyable { public: void registerCommands(Inspector* ins); private: static string procStatus(const Inspector::ArgList& args); + static string openedFiles(const Inspector::ArgList& args); }; } } -#endif // MUDUO_NET_INSPECT_PROCESSINFO_H +#endif // MUDUO_NET_INSPECT_PROCESSINSPECTOR_H From 1de739a0ccb5bd7c9de45e89dfe7c294c513b99a Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 13 May 2010 01:39:34 +0800 Subject: [PATCH 074/371] add globalInspector --- muduo/base/ProcessInfo.cc | 9 ++++++++- muduo/base/ProcessInfo.h | 3 ++- muduo/base/Thread.cc | 6 ++++++ muduo/base/Thread.h | 1 + muduo/net/inspect/Inspector.cc | 13 ++++++++++++- 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/muduo/base/ProcessInfo.cc b/muduo/base/ProcessInfo.cc index d6967e849..0e366d4cf 100644 --- a/muduo/base/ProcessInfo.cc +++ b/muduo/base/ProcessInfo.cc @@ -8,21 +8,28 @@ // #include + #include #include +#include using namespace muduo; namespace { __thread int t_numOpenedFiles = 0; - int fdDirFilter(const struct dirent* d) + int fdDirFilter(const struct dirent*) { ++t_numOpenedFiles; return 0; } } +pid_t ProcessInfo::pid() +{ + return ::getpid(); +} + string ProcessInfo::procStatus() { string result; diff --git a/muduo/base/ProcessInfo.h b/muduo/base/ProcessInfo.h index 857c9c58a..e1ead36e1 100644 --- a/muduo/base/ProcessInfo.h +++ b/muduo/base/ProcessInfo.h @@ -18,10 +18,11 @@ namespace muduo namespace ProcessInfo { + pid_t pid(); + /// read /proc/self/status string procStatus(); - int openedFiles(); } diff --git a/muduo/base/Thread.cc b/muduo/base/Thread.cc index bd80299da..cdce5f73e 100644 --- a/muduo/base/Thread.cc +++ b/muduo/base/Thread.cc @@ -1,4 +1,5 @@ #include +#include #include #include @@ -27,6 +28,11 @@ pid_t CurrentThread::tid() return t_cachedTid; } +bool CurrentThread::isMainThread() +{ + return tid() == ProcessInfo::pid(); +} + Thread::Thread(const ThreadFunc& func) : started_(false), pthreadId_(0), diff --git a/muduo/base/Thread.h b/muduo/base/Thread.h index 988de403c..836f8ef39 100644 --- a/muduo/base/Thread.h +++ b/muduo/base/Thread.h @@ -34,6 +34,7 @@ class Thread namespace CurrentThread { pid_t tid(); + bool isMainThread(); } } diff --git a/muduo/net/inspect/Inspector.cc b/muduo/net/inspect/Inspector.cc index 1488a814e..087a613a5 100644 --- a/muduo/net/inspect/Inspector.cc +++ b/muduo/net/inspect/Inspector.cc @@ -8,6 +8,8 @@ // #include + +#include #include #include #include @@ -25,6 +27,9 @@ using namespace muduo::net; namespace { +Inspector* g_globalInspector = 0; + +// Looks buggy std::vector split(const string& str) { std::vector result; @@ -47,6 +52,7 @@ std::vector split(const string& str) return result; } + } Inspector::Inspector(EventLoop* loop, @@ -55,13 +61,18 @@ Inspector::Inspector(EventLoop* loop, : server_(loop, httpAddr, "Inspector:"+name), processInspector_(new ProcessInspector) { + assert(CurrentThread::isMainThread()); + assert(g_globalInspector == 0); + g_globalInspector = this; server_.setHttpCallback(boost::bind(&Inspector::onRequest, this, _1, _2)); processInspector_->registerCommands(this); - loop->runAfter(0, boost::bind(&Inspector::start, this)); + loop->runAfter(0, boost::bind(&Inspector::start, this)); // little race condition } Inspector::~Inspector() { + assert(CurrentThread::isMainThread()); + g_globalInspector = NULL; } void Inspector::add(const string& module, From 95a3b027ffff8bc0b26162805ea72c457cfef604 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Thu, 13 May 2010 18:41:06 +0800 Subject: [PATCH 075/371] add hub directory --- examples/CMakeLists.txt | 1 + examples/asio/chat/codec.h | 4 ++++ examples/hub/CMakeLists.txt | 12 ++++++++++++ examples/hub/codec.h | 8 ++++++++ examples/hub/hub.cc | 4 ++++ examples/hub/pub.cc | 4 ++++ examples/hub/pubsub.cc | 3 +++ examples/hub/pubsub.h | 8 ++++++++ examples/hub/sub.cc | 4 ++++ 9 files changed, 48 insertions(+) create mode 100644 examples/hub/CMakeLists.txt create mode 100644 examples/hub/codec.h create mode 100644 examples/hub/hub.cc create mode 100644 examples/hub/pub.cc create mode 100644 examples/hub/pubsub.cc create mode 100644 examples/hub/pubsub.h create mode 100644 examples/hub/sub.cc diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 2f232c970..b7faa7f85 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(simple) add_subdirectory(roundtrip) +add_subdirectory(hub) add_subdirectory(asio/tutorial) add_subdirectory(asio/chat) diff --git a/examples/asio/chat/codec.h b/examples/asio/chat/codec.h index 2bd502264..aa3912260 100644 --- a/examples/asio/chat/codec.h +++ b/examples/asio/chat/codec.h @@ -1,3 +1,6 @@ +#ifndef MUDUO_EXAMPLES_ASIO_CHAT_CODEC_H +#define MUDUO_EXAMPLES_ASIO_CHAT_CODEC_H + #include #include #include @@ -65,3 +68,4 @@ class LengthHeaderCodec : boost::noncopyable const static size_t kHeaderLen = sizeof(int32_t); }; +#endif // MUDUO_EXAMPLES_ASIO_CHAT_CODEC_H diff --git a/examples/hub/CMakeLists.txt b/examples/hub/CMakeLists.txt new file mode 100644 index 000000000..411957112 --- /dev/null +++ b/examples/hub/CMakeLists.txt @@ -0,0 +1,12 @@ +add_executable(hub hub.cc) +target_link_libraries(hub muduo_inspect) + +add_library(muduo_pubsub pubsub.cc) +target_link_libraries(muduo_pubsub muduo_inspect) + +add_executable(pub pub.cc) +target_link_libraries(pub muduo_pubsub) + +add_executable(sub sub.cc) +target_link_libraries(sub muduo_pubsub) + diff --git a/examples/hub/codec.h b/examples/hub/codec.h new file mode 100644 index 000000000..8a2c4edf0 --- /dev/null +++ b/examples/hub/codec.h @@ -0,0 +1,8 @@ +#ifndef MUDUO_EXAMPLES_HUB_CODEC_H +#define MUDUO_EXAMPLES_HUB_CODEC_H + +namespace pubsub +{ +} + +#endif // MUDUO_EXAMPLES_HUB_CODEC_H diff --git a/examples/hub/hub.cc b/examples/hub/hub.cc new file mode 100644 index 000000000..9fec59b39 --- /dev/null +++ b/examples/hub/hub.cc @@ -0,0 +1,4 @@ + +int main(int argc, char* argv[]) +{ +} diff --git a/examples/hub/pub.cc b/examples/hub/pub.cc new file mode 100644 index 000000000..9fec59b39 --- /dev/null +++ b/examples/hub/pub.cc @@ -0,0 +1,4 @@ + +int main(int argc, char* argv[]) +{ +} diff --git a/examples/hub/pubsub.cc b/examples/hub/pubsub.cc new file mode 100644 index 000000000..0906e4bda --- /dev/null +++ b/examples/hub/pubsub.cc @@ -0,0 +1,3 @@ +#include "pubsub.h" + + diff --git a/examples/hub/pubsub.h b/examples/hub/pubsub.h new file mode 100644 index 000000000..3d67b41ef --- /dev/null +++ b/examples/hub/pubsub.h @@ -0,0 +1,8 @@ +#ifndef MUDUO_EXAMPLES_HUB_PUBSUB_H +#define MUDUO_EXAMPLES_HUB_PUBSUB_H + +namespace pubsub +{ +} + +#endif // MUDUO_EXAMPLES_HUB_PUBSUB_H diff --git a/examples/hub/sub.cc b/examples/hub/sub.cc new file mode 100644 index 000000000..9fec59b39 --- /dev/null +++ b/examples/hub/sub.cc @@ -0,0 +1,4 @@ + +int main(int argc, char* argv[]) +{ +} From d18b968d531c998378e5dc4f0b1faab5fa7b4219 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 14 May 2010 02:10:23 +0800 Subject: [PATCH 076/371] parse hub message --- CMakeLists.txt | 3 +- examples/asio/chat/client.cc | 1 + examples/asio/chat/codec.h | 2 +- examples/asio/chat/server.cc | 1 + examples/hub/codec.cc | 17 ++++ examples/hub/codec.h | 28 ++++++ examples/hub/hub.cc | 163 +++++++++++++++++++++++++++++++++ examples/hub/pubsub.cc | 3 + examples/hub/pubsub.h | 18 ++++ examples/simple/time/time.h | 2 +- muduo/net/Buffer.h | 27 +++++- muduo/net/http/HttpResponse.h | 1 + muduo/net/http/HttpServer.cc | 4 +- muduo/net/http/HttpServer.h | 2 +- muduo/net/inspect/Inspector.cc | 7 +- muduo/net/inspect/Inspector.h | 2 +- 16 files changed, 270 insertions(+), 11 deletions(-) create mode 100644 examples/hub/codec.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 94cfeb26d..7318ac84b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(muduo CXX) set(CXX_FLAGS -g - -DVALGRIND + # -DVALGRIND # -DMUDUO_STD_STRING -Wall -Wextra @@ -13,6 +13,7 @@ set(CXX_FLAGS -Wconversion -Wunused-parameter -Wold-style-cast + -Woverloaded-virtual -Wpointer-arith -Wshadow -Wwrite-strings diff --git a/examples/asio/chat/client.cc b/examples/asio/chat/client.cc index 31b61434c..6ca91e2fd 100644 --- a/examples/asio/chat/client.cc +++ b/examples/asio/chat/client.cc @@ -58,6 +58,7 @@ class ChatClient : boost::noncopyable MutexLockGuard lock(mutex_); if (conn->connected()) { + conn->setContext(Timestamp()); connection_ = conn; } else diff --git a/examples/asio/chat/codec.h b/examples/asio/chat/codec.h index aa3912260..1abb19d4f 100644 --- a/examples/asio/chat/codec.h +++ b/examples/asio/chat/codec.h @@ -27,6 +27,7 @@ class LengthHeaderCodec : boost::noncopyable muduo::net::Buffer* buf, muduo::Timestamp receiveTime) { + muduo::Timestamp& receiveTime_ = boost::any_cast(conn->getContext()); if (!receiveTime_.valid()) { receiveTime_ = receiveTime; @@ -64,7 +65,6 @@ class LengthHeaderCodec : boost::noncopyable private: StringMessageCallback messageCallback_; - muduo::Timestamp receiveTime_; // FIXME: this should be per connection, not per server. const static size_t kHeaderLen = sizeof(int32_t); }; diff --git a/examples/asio/chat/server.cc b/examples/asio/chat/server.cc index 20d2ed35a..f71e2bc89 100644 --- a/examples/asio/chat/server.cc +++ b/examples/asio/chat/server.cc @@ -44,6 +44,7 @@ class ChatServer : boost::noncopyable MutexLockGuard lock(mutex_); if (conn->connected()) { + conn->setContext(Timestamp()); connections_.insert(conn); } else diff --git a/examples/hub/codec.cc b/examples/hub/codec.cc new file mode 100644 index 000000000..3069ec295 --- /dev/null +++ b/examples/hub/codec.cc @@ -0,0 +1,17 @@ +#include "codec.h" + +using namespace muduo; +using namespace muduo::net; +using namespace pubsub; + +void PubSubCodec::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + //ClientContext* context = &boost::any_cast(conn->getContext()); + const char* crlf = buf->findCRLF(); + if (crlf) + { + } +} + diff --git a/examples/hub/codec.h b/examples/hub/codec.h index 8a2c4edf0..839b99a99 100644 --- a/examples/hub/codec.h +++ b/examples/hub/codec.h @@ -1,8 +1,36 @@ #ifndef MUDUO_EXAMPLES_HUB_CODEC_H #define MUDUO_EXAMPLES_HUB_CODEC_H +// internal header file + +#include +#include + +#include + namespace pubsub { +using muduo::string; + +class PubSubCodec : boost::noncopyable +{ + public: + typedef boost::function SubscribeCallback; + typedef SubscribeCallback UnsubscribeCallback; + typedef boost::function PublishCallback; + + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp receiveTime); + + // LoginCallback loginCallback_; + PublishCallback publishCallback_; + SubscribeCallback subscribeCallback_; + UnsubscribeCallback unsubscribeCallback_; +}; + } #endif // MUDUO_EXAMPLES_HUB_CODEC_H + diff --git a/examples/hub/hub.cc b/examples/hub/hub.cc index 9fec59b39..f8ca643dd 100644 --- a/examples/hub/hub.cc +++ b/examples/hub/hub.cc @@ -1,4 +1,167 @@ +#include "codec.h" + +#include +#include +#include + +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +namespace pubsub +{ +class PubSubServer; + +class ClientContext : muduo::copyable +{ + public: + ClientContext(PubSubServer* owner) + : owner_(owner) + { + } + + // default copy-ctor, dtor and assignment are fine + + private: + PubSubServer* owner_; +}; + +class PubSubServer : boost::noncopyable +{ + public: + PubSubServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "PubSubServer") + { + server_.setConnectionCallback( + boost::bind(&PubSubServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&PubSubServer::onMessage, this, _1, _2, _3)); + } + + void start(int numThreads) + { + server_.setThreadNum(numThreads); + server_.start(); + } + + private: + void onConnection(const TcpConnectionPtr& conn) + { + if (conn->connected()) + { + conn->setContext(ClientContext(this)); + } + else + { + + } + } + + // FIXME extract paring function + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + const char* space = std::find(buf->peek(), crlf, ' '); + if (space != crlf) + { + string cmd(buf->peek(), space); + string topic(space+1, crlf); + if (cmd == "pub") + { + const char* start = crlf+2; + crlf = buf->findCRLF(start); + if (crlf) + { + string content(start, crlf); + buf->retrieveUntil(crlf + 2); + doPublish(conn, topic, content, receiveTime); + } + else + { + LOG_DEBUG << "More"; + } + } + else + { + buf->retrieveUntil(crlf + 2); + if (cmd == "sub") + { + doSubscribe(conn, topic); + } + else if (cmd == "unsub") + { + doUnsubscribe(conn, topic); + } + else + { + conn->shutdown(); + } + } + } + else + { + conn->shutdown(); + } + } + } + + void timePublish() + { + } + + void doSubscribe(const TcpConnectionPtr& conn, + const string& topic) + { + LOG_INFO << "conn " << conn->name() << " sub " << topic; + } + + void doUnsubscribe(const TcpConnectionPtr& conn, + const string& topic) + { + LOG_INFO << "conn " << conn->name() << " unsub " << topic; + } + + void doPublish(const TcpConnectionPtr& conn, + const string& topic, + const string& content, + Timestamp time) + { + LOG_INFO << "conn " << conn->name() << " pub " << topic; + } + + EventLoop* loop_; + TcpServer server_; +}; + +} int main(int argc, char* argv[]) { + if (argc > 2) + { + int port = atoi(argv[1]); + int inspectPort = atoi(argv[2]); + int threads = 0; + if (argc > 3) + { + threads = atoi(argv[3]); + } + EventLoop loop; + pubsub::PubSubServer server(&loop, InetAddress(port)); + server.start(threads); + loop.loop(); + } + else + { + printf("Usage: %s pubsub_port inspect_port [num_threads]\n", argv[0]); + } } diff --git a/examples/hub/pubsub.cc b/examples/hub/pubsub.cc index 0906e4bda..82011dd02 100644 --- a/examples/hub/pubsub.cc +++ b/examples/hub/pubsub.cc @@ -1,3 +1,6 @@ #include "pubsub.h" +using namespace muduo; +using namespace muduo::net; +using namespace pubsub; diff --git a/examples/hub/pubsub.h b/examples/hub/pubsub.h index 3d67b41ef..42ba529ae 100644 --- a/examples/hub/pubsub.h +++ b/examples/hub/pubsub.h @@ -1,8 +1,26 @@ #ifndef MUDUO_EXAMPLES_HUB_PUBSUB_H #define MUDUO_EXAMPLES_HUB_PUBSUB_H +#include + namespace pubsub { +using muduo::string; +using muduo::Timestamp; + +class PubSubClient : boost::noncopyable +{ + public: + typedef boost::function Callback; + PubSubClient(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& hubAddr); + void subscribe(const string& topic, const Callback& cb); + void unsubscribe(const string& topic); + + private: + muduo::net::EventLoop* loop_; + muduo::net::TcpClient client_; +}; } #endif // MUDUO_EXAMPLES_HUB_PUBSUB_H diff --git a/examples/simple/time/time.h b/examples/simple/time/time.h index c67b51b48..3580f0e0c 100644 --- a/examples/simple/time/time.h +++ b/examples/simple/time/time.h @@ -8,7 +8,7 @@ class TimeServer { public: TimeServer(muduo::net::EventLoop* loop, - const muduo::net::InetAddress& listenAddr); + const muduo::net::InetAddress& listenAddr); void start(); diff --git a/muduo/net/Buffer.h b/muduo/net/Buffer.h index ea4cc98c5..7e9797a70 100644 --- a/muduo/net/Buffer.h +++ b/muduo/net/Buffer.h @@ -74,8 +74,16 @@ class Buffer : public muduo::copyable const char* findCRLF() const { - const char* crlf = std::search(peek(), begin()+writerIndex_, kCRLF, kCRLF+2); - return crlf == begin()+writerIndex_ ? NULL : crlf; + const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2); + return crlf == beginWrite() ? NULL : crlf; + } + + const char* findCRLF(const char* start) const + { + assert(peek() <= start); + assert(start <= beginWrite()); + const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2); + return crlf == beginWrite() ? NULL : crlf; } // retrieve returns void, to prevent @@ -87,6 +95,13 @@ class Buffer : public muduo::copyable readerIndex_ += len; } + void retrieveUntil(const char* end) + { + assert(peek() <= end); + assert(end <= beginWrite()); + retrieve(end - peek()); + } + void retrieveAll() { readerIndex_ = kCheapPrepend; @@ -113,7 +128,7 @@ class Buffer : public muduo::copyable makeSpace(len); } assert(len <= writableBytes()); - std::copy(data, data+len, begin()+writerIndex_); + std::copy(data, data+len, beginWrite()); writerIndex_ += len; } @@ -139,6 +154,12 @@ class Buffer : public muduo::copyable ssize_t readFd(int fd, int* savedErrno); private: + char* beginWrite() + { return begin() + writerIndex_; } + + const char* beginWrite() const + { return begin() + writerIndex_; } + char* begin() { return &*buffer_.begin(); } diff --git a/muduo/net/http/HttpResponse.h b/muduo/net/http/HttpResponse.h index f2c070634..3664e45ff 100644 --- a/muduo/net/http/HttpResponse.h +++ b/muduo/net/http/HttpResponse.h @@ -29,6 +29,7 @@ class HttpResponse : public muduo::copyable { kUnknown, k200Ok = 200, + k400BadRequest = 400, k404NotFound = 404, }; diff --git a/muduo/net/http/HttpServer.cc b/muduo/net/http/HttpServer.cc index 4eeaa2caa..1943ce5e4 100644 --- a/muduo/net/http/HttpServer.cc +++ b/muduo/net/http/HttpServer.cc @@ -56,7 +56,7 @@ bool parseRequest(Buffer* buf, HttpContext* context, Timestamp receiveTime) if (ok) { context->request().setReceiveTime(receiveTime); - buf->retrieve(crlf - buf->peek() + 2); + buf->retrieveUntil(crlf + 2); context->receiveRequestLine(); } else @@ -84,7 +84,7 @@ bool parseRequest(Buffer* buf, HttpContext* context, Timestamp receiveTime) context->receiveHeaders(); hasMore = !context->gotAll(); } - buf->retrieve(crlf - buf->peek() + 2); + buf->retrieveUntil(crlf + 2); } else { diff --git a/muduo/net/http/HttpServer.h b/muduo/net/http/HttpServer.h index 54d7364a5..32cced6da 100644 --- a/muduo/net/http/HttpServer.h +++ b/muduo/net/http/HttpServer.h @@ -32,7 +32,7 @@ class HttpServer : boost::noncopyable typedef boost::function HttpCallback; - HttpServer(EventLoop* loop, + HttpServer(EventLoop* loop, const InetAddress& listenAddr, const string& name); diff --git a/muduo/net/inspect/Inspector.cc b/muduo/net/inspect/Inspector.cc index 087a613a5..fa85c599f 100644 --- a/muduo/net/inspect/Inspector.cc +++ b/muduo/net/inspect/Inspector.cc @@ -92,7 +92,12 @@ void Inspector::start() void Inspector::onRequest(const HttpRequest& req, HttpResponse* resp) { - if (req.path() == "/") + if (req.method() != HttpRequest::kGet) + { + resp->setStatusCode(HttpResponse::k400BadRequest); + resp->setStatusMessage("Unsupported method"); + } + else if (req.path() == "/") { string result; MutexLockGuard lock(mutex_); diff --git a/muduo/net/inspect/Inspector.h b/muduo/net/inspect/Inspector.h index dc6ab98c5..a708d9c59 100644 --- a/muduo/net/inspect/Inspector.h +++ b/muduo/net/inspect/Inspector.h @@ -32,7 +32,7 @@ class Inspector : boost::noncopyable public: typedef std::vector ArgList; typedef boost::function Callback; - Inspector(EventLoop* loop, + Inspector(EventLoop* loop, const InetAddress& httpAddr, const string& name); ~Inspector(); From 1eddf97cd8e318b17943269654d72d58f033eebe Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 14 May 2010 10:24:22 +0800 Subject: [PATCH 077/371] hub works --- examples/hub/codec.cc | 1 - examples/hub/hub.cc | 213 ++++++++++++++++++++++++++++++------------ 2 files changed, 154 insertions(+), 60 deletions(-) diff --git a/examples/hub/codec.cc b/examples/hub/codec.cc index 3069ec295..3eca50a58 100644 --- a/examples/hub/codec.cc +++ b/examples/hub/codec.cc @@ -8,7 +8,6 @@ void PubSubCodec::onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime) { - //ClientContext* context = &boost::any_cast(conn->getContext()); const char* crlf = buf->findCRLF(); if (crlf) { diff --git a/examples/hub/hub.cc b/examples/hub/hub.cc index f8ca643dd..281e91e6d 100644 --- a/examples/hub/hub.cc +++ b/examples/hub/hub.cc @@ -6,27 +6,118 @@ #include +#include +#include #include using namespace muduo; using namespace muduo::net; +namespace +{ +enum ParseResult +{ + kError, + kSuccess, + kContinue, +}; + +ParseResult parseMessage(Buffer* buf, string* cmd, string* topic, string* content) +{ + ParseResult result = kError; + const char* crlf = buf->findCRLF(); + if (crlf) + { + const char* space = std::find(buf->peek(), crlf, ' '); + if (space != crlf) + { + cmd->assign(buf->peek(), space); + topic->assign(space+1, crlf); + if (*cmd == "pub") + { + const char* start = crlf + 2; + crlf = buf->findCRLF(start); + if (crlf) + { + content->assign(start, crlf); + buf->retrieveUntil(crlf+2); + result = kSuccess; + } + else + { + result = kContinue; + } + } + else + { + buf->retrieveUntil(crlf+2); + result = kSuccess; + } + } + else + { + result = kError; + } + } + else + { + result = kContinue; + } + return result; +} +} + namespace pubsub { -class PubSubServer; -class ClientContext : muduo::copyable +typedef std::set ConnectionSubscription; + +class Topic : public muduo::copyable { public: - ClientContext(PubSubServer* owner) - : owner_(owner) + Topic(const string topic) + : topic_(topic) + { + } + + void add(const TcpConnectionPtr& conn) + { + audiences_.insert(conn); + if (lastPubTime_.valid()) + { + conn->send(makeMessage()); + } + } + + void remove(const TcpConnectionPtr& conn) { + audiences_.erase(conn); } - // default copy-ctor, dtor and assignment are fine + void publish(const string& content, Timestamp time) + { + content_ = content; + lastPubTime_ = time; + string message = makeMessage(); + for (std::set::iterator it = audiences_.begin(); + it != audiences_.end(); + ++it) + { + (*it)->send(message); + } + } private: - PubSubServer* owner_; + + string makeMessage() + { + return "pub " + topic_ + "\r\n" + content_ + "\r\n"; + } + + string topic_; + string content_; + Timestamp lastPubTime_; + std::set audiences_; }; class PubSubServer : boost::noncopyable @@ -43,9 +134,8 @@ class PubSubServer : boost::noncopyable boost::bind(&PubSubServer::onMessage, this, _1, _2, _3)); } - void start(int numThreads) + void start() { - server_.setThreadNum(numThreads); server_.start(); } @@ -54,64 +144,52 @@ class PubSubServer : boost::noncopyable { if (conn->connected()) { - conn->setContext(ClientContext(this)); + conn->setContext(ConnectionSubscription()); } else { - + ConnectionSubscription& connSub + = boost::any_cast(conn->getContext()); + for (ConnectionSubscription::iterator it = connSub.begin(); + it != connSub.end(); + ++it) + { + doUnsubscribe(conn, *it); + } } } - // FIXME extract paring function void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime) { - const char* crlf = buf->findCRLF(); - if (crlf) + string cmd; + string topic; + string content; + ParseResult result = parseMessage(buf, &cmd, &topic, &content); + if (result == kSuccess) { - const char* space = std::find(buf->peek(), crlf, ' '); - if (space != crlf) + if (cmd == "pub") { - string cmd(buf->peek(), space); - string topic(space+1, crlf); - if (cmd == "pub") - { - const char* start = crlf+2; - crlf = buf->findCRLF(start); - if (crlf) - { - string content(start, crlf); - buf->retrieveUntil(crlf + 2); - doPublish(conn, topic, content, receiveTime); - } - else - { - LOG_DEBUG << "More"; - } - } - else - { - buf->retrieveUntil(crlf + 2); - if (cmd == "sub") - { - doSubscribe(conn, topic); - } - else if (cmd == "unsub") - { - doUnsubscribe(conn, topic); - } - else - { - conn->shutdown(); - } - } + doPublish(conn, topic, content, receiveTime); + } + else if (cmd == "sub") + { + doSubscribe(conn, topic); + } + else if (cmd == "unsub") + { + doUnsubscribe(conn, topic); } else { conn->shutdown(); } } + else if (result == kError) + { + conn->shutdown(); + } } void timePublish() @@ -121,13 +199,20 @@ class PubSubServer : boost::noncopyable void doSubscribe(const TcpConnectionPtr& conn, const string& topic) { - LOG_INFO << "conn " << conn->name() << " sub " << topic; + ConnectionSubscription& connSub + = boost::any_cast(conn->getContext()); + + connSub.insert(topic); + getTopic(topic).add(conn); } void doUnsubscribe(const TcpConnectionPtr& conn, const string& topic) { - LOG_INFO << "conn " << conn->name() << " unsub " << topic; + ConnectionSubscription& connSub + = boost::any_cast(conn->getContext()); + connSub.erase(topic); + getTopic(topic).remove(conn); } void doPublish(const TcpConnectionPtr& conn, @@ -135,33 +220,43 @@ class PubSubServer : boost::noncopyable const string& content, Timestamp time) { - LOG_INFO << "conn " << conn->name() << " pub " << topic; + getTopic(topic).publish(content, time); + } + + Topic& getTopic(const string& topic) + { + std::map::iterator it = topics_.find(topic); + if (it == topics_.end()) + { + it = topics_.insert(make_pair(topic, Topic(topic))).first; + } + return it->second; } EventLoop* loop_; TcpServer server_; + std::map topics_; }; } int main(int argc, char* argv[]) { - if (argc > 2) + if (argc > 1) { int port = atoi(argv[1]); - int inspectPort = atoi(argv[2]); - int threads = 0; - if (argc > 3) + EventLoop loop; + if (argc > 2) { - threads = atoi(argv[3]); + int inspectPort = atoi(argv[2]); } - EventLoop loop; pubsub::PubSubServer server(&loop, InetAddress(port)); - server.start(threads); + server.start(); loop.loop(); } else { - printf("Usage: %s pubsub_port inspect_port [num_threads]\n", argv[0]); + printf("Usage: %s pubsub_port [inspect_port]\n", argv[0]); } } + From 69364b10ebcceca18d4206be46139578250cc883 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 14 May 2010 10:29:55 +0800 Subject: [PATCH 078/371] hub pubs utc_time --- examples/hub/hub.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/hub/hub.cc b/examples/hub/hub.cc index 281e91e6d..1bfb6e98e 100644 --- a/examples/hub/hub.cc +++ b/examples/hub/hub.cc @@ -132,6 +132,7 @@ class PubSubServer : boost::noncopyable boost::bind(&PubSubServer::onConnection, this, _1)); server_.setMessageCallback( boost::bind(&PubSubServer::onMessage, this, _1, _2, _3)); + loop_->runEvery(1.0, boost::bind(&PubSubServer::timePublish, this)); } void start() @@ -171,7 +172,7 @@ class PubSubServer : boost::noncopyable { if (cmd == "pub") { - doPublish(conn, topic, content, receiveTime); + doPublish(conn->name(), topic, content, receiveTime); } else if (cmd == "sub") { @@ -194,6 +195,8 @@ class PubSubServer : boost::noncopyable void timePublish() { + Timestamp now = Timestamp::now(); + doPublish("internal", "utc_time", now.toFormattedString(), now); } void doSubscribe(const TcpConnectionPtr& conn, @@ -215,7 +218,7 @@ class PubSubServer : boost::noncopyable getTopic(topic).remove(conn); } - void doPublish(const TcpConnectionPtr& conn, + void doPublish(const string& source, const string& topic, const string& content, Timestamp time) From 479b1120d19a43e29e7542e183827de34357e93b Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 14 May 2010 23:03:41 +0800 Subject: [PATCH 079/371] inspect threads --- muduo/base/ProcessInfo.cc | 23 ++++++++++++++++++- muduo/base/ProcessInfo.h | 3 +++ muduo/net/http/HttpRequest.h | 3 +++ muduo/net/inspect/Inspector.cc | 10 +++------ muduo/net/inspect/Inspector.h | 3 ++- muduo/net/inspect/ProcessInspector.cc | 27 +++++++++++++++++++++-- muduo/net/inspect/ProcessInspector.h | 6 +++-- muduo/net/inspect/tests/Inspector_test.cc | 4 +++- 8 files changed, 65 insertions(+), 14 deletions(-) diff --git a/muduo/base/ProcessInfo.cc b/muduo/base/ProcessInfo.cc index 0e366d4cf..de3b41797 100644 --- a/muduo/base/ProcessInfo.cc +++ b/muduo/base/ProcessInfo.cc @@ -9,8 +9,11 @@ #include +#include + #include #include +#include #include using namespace muduo; @@ -23,6 +26,16 @@ namespace ++t_numOpenedFiles; return 0; } + + __thread std::vector* t_pids = 0; + int taskDirFilter(const struct dirent* d) + { + if (isdigit(d->d_name[0])) + { + t_pids->push_back(atoi(d->d_name)); + } + return 0; + } } pid_t ProcessInfo::pid() @@ -52,7 +65,15 @@ int ProcessInfo::openedFiles() t_numOpenedFiles = 0; struct dirent** namelist; scandir("/proc/self/fd", &namelist, fdDirFilter, alphasort); - return t_numOpenedFiles-2; // "." and ".." } +std::vector ProcessInfo::threads() +{ + std::vector result; + t_pids = &result; + struct dirent** namelist; + scandir("/proc/self/task", &namelist, taskDirFilter, alphasort); + std::sort(result.begin(), result.end()); + return result; +} diff --git a/muduo/base/ProcessInfo.h b/muduo/base/ProcessInfo.h index e1ead36e1..263c3b0d2 100644 --- a/muduo/base/ProcessInfo.h +++ b/muduo/base/ProcessInfo.h @@ -12,6 +12,7 @@ #define MUDUO_BASE_PROCESSINFO_H #include +#include namespace muduo { @@ -24,6 +25,8 @@ namespace ProcessInfo string procStatus(); int openedFiles(); + + std::vector threads(); } } diff --git a/muduo/net/http/HttpRequest.h b/muduo/net/http/HttpRequest.h index 6c31d6be2..2c034e8d9 100644 --- a/muduo/net/http/HttpRequest.h +++ b/muduo/net/http/HttpRequest.h @@ -12,8 +12,11 @@ #define MUDUO_NET_HTTP_HTTPREQUEST_H #include +#include +#include #include +#include #include namespace muduo diff --git a/muduo/net/inspect/Inspector.cc b/muduo/net/inspect/Inspector.cc index fa85c599f..8e4f1ff02 100644 --- a/muduo/net/inspect/Inspector.cc +++ b/muduo/net/inspect/Inspector.cc @@ -92,12 +92,7 @@ void Inspector::start() void Inspector::onRequest(const HttpRequest& req, HttpResponse* resp) { - if (req.method() != HttpRequest::kGet) - { - resp->setStatusCode(HttpResponse::k400BadRequest); - resp->setStatusMessage("Unsupported method"); - } - else if (req.path() == "/") + if (req.path() == "/") { string result; MutexLockGuard lock(mutex_); @@ -155,7 +150,8 @@ void Inspector::onRequest(const HttpRequest& req, HttpResponse* resp) resp->setStatusCode(HttpResponse::k200Ok); resp->setStatusMessage("OK"); resp->setContentType("text/plain"); - resp->setBody(it->second(args)); + const Callback& cb = it->second; + resp->setBody(cb(req.method(), args)); ok = true; } } diff --git a/muduo/net/inspect/Inspector.h b/muduo/net/inspect/Inspector.h index a708d9c59..7d197fda4 100644 --- a/muduo/net/inspect/Inspector.h +++ b/muduo/net/inspect/Inspector.h @@ -12,6 +12,7 @@ #define MUDUO_NET_INSPECT_INSPECTOR_H #include +#include #include #include @@ -31,7 +32,7 @@ class Inspector : boost::noncopyable { public: typedef std::vector ArgList; - typedef boost::function Callback; + typedef boost::function Callback; Inspector(EventLoop* loop, const InetAddress& httpAddr, const string& name); diff --git a/muduo/net/inspect/ProcessInspector.cc b/muduo/net/inspect/ProcessInspector.cc index c92891f4b..169e644a3 100644 --- a/muduo/net/inspect/ProcessInspector.cc +++ b/muduo/net/inspect/ProcessInspector.cc @@ -16,18 +16,41 @@ using namespace muduo::net; void ProcessInspector::registerCommands(Inspector* ins) { + ins->add("proc", "pid", ProcessInspector::pid, "print pid"); ins->add("proc", "status", ProcessInspector::procStatus, "print /proc/self/status"); ins->add("proc", "opened_files", ProcessInspector::openedFiles, "count /proc/self/fd"); + ins->add("proc", "threads", ProcessInspector::threads, "list /proc/self/task"); } -string ProcessInspector::procStatus(const Inspector::ArgList& args) +string ProcessInspector::pid(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", ProcessInfo::pid()); + return buf; +} + +string ProcessInspector::procStatus(HttpRequest::Method, const Inspector::ArgList&) { return ProcessInfo::procStatus(); } -string ProcessInspector::openedFiles(const Inspector::ArgList& args) +string ProcessInspector::openedFiles(HttpRequest::Method, const Inspector::ArgList&) { char buf[32]; snprintf(buf, sizeof buf, "%d", ProcessInfo::openedFiles()); return buf; } + +string ProcessInspector::threads(HttpRequest::Method, const Inspector::ArgList&) +{ + std::vector threads = ProcessInfo::threads(); + string result; + for (size_t i = 0; i < threads.size(); ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "%d\n", threads[i]); + result += buf; + } + return result; +} + diff --git a/muduo/net/inspect/ProcessInspector.h b/muduo/net/inspect/ProcessInspector.h index 2ce9a55d5..eace20768 100644 --- a/muduo/net/inspect/ProcessInspector.h +++ b/muduo/net/inspect/ProcessInspector.h @@ -25,8 +25,10 @@ class ProcessInspector : boost::noncopyable void registerCommands(Inspector* ins); private: - static string procStatus(const Inspector::ArgList& args); - static string openedFiles(const Inspector::ArgList& args); + static string pid(HttpRequest::Method, const Inspector::ArgList&); + static string procStatus(HttpRequest::Method, const Inspector::ArgList&); + static string openedFiles(HttpRequest::Method, const Inspector::ArgList&); + static string threads(HttpRequest::Method, const Inspector::ArgList&); }; diff --git a/muduo/net/inspect/tests/Inspector_test.cc b/muduo/net/inspect/tests/Inspector_test.cc index d665a82b7..bc8777164 100644 --- a/muduo/net/inspect/tests/Inspector_test.cc +++ b/muduo/net/inspect/tests/Inspector_test.cc @@ -1,5 +1,6 @@ #include #include +#include using namespace muduo; using namespace muduo::net; @@ -7,7 +8,8 @@ using namespace muduo::net; int main() { EventLoop loop; - Inspector ins(&loop, InetAddress(12345), "test"); + EventLoopThread t; + Inspector ins(t.startLoop(), InetAddress(12345), "test"); loop.loop(); } From 69b3f683f12fe8e517061d8602c009f1a481dc9f Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 15 May 2010 12:55:34 +0800 Subject: [PATCH 080/371] process info for username hostname etc. --- examples/hub/README | 5 +++++ examples/hub/pub.cc | 36 ++++++++++++++++++++++++++++++++++++ examples/hub/pubsub.cc | 20 ++++++++++++++++++++ examples/hub/pubsub.h | 14 +++++++++++--- muduo/base/ProcessInfo.cc | 36 ++++++++++++++++++++++++++++++++++++ muduo/base/ProcessInfo.h | 5 +++++ muduo/net/TcpClient.cc | 10 +++++++++- muduo/net/TcpClient.h | 3 ++- 8 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 examples/hub/README diff --git a/examples/hub/README b/examples/hub/README new file mode 100644 index 000000000..107c691e6 --- /dev/null +++ b/examples/hub/README @@ -0,0 +1,5 @@ +hub - a server for broadcasting +pubsub - a client library of hub +pub - a command line tool for publishing content on a topic +sub - a demo tool for subscribing a topic + diff --git a/examples/hub/pub.cc b/examples/hub/pub.cc index 9fec59b39..f0bf90b31 100644 --- a/examples/hub/pub.cc +++ b/examples/hub/pub.cc @@ -1,4 +1,40 @@ +#include "pubsub.h" +#include +#include + +#include + +using namespace muduo; +using namespace muduo::net; +using namespace pubsub; int main(int argc, char* argv[]) { + if (argc == 4) + { + string hostport = argv[1]; + size_t colon = hostport.find(':'); + if (colon != string::npos) + { + string hostip = hostport.substr(0, colon); + uint16_t port = atoi(hostport.c_str()+colon+1); + string topic = argv[2]; + string content = argv[3]; + + EventLoop loop; + string name = ProcessInfo::username()+"@"+ProcessInfo::hostname(); + name += ":" + ProcessInfo::pidString(); + PubSubClient client(&loop, InetAddress(hostport, port), name); + client.start(); + loop.loop(); + } + else + { + printf("Usage: %s hub_ip:port topic content\n", argv[0]); + } + } + else + { + printf("Usage: %s hub_ip:port topic content\n", argv[0]); + } } diff --git a/examples/hub/pubsub.cc b/examples/hub/pubsub.cc index 82011dd02..84844f8e1 100644 --- a/examples/hub/pubsub.cc +++ b/examples/hub/pubsub.cc @@ -4,3 +4,23 @@ using namespace muduo; using namespace muduo::net; using namespace pubsub; +PubSubClient::PubSubClient(EventLoop* loop, + const InetAddress& hubAddr, + const string& name) + : loop_(loop), + client_(loop, hubAddr, name) +{ +} + +void PubSubClient::start() +{ + client_.connect(); +} + +void PubSubClient::stop() +{ + client_.disconnect(); +} + + + diff --git a/examples/hub/pubsub.h b/examples/hub/pubsub.h index 42ba529ae..5aef994e9 100644 --- a/examples/hub/pubsub.h +++ b/examples/hub/pubsub.h @@ -11,11 +11,19 @@ using muduo::Timestamp; class PubSubClient : boost::noncopyable { public: - typedef boost::function Callback; + typedef boost::function SubscribeCallback; + typedef boost::function ConnectionCallback; + PubSubClient(muduo::net::EventLoop* loop, - const muduo::net::InetAddress& hubAddr); - void subscribe(const string& topic, const Callback& cb); + const muduo::net::InetAddress& hubAddr, + const string& name); + void start(); + void stop(); + bool connected() const; + + void subscribe(const string& topic, const SubscribeCallback& cb); void unsubscribe(const string& topic); + void publish(const string& topic, const string& content); private: muduo::net::EventLoop* loop_; diff --git a/muduo/base/ProcessInfo.cc b/muduo/base/ProcessInfo.cc index de3b41797..3537597f7 100644 --- a/muduo/base/ProcessInfo.cc +++ b/muduo/base/ProcessInfo.cc @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -43,6 +44,41 @@ pid_t ProcessInfo::pid() return ::getpid(); } +string ProcessInfo::pidString() +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", pid()); + return buf; +} + +uid_t ProcessInfo::uid() +{ + return ::getuid(); +} + +string ProcessInfo::username() +{ + struct passwd pwd; + struct passwd* result = NULL; + char passwdbuf[8192]; + const char* name = "unknown"; + + getpwuid_r(uid(), &pwd, passwdbuf, sizeof passwdbuf, &result); + if (result) + { + name = pwd.pw_name; + } + return name; +} + +string ProcessInfo::hostname() +{ + char buf[64] = "unknownhost"; + buf[sizeof(buf)-1] = '\0'; + gethostname(buf, sizeof buf); + return buf; +} + string ProcessInfo::procStatus() { string result; diff --git a/muduo/base/ProcessInfo.h b/muduo/base/ProcessInfo.h index 263c3b0d2..82df82148 100644 --- a/muduo/base/ProcessInfo.h +++ b/muduo/base/ProcessInfo.h @@ -20,6 +20,11 @@ namespace muduo namespace ProcessInfo { pid_t pid(); + string pidString(); + uid_t uid(); + string username(); + + string hostname(); /// read /proc/self/status string procStatus(); diff --git a/muduo/net/TcpClient.cc b/muduo/net/TcpClient.cc index b50809991..0bf0c3c8e 100644 --- a/muduo/net/TcpClient.cc +++ b/muduo/net/TcpClient.cc @@ -42,6 +42,7 @@ TcpClient::TcpClient(EventLoop* loop, connectionCallback_(defaultConnectionCallback), messageCallback_(defaultMessageCallback), retry_(false), + connect_(true), nextConnId_(1) { connector_->setNewConnectionCallback( @@ -58,9 +59,16 @@ void TcpClient::connect() // FIXME: check state LOG_INFO << "TcpClient::connect[" << name_ << "] - connecting to " << connector_->serverAddress().toHostPort(); + connect_ = true; connector_->start(); } +void TcpClient::disconnect() +{ + // FIXME: do-it + connect_ = false; +} + void TcpClient::newConnection(int sockfd) { loop_->assertInLoopThread(); @@ -100,7 +108,7 @@ void TcpClient::removeConnection(const TcpConnectionPtr& conn) loop_->queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn)); // FIXME wake up ? - if (retry_) + if (retry_ && connect_) { LOG_INFO << "TcpClient::connect[" << name_ << "] - Reconnecting to " << connector_->serverAddress().toHostPort(); diff --git a/muduo/net/TcpClient.h b/muduo/net/TcpClient.h index 5e8c727bc..57dca4c19 100644 --- a/muduo/net/TcpClient.h +++ b/muduo/net/TcpClient.h @@ -35,7 +35,7 @@ class TcpClient : boost::noncopyable ~TcpClient(); // force out-line dtor, for scoped_ptr members. void connect(); - // void disconnect(); + void disconnect(); bool retry() const; void enableRetry() { retry_ = true; } @@ -68,6 +68,7 @@ class TcpClient : boost::noncopyable MessageCallback messageCallback_; WriteCompleteCallback writeCompleteCallback_; bool retry_; // atmoic + bool connect_; // always in loop thread int nextConnId_; MutexLock mutex_; From 5d0030637e5643ee6ba1cdfced7bfd379da5f200 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 15 May 2010 20:57:16 +0800 Subject: [PATCH 081/371] pub works --- examples/hub/pub.cc | 25 ++++++++++++++++++++++--- examples/hub/pubsub.cc | 37 +++++++++++++++++++++++++++++++++++++ examples/hub/pubsub.h | 13 +++++++++++-- muduo/base/ProcessInfo.cc | 20 ++++++++++++-------- muduo/net/TcpClient.cc | 9 ++++++++- muduo/net/TcpClient.h | 4 ++-- 6 files changed, 92 insertions(+), 16 deletions(-) diff --git a/examples/hub/pub.cc b/examples/hub/pub.cc index f0bf90b31..689242dae 100644 --- a/examples/hub/pub.cc +++ b/examples/hub/pub.cc @@ -8,6 +8,23 @@ using namespace muduo; using namespace muduo::net; using namespace pubsub; +EventLoop* g_loop = NULL; +string g_topic; +string g_content; + +void connection(PubSubClient* client) +{ + if (client->connected()) + { + client->publish(g_topic, g_content); + client->stop(); + } + else + { + g_loop->quit(); + } +} + int main(int argc, char* argv[]) { if (argc == 4) @@ -18,13 +35,15 @@ int main(int argc, char* argv[]) { string hostip = hostport.substr(0, colon); uint16_t port = atoi(hostport.c_str()+colon+1); - string topic = argv[2]; - string content = argv[3]; + g_topic = argv[2]; + g_content = argv[3]; EventLoop loop; + g_loop = &loop; string name = ProcessInfo::username()+"@"+ProcessInfo::hostname(); name += ":" + ProcessInfo::pidString(); - PubSubClient client(&loop, InetAddress(hostport, port), name); + PubSubClient client(&loop, InetAddress(hostip, port), name); + client.setConnectionCallback(connection); client.start(); loop.loop(); } diff --git a/examples/hub/pubsub.cc b/examples/hub/pubsub.cc index 84844f8e1..861cad613 100644 --- a/examples/hub/pubsub.cc +++ b/examples/hub/pubsub.cc @@ -1,5 +1,7 @@ #include "pubsub.h" +#include + using namespace muduo; using namespace muduo::net; using namespace pubsub; @@ -10,6 +12,9 @@ PubSubClient::PubSubClient(EventLoop* loop, : loop_(loop), client_(loop, hubAddr, name) { + // FIXME: dtor is not thread safe + client_.setConnectionCallback( + boost::bind(&PubSubClient::onConnection, this, _1)); } void PubSubClient::start() @@ -22,5 +27,37 @@ void PubSubClient::stop() client_.disconnect(); } +bool PubSubClient::connected() const +{ + return conn_ && conn_->connected(); +} + +bool PubSubClient::publish(const string& topic, const string& content) +{ + string message = "pub " + topic + "\r\n" + content + "\r\n"; + bool succeed = false; + if (conn_ && conn_->connected()) + { + conn_->send(message); + succeed = true; + } + return succeed; +} +void PubSubClient::onConnection(const muduo::net::TcpConnectionPtr& conn) +{ + if (conn->connected()) + { + conn_ = conn; + // FIXME: re-sub + } + else + { + conn_.reset(); + } + if (connectionCallback_) + { + connectionCallback_(this); + } +} diff --git a/examples/hub/pubsub.h b/examples/hub/pubsub.h index 5aef994e9..0d8ef4c71 100644 --- a/examples/hub/pubsub.h +++ b/examples/hub/pubsub.h @@ -8,11 +8,12 @@ namespace pubsub using muduo::string; using muduo::Timestamp; +// FIXME: dtor is not thread safe class PubSubClient : boost::noncopyable { public: - typedef boost::function SubscribeCallback; typedef boost::function ConnectionCallback; + typedef boost::function SubscribeCallback; PubSubClient(muduo::net::EventLoop* loop, const muduo::net::InetAddress& hubAddr, @@ -21,13 +22,21 @@ class PubSubClient : boost::noncopyable void stop(); bool connected() const; + void setConnectionCallback(const ConnectionCallback& cb) + { connectionCallback_ = cb; } + void subscribe(const string& topic, const SubscribeCallback& cb); void unsubscribe(const string& topic); - void publish(const string& topic, const string& content); + bool publish(const string& topic, const string& content); private: + void onConnection(const muduo::net::TcpConnectionPtr& conn); + muduo::net::EventLoop* loop_; muduo::net::TcpClient client_; + muduo::net::TcpConnectionPtr conn_; + ConnectionCallback connectionCallback_; + SubscribeCallback subscribeCallback_; }; } diff --git a/muduo/base/ProcessInfo.cc b/muduo/base/ProcessInfo.cc index 3537597f7..8e5afe0dd 100644 --- a/muduo/base/ProcessInfo.cc +++ b/muduo/base/ProcessInfo.cc @@ -22,16 +22,19 @@ using namespace muduo; namespace { __thread int t_numOpenedFiles = 0; - int fdDirFilter(const struct dirent*) + int fdDirFilter(const struct dirent* d) { - ++t_numOpenedFiles; + if (::isdigit(d->d_name[0])) + { + ++t_numOpenedFiles; + } return 0; } - __thread std::vector* t_pids = 0; + __thread std::vector* t_pids = NULL; int taskDirFilter(const struct dirent* d) { - if (isdigit(d->d_name[0])) + if (::isdigit(d->d_name[0])) { t_pids->push_back(atoi(d->d_name)); } @@ -60,10 +63,10 @@ string ProcessInfo::username() { struct passwd pwd; struct passwd* result = NULL; - char passwdbuf[8192]; - const char* name = "unknown"; + char buf[8192]; + const char* name = "unknownuser"; - getpwuid_r(uid(), &pwd, passwdbuf, sizeof passwdbuf, &result); + getpwuid_r(uid(), &pwd, buf, sizeof buf, &result); if (result) { name = pwd.pw_name; @@ -101,7 +104,7 @@ int ProcessInfo::openedFiles() t_numOpenedFiles = 0; struct dirent** namelist; scandir("/proc/self/fd", &namelist, fdDirFilter, alphasort); - return t_numOpenedFiles-2; // "." and ".." + return t_numOpenedFiles; } std::vector ProcessInfo::threads() @@ -113,3 +116,4 @@ std::vector ProcessInfo::threads() std::sort(result.begin(), result.end()); return result; } + diff --git a/muduo/net/TcpClient.cc b/muduo/net/TcpClient.cc index 0bf0c3c8e..b85a35320 100644 --- a/muduo/net/TcpClient.cc +++ b/muduo/net/TcpClient.cc @@ -65,8 +65,15 @@ void TcpClient::connect() void TcpClient::disconnect() { - // FIXME: do-it connect_ = false; + + { + MutexLockGuard lock(mutex_); + if (connection_) + { + connection_->shutdown(); + } + } } void TcpClient::newConnection(int sockfd) diff --git a/muduo/net/TcpClient.h b/muduo/net/TcpClient.h index 57dca4c19..9eb413dcf 100644 --- a/muduo/net/TcpClient.h +++ b/muduo/net/TcpClient.h @@ -67,8 +67,8 @@ class TcpClient : boost::noncopyable ConnectionCallback connectionCallback_; MessageCallback messageCallback_; WriteCompleteCallback writeCompleteCallback_; - bool retry_; // atmoic - bool connect_; + bool retry_; // atmoic + bool connect_; // atomic // always in loop thread int nextConnId_; MutexLock mutex_; From 0885c0529aed1c112090d09b280b4d9bac207724 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 15 May 2010 23:32:09 +0800 Subject: [PATCH 082/371] add example/paxos directory --- examples/CMakeLists.txt | 1 + examples/paxos/CMakeLists.txt | 6 ++++++ examples/paxos/lobby.cc | 0 examples/paxos/paxos.cc | 0 examples/paxos/paxos.h | 0 5 files changed, 7 insertions(+) create mode 100644 examples/paxos/CMakeLists.txt create mode 100644 examples/paxos/lobby.cc create mode 100644 examples/paxos/paxos.cc create mode 100644 examples/paxos/paxos.h diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b7faa7f85..e9ae25df8 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(simple) add_subdirectory(roundtrip) add_subdirectory(hub) +add_subdirectory(paxos) add_subdirectory(asio/tutorial) add_subdirectory(asio/chat) diff --git a/examples/paxos/CMakeLists.txt b/examples/paxos/CMakeLists.txt new file mode 100644 index 000000000..367de7394 --- /dev/null +++ b/examples/paxos/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(muduo_paxos paxos.cc) +target_link_libraries(muduo_paxos muduo_inspect) + +add_library(muduo_lobby lobby.cc) +target_link_libraries(muduo_lobby muduo_inspect) + diff --git a/examples/paxos/lobby.cc b/examples/paxos/lobby.cc new file mode 100644 index 000000000..e69de29bb diff --git a/examples/paxos/paxos.cc b/examples/paxos/paxos.cc new file mode 100644 index 000000000..e69de29bb diff --git a/examples/paxos/paxos.h b/examples/paxos/paxos.h new file mode 100644 index 000000000..e69de29bb From 3236938f92a70f04dff82a3a937c03c5e040b16c Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 31 Jul 2010 08:48:10 +0800 Subject: [PATCH 083/371] add date and timezone, not finish yet. --- muduo/base/CMakeLists.txt | 2 ++ muduo/base/Date.cc | 19 +++++++++++ muduo/base/Date.h | 27 ++++++++++++++++ muduo/base/Thread.h | 3 +- muduo/base/TimeZone.cc | 45 +++++++++++++++++++++++++++ muduo/base/TimeZone.h | 26 ++++++++++++++++ muduo/base/tests/CMakeLists.txt | 6 ++++ muduo/base/tests/Date_unittest.cc | 23 ++++++++++++++ muduo/base/tests/TimeZone_unittest.cc | 10 ++++++ 9 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 muduo/base/Date.cc create mode 100644 muduo/base/Date.h create mode 100644 muduo/base/TimeZone.cc create mode 100644 muduo/base/TimeZone.h create mode 100644 muduo/base/tests/Date_unittest.cc create mode 100644 muduo/base/tests/TimeZone_unittest.cc diff --git a/muduo/base/CMakeLists.txt b/muduo/base/CMakeLists.txt index d2e23f349..36c75fe38 100644 --- a/muduo/base/CMakeLists.txt +++ b/muduo/base/CMakeLists.txt @@ -1,7 +1,9 @@ set(base_SRCS + Date.cc Logging.cc ProcessInfo.cc Timestamp.cc + TimeZone.cc Thread.cc ) diff --git a/muduo/base/Date.cc b/muduo/base/Date.cc new file mode 100644 index 000000000..bf8de6eba --- /dev/null +++ b/muduo/base/Date.cc @@ -0,0 +1,19 @@ +#include + +using namespace muduo; + +Date::Date() + : julianDayNumber_(0) +{ +} + +Date::Date(int year, int month, int day) + : julianDayNumber_(0) +{ +} + +string Date::toString() const +{ + return ""; +} + diff --git a/muduo/base/Date.h b/muduo/base/Date.h new file mode 100644 index 000000000..bbffb5ab0 --- /dev/null +++ b/muduo/base/Date.h @@ -0,0 +1,27 @@ +#ifndef MUDUO_BASE_DATE_H +#define MUDUO_BASE_DATE_H + +#include +#include + +namespace muduo +{ + +class Date : public muduo::copyable +{ + public: + /// + /// Constucts an invalid Date. + /// + Date(); + Date(int year, int month, int day); + string toString() const; + + int julianDayNumber() const { return julianDayNumber_; } + + private: + int julianDayNumber_; +}; + +} +#endif // MUDUO_BASE_DATE_H diff --git a/muduo/base/Thread.h b/muduo/base/Thread.h index 836f8ef39..9d9bfa797 100644 --- a/muduo/base/Thread.h +++ b/muduo/base/Thread.h @@ -3,11 +3,12 @@ #include #include +#include namespace muduo { -class Thread +class Thread : boost::noncopyable { public: typedef boost::function ThreadFunc; diff --git a/muduo/base/TimeZone.cc b/muduo/base/TimeZone.cc new file mode 100644 index 000000000..d67ed95a5 --- /dev/null +++ b/muduo/base/TimeZone.cc @@ -0,0 +1,45 @@ +#include +#include +#include + +namespace +{ + +struct Transition +{ +}; + +struct Localtime +{ +}; + +} + +using namespace muduo; +using namespace std; + +struct TimeZone::Data +{ + vector transitions_; + vector localtimes_; + vector names_; +}; + +namespace +{ + bool readTimeZoneFile(const char* zonefile, struct TimeZone::Data* data) + { + return true; + } +} + + +TimeZone::TimeZone(const char* zonefile) + : data_(new TimeZone::Data) +{ + if (!readTimeZoneFile(zonefile, data_.get())) + { + data_.reset(); + } +} + diff --git a/muduo/base/TimeZone.h b/muduo/base/TimeZone.h new file mode 100644 index 000000000..e96b50681 --- /dev/null +++ b/muduo/base/TimeZone.h @@ -0,0 +1,26 @@ +#ifndef MUDUO_BASE_TIMEZONE_H +#define MUDUO_BASE_TIMEZONE_H + +#include +#include +#include + +namespace muduo +{ + +class TimeZone : public muduo::copyable +{ + public: + explicit TimeZone(const char* zonefile); + + bool valid() const { return data_; } + struct tm toLocalTime(time_t secondsSinceEpoch) const; + time_t fromLocalTime(const struct tm&) const; + + struct Data; + private: + boost::shared_ptr data_; +}; + +} +#endif // MUDUO_BASE_TIMEZONE_H diff --git a/muduo/base/tests/CMakeLists.txt b/muduo/base/tests/CMakeLists.txt index ee40f42e5..c83825537 100644 --- a/muduo/base/tests/CMakeLists.txt +++ b/muduo/base/tests/CMakeLists.txt @@ -1,3 +1,9 @@ +add_executable(date_unittest Date_unittest.cc) +target_link_libraries(date_unittest muduo_base) + add_executable(timestamp_unittest Timestamp_unittest.cc) target_link_libraries(timestamp_unittest muduo_base) +add_executable(timezone_unittest TimeZone_unittest.cc) +target_link_libraries(timezone_unittest muduo_base) + diff --git a/muduo/base/tests/Date_unittest.cc b/muduo/base/tests/Date_unittest.cc new file mode 100644 index 000000000..f267b6e7c --- /dev/null +++ b/muduo/base/tests/Date_unittest.cc @@ -0,0 +1,23 @@ +#include +#include + +using muduo::Date; + +void passByConstReference(const Date& x) +{ + printf("%s\n", x.toString().c_str()); +} + +void passByValue(Date x) +{ + printf("%s\n", x.toString().c_str()); +} + +int main() +{ + Date someDay(1982, 4, 3); + printf("%s\n", someDay.toString().c_str()); + passByValue(someDay); + passByConstReference(someDay); +} + diff --git a/muduo/base/tests/TimeZone_unittest.cc b/muduo/base/tests/TimeZone_unittest.cc new file mode 100644 index 000000000..7d544f5c7 --- /dev/null +++ b/muduo/base/tests/TimeZone_unittest.cc @@ -0,0 +1,10 @@ +#include +#include + +using muduo::TimeZone; + +int main() +{ + TimeZone tz("/etc/localtime"); +} + From 06cad7e9c14a211d2cf7117d1e65fea4be41294b Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 7 Aug 2010 13:59:03 +0800 Subject: [PATCH 084/371] Finish Date. --- muduo/base/Date.cc | 42 +++++++++++++++++--- muduo/base/Date.h | 64 ++++++++++++++++++++++++++++++- muduo/base/Timestamp.h | 2 +- muduo/base/tests/Date_unittest.cc | 57 +++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 7 deletions(-) diff --git a/muduo/base/Date.cc b/muduo/base/Date.cc index bf8de6eba..8f481b211 100644 --- a/muduo/base/Date.cc +++ b/muduo/base/Date.cc @@ -1,19 +1,51 @@ #include +#include // snprintf using namespace muduo; -Date::Date() - : julianDayNumber_(0) +namespace { + +int getJulianDayNumber(int year, int month, int day) +{ + int a = (14 - month) / 12; + int y = year + 4800 - a; + int m = month + 12 * a - 3; + return day + (153*m + 2) / 5 + y*365 + y/4 - y/100 + y/400 - 32045; +} + +Date::YearMonthDay getYearMonthDay(int julianDayNumber) +{ + int a = julianDayNumber + 32044; + int b = (4 * a + 3) / 146097; + int c = a - ((b * 146097) / 4); + int d = (4 * c + 3) / 1461; + int e = c - ((1461 * d) / 4); + int m = (5 * e + 2) / 153; + Date::YearMonthDay ymd; + ymd.day = e - ((153 * m + 2) / 5) + 1; + ymd.month = m + 3 - 12 * (m / 10); + ymd.year = b * 100 + d - 4800 + (m / 10); + return ymd; } -Date::Date(int year, int month, int day) - : julianDayNumber_(0) +} + +Date::Date(int y, int m, int d) + : julianDayNumber_(getJulianDayNumber(y, m, d)) { } string Date::toString() const { - return ""; + char buf[32]; + YearMonthDay ymd(yearMonthDay()); + snprintf(buf, sizeof buf, "%4d-%02d-%02d", ymd.year, ymd.month, ymd.day); + return buf; +} + +Date::YearMonthDay Date::yearMonthDay() const +{ + return getYearMonthDay(julianDayNumber_); } diff --git a/muduo/base/Date.h b/muduo/base/Date.h index bbffb5ab0..ce6f35a46 100644 --- a/muduo/base/Date.h +++ b/muduo/base/Date.h @@ -7,16 +7,78 @@ namespace muduo { +/// +/// Date in Gregorian calendar. +/// +/// This class is immutable. +/// It's recommended to pass it by value, since it's passed in register on x64. +/// class Date : public muduo::copyable { public: + + struct YearMonthDay + { + int year; // [1900..2500] + int month; // [1..12] + int day; // [1..31] + }; + + static const int kDaysPerWeek = 7; + /// /// Constucts an invalid Date. /// - Date(); + Date() + : julianDayNumber_(0) + {} + + /// + /// Constucts a yyyy-mm-dd Date. + /// + /// 1 <= month <= 12 Date(int year, int month, int day); + + /// + /// Constucts a Date from Julian Day Number. + /// + /// 1 <= month <= 12 + explicit Date(int julianDayNum) + : julianDayNumber_(julianDayNum) + {} + + // default copy/assignment/dtor are Okay + + bool valid() const { return julianDayNumber_ > 0; } + + /// + /// Converts to yyyy-mm-dd format. + /// string toString() const; + YearMonthDay yearMonthDay() const; + + int year() const + { + return yearMonthDay().year; + } + + int month() const + { + return yearMonthDay().month; + } + + int day() const + { + return yearMonthDay().day; + } + + // [0, 1, ..., 6] => [Sunday, Monday, ..., Saturday ] + int weekDay() const + { + return (julianDayNumber_+1) % kDaysPerWeek; + } + int julianDayNumber() const { return julianDayNumber_; } private: diff --git a/muduo/base/Timestamp.h b/muduo/base/Timestamp.h index e0cbb34c0..517f4d5ea 100644 --- a/muduo/base/Timestamp.h +++ b/muduo/base/Timestamp.h @@ -32,7 +32,7 @@ class Timestamp : public muduo::copyable std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_); } - // default copy/assignment are Okay + // default copy/assignment/dtor are Okay string toString() const; string toFormattedString() const; diff --git a/muduo/base/tests/Date_unittest.cc b/muduo/base/tests/Date_unittest.cc index f267b6e7c..b7384c127 100644 --- a/muduo/base/tests/Date_unittest.cc +++ b/muduo/base/tests/Date_unittest.cc @@ -1,8 +1,33 @@ #include +#include #include using muduo::Date; +const int MonthsOfYear = 12; + +int isLeapYear(int year) +{ + if (year % 400 == 0) + return 1; + else if (year % 100 == 0) + return 0; + else if (year % 4 == 0) + return 1; + else + return 0; +} + +int daysOfMonth(int year, int month) +{ + static int days[2][MonthsOfYear+1] = + { + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + }; + return days[isLeapYear(year)][month]; +} + void passByConstReference(const Date& x) { printf("%s\n", x.toString().c_str()); @@ -19,5 +44,37 @@ int main() printf("%s\n", someDay.toString().c_str()); passByValue(someDay); passByConstReference(someDay); + + int julianDayNumber = 2415021; + int weekDay = 1; // Monday + + for (int year = 1900; year < 2500; ++year) + { + assert(Date(year, 3, 1).julianDayNumber() - Date(year, 2, 29).julianDayNumber() == isLeapYear(year)); + for (int month = 1; month <= MonthsOfYear; ++month) + { + for (int day = 1; day <= daysOfMonth(year, month); ++day) + { + Date d(year, month, day); + // printf("%s %d\n", d.toString().c_str(), d.weekDay()); + assert(year == d.year()); + assert(month == d.month()); + assert(day == d.day()); + assert(weekDay == d.weekDay()); + assert(julianDayNumber == d.julianDayNumber()); + + Date d2(julianDayNumber); + assert(year == d2.year()); + assert(month == d2.month()); + assert(day == d2.day()); + assert(weekDay == d2.weekDay()); + assert(julianDayNumber == d2.julianDayNumber()); + + ++julianDayNumber; + weekDay = (weekDay+1) % 7; + } + } + } + } From 2c84280a884464835c588d45da63094b721b4dfe Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 13 Aug 2010 20:02:13 +0800 Subject: [PATCH 085/371] Date from struct tm --- muduo/base/Date.cc | 19 ++++++++++++++++++- muduo/base/Date.h | 27 ++++++++++++++++++++++++++- muduo/base/TimeZone.cc | 8 ++++---- muduo/base/TimeZone.h | 3 +++ muduo/base/tests/Date_unittest.cc | 26 +++++++++++++++++--------- 5 files changed, 68 insertions(+), 15 deletions(-) diff --git a/muduo/base/Date.cc b/muduo/base/Date.cc index 8f481b211..fd30f11d3 100644 --- a/muduo/base/Date.cc +++ b/muduo/base/Date.cc @@ -1,3 +1,8 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + #include #include // snprintf @@ -6,6 +11,10 @@ using namespace muduo; namespace { +// algorithm and explanation see: +// http://www.faqs.org/faqs/calendars/faq/part2/ +// http://blog.csdn.net/Solstice + int getJulianDayNumber(int year, int month, int day) { int a = (14 - month) / 12; @@ -36,7 +45,15 @@ Date::Date(int y, int m, int d) { } -string Date::toString() const +Date::Date(const struct tm& t) + : julianDayNumber_(getJulianDayNumber( + t.tm_year+1900, + t.tm_mon+1, + t.tm_mday)) +{ +} + +string Date::toIsoString() const { char buf[32]; YearMonthDay ymd(yearMonthDay()); diff --git a/muduo/base/Date.h b/muduo/base/Date.h index ce6f35a46..c0bb883f4 100644 --- a/muduo/base/Date.h +++ b/muduo/base/Date.h @@ -1,9 +1,16 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + #ifndef MUDUO_BASE_DATE_H #define MUDUO_BASE_DATE_H #include #include +struct tm; + namespace muduo { @@ -14,6 +21,8 @@ namespace muduo /// It's recommended to pass it by value, since it's passed in register on x64. /// class Date : public muduo::copyable + // public boost::less_than_comparable, + // public boost::equality_comparable { public: @@ -47,6 +56,12 @@ class Date : public muduo::copyable : julianDayNumber_(julianDayNum) {} + /// + /// Constucts a Date from struct tm + /// + /// 1 <= month <= 12 + explicit Date(const struct tm&); + // default copy/assignment/dtor are Okay bool valid() const { return julianDayNumber_ > 0; } @@ -54,7 +69,7 @@ class Date : public muduo::copyable /// /// Converts to yyyy-mm-dd format. /// - string toString() const; + string toIsoString() const; YearMonthDay yearMonthDay() const; @@ -85,5 +100,15 @@ class Date : public muduo::copyable int julianDayNumber_; }; +inline bool operator<(Date x, Date y) +{ + return x.julianDayNumber() < y.julianDayNumber(); +} + +inline bool operator==(Date x, Date y) +{ + return x.julianDayNumber() == y.julianDayNumber(); +} + } #endif // MUDUO_BASE_DATE_H diff --git a/muduo/base/TimeZone.cc b/muduo/base/TimeZone.cc index d67ed95a5..8d9465854 100644 --- a/muduo/base/TimeZone.cc +++ b/muduo/base/TimeZone.cc @@ -27,10 +27,10 @@ struct TimeZone::Data namespace { - bool readTimeZoneFile(const char* zonefile, struct TimeZone::Data* data) - { - return true; - } +bool readTimeZoneFile(const char* zonefile, struct TimeZone::Data* data) +{ + return true; +} } diff --git a/muduo/base/TimeZone.h b/muduo/base/TimeZone.h index e96b50681..cdd3959c5 100644 --- a/muduo/base/TimeZone.h +++ b/muduo/base/TimeZone.h @@ -13,11 +13,14 @@ class TimeZone : public muduo::copyable public: explicit TimeZone(const char* zonefile); + // default copy ctor/assignment/dtor are Okay. + bool valid() const { return data_; } struct tm toLocalTime(time_t secondsSinceEpoch) const; time_t fromLocalTime(const struct tm&) const; struct Data; + private: boost::shared_ptr data_; }; diff --git a/muduo/base/tests/Date_unittest.cc b/muduo/base/tests/Date_unittest.cc index b7384c127..053078fee 100644 --- a/muduo/base/tests/Date_unittest.cc +++ b/muduo/base/tests/Date_unittest.cc @@ -4,7 +4,7 @@ using muduo::Date; -const int MonthsOfYear = 12; +const int kMonthsOfYear = 12; int isLeapYear(int year) { @@ -20,7 +20,7 @@ int isLeapYear(int year) int daysOfMonth(int year, int month) { - static int days[2][MonthsOfYear+1] = + static int days[2][kMonthsOfYear+1] = { { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, @@ -30,28 +30,36 @@ int daysOfMonth(int year, int month) void passByConstReference(const Date& x) { - printf("%s\n", x.toString().c_str()); + printf("%s\n", x.toIsoString().c_str()); } void passByValue(Date x) { - printf("%s\n", x.toString().c_str()); + printf("%s\n", x.toIsoString().c_str()); } int main() { - Date someDay(1982, 4, 3); - printf("%s\n", someDay.toString().c_str()); + time_t now = time(NULL); + struct tm t1 = *gmtime(&now); + struct tm t2 = *localtime(&now); + Date someDay(2008, 9, 10); + printf("%s\n", someDay.toIsoString().c_str()); passByValue(someDay); passByConstReference(someDay); + Date todayUtc(t1); + printf("%s\n", someDay2.toIsoString().c_str()); + Date todayLocal(t2); + printf("%s\n", someDay2.toIsoString().c_str()); int julianDayNumber = 2415021; int weekDay = 1; // Monday for (int year = 1900; year < 2500; ++year) { - assert(Date(year, 3, 1).julianDayNumber() - Date(year, 2, 29).julianDayNumber() == isLeapYear(year)); - for (int month = 1; month <= MonthsOfYear; ++month) + assert(Date(year, 3, 1).julianDayNumber() - Date(year, 2, 29).julianDayNumber() + == isLeapYear(year)); + for (int month = 1; month <= kMonthsOfYear; ++month) { for (int day = 1; day <= daysOfMonth(year, month); ++day) { @@ -75,6 +83,6 @@ int main() } } } - + printf("All passed.\n"); } From d27fe905288070097acf0cda2a618f6615539c2b Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 15 Aug 2010 22:36:11 +0800 Subject: [PATCH 086/371] Update change log --- ChangeLog | 20 ++++++++++++++++++++ muduo/base/Date.cc | 5 ++++- muduo/base/Date.h | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0b29b4549..74632d848 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,26 @@ * First alpha release, version 0.1.0 +2010-08-07 Shuo Chen + + * Add Date. + +2010-05-15 Shuo Chen + + * Hub works. + +2010-05-14 Shuo Chen + + * Inspects opened files and threads. + +2010-05-11 Shuo Chen + + * Add inspector for process info. + +2010-05-04 Shuo Chen + + * Add simple http server and client. + 2010-04-25 Shuo Chen * Add examples. diff --git a/muduo/base/Date.cc b/muduo/base/Date.cc index fd30f11d3..82ffd5aa8 100644 --- a/muduo/base/Date.cc +++ b/muduo/base/Date.cc @@ -11,19 +11,22 @@ using namespace muduo; namespace { +char require_32_bit_integer_at_least[sizeof(int) >= sizeof(int32_t) ? 1 : -1]; + // algorithm and explanation see: // http://www.faqs.org/faqs/calendars/faq/part2/ // http://blog.csdn.net/Solstice int getJulianDayNumber(int year, int month, int day) { + (void) require_32_bit_integer_at_least; // no warning please int a = (14 - month) / 12; int y = year + 4800 - a; int m = month + 12 * a - 3; return day + (153*m + 2) / 5 + y*365 + y/4 - y/100 + y/400 - 32045; } -Date::YearMonthDay getYearMonthDay(int julianDayNumber) +struct Date::YearMonthDay getYearMonthDay(int julianDayNumber) { int a = julianDayNumber + 32044; int b = (4 * a + 3) / 146097; diff --git a/muduo/base/Date.h b/muduo/base/Date.h index c0bb883f4..cb393b123 100644 --- a/muduo/base/Date.h +++ b/muduo/base/Date.h @@ -71,7 +71,7 @@ class Date : public muduo::copyable /// string toIsoString() const; - YearMonthDay yearMonthDay() const; + struct YearMonthDay yearMonthDay() const; int year() const { From b578ae218adba75664e11453d986090805c079b4 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 17 Aug 2010 23:24:37 +0800 Subject: [PATCH 087/371] fix date unittest --- muduo/base/Thread.cc | 5 +++++ muduo/base/Thread.h | 5 +++++ muduo/base/tests/Date_unittest.cc | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/muduo/base/Thread.cc b/muduo/base/Thread.cc index cdce5f73e..2cc6c1b88 100644 --- a/muduo/base/Thread.cc +++ b/muduo/base/Thread.cc @@ -1,3 +1,8 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + #include #include diff --git a/muduo/base/Thread.h b/muduo/base/Thread.h index 9d9bfa797..a103af813 100644 --- a/muduo/base/Thread.h +++ b/muduo/base/Thread.h @@ -1,3 +1,8 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + #ifndef MUDUO_BASE_THREAD_H #define MUDUO_BASE_THREAD_H diff --git a/muduo/base/tests/Date_unittest.cc b/muduo/base/tests/Date_unittest.cc index 053078fee..3242934c3 100644 --- a/muduo/base/tests/Date_unittest.cc +++ b/muduo/base/tests/Date_unittest.cc @@ -48,9 +48,9 @@ int main() passByValue(someDay); passByConstReference(someDay); Date todayUtc(t1); - printf("%s\n", someDay2.toIsoString().c_str()); + printf("%s\n", todayUtc.toIsoString().c_str()); Date todayLocal(t2); - printf("%s\n", someDay2.toIsoString().c_str()); + printf("%s\n", todayLocal.toIsoString().c_str()); int julianDayNumber = 2415021; int weekDay = 1; // Monday From 7ab144e0075bd3a460fcd0145cbe9f15f250c385 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Fri, 27 Aug 2010 00:13:53 +0800 Subject: [PATCH 088/371] migrate Atomic from recipes --- TODO | 1 + muduo/base/Atomic.h | 58 ++++++++++++++++++++++++----- muduo/base/tests/Atomic_unittest.cc | 38 +++++++++++++++++++ muduo/base/tests/CMakeLists.txt | 3 ++ 4 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 muduo/base/tests/Atomic_unittest.cc diff --git a/TODO b/TODO index c78e9cff9..d1885a327 100644 --- a/TODO +++ b/TODO @@ -2,4 +2,5 @@ Always processing timer before IO Support string and line protocol Add Resolver Add Benchmark +Support signal handling diff --git a/muduo/base/Atomic.h b/muduo/base/Atomic.h index f8c522574..f774c1a1c 100644 --- a/muduo/base/Atomic.h +++ b/muduo/base/Atomic.h @@ -1,42 +1,82 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + #ifndef MUDUO_BASE_ATOMIC_H #define MUDUO_BASE_ATOMIC_H #include +#include namespace muduo { -class AtomicInt64 : boost::noncopyable +namespace detail +{ +template +class AtomicIntegerT : boost::noncopyable { public: - AtomicInt64() + AtomicIntegerT() : value_(0) { } - int64_t get() + // uncomment if you need copying and assignment + // + // AtomicIntegerT(const AtomicIntegerT& that) + // : value_(that.get()) + // {} + // + // AtomicIntegerT& operator=(const AtomicIntegerT& that) + // { + // getAndSet(that.get()); + // return *this; + // } + + T get() { - return value_; + return __sync_val_compare_and_swap(&value_, 0, 0); } - int64_t addAndGet(int64_t x) + T getAndAdd(T x) { - return __sync_add_and_fetch(&value_, x); + return __sync_fetch_and_add(&value_, x); } - int64_t incrementAndGet() + T addAndGet(T x) + { + return getAndAdd(x) + x; + } + + T incrementAndGet() { return addAndGet(1); } - int64_t getAndSet(int64_t newValue) + void increment() + { + incrementAndGet(); + } + + void decrement() + { + getAndAdd(-1); + } + + T getAndSet(T newValue) { return __sync_lock_test_and_set(&value_, newValue); } private: - volatile int64_t value_; + volatile T value_; }; +} +typedef detail::AtomicIntegerT AtomicInt32; +typedef detail::AtomicIntegerT AtomicInt64; } + #endif // MUDUO_BASE_ATOMIC_H diff --git a/muduo/base/tests/Atomic_unittest.cc b/muduo/base/tests/Atomic_unittest.cc new file mode 100644 index 000000000..1ca35e44b --- /dev/null +++ b/muduo/base/tests/Atomic_unittest.cc @@ -0,0 +1,38 @@ +#include +#include + +int main() +{ + { + muduo::AtomicInt64 a0; + assert(a0.get() == 0); + assert(a0.getAndAdd(1) == 0); + assert(a0.get() == 1); + assert(a0.addAndGet(2) == 3); + assert(a0.get() == 3); + assert(a0.incrementAndGet() == 4); + assert(a0.get() == 4); + a0.increment(); + assert(a0.get() == 5); + assert(a0.addAndGet(-3) == 2); + assert(a0.getAndSet(100) == 2); + assert(a0.get() == 100); + } + + { + muduo::AtomicInt32 a1; + assert(a1.get() == 0); + assert(a1.getAndAdd(1) == 0); + assert(a1.get() == 1); + assert(a1.addAndGet(2) == 3); + assert(a1.get() == 3); + assert(a1.incrementAndGet() == 4); + assert(a1.get() == 4); + a1.increment(); + assert(a1.get() == 5); + assert(a1.addAndGet(-3) == 2); + assert(a1.getAndSet(100) == 2); + assert(a1.get() == 100); + } +} + diff --git a/muduo/base/tests/CMakeLists.txt b/muduo/base/tests/CMakeLists.txt index c83825537..8b3d19846 100644 --- a/muduo/base/tests/CMakeLists.txt +++ b/muduo/base/tests/CMakeLists.txt @@ -1,3 +1,6 @@ +add_executable(atomic_unittest Atomic_unittest.cc) +# target_link_libraries(atomic_unittest muduo_base) + add_executable(date_unittest Date_unittest.cc) target_link_libraries(date_unittest muduo_base) From 16f18075765cfa16f6ed25a49700ae2484ea48ac Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 28 Aug 2010 00:15:24 +0800 Subject: [PATCH 089/371] merge thread base lib from recipes --- muduo/base/BlockingQueue.h | 64 ++++++++++ muduo/base/CMakeLists.txt | 3 + muduo/base/Condition.h | 9 +- muduo/base/CountDownLatch.cc | 39 ++++++ muduo/base/CountDownLatch.h | 36 ++++++ muduo/base/Exception.cc | 57 +++++++++ muduo/base/Exception.h | 33 +++++ muduo/base/Mutex.h | 8 +- muduo/base/Singleton.h | 16 ++- muduo/base/Thread.cc | 45 ++++++- muduo/base/Thread.h | 18 ++- muduo/base/ThreadLocal.h | 53 ++++++++ muduo/base/ThreadLocalSingleton.h | 44 +++++++ muduo/base/ThreadPool.cc | 114 ++++++++++++++++++ muduo/base/ThreadPool.h | 50 ++++++++ muduo/base/tests/BlockingQueue_test.cc | 85 +++++++++++++ muduo/base/tests/CMakeLists.txt | 24 ++++ muduo/base/tests/Exception_test.cc | 30 +++++ muduo/base/tests/SingletonThreadLocal_test.cc | 58 +++++++++ muduo/base/tests/Singleton_test.cc | 46 +++++++ muduo/base/tests/ThreadLocalSingleton_test.cc | 57 +++++++++ muduo/base/tests/ThreadLocal_test.cc | 61 ++++++++++ muduo/base/tests/ThreadPool_test.cc | 36 ++++++ muduo/base/tests/Thread_test.cc | 63 ++++++++++ muduo/net/EventLoop.cc | 3 +- muduo/net/tests/CMakeLists.txt | 4 +- ...est.cc => EventLoopThreadPool_unittest.cc} | 0 27 files changed, 1035 insertions(+), 21 deletions(-) create mode 100644 muduo/base/BlockingQueue.h create mode 100644 muduo/base/CountDownLatch.cc create mode 100644 muduo/base/CountDownLatch.h create mode 100644 muduo/base/Exception.cc create mode 100644 muduo/base/Exception.h create mode 100644 muduo/base/ThreadLocal.h create mode 100644 muduo/base/ThreadLocalSingleton.h create mode 100644 muduo/base/ThreadPool.cc create mode 100644 muduo/base/ThreadPool.h create mode 100644 muduo/base/tests/BlockingQueue_test.cc create mode 100644 muduo/base/tests/Exception_test.cc create mode 100644 muduo/base/tests/SingletonThreadLocal_test.cc create mode 100644 muduo/base/tests/Singleton_test.cc create mode 100644 muduo/base/tests/ThreadLocalSingleton_test.cc create mode 100644 muduo/base/tests/ThreadLocal_test.cc create mode 100644 muduo/base/tests/ThreadPool_test.cc create mode 100644 muduo/base/tests/Thread_test.cc rename muduo/net/tests/{ThreadPool_unittest.cc => EventLoopThreadPool_unittest.cc} (100%) diff --git a/muduo/base/BlockingQueue.h b/muduo/base/BlockingQueue.h new file mode 100644 index 000000000..54b901d57 --- /dev/null +++ b/muduo/base/BlockingQueue.h @@ -0,0 +1,64 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_BLOCKINGQUEUE_H +#define MUDUO_BASE_BLOCKINGQUEUE_H + +#include +#include + +#include +#include +#include + +namespace muduo +{ + +template +class BlockingQueue : boost::noncopyable +{ + public: + BlockingQueue() + : mutex_(), + cond_(mutex_), + queue_() + { + } + + void put(const T& x) + { + MutexLockGuard lock(mutex_); + queue_.push_back(x); + cond_.notify(); + } + + T take() + { + MutexLockGuard lock(mutex_); + while (queue_.empty()) + { + cond_.wait(); + } + assert(!queue_.empty()); + T front(queue_.front()); + queue_.pop_front(); + return front; + } + + size_t size() const + { + MutexLockGuard lock(mutex_); + return queue_.size(); + } + + private: + mutable MutexLock mutex_; + Condition cond_; + std::deque queue_; +}; + +} + +#endif // MUDUO_BASE_BLOCKINGQUEUE_H diff --git a/muduo/base/CMakeLists.txt b/muduo/base/CMakeLists.txt index 36c75fe38..8f1a8eb6e 100644 --- a/muduo/base/CMakeLists.txt +++ b/muduo/base/CMakeLists.txt @@ -1,10 +1,13 @@ set(base_SRCS + CountDownLatch.cc Date.cc + Exception.cc Logging.cc ProcessInfo.cc Timestamp.cc TimeZone.cc Thread.cc + ThreadPool.cc ) add_library(muduo_base ${base_SRCS}) diff --git a/muduo/base/Condition.h b/muduo/base/Condition.h index 250b8ab25..98a4dde33 100644 --- a/muduo/base/Condition.h +++ b/muduo/base/Condition.h @@ -1,11 +1,16 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + #ifndef MUDUO_BASE_CONDITION_H #define MUDUO_BASE_CONDITION_H -#include +#include #include +#include -#include namespace muduo { diff --git a/muduo/base/CountDownLatch.cc b/muduo/base/CountDownLatch.cc new file mode 100644 index 000000000..e94dd9a6d --- /dev/null +++ b/muduo/base/CountDownLatch.cc @@ -0,0 +1,39 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include + +using namespace muduo; + +CountDownLatch::CountDownLatch(int count) + : mutex_(), + condition_(mutex_), + count_(count) +{ +} + +void CountDownLatch::wait() +{ + MutexLockGuard lock(mutex_); + while (count_ > 0) { + condition_.wait(); + } +} + +void CountDownLatch::countDown() +{ + MutexLockGuard lock(mutex_); + --count_; + if (count_ == 0) { + condition_.notifyAll(); + } +} + +int CountDownLatch::getCount() const +{ + MutexLockGuard lock(mutex_); + return count_; +} + diff --git a/muduo/base/CountDownLatch.h b/muduo/base/CountDownLatch.h new file mode 100644 index 000000000..c65489016 --- /dev/null +++ b/muduo/base/CountDownLatch.h @@ -0,0 +1,36 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_COUNTDOWNLATCH_H +#define MUDUO_BASE_COUNTDOWNLATCH_H + +#include +#include + +#include + +namespace muduo +{ + +class CountDownLatch : boost::noncopyable +{ + public: + + CountDownLatch(int count); + + void wait(); + + void countDown(); + + int getCount() const; + + private: + mutable MutexLock mutex_; + Condition condition_; + int count_; +}; + +} +#endif // MUDUO_BASE_COUNTDOWNLATCH_H diff --git a/muduo/base/Exception.cc b/muduo/base/Exception.cc new file mode 100644 index 000000000..9962f967d --- /dev/null +++ b/muduo/base/Exception.cc @@ -0,0 +1,57 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include + +//#include +#include +#include + +using namespace muduo; + +Exception::Exception(const char* msg) + : message_(msg) +{ + fillStackTrace(); +} + +Exception::Exception(const string& msg) + : message_(msg) +{ + fillStackTrace(); +} + +Exception::~Exception() throw () +{ +} + +const char* Exception::what() const throw() +{ + return message_.c_str(); +} + +const char* Exception::stackTrace() const throw() +{ + return stack_.c_str(); +} + +void Exception::fillStackTrace() +{ + const int len = 200; + void* buffer[len]; + int nptrs = ::backtrace(buffer, len); + char** strings = ::backtrace_symbols(buffer, nptrs); + if (strings) + { + for (int i = 0; i < nptrs; ++i) + { + // TODO demangle funcion name with abi::__cxa_demangle + stack_.append(strings[i]); + stack_.push_back('\n'); + } + free(strings); + } +} + diff --git a/muduo/base/Exception.h b/muduo/base/Exception.h new file mode 100644 index 000000000..4c55e8417 --- /dev/null +++ b/muduo/base/Exception.h @@ -0,0 +1,33 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_EXCEPTION_H +#define MUDUO_BASE_EXCEPTION_H + +#include +#include + +namespace muduo +{ + +class Exception : public std::exception +{ + public: + explicit Exception(const char* what); + explicit Exception(const string& what); + virtual ~Exception() throw(); + virtual const char* what() const throw(); + const char* stackTrace() const throw(); + + private: + void fillStackTrace(); + + string message_; + string stack_; +}; + +} + +#endif // MUDUO_BASE_EXCEPTION_H diff --git a/muduo/base/Mutex.h b/muduo/base/Mutex.h index 81b6b9009..477b177b3 100644 --- a/muduo/base/Mutex.h +++ b/muduo/base/Mutex.h @@ -1,9 +1,13 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + #ifndef MUDUO_BASE_MUTEX_H #define MUDUO_BASE_MUTEX_H -#include - #include +#include namespace muduo { diff --git a/muduo/base/Singleton.h b/muduo/base/Singleton.h index 3f8130054..40f90df8e 100644 --- a/muduo/base/Singleton.h +++ b/muduo/base/Singleton.h @@ -1,11 +1,20 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + #ifndef MUDUO_BASE_SINGLETON_H #define MUDUO_BASE_SINGLETON_H +#include #include #include // atexit +namespace muduo +{ + template -class Singleton +class Singleton : boost::noncopyable { public: static T& instance() @@ -16,14 +25,12 @@ class Singleton private: Singleton(); - Singleton(const Singleton&); - Singleton& operator=(const Singleton&); ~Singleton(); static void init() { value_ = new T(); - atexit(destroy); + ::atexit(destroy); } static void destroy() @@ -42,5 +49,6 @@ pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT; template T* Singleton::value_ = NULL; +} #endif diff --git a/muduo/base/Thread.cc b/muduo/base/Thread.cc index 2cc6c1b88..4bb0a1341 100644 --- a/muduo/base/Thread.cc +++ b/muduo/base/Thread.cc @@ -4,13 +4,20 @@ // Author: Shuo Chen (chenshuo at chenshuo dot com) #include -#include #include #include #include #include +namespace muduo +{ +namespace CurrentThread +{ + __thread const char* t_threadName = "unknown"; +} +} + namespace { __thread pid_t t_cachedTid = 0; @@ -20,6 +27,16 @@ pid_t gettid() return static_cast(::syscall(SYS_gettid)); } +class ThreadNameInitializer +{ + public: + ThreadNameInitializer() + { + muduo::CurrentThread::t_threadName = "main"; + } +}; + +ThreadNameInitializer init; } using namespace muduo; @@ -33,17 +50,26 @@ pid_t CurrentThread::tid() return t_cachedTid; } +const char* CurrentThread::name() +{ + return t_threadName; +} + bool CurrentThread::isMainThread() { - return tid() == ProcessInfo::pid(); + return tid() == ::getpid(); } -Thread::Thread(const ThreadFunc& func) +AtomicInt32 Thread::numCreated_; + +Thread::Thread(const ThreadFunc& func, const string& n) : started_(false), pthreadId_(0), tid_(0), - func_(func) + func_(func), + name_(n) { + numCreated_.increment(); } Thread::~Thread() @@ -66,8 +92,15 @@ void Thread::join() void* Thread::startThread(void* obj) { Thread* thread = static_cast(obj); - thread->tid_ = CurrentThread::tid(); - thread->func_(); + thread->runInThread(); return NULL; } +void Thread::runInThread() +{ + tid_ = CurrentThread::tid(); + muduo::CurrentThread::t_threadName = name_.c_str(); + func_(); + muduo::CurrentThread::t_threadName = "finished"; +} + diff --git a/muduo/base/Thread.h b/muduo/base/Thread.h index a103af813..e9e5803b4 100644 --- a/muduo/base/Thread.h +++ b/muduo/base/Thread.h @@ -6,9 +6,12 @@ #ifndef MUDUO_BASE_THREAD_H #define MUDUO_BASE_THREAD_H -#include +#include +#include + #include #include +#include namespace muduo { @@ -18,31 +21,38 @@ class Thread : boost::noncopyable public: typedef boost::function ThreadFunc; - explicit Thread(const ThreadFunc&); + Thread(const ThreadFunc&, const string& name = string()); ~Thread(); void start(); void join(); bool started() const { return started_; } - pthread_t pthreadId() const { return pthreadId_; } + // pthread_t pthreadId() const { return pthreadId_; } pid_t tid() const { return tid_; } + const string& name() const { return name_; } + + static int numCreated() { return numCreated_.get(); } private: static void* startThread(void* thread); + void runInThread(); bool started_; pthread_t pthreadId_; pid_t tid_; ThreadFunc func_; + string name_; + + static AtomicInt32 numCreated_; }; namespace CurrentThread { pid_t tid(); + const char* name(); bool isMainThread(); } } - #endif diff --git a/muduo/base/ThreadLocal.h b/muduo/base/ThreadLocal.h new file mode 100644 index 000000000..374fa557a --- /dev/null +++ b/muduo/base/ThreadLocal.h @@ -0,0 +1,53 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADLOCAL_H +#define MUDUO_BASE_THREADLOCAL_H + +#include +#include + +namespace muduo +{ + +template +class ThreadLocal : boost::noncopyable +{ + public: + ThreadLocal() + { + pthread_key_create(&pkey_, &ThreadLocal::destructor); + } + + ~ThreadLocal() + { + pthread_key_delete(pkey_); + } + + T& value() + { + T* perThreadValue = static_cast(pthread_getspecific(pkey_)); + if (!perThreadValue) { + T* newObj = new T(); + pthread_setspecific(pkey_, newObj); + perThreadValue = newObj; + } + return *perThreadValue; + } + + private: + + static void destructor(void *x) + { + T* obj = static_cast(x); + delete obj; + } + + private: + pthread_key_t pkey_; +}; + +} +#endif diff --git a/muduo/base/ThreadLocalSingleton.h b/muduo/base/ThreadLocalSingleton.h new file mode 100644 index 000000000..83aba1b4d --- /dev/null +++ b/muduo/base/ThreadLocalSingleton.h @@ -0,0 +1,44 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADLOCALSINGLETON_H +#define MUDUO_BASE_THREADLOCALSINGLETON_H + +#include + +namespace muduo +{ + +template +class ThreadLocalSingleton : boost::noncopyable +{ + public: + + static T& instance() + { + if (!t_value_) + { + t_value_ = new T(); + } + return *t_value_; + } + + // no way to auto delete it + static void destroy() + { + delete t_value_; + t_value_ = 0; + } + + private: + + static __thread T* t_value_; +}; + +template +__thread T* ThreadLocalSingleton::t_value_ = 0; + +} +#endif diff --git a/muduo/base/ThreadPool.cc b/muduo/base/ThreadPool.cc new file mode 100644 index 000000000..ef27783fa --- /dev/null +++ b/muduo/base/ThreadPool.cc @@ -0,0 +1,114 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include + +#include + +#include +#include +#include + +using namespace muduo; + +ThreadPool::ThreadPool(const string& name) + : mutex_(), + cond_(mutex_), + name_(name), + running_(false) +{ +} + +ThreadPool::~ThreadPool() +{ +} + +void ThreadPool::start(int numThreads) +{ + assert(threads_.empty()); + running_ = true; + threads_.reserve(numThreads); + for (int i = 0; i < numThreads; ++i) + { + char id[32]; + snprintf(id, sizeof id, "%d", i); + threads_.push_back(new muduo::Thread( + boost::bind(&ThreadPool::runInThread, this), name_+id)); + threads_[i].start(); + } +} + +void ThreadPool::stop() +{ + running_ = false; + cond_.notifyAll(); + for_each(threads_.begin(), + threads_.end(), + boost::bind(&muduo::Thread::join, _1)); +} + +void ThreadPool::run(const Task& task) +{ + if (threads_.empty()) + { + task(); + } + else + { + MutexLockGuard lock(mutex_); + queue_.push_back(task); + cond_.notify(); + } +} + +ThreadPool::Task ThreadPool::take() +{ + MutexLockGuard lock(mutex_); + while (queue_.empty() && running_) + { + cond_.wait(); + } + Task task; + if(!queue_.empty()) + { + task = queue_.front(); + queue_.pop_front(); + } + return task; +} + +void ThreadPool::runInThread() +{ + try + { + while (running_) + { + Task task(take()); + if (task) + { + task(); + } + } + } + catch (const Exception& ex) + { + fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); + abort(); + } + catch (const std::exception ex) + { + fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + abort(); + } + catch (...) + { + fprintf(stderr, "unknown exception caught in ThreadPool %s\n", name_.c_str()); + abort(); + } +} + diff --git a/muduo/base/ThreadPool.h b/muduo/base/ThreadPool.h new file mode 100644 index 000000000..2351bd242 --- /dev/null +++ b/muduo/base/ThreadPool.h @@ -0,0 +1,50 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADPOOL_H +#define MUDUO_BASE_THREADPOOL_H + +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace muduo +{ + +class ThreadPool : boost::noncopyable +{ + public: + typedef boost::function Task; + + explicit ThreadPool(const string& name = string()); + ~ThreadPool(); + + void start(int numThreads); + void stop(); + + void run(const Task& f); + + private: + void runInThread(); + Task take(); + + MutexLock mutex_; + Condition cond_; + string name_; + boost::ptr_vector threads_; + std::deque queue_; + bool running_; +}; + +} + +#endif diff --git a/muduo/base/tests/BlockingQueue_test.cc b/muduo/base/tests/BlockingQueue_test.cc new file mode 100644 index 000000000..9f3fa5b0e --- /dev/null +++ b/muduo/base/tests/BlockingQueue_test.cc @@ -0,0 +1,85 @@ +#include +#include +#include + +#include +#include +#include +#include + +class Test +{ + public: + Test(int numThreads) + : latch_(numThreads), + threads_(numThreads) + { + for (int i = 0; i < numThreads; ++i) + { + char name[32]; + snprintf(name, sizeof name, "work thread %d", i); + threads_.push_back(new muduo::Thread( + boost::bind(&Test::threadFunc, this), muduo::string(name))); + } + for_each(threads_.begin(), threads_.end(), boost::bind(&muduo::Thread::start, _1)); + } + + void run(int times) + { + printf("waiting for count down latch\n"); + latch_.wait(); + printf("all threads started\n"); + for (int i = 0; i < times; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "hello %d", i); + queue_.put(buf); + } + } + + void joinAll() + { + for (size_t i = 0; i < threads_.size(); ++i) + { + queue_.put("stop"); + } + + for_each(threads_.begin(), threads_.end(), boost::bind(&muduo::Thread::join, _1)); + } + + private: + + void threadFunc() + { + printf("tid=%d, %s started\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + + latch_.countDown(); + bool running = true; + while (running) + { + std::string d(queue_.take()); + printf("tid=%d, data = %s\n", muduo::CurrentThread::tid(), d.c_str()); + running = (d != "stop"); + } + + printf("tid=%d, %s stopped\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + } + + muduo::BlockingQueue queue_; + muduo::CountDownLatch latch_; + boost::ptr_vector threads_; +}; + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + Test t(5); + t.run(100); + t.joinAll(); + + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/muduo/base/tests/CMakeLists.txt b/muduo/base/tests/CMakeLists.txt index 8b3d19846..ef48a8846 100644 --- a/muduo/base/tests/CMakeLists.txt +++ b/muduo/base/tests/CMakeLists.txt @@ -1,12 +1,36 @@ add_executable(atomic_unittest Atomic_unittest.cc) # target_link_libraries(atomic_unittest muduo_base) +add_executable(blockingqueue_test BlockingQueue_test.cc) +target_link_libraries(blockingqueue_test muduo_base) + add_executable(date_unittest Date_unittest.cc) target_link_libraries(date_unittest muduo_base) +add_executable(exception_test Exception_test.cc) +target_link_libraries(exception_test muduo_base) + +add_executable(singleton_test Singleton_test.cc) +target_link_libraries(singleton_test muduo_base) + +add_executable(singleton_threadlocal_test SingletonThreadLocal_test.cc) +target_link_libraries(singleton_threadlocal_test muduo_base) + add_executable(timestamp_unittest Timestamp_unittest.cc) target_link_libraries(timestamp_unittest muduo_base) add_executable(timezone_unittest TimeZone_unittest.cc) target_link_libraries(timezone_unittest muduo_base) +add_executable(thread_test Thread_test.cc) +target_link_libraries(thread_test muduo_base) + +add_executable(threadlocal_test ThreadLocal_test.cc) +target_link_libraries(threadlocal_test muduo_base) + +add_executable(threadlocalsingleton_test ThreadLocalSingleton_test.cc) +target_link_libraries(threadlocalsingleton_test muduo_base) + +add_executable(threadpool_test ThreadPool_test.cc) +target_link_libraries(threadpool_test muduo_base) + diff --git a/muduo/base/tests/Exception_test.cc b/muduo/base/tests/Exception_test.cc new file mode 100644 index 000000000..e1d5d03d9 --- /dev/null +++ b/muduo/base/tests/Exception_test.cc @@ -0,0 +1,30 @@ +#include +#include + +class Bar +{ + public: + void test() + { + throw muduo::Exception("oops"); + } +}; + +void foo() +{ + Bar b; + b.test(); +} + +int main() +{ + try + { + foo(); + } + catch (const muduo::Exception& ex) + { + printf("reason: %s\n", ex.what()); + printf("stack trace: %s\n", ex.stackTrace()); + } +} diff --git a/muduo/base/tests/SingletonThreadLocal_test.cc b/muduo/base/tests/SingletonThreadLocal_test.cc new file mode 100644 index 000000000..4ccebad8e --- /dev/null +++ b/muduo/base/tests/SingletonThreadLocal_test.cc @@ -0,0 +1,58 @@ +#include +#include +#include + +#include +#include +#include + +class Test : boost::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const std::string& name() const { return name_; } + void setName(const std::string& n) { name_ = n; } + + private: + std::string name_; +}; + +#define STL muduo::Singleton >::instance().value() + +void print() +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &STL, + STL.name().c_str()); +} + +void threadFunc(const char* changeTo) +{ + print(); + STL.setName(changeTo); + sleep(1); + print(); +} + +int main() +{ + STL.setName("main one"); + muduo::Thread t1(boost::bind(threadFunc, "thread1")); + muduo::Thread t2(boost::bind(threadFunc, "thread2")); + t1.start(); + t2.start(); + t1.join(); + print(); + t2.join(); + pthread_exit(0); +} diff --git a/muduo/base/tests/Singleton_test.cc b/muduo/base/tests/Singleton_test.cc new file mode 100644 index 000000000..072f9c29a --- /dev/null +++ b/muduo/base/tests/Singleton_test.cc @@ -0,0 +1,46 @@ +#include +#include + +#include +#include + +class Test : boost::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const std::string& name() const { return name_; } + void setName(const std::string& n) { name_ = n; } + + private: + std::string name_; +}; + +void threadFunc() +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::Singleton::instance(), + muduo::Singleton::instance().name().c_str()); + muduo::Singleton::instance().setName("only one, changed"); +} + +int main() +{ + muduo::Singleton::instance().setName("only one"); + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::Singleton::instance(), + muduo::Singleton::instance().name().c_str()); +} diff --git a/muduo/base/tests/ThreadLocalSingleton_test.cc b/muduo/base/tests/ThreadLocalSingleton_test.cc new file mode 100644 index 000000000..b69ab86ca --- /dev/null +++ b/muduo/base/tests/ThreadLocalSingleton_test.cc @@ -0,0 +1,57 @@ +#include +#include + +#include +#include +#include + +class Test : boost::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const std::string& name() const { return name_; } + void setName(const std::string& n) { name_ = n; } + + private: + std::string name_; +}; + +void threadFunc(const char* changeTo) +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + muduo::ThreadLocalSingleton::instance().setName(changeTo); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + + // manually delete it + muduo::ThreadLocalSingleton::destroy(); +} + +int main() +{ + muduo::ThreadLocalSingleton::instance().setName("main one"); + muduo::Thread t1(boost::bind(threadFunc, "thread1")); + muduo::Thread t2(boost::bind(threadFunc, "thread2")); + t1.start(); + t2.start(); + t1.join(); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + t2.join(); +} diff --git a/muduo/base/tests/ThreadLocal_test.cc b/muduo/base/tests/ThreadLocal_test.cc new file mode 100644 index 000000000..c53032a38 --- /dev/null +++ b/muduo/base/tests/ThreadLocal_test.cc @@ -0,0 +1,61 @@ +#include +#include + +#include +#include + +class Test : boost::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const std::string& name() const { return name_; } + void setName(const std::string& n) { name_ = n; } + + private: + std::string name_; +}; + +muduo::ThreadLocal testObj1; +muduo::ThreadLocal testObj2; + +void print() +{ + printf("tid=%d, obj1 %p name=%s\n", + muduo::CurrentThread::tid(), + &testObj1.value(), + testObj1.value().name().c_str()); + printf("tid=%d, obj2 %p name=%s\n", + muduo::CurrentThread::tid(), + &testObj2.value(), + testObj2.value().name().c_str()); +} + +void threadFunc() +{ + print(); + testObj1.value().setName("changed 1"); + testObj2.value().setName("changed 42"); + print(); +} + +int main() +{ + testObj1.value().setName("main one"); + print(); + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + testObj2.value().setName("main two"); + print(); + + pthread_exit(0); +} diff --git a/muduo/base/tests/ThreadPool_test.cc b/muduo/base/tests/ThreadPool_test.cc new file mode 100644 index 000000000..fc0c2b809 --- /dev/null +++ b/muduo/base/tests/ThreadPool_test.cc @@ -0,0 +1,36 @@ +#include +#include + +#include +#include + +void print() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void printString(const std::string& str) +{ + printf("tid=%d, str=%s\n", muduo::CurrentThread::tid(), str.c_str()); +} + +int main() +{ + muduo::ThreadPool pool("MainThreadPool"); + pool.start(5); + + pool.run(print); + pool.run(print); + for (int i = 0; i < 100; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "task %d", i); + pool.run(boost::bind(printString, std::string(buf))); + } + + muduo::CountDownLatch latch(1); + pool.run(boost::bind(&muduo::CountDownLatch::countDown, &latch)); + latch.wait(); + pool.stop(); +} + diff --git a/muduo/base/tests/Thread_test.cc b/muduo/base/tests/Thread_test.cc new file mode 100644 index 000000000..0cc202be9 --- /dev/null +++ b/muduo/base/tests/Thread_test.cc @@ -0,0 +1,63 @@ +#include + +#include +#include +#include + +void threadFunc() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void threadFunc2(int x) +{ + printf("tid=%d, x=%d\n", muduo::CurrentThread::tid(), x); +} + +class Foo +{ + public: + explicit Foo(double x) + : x_(x) + { + } + + void memberFunc() + { + printf("tid=%d, Foo::x_=%f\n", muduo::CurrentThread::tid(), x_); + } + + void memberFunc2(const std::string& text) + { + printf("tid=%d, Foo::x_=%f, text=%s\n", muduo::CurrentThread::tid(), x_, text.c_str()); + } + + private: + double x_; +}; + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + + muduo::Thread t2(boost::bind(threadFunc2, 42), + "thread for free function with argument"); + t2.start(); + t2.join(); + + Foo foo(87.53); + muduo::Thread t3(boost::bind(&Foo::memberFunc, &foo), + "thread for member function without argument"); + t3.start(); + t3.join(); + + muduo::Thread t4(boost::bind(&Foo::memberFunc2, boost::ref(foo), std::string("Shuo Chen"))); + t4.start(); + t4.join(); + + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 743bcbb9a..6d0eb2de5 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -51,6 +51,8 @@ class IgnoreSigPipe } }; #pragma GCC diagnostic error "-Wold-style-cast" + +IgnoreSigPipe initObj; } EventLoop::EventLoop() @@ -63,7 +65,6 @@ EventLoop::EventLoop() wakeupFd_(createEventfd()), wakeupChannel_(new Channel(this, wakeupFd_)) { - Singleton::instance(); LOG_TRACE << "EventLoop created " << this << " in thread " << threadId_; if (t_loopInThisThread) { diff --git a/muduo/net/tests/CMakeLists.txt b/muduo/net/tests/CMakeLists.txt index cdaf193bb..1896353ea 100644 --- a/muduo/net/tests/CMakeLists.txt +++ b/muduo/net/tests/CMakeLists.txt @@ -7,8 +7,8 @@ target_link_libraries(echoclient_unittest muduo_net) add_executable(eventloop_unittest EventLoop_unittest.cc) target_link_libraries(eventloop_unittest muduo_net) -add_executable(threadpool_unittest ThreadPool_unittest.cc) -target_link_libraries(threadpool_unittest muduo_net) +add_executable(eventloopthreadpool_unittest EventLoopThreadPool_unittest.cc) +target_link_libraries(eventloopthreadpool_unittest muduo_net) add_executable(timerqueue_unittest TimerQueue_unittest.cc) target_link_libraries(timerqueue_unittest muduo_net) diff --git a/muduo/net/tests/ThreadPool_unittest.cc b/muduo/net/tests/EventLoopThreadPool_unittest.cc similarity index 100% rename from muduo/net/tests/ThreadPool_unittest.cc rename to muduo/net/tests/EventLoopThreadPool_unittest.cc From 2162db288f56a3746f3666de65d91d76414fef89 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 28 Aug 2010 11:39:31 +0800 Subject: [PATCH 090/371] Remove TimeZone for now --- muduo/base/CMakeLists.txt | 1 - muduo/base/TimeZone.cc | 45 --------------------------- muduo/base/TimeZone.h | 29 ----------------- muduo/base/tests/CMakeLists.txt | 3 -- muduo/base/tests/TimeZone_unittest.cc | 10 ------ 5 files changed, 88 deletions(-) delete mode 100644 muduo/base/TimeZone.cc delete mode 100644 muduo/base/TimeZone.h delete mode 100644 muduo/base/tests/TimeZone_unittest.cc diff --git a/muduo/base/CMakeLists.txt b/muduo/base/CMakeLists.txt index 8f1a8eb6e..64a41c2aa 100644 --- a/muduo/base/CMakeLists.txt +++ b/muduo/base/CMakeLists.txt @@ -5,7 +5,6 @@ set(base_SRCS Logging.cc ProcessInfo.cc Timestamp.cc - TimeZone.cc Thread.cc ThreadPool.cc ) diff --git a/muduo/base/TimeZone.cc b/muduo/base/TimeZone.cc deleted file mode 100644 index 8d9465854..000000000 --- a/muduo/base/TimeZone.cc +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include - -namespace -{ - -struct Transition -{ -}; - -struct Localtime -{ -}; - -} - -using namespace muduo; -using namespace std; - -struct TimeZone::Data -{ - vector transitions_; - vector localtimes_; - vector names_; -}; - -namespace -{ -bool readTimeZoneFile(const char* zonefile, struct TimeZone::Data* data) -{ - return true; -} -} - - -TimeZone::TimeZone(const char* zonefile) - : data_(new TimeZone::Data) -{ - if (!readTimeZoneFile(zonefile, data_.get())) - { - data_.reset(); - } -} - diff --git a/muduo/base/TimeZone.h b/muduo/base/TimeZone.h deleted file mode 100644 index cdd3959c5..000000000 --- a/muduo/base/TimeZone.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MUDUO_BASE_TIMEZONE_H -#define MUDUO_BASE_TIMEZONE_H - -#include -#include -#include - -namespace muduo -{ - -class TimeZone : public muduo::copyable -{ - public: - explicit TimeZone(const char* zonefile); - - // default copy ctor/assignment/dtor are Okay. - - bool valid() const { return data_; } - struct tm toLocalTime(time_t secondsSinceEpoch) const; - time_t fromLocalTime(const struct tm&) const; - - struct Data; - - private: - boost::shared_ptr data_; -}; - -} -#endif // MUDUO_BASE_TIMEZONE_H diff --git a/muduo/base/tests/CMakeLists.txt b/muduo/base/tests/CMakeLists.txt index ef48a8846..c682d6add 100644 --- a/muduo/base/tests/CMakeLists.txt +++ b/muduo/base/tests/CMakeLists.txt @@ -19,9 +19,6 @@ target_link_libraries(singleton_threadlocal_test muduo_base) add_executable(timestamp_unittest Timestamp_unittest.cc) target_link_libraries(timestamp_unittest muduo_base) -add_executable(timezone_unittest TimeZone_unittest.cc) -target_link_libraries(timezone_unittest muduo_base) - add_executable(thread_test Thread_test.cc) target_link_libraries(thread_test muduo_base) diff --git a/muduo/base/tests/TimeZone_unittest.cc b/muduo/base/tests/TimeZone_unittest.cc deleted file mode 100644 index 7d544f5c7..000000000 --- a/muduo/base/tests/TimeZone_unittest.cc +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -using muduo::TimeZone; - -int main() -{ - TimeZone tz("/etc/localtime"); -} - From 058231bd8c08007fded2f1af99bf313153c63708 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 28 Aug 2010 12:37:56 +0800 Subject: [PATCH 091/371] remove unused members of Timestamp class. add swap() to Date. --- muduo/base/Date.h | 7 +++++-- muduo/base/Timestamp.h | 24 ++++++------------------ muduo/net/TimerQueue.cc | 8 ++++---- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/muduo/base/Date.h b/muduo/base/Date.h index cb393b123..e814205eb 100644 --- a/muduo/base/Date.h +++ b/muduo/base/Date.h @@ -51,7 +51,6 @@ class Date : public muduo::copyable /// /// Constucts a Date from Julian Day Number. /// - /// 1 <= month <= 12 explicit Date(int julianDayNum) : julianDayNumber_(julianDayNum) {} @@ -59,11 +58,15 @@ class Date : public muduo::copyable /// /// Constucts a Date from struct tm /// - /// 1 <= month <= 12 explicit Date(const struct tm&); // default copy/assignment/dtor are Okay + void swap(Date& that) + { + std::swap(julianDayNumber_, that.julianDayNumber_); + } + bool valid() const { return julianDayNumber_ > 0; } /// diff --git a/muduo/base/Timestamp.h b/muduo/base/Timestamp.h index 517f4d5ea..1aa752596 100644 --- a/muduo/base/Timestamp.h +++ b/muduo/base/Timestamp.h @@ -4,6 +4,8 @@ #include #include +#include + namespace muduo { @@ -13,7 +15,8 @@ namespace muduo /// This class is immutable. /// It's recommended to pass it by value, since it's passed in register on x64. /// -class Timestamp : public muduo::copyable +class Timestamp : public muduo::copyable, + public boost::less_than_comparable { public: /// @@ -39,21 +42,6 @@ class Timestamp : public muduo::copyable bool valid() const { return microSecondsSinceEpoch_ > 0; } - bool before(Timestamp rhs) const - { - return microSecondsSinceEpoch_ < rhs.microSecondsSinceEpoch_; - } - - bool after(Timestamp rhs) const - { - return microSecondsSinceEpoch_ > rhs.microSecondsSinceEpoch_; - } - - bool equals(Timestamp rhs) const - { - return microSecondsSinceEpoch_ == rhs.microSecondsSinceEpoch_; - } - // for internal usage. int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; } @@ -71,12 +59,12 @@ class Timestamp : public muduo::copyable inline bool operator<(Timestamp lhs, Timestamp rhs) { - return lhs.before(rhs); + return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch(); } inline bool operator==(Timestamp lhs, Timestamp rhs) { - return lhs.equals(rhs); + return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch(); } /// diff --git a/muduo/net/TimerQueue.cc b/muduo/net/TimerQueue.cc index 23e167b52..66e78e3ed 100644 --- a/muduo/net/TimerQueue.cc +++ b/muduo/net/TimerQueue.cc @@ -110,11 +110,11 @@ void TimerQueue::handleRead() MutexLockGuard lock(mutex_); // shall never callback in critical section TimerList::iterator it = timers_.begin(); - while (it != timers_.end() && !(*it)->expiration().after(now)) + while (it != timers_.end() && (*it)->expiration() <= now) { ++it; } - assert(it == timers_.end() || (*it)->expiration().after(now)); + assert(it == timers_.end() || (*it)->expiration() > now); expired.splice(expired.begin(), timers_, timers_.begin(), it); } @@ -181,14 +181,14 @@ bool TimerQueue::insertWithLockHold(Timer* timer) bool earliestChanged = false; Timestamp when = timer->expiration(); TimerList::iterator it = timers_.begin(); - if (it == timers_.end() || (*it)->expiration().after(when)) + if (it == timers_.end() || (*it)->expiration() > when) { timers_.push_front(timer); earliestChanged = true; } else { - while (it != timers_.end() && (*it)->expiration().before(when)) + while (it != timers_.end() && (*it)->expiration() < when) { ++it; } From f1c778c8ae2dce4e0a9878bbc99110170f206b97 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 28 Aug 2010 19:26:44 +0800 Subject: [PATCH 092/371] Fix warnings --- CMakeLists.txt | 4 ++-- examples/CMakeLists.txt | 1 - examples/hub/hub.cc | 5 +++-- examples/hub/pub.cc | 2 +- examples/hub/sub.cc | 7 +++++++ examples/netty/uptime/uptime.cc | 3 ++- examples/paxos/CMakeLists.txt | 6 ------ examples/paxos/lobby.cc | 0 examples/paxos/paxos.cc | 0 examples/paxos/paxos.h | 0 muduo/base/Logging.cc | 2 ++ 11 files changed, 17 insertions(+), 13 deletions(-) delete mode 100644 examples/paxos/CMakeLists.txt delete mode 100644 examples/paxos/lobby.cc delete mode 100644 examples/paxos/paxos.cc delete mode 100644 examples/paxos/paxos.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7318ac84b..b1945216e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,9 +9,9 @@ set(CXX_FLAGS -Wall -Wextra # -m32 - # -Werror + -Werror -Wconversion - -Wunused-parameter + -Wno-unused-parameter -Wold-style-cast -Woverloaded-virtual -Wpointer-arith diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e9ae25df8..b7faa7f85 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,7 +1,6 @@ add_subdirectory(simple) add_subdirectory(roundtrip) add_subdirectory(hub) -add_subdirectory(paxos) add_subdirectory(asio/tutorial) add_subdirectory(asio/chat) diff --git a/examples/hub/hub.cc b/examples/hub/hub.cc index 1bfb6e98e..b0e125ca9 100644 --- a/examples/hub/hub.cc +++ b/examples/hub/hub.cc @@ -223,6 +223,7 @@ class PubSubServer : boost::noncopyable const string& content, Timestamp time) { + (void)source; getTopic(topic).publish(content, time); } @@ -247,11 +248,11 @@ int main(int argc, char* argv[]) { if (argc > 1) { - int port = atoi(argv[1]); + uint16_t port = static_cast(atoi(argv[1])); EventLoop loop; if (argc > 2) { - int inspectPort = atoi(argv[2]); + //int inspectPort = atoi(argv[2]); } pubsub::PubSubServer server(&loop, InetAddress(port)); server.start(); diff --git a/examples/hub/pub.cc b/examples/hub/pub.cc index 689242dae..699eb35a4 100644 --- a/examples/hub/pub.cc +++ b/examples/hub/pub.cc @@ -34,7 +34,7 @@ int main(int argc, char* argv[]) if (colon != string::npos) { string hostip = hostport.substr(0, colon); - uint16_t port = atoi(hostport.c_str()+colon+1); + uint16_t port = static_cast(atoi(hostport.c_str()+colon+1)); g_topic = argv[2]; g_content = argv[3]; diff --git a/examples/hub/sub.cc b/examples/hub/sub.cc index 9fec59b39..36fa6439b 100644 --- a/examples/hub/sub.cc +++ b/examples/hub/sub.cc @@ -1,4 +1,11 @@ +#include int main(int argc, char* argv[]) { + if (argc > 1) + { + } + else + { + } } diff --git a/examples/netty/uptime/uptime.cc b/examples/netty/uptime/uptime.cc index 8016f0865..bb18b1317 100644 --- a/examples/netty/uptime/uptime.cc +++ b/examples/netty/uptime/uptime.cc @@ -57,7 +57,8 @@ int main(int argc, char* argv[]) if (argc > 2) { EventLoop loop; - InetAddress serverAddr(argv[1], atoi(argv[2])); + uint16_t port = static_cast(atoi(argv[2])); + InetAddress serverAddr(argv[1], port); UptimeClient client(&loop, serverAddr); client.connect(); diff --git a/examples/paxos/CMakeLists.txt b/examples/paxos/CMakeLists.txt deleted file mode 100644 index 367de7394..000000000 --- a/examples/paxos/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -add_library(muduo_paxos paxos.cc) -target_link_libraries(muduo_paxos muduo_inspect) - -add_library(muduo_lobby lobby.cc) -target_link_libraries(muduo_lobby muduo_inspect) - diff --git a/examples/paxos/lobby.cc b/examples/paxos/lobby.cc deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/paxos/paxos.cc b/examples/paxos/paxos.cc deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/paxos/paxos.h b/examples/paxos/paxos.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/muduo/base/Logging.cc b/muduo/base/Logging.cc index c131a5504..0727909d8 100644 --- a/muduo/base/Logging.cc +++ b/muduo/base/Logging.cc @@ -118,6 +118,8 @@ Logger::~Logger() impl_->finish(); std::string buf(impl_->stream_.str()); ssize_t n = ::write(1, buf.data(), buf.size()); + //FIXME check n + (void)n; if (impl_->level_ == FATAL) { abort(); From 96cdb14e9c72ee681858b77b8f22880520c58408 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 28 Aug 2010 23:01:00 +0800 Subject: [PATCH 093/371] new simple chargen server --- examples/netty/discard/server.cc | 3 +- examples/simple/CMakeLists.txt | 23 ++++---- examples/simple/allinone/allinone.cc | 4 ++ examples/simple/chargen/chargen.cc | 79 ++++++++++++++++++++++++++++ examples/simple/chargen/chargen.h | 34 ++++++++++++ examples/simple/chargen/main.cc | 18 +++++++ examples/simple/daytime/daytime.cc | 8 +-- examples/simple/discard/discard.cc | 8 +-- examples/simple/discard/discard.h | 1 + examples/simple/echo/echo.h | 1 + examples/simple/time/time.cc | 8 +-- 11 files changed, 165 insertions(+), 22 deletions(-) create mode 100644 examples/simple/chargen/chargen.cc create mode 100644 examples/simple/chargen/chargen.h create mode 100644 examples/simple/chargen/main.cc diff --git a/examples/netty/discard/server.cc b/examples/netty/discard/server.cc index 565aa630e..5fddf709c 100644 --- a/examples/netty/discard/server.cc +++ b/examples/netty/discard/server.cc @@ -53,7 +53,7 @@ class DiscardServer void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp) { size_t len = buf->readableBytes(); - transferred_.addAndGet(len); + transferred_.add(len); receivedMessages_.incrementAndGet(); buf->retrieveAll(); } @@ -76,6 +76,7 @@ class DiscardServer EventLoop* loop_; TcpServer server_; + AtomicInt64 transferred_; AtomicInt64 receivedMessages_; int64_t oldCounter_; diff --git a/examples/simple/CMakeLists.txt b/examples/simple/CMakeLists.txt index 2bfa8518c..9583ae52d 100644 --- a/examples/simple/CMakeLists.txt +++ b/examples/simple/CMakeLists.txt @@ -1,21 +1,26 @@ -add_executable(simple_discard discard/discard.cc discard/main.cc) -target_link_libraries(simple_discard muduo_net) +add_executable(simple_chargen chargen/chargen.cc chargen/main.cc) +target_link_libraries(simple_chargen muduo_net) add_executable(simple_daytime daytime/daytime.cc daytime/main.cc) target_link_libraries(simple_daytime muduo_net) -add_executable(simple_time time/time.cc time/main.cc) -target_link_libraries(simple_time muduo_net) +add_executable(simple_discard discard/discard.cc discard/main.cc) +target_link_libraries(simple_discard muduo_net) add_executable(simple_echo echo/echo.cc echo/main.cc) target_link_libraries(simple_echo muduo_net) +add_executable(simple_time time/time.cc time/main.cc) +target_link_libraries(simple_time muduo_net) + add_executable(simple_allinone - discard/discard.cc - daytime/daytime.cc - time/time.cc - echo/echo.cc - allinone/allinone.cc) + allinone/allinone.cc + chargen/chargen.cc + daytime/daytime.cc + discard/discard.cc + echo/echo.cc + time/time.cc + ) target_link_libraries(simple_allinone muduo_net) add_executable(simple_timeclient timeclient/timeclient.cc) diff --git a/examples/simple/allinone/allinone.cc b/examples/simple/allinone/allinone.cc index 9f72fcd48..8157eadb6 100644 --- a/examples/simple/allinone/allinone.cc +++ b/examples/simple/allinone/allinone.cc @@ -1,3 +1,4 @@ +#include "../chargen/chargen.h" #include "../daytime/daytime.h" #include "../discard/discard.h" #include "../echo/echo.h" @@ -16,6 +17,9 @@ int main() LOG_INFO << "pid = " << getpid(); EventLoop loop; + ChargenServer ChargenServer(&loop, InetAddress(2019)); + ChargenServer.start(); + DaytimeServer daytimeServer(&loop, InetAddress(2013)); daytimeServer.start(); diff --git a/examples/simple/chargen/chargen.cc b/examples/simple/chargen/chargen.cc new file mode 100644 index 000000000..18eb01757 --- /dev/null +++ b/examples/simple/chargen/chargen.cc @@ -0,0 +1,79 @@ +#include "chargen.h" + +#include +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +ChargenServer::ChargenServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr, + bool print) + : loop_(loop), + server_(loop, listenAddr, "ChargenServer"), + transferred_(0), + startTime_(Timestamp::now()) +{ + server_.setConnectionCallback( + boost::bind(&ChargenServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&ChargenServer::onMessage, this, _1, _2, _3)); + server_.setWriteCompleteCallback( + boost::bind(&ChargenServer::onWriteComplete, this, _1)); + if (print) + { + loop->runEvery(3.0, boost::bind(&ChargenServer::printThroughput, this)); + } + + string line; + for (int i = 33; i < 127; ++i) + { + line.push_back(char(i)); + } + line += line; + + for (size_t i = 0; i < 127-33; ++i) + { + message_ += line.substr(i, 72) + '\n'; + } +} + +void ChargenServer::start() +{ + server_.start(); +} + +void ChargenServer::onConnection(const muduo::net::TcpConnectionPtr& conn) +{ + LOG_INFO << "ChargenServer - " << conn->peerAddress().toHostPort() << " -> " + << conn->localAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + conn->send(message_); +} + +void ChargenServer::onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time) +{ + string msg(buf->retrieveAsString()); + LOG_INFO << conn->name() << " discards " << msg.size() << " bytes at " << time.toString(); +} + +void ChargenServer::onWriteComplete(const TcpConnectionPtr& conn) +{ + transferred_ += message_.size(); + conn->send(message_); +} + +void ChargenServer::printThroughput() +{ + Timestamp endTime = Timestamp::now(); + double time = timeDifference(endTime, startTime_); + printf("%4.3f MiB/s\n", static_cast(transferred_)/time/1024/1024); + transferred_ = 0; + startTime_ = endTime; +} + diff --git a/examples/simple/chargen/chargen.h b/examples/simple/chargen/chargen.h new file mode 100644 index 000000000..6abcefd39 --- /dev/null +++ b/examples/simple/chargen/chargen.h @@ -0,0 +1,34 @@ +#ifndef MUDUO_EXAMPLES_SIMPLE_CHARGEN_CHARGEN_H +#define MUDUO_EXAMPLES_SIMPLE_CHARGEN_CHARGEN_H + +#include + +// RFC 864 +class ChargenServer +{ + public: + ChargenServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr, + bool print = false); + + void start(); + + private: + void onConnection(const muduo::net::TcpConnectionPtr& conn); + + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time); + + void onWriteComplete(const muduo::net::TcpConnectionPtr& conn); + void printThroughput(); + + muduo::net::EventLoop* loop_; + muduo::net::TcpServer server_; + + muduo::string message_; + int64_t transferred_; + muduo::Timestamp startTime_; +}; + +#endif // MUDUO_EXAMPLES_SIMPLE_CHARGEN_CHARGEN_H diff --git a/examples/simple/chargen/main.cc b/examples/simple/chargen/main.cc new file mode 100644 index 000000000..82f3dc094 --- /dev/null +++ b/examples/simple/chargen/main.cc @@ -0,0 +1,18 @@ +#include "chargen.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + LOG_INFO << "pid = " << getpid(); + EventLoop loop; + InetAddress listenAddr(2019); + ChargenServer server(&loop, listenAddr, true); + server.start(); + loop.loop(); +} + diff --git a/examples/simple/daytime/daytime.cc b/examples/simple/daytime/daytime.cc index 80387a225..b776ae8db 100644 --- a/examples/simple/daytime/daytime.cc +++ b/examples/simple/daytime/daytime.cc @@ -13,10 +13,10 @@ DaytimeServer::DaytimeServer(muduo::net::EventLoop* loop, : loop_(loop), server_(loop, listenAddr, "DaytimeServer") { - server_.setConnectionCallback( - boost::bind(&DaytimeServer::onConnection, this, _1)); - server_.setMessageCallback( - boost::bind(&DaytimeServer::onMessage, this, _1, _2, _3)); + server_.setConnectionCallback( + boost::bind(&DaytimeServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&DaytimeServer::onMessage, this, _1, _2, _3)); } void DaytimeServer::start() diff --git a/examples/simple/discard/discard.cc b/examples/simple/discard/discard.cc index 427d1c0c0..cc19ae76a 100644 --- a/examples/simple/discard/discard.cc +++ b/examples/simple/discard/discard.cc @@ -12,10 +12,10 @@ DiscardServer::DiscardServer(muduo::net::EventLoop* loop, : loop_(loop), server_(loop, listenAddr, "DiscardServer") { - server_.setConnectionCallback( - boost::bind(&DiscardServer::onConnection, this, _1)); - server_.setMessageCallback( - boost::bind(&DiscardServer::onMessage, this, _1, _2, _3)); + server_.setConnectionCallback( + boost::bind(&DiscardServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&DiscardServer::onMessage, this, _1, _2, _3)); } void DiscardServer::start() diff --git a/examples/simple/discard/discard.h b/examples/simple/discard/discard.h index 45f78d348..fd1d61315 100644 --- a/examples/simple/discard/discard.h +++ b/examples/simple/discard/discard.h @@ -3,6 +3,7 @@ #include +// RFC 863 class DiscardServer { public: diff --git a/examples/simple/echo/echo.h b/examples/simple/echo/echo.h index f10aee89e..db2cbee02 100644 --- a/examples/simple/echo/echo.h +++ b/examples/simple/echo/echo.h @@ -3,6 +3,7 @@ #include +// RFC 862 class EchoServer { public: diff --git a/examples/simple/time/time.cc b/examples/simple/time/time.cc index 6bf124baa..0ff8773b6 100644 --- a/examples/simple/time/time.cc +++ b/examples/simple/time/time.cc @@ -13,10 +13,10 @@ TimeServer::TimeServer(muduo::net::EventLoop* loop, : loop_(loop), server_(loop, listenAddr, "TimeServer") { - server_.setConnectionCallback( - boost::bind(&TimeServer::onConnection, this, _1)); - server_.setMessageCallback( - boost::bind(&TimeServer::onMessage, this, _1, _2, _3)); + server_.setConnectionCallback( + boost::bind(&TimeServer::onConnection, this, _1)); + server_.setMessageCallback( + boost::bind(&TimeServer::onMessage, this, _1, _2, _3)); } void TimeServer::start() From 0b81baa0d33df49e82bb8c786e921ab0216f8e38 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 28 Aug 2010 23:02:01 +0800 Subject: [PATCH 094/371] fix queueInLoop for writeCompleteCallback --- muduo/base/Atomic.h | 5 +++++ muduo/net/EventLoop.cc | 34 ++++++++++++++++++++-------------- muduo/net/EventLoop.h | 12 ++++++++---- muduo/net/TcpConnection.cc | 3 ++- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/muduo/base/Atomic.h b/muduo/base/Atomic.h index f774c1a1c..d52d8625c 100644 --- a/muduo/base/Atomic.h +++ b/muduo/base/Atomic.h @@ -55,6 +55,11 @@ class AtomicIntegerT : boost::noncopyable return addAndGet(1); } + void add(T x) + { + getAndAdd(x); + } + void increment() { incrementAndGet(); diff --git a/muduo/net/EventLoop.cc b/muduo/net/EventLoop.cc index 6d0eb2de5..5f880f045 100644 --- a/muduo/net/EventLoop.cc +++ b/muduo/net/EventLoop.cc @@ -59,6 +59,7 @@ EventLoop::EventLoop() : looping_(false), quit_(false), eventHandling_(false), + callingPendingFunctors_(false), threadId_(CurrentThread::tid()), poller_(Poller::newDefaultPoller(this)), timerQueue_(new TimerQueue(this)), @@ -96,7 +97,7 @@ void EventLoop::loop() while (!quit_) { activeChannels_.clear(); - happenTime_ = poller_->poll(kPollTimeMs, &activeChannels_); + pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_); if (Logger::logLevel() <= Logger::TRACE) { printActiveChannels(); @@ -106,7 +107,7 @@ void EventLoop::loop() for (ChannelList::iterator it = activeChannels_.begin(); it != activeChannels_.end(); ++it) { - (*it)->handleEvent(happenTime_); + (*it)->handleEvent(pollReturnTime_); } eventHandling_ = false; doPendingFunctors(); @@ -149,8 +150,15 @@ void EventLoop::runInLoop(const Functor& cb) void EventLoop::queueInLoop(const Functor& cb) { + { MutexLockGuard lock(mutex_); pendingFunctors_.push_back(cb); + } + + if (isInLoopThread() && callingPendingFunctors_) + { + wakeup(); + } } TimerId EventLoop::runAt(const Timestamp& time, const TimerCallback& cb) @@ -202,20 +210,18 @@ void EventLoop::handleRead() void EventLoop::doPendingFunctors() { std::vector functors; - do - { - functors.clear(); + callingPendingFunctors_ = true; - { - MutexLockGuard lock(mutex_); - functors.swap(pendingFunctors_); - } + { + MutexLockGuard lock(mutex_); + functors.swap(pendingFunctors_); + } - for (size_t i = 0; i < functors.size(); ++i) - { - functors[i](); - } - } while (!functors.empty()); + for (size_t i = 0; i < functors.size(); ++i) + { + functors[i](); + } + callingPendingFunctors_ = false; } void EventLoop::printActiveChannels() const diff --git a/muduo/net/EventLoop.h b/muduo/net/EventLoop.h index 3c3eb9f17..0e5144080 100644 --- a/muduo/net/EventLoop.h +++ b/muduo/net/EventLoop.h @@ -53,9 +53,10 @@ class EventLoop : boost::noncopyable void quit(); + /// /// Time when poll returns, usually means data arrivial. /// - Timestamp receiveTime(); + Timestamp pollReturnTime() const { return pollReturnTime_; } // timers @@ -82,11 +83,12 @@ class EventLoop : boost::noncopyable /// Safe to call from other threads. // void cancel(TimerId timerId); + // internal usage void wakeup(); void updateChannel(Channel* channel); void removeChannel(Channel* channel); - pid_t threadId() { return threadId_; } + pid_t threadId() const { return threadId_; } void assertInLoopThread() { if (!isInLoopThread()) @@ -94,7 +96,8 @@ class EventLoop : boost::noncopyable abortNotInLoopThread(); } } - bool isInLoopThread() { return threadId_ == CurrentThread::tid(); } + bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); } + // bool callingPendingFunctors() const { return callingPendingFunctors_; } private: void abortNotInLoopThread(); @@ -108,7 +111,8 @@ class EventLoop : boost::noncopyable bool looping_; /* atomic */ bool quit_; /* atomic */ bool eventHandling_; /* atomic */ - Timestamp happenTime_; + bool callingPendingFunctors_; /* atomic */ + Timestamp pollReturnTime_; const pid_t threadId_; boost::scoped_ptr poller_; boost::scoped_ptr timerQueue_; diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index ab36c7cd0..7817a1ecb 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -99,7 +99,7 @@ void TcpConnection::send(const StringPiece& message) loop_->runInLoop( boost::bind(&TcpConnection::sendInLoop, this, - message)); + message.as_string())); //std::forward(message))); } } @@ -135,6 +135,7 @@ void TcpConnection::sendInLoop(const void* data, size_t len) { loop_->assertInLoopThread(); ssize_t nwrote = 0; + // if no thing in output queue, try writing directly if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0) { nwrote = ::write(channel_->fd(), data, len); From fe8666eea3cb778412d200881c2e50c52cb35dc3 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 29 Aug 2010 00:17:06 +0800 Subject: [PATCH 095/371] add twisted finger examples --- examples/CMakeLists.txt | 2 ++ examples/twisted/finger/CMakeLists.txt | 21 ++++++++++++ examples/twisted/finger/finger01.cc | 10 ++++++ examples/twisted/finger/finger02.cc | 13 ++++++++ examples/twisted/finger/finger03.cc | 22 +++++++++++++ examples/twisted/finger/finger04.cc | 24 ++++++++++++++ examples/twisted/finger/finger05.cc | 25 ++++++++++++++ examples/twisted/finger/finger06.cc | 44 +++++++++++++++++++++++++ examples/twisted/finger/finger07.cc | 45 ++++++++++++++++++++++++++ 9 files changed, 206 insertions(+) create mode 100644 examples/twisted/finger/CMakeLists.txt create mode 100644 examples/twisted/finger/finger01.cc create mode 100644 examples/twisted/finger/finger02.cc create mode 100644 examples/twisted/finger/finger03.cc create mode 100644 examples/twisted/finger/finger04.cc create mode 100644 examples/twisted/finger/finger05.cc create mode 100644 examples/twisted/finger/finger06.cc create mode 100644 examples/twisted/finger/finger07.cc diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b7faa7f85..2103a7112 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,3 +8,5 @@ add_subdirectory(asio/chat) add_subdirectory(netty/discard) add_subdirectory(netty/echo) add_subdirectory(netty/uptime) + +add_subdirectory(twisted/finger) diff --git a/examples/twisted/finger/CMakeLists.txt b/examples/twisted/finger/CMakeLists.txt new file mode 100644 index 000000000..aeb82bbba --- /dev/null +++ b/examples/twisted/finger/CMakeLists.txt @@ -0,0 +1,21 @@ +add_executable(twisted_finger01 finger01.cc) +target_link_libraries(twisted_finger01 muduo_net) + +add_executable(twisted_finger02 finger02.cc) +target_link_libraries(twisted_finger02 muduo_net) + +add_executable(twisted_finger03 finger03.cc) +target_link_libraries(twisted_finger03 muduo_net) + +add_executable(twisted_finger04 finger04.cc) +target_link_libraries(twisted_finger04 muduo_net) + +add_executable(twisted_finger05 finger05.cc) +target_link_libraries(twisted_finger05 muduo_net) + +add_executable(twisted_finger06 finger06.cc) +target_link_libraries(twisted_finger06 muduo_net) + +add_executable(twisted_finger07 finger07.cc) +target_link_libraries(twisted_finger07 muduo_net) + diff --git a/examples/twisted/finger/finger01.cc b/examples/twisted/finger/finger01.cc new file mode 100644 index 000000000..989fa2cfe --- /dev/null +++ b/examples/twisted/finger/finger01.cc @@ -0,0 +1,10 @@ +#include + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + EventLoop loop; + loop.loop(); +} diff --git a/examples/twisted/finger/finger02.cc b/examples/twisted/finger/finger02.cc new file mode 100644 index 000000000..ab7107346 --- /dev/null +++ b/examples/twisted/finger/finger02.cc @@ -0,0 +1,13 @@ +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + EventLoop loop; + TcpServer server(&loop, InetAddress(1079), "Finger"); + server.start(); + loop.loop(); +} diff --git a/examples/twisted/finger/finger03.cc b/examples/twisted/finger/finger03.cc new file mode 100644 index 000000000..5a4ea6a59 --- /dev/null +++ b/examples/twisted/finger/finger03.cc @@ -0,0 +1,22 @@ +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void onConnection(const TcpConnectionPtr& conn) +{ + if (conn->connected()) + { + conn->shutdown(); + } +} + +int main() +{ + EventLoop loop; + TcpServer server(&loop, InetAddress(1079), "Finger"); + server.setConnectionCallback(onConnection); + server.start(); + loop.loop(); +} diff --git a/examples/twisted/finger/finger04.cc b/examples/twisted/finger/finger04.cc new file mode 100644 index 000000000..28195408f --- /dev/null +++ b/examples/twisted/finger/finger04.cc @@ -0,0 +1,24 @@ +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + if (buf->findCRLF()) + { + conn->shutdown(); + } +} + +int main() +{ + EventLoop loop; + TcpServer server(&loop, InetAddress(1079), "Finger"); + server.setMessageCallback(onMessage); + server.start(); + loop.loop(); +} diff --git a/examples/twisted/finger/finger05.cc b/examples/twisted/finger/finger05.cc new file mode 100644 index 000000000..8558260c7 --- /dev/null +++ b/examples/twisted/finger/finger05.cc @@ -0,0 +1,25 @@ +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + if (buf->findCRLF()) + { + conn->send("No such user\r\n"); + conn->shutdown(); + } +} + +int main() +{ + EventLoop loop; + TcpServer server(&loop, InetAddress(1079), "Finger"); + server.setMessageCallback(onMessage); + server.start(); + loop.loop(); +} diff --git a/examples/twisted/finger/finger06.cc b/examples/twisted/finger/finger06.cc new file mode 100644 index 000000000..c0e7e602f --- /dev/null +++ b/examples/twisted/finger/finger06.cc @@ -0,0 +1,44 @@ +#include +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +typedef std::map UserMap; +UserMap users; + +string getUser(const string& user) +{ + string result = "No such user"; + UserMap::iterator it = users.find(user); + if (it != users.end()) + { + result = it->second; + } + return result; +} + +void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + const char* crlf = buf->findCRLF(); + if (crlf) + { + string user(buf->peek(), crlf); + conn->send(getUser(user) + "\r\n"); + buf->retrieveUntil(crlf + 2); + conn->shutdown(); + } +} + +int main() +{ + EventLoop loop; + TcpServer server(&loop, InetAddress(1079), "Finger"); + server.setMessageCallback(onMessage); + server.start(); + loop.loop(); +} diff --git a/examples/twisted/finger/finger07.cc b/examples/twisted/finger/finger07.cc new file mode 100644 index 000000000..ea5bae52d --- /dev/null +++ b/examples/twisted/finger/finger07.cc @@ -0,0 +1,45 @@ +#include +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +typedef std::map UserMap; +UserMap users; + +string getUser(const string& user) +{ + string result = "No such user"; + UserMap::iterator it = users.find(user); + if (it != users.end()) + { + result = it->second; + } + return result; +} + +void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + const char* crlf = buf->findCRLF(); + if (crlf) + { + string user(buf->peek(), crlf); + conn->send(getUser(user) + "\r\n"); + buf->retrieveUntil(crlf + 2); + conn->shutdown(); + } +} + +int main() +{ + users["schen"] = "Happy and well"; + EventLoop loop; + TcpServer server(&loop, InetAddress(1079), "Finger"); + server.setMessageCallback(onMessage); + server.start(); + loop.loop(); +} From cbfce80d9b2170087761a4befd319a8423a46d7e Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 29 Aug 2010 11:48:23 +0800 Subject: [PATCH 096/371] sub works --- examples/hub/CMakeLists.txt | 4 +- examples/hub/codec.cc | 43 +++++++++++++-- examples/hub/codec.h | 25 ++++----- examples/hub/hub.cc | 102 ++++++++++-------------------------- examples/hub/pub.cc | 36 ++++++++++--- examples/hub/pubsub.cc | 62 +++++++++++++++++++--- examples/hub/pubsub.h | 10 +++- examples/hub/sub.cc | 61 ++++++++++++++++++++- 8 files changed, 229 insertions(+), 114 deletions(-) diff --git a/examples/hub/CMakeLists.txt b/examples/hub/CMakeLists.txt index 411957112..19a36f33d 100644 --- a/examples/hub/CMakeLists.txt +++ b/examples/hub/CMakeLists.txt @@ -1,7 +1,7 @@ -add_executable(hub hub.cc) +add_executable(hub hub.cc codec.cc) target_link_libraries(hub muduo_inspect) -add_library(muduo_pubsub pubsub.cc) +add_library(muduo_pubsub pubsub.cc codec.cc) target_link_libraries(muduo_pubsub muduo_inspect) add_executable(pub pub.cc) diff --git a/examples/hub/codec.cc b/examples/hub/codec.cc index 3eca50a58..fc6e8d3d0 100644 --- a/examples/hub/codec.cc +++ b/examples/hub/codec.cc @@ -4,13 +4,50 @@ using namespace muduo; using namespace muduo::net; using namespace pubsub; -void PubSubCodec::onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime) +ParseResult pubsub::parseMessage(Buffer* buf, + string* cmd, + string* topic, + string* content) { + ParseResult result = kError; const char* crlf = buf->findCRLF(); if (crlf) { + const char* space = std::find(buf->peek(), crlf, ' '); + if (space != crlf) + { + cmd->assign(buf->peek(), space); + topic->assign(space+1, crlf); + if (*cmd == "pub") + { + const char* start = crlf + 2; + crlf = buf->findCRLF(start); + if (crlf) + { + content->assign(start, crlf); + buf->retrieveUntil(crlf+2); + result = kSuccess; + } + else + { + result = kContinue; + } + } + else + { + buf->retrieveUntil(crlf+2); + result = kSuccess; + } + } + else + { + result = kError; + } } + else + { + result = kContinue; + } + return result; } diff --git a/examples/hub/codec.h b/examples/hub/codec.h index 839b99a99..e6ba63d8a 100644 --- a/examples/hub/codec.h +++ b/examples/hub/codec.h @@ -4,7 +4,7 @@ // internal header file #include -#include +#include #include @@ -12,24 +12,17 @@ namespace pubsub { using muduo::string; -class PubSubCodec : boost::noncopyable +enum ParseResult { - public: - typedef boost::function SubscribeCallback; - typedef SubscribeCallback UnsubscribeCallback; - typedef boost::function PublishCallback; - - void onMessage(const muduo::net::TcpConnectionPtr& conn, - muduo::net::Buffer* buf, - muduo::Timestamp receiveTime); - - // LoginCallback loginCallback_; - PublishCallback publishCallback_; - SubscribeCallback subscribeCallback_; - UnsubscribeCallback unsubscribeCallback_; + kError, + kSuccess, + kContinue, }; +ParseResult parseMessage(muduo::net::Buffer* buf, + string* cmd, + string* topic, + string* content); } #endif // MUDUO_EXAMPLES_HUB_CODEC_H diff --git a/examples/hub/hub.cc b/examples/hub/hub.cc index b0e125ca9..75e812f19 100644 --- a/examples/hub/hub.cc +++ b/examples/hub/hub.cc @@ -13,60 +13,6 @@ using namespace muduo; using namespace muduo::net; -namespace -{ -enum ParseResult -{ - kError, - kSuccess, - kContinue, -}; - -ParseResult parseMessage(Buffer* buf, string* cmd, string* topic, string* content) -{ - ParseResult result = kError; - const char* crlf = buf->findCRLF(); - if (crlf) - { - const char* space = std::find(buf->peek(), crlf, ' '); - if (space != crlf) - { - cmd->assign(buf->peek(), space); - topic->assign(space+1, crlf); - if (*cmd == "pub") - { - const char* start = crlf + 2; - crlf = buf->findCRLF(start); - if (crlf) - { - content->assign(start, crlf); - buf->retrieveUntil(crlf+2); - result = kSuccess; - } - else - { - result = kContinue; - } - } - else - { - buf->retrieveUntil(crlf+2); - result = kSuccess; - } - } - else - { - result = kError; - } - } - else - { - result = kContinue; - } - return result; -} -} - namespace pubsub { @@ -164,33 +110,39 @@ class PubSubServer : boost::noncopyable Buffer* buf, Timestamp receiveTime) { - string cmd; - string topic; - string content; - ParseResult result = parseMessage(buf, &cmd, &topic, &content); - if (result == kSuccess) + ParseResult result = kSuccess; + while (result == kSuccess) { - if (cmd == "pub") + string cmd; + string topic; + string content; + result = parseMessage(buf, &cmd, &topic, &content); + if (result == kSuccess) { - doPublish(conn->name(), topic, content, receiveTime); - } - else if (cmd == "sub") - { - doSubscribe(conn, topic); - } - else if (cmd == "unsub") - { - doUnsubscribe(conn, topic); + if (cmd == "pub") + { + doPublish(conn->name(), topic, content, receiveTime); + } + else if (cmd == "sub") + { + LOG_INFO << conn->name() << " subscribes " << topic; + doSubscribe(conn, topic); + } + else if (cmd == "unsub") + { + doUnsubscribe(conn, topic); + } + else + { + conn->shutdown(); + result = kError; + } } - else + else if (result == kError) { conn->shutdown(); } } - else if (result == kError) - { - conn->shutdown(); - } } void timePublish() @@ -212,6 +164,7 @@ class PubSubServer : boost::noncopyable void doUnsubscribe(const TcpConnectionPtr& conn, const string& topic) { + LOG_INFO << conn->name() << " unsubscribes " << topic; ConnectionSubscription& connSub = boost::any_cast(conn->getContext()); connSub.erase(topic); @@ -223,7 +176,6 @@ class PubSubServer : boost::noncopyable const string& content, Timestamp time) { - (void)source; getTopic(topic).publish(content, time); } diff --git a/examples/hub/pub.cc b/examples/hub/pub.cc index 699eb35a4..f8013910a 100644 --- a/examples/hub/pub.cc +++ b/examples/hub/pub.cc @@ -1,7 +1,9 @@ #include "pubsub.h" #include #include +#include +#include #include using namespace muduo; @@ -38,14 +40,32 @@ int main(int argc, char* argv[]) g_topic = argv[2]; g_content = argv[3]; - EventLoop loop; - g_loop = &loop; string name = ProcessInfo::username()+"@"+ProcessInfo::hostname(); name += ":" + ProcessInfo::pidString(); - PubSubClient client(&loop, InetAddress(hostip, port), name); - client.setConnectionCallback(connection); - client.start(); - loop.loop(); + + if (g_content == "-") + { + EventLoopThread loopThread; + g_loop = loopThread.startLoop(); + PubSubClient client(g_loop, InetAddress(hostip, port), name); + client.start(); + + string line; + while (getline(std::cin, line)) + { + client.publish(g_topic, line); + } + client.stop(); + } + else + { + EventLoop loop; + g_loop = &loop; + PubSubClient client(g_loop, InetAddress(hostip, port), name); + client.setConnectionCallback(connection); + client.start(); + loop.loop(); + } } else { @@ -54,6 +74,8 @@ int main(int argc, char* argv[]) } else { - printf("Usage: %s hub_ip:port topic content\n", argv[0]); + printf("Usage: %s hub_ip:port topic content\n" + "Read contents from stdin:\n" + " %s hub_ip:port topic -\n", argv[0], argv[0]); } } diff --git a/examples/hub/pubsub.cc b/examples/hub/pubsub.cc index 861cad613..7772a3b38 100644 --- a/examples/hub/pubsub.cc +++ b/examples/hub/pubsub.cc @@ -1,4 +1,5 @@ #include "pubsub.h" +#include "codec.h" #include @@ -15,6 +16,8 @@ PubSubClient::PubSubClient(EventLoop* loop, // FIXME: dtor is not thread safe client_.setConnectionCallback( boost::bind(&PubSubClient::onConnection, this, _1)); + client_.setMessageCallback( + boost::bind(&PubSubClient::onMessage, this, _1, _2, _3)); } void PubSubClient::start() @@ -32,19 +35,27 @@ bool PubSubClient::connected() const return conn_ && conn_->connected(); } +bool PubSubClient::subscribe(const string& topic, const SubscribeCallback& cb) +{ + string message = "sub " + topic + "\r\n"; + subscribeCallback_ = cb; + return send(message); +} + +void PubSubClient::unsubscribe(const string& topic) +{ + string message = "unsub " + topic + "\r\n"; + send(message); +} + + bool PubSubClient::publish(const string& topic, const string& content) { string message = "pub " + topic + "\r\n" + content + "\r\n"; - bool succeed = false; - if (conn_ && conn_->connected()) - { - conn_->send(message); - succeed = true; - } - return succeed; + return send(message); } -void PubSubClient::onConnection(const muduo::net::TcpConnectionPtr& conn) +void PubSubClient::onConnection(const TcpConnectionPtr& conn) { if (conn->connected()) { @@ -61,3 +72,38 @@ void PubSubClient::onConnection(const muduo::net::TcpConnectionPtr& conn) } } +void PubSubClient::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + ParseResult result = kSuccess; + while (result == kSuccess) + { + string cmd; + string topic; + string content; + result = parseMessage(buf, &cmd, &topic, &content); + if (result == kSuccess) + { + if (cmd == "pub" && subscribeCallback_) + { + subscribeCallback_(topic, content, receiveTime); + } + } + else if (result == kError) + { + conn->shutdown(); + } + } +} + +bool PubSubClient::send(const string& message) +{ + bool succeed = false; + if (conn_ && conn_->connected()) + { + conn_->send(message); + succeed = true; + } + return succeed; +} diff --git a/examples/hub/pubsub.h b/examples/hub/pubsub.h index 0d8ef4c71..32d5dc0d1 100644 --- a/examples/hub/pubsub.h +++ b/examples/hub/pubsub.h @@ -13,7 +13,9 @@ class PubSubClient : boost::noncopyable { public: typedef boost::function ConnectionCallback; - typedef boost::function SubscribeCallback; + typedef boost::function SubscribeCallback; PubSubClient(muduo::net::EventLoop* loop, const muduo::net::InetAddress& hubAddr, @@ -25,12 +27,16 @@ class PubSubClient : boost::noncopyable void setConnectionCallback(const ConnectionCallback& cb) { connectionCallback_ = cb; } - void subscribe(const string& topic, const SubscribeCallback& cb); + bool subscribe(const string& topic, const SubscribeCallback& cb); void unsubscribe(const string& topic); bool publish(const string& topic, const string& content); private: void onConnection(const muduo::net::TcpConnectionPtr& conn); + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp receiveTime); + bool send(const string& message); muduo::net::EventLoop* loop_; muduo::net::TcpClient client_; diff --git a/examples/hub/sub.cc b/examples/hub/sub.cc index 36fa6439b..2e8ff6ccb 100644 --- a/examples/hub/sub.cc +++ b/examples/hub/sub.cc @@ -1,11 +1,70 @@ +#include "pubsub.h" +#include +#include + +#include +#include #include +using namespace muduo; +using namespace muduo::net; +using namespace pubsub; + +EventLoop* g_loop = NULL; +std::vector g_topics; + +void subscription(const string& topic, const string& content, Timestamp) +{ + printf("%s: %s\n", topic.c_str(), content.c_str()); +} + +void connection(PubSubClient* client) +{ + if (client->connected()) + { + for (std::vector::iterator it = g_topics.begin(); + it != g_topics.end(); ++it) + { + client->subscribe(*it, subscription); + } + } + else + { + g_loop->quit(); + } +} + int main(int argc, char* argv[]) { - if (argc > 1) + if (argc > 2) { + string hostport = argv[1]; + size_t colon = hostport.find(':'); + if (colon != string::npos) + { + string hostip = hostport.substr(0, colon); + uint16_t port = static_cast(atoi(hostport.c_str()+colon+1)); + for (int i = 2; i < argc; ++i) + { + g_topics.push_back(argv[i]); + } + + EventLoop loop; + g_loop = &loop; + string name = ProcessInfo::username()+"@"+ProcessInfo::hostname(); + name += ":" + ProcessInfo::pidString(); + PubSubClient client(&loop, InetAddress(hostip, port), name); + client.setConnectionCallback(connection); + client.start(); + loop.loop(); + } + else + { + printf("Usage: %s hub_ip:port topic [topic ...]\n", argv[0]); + } } else { + printf("Usage: %s hub_ip:port topic [topic ...]\n", argv[0]); } } From cbbe955373ca0a0ecdeda008312a8a52dca1e7a2 Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sun, 29 Aug 2010 11:54:08 +0800 Subject: [PATCH 097/371] first pre-alpha release --- ChangeLog | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 74632d848..31fb3a792 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,18 @@ -2010-??-?? Shuo Chen +2010-08-30 Shuo Chen - * First alpha release, version 0.1.0 + * First pre-alpha release, version 0.1.0 + +2010-08-29 Shuo Chen + + * Sub works. + +2010-08-28 Shuo Chen + + * Add twisted finger examples. + +2010-08-27 Shuo Chen + + * Add simple chargen example. 2010-08-07 Shuo Chen From 24535daa645f9f87e3d67dcd29102e9415a8bc3a Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 31 Aug 2010 12:18:58 +0800 Subject: [PATCH 098/371] set TCP_NODELAY for roundtrip --- examples/roundtrip/roundtrip.cc | 20 ++++++++++++++++++-- muduo/net/TcpConnection.cc | 5 +++++ muduo/net/TcpConnection.h | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/examples/roundtrip/roundtrip.cc b/examples/roundtrip/roundtrip.cc index 14acddec8..2f1ee048c 100644 --- a/examples/roundtrip/roundtrip.cc +++ b/examples/roundtrip/roundtrip.cc @@ -10,12 +10,26 @@ using namespace muduo::net; const size_t frameLen = 2*sizeof(int64_t); +void serverConnectionCallback(const TcpConnectionPtr& conn) +{ + LOG_TRACE << conn->name() << " " << conn->peerAddress().toHostPort() << " -> " + << conn->localAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + if (conn->connected()) + { + conn->setTcpNoDelay(true); + } + else + { + } +} + void serverMessageCallback(const TcpConnectionPtr& conn, Buffer* buffer, muduo::Timestamp receiveTime) { int64_t message[2]; - if (buffer->readableBytes() >= frameLen) + while (buffer->readableBytes() >= frameLen) { memcpy(message, buffer->peek(), frameLen); buffer->retrieve(frameLen); @@ -28,6 +42,7 @@ void runServer(uint16_t port) { EventLoop loop; TcpServer server(&loop, InetAddress(port), "ClockServer"); + server.setConnectionCallback(serverConnectionCallback); server.setMessageCallback(serverMessageCallback); server.start(); loop.loop(); @@ -43,6 +58,7 @@ void clientConnectionCallback(const TcpConnectionPtr& conn) if (conn->connected()) { clientConnection = conn; + conn->setTcpNoDelay(true); } else { @@ -55,7 +71,7 @@ void clientMessageCallback(const TcpConnectionPtr&, muduo::Timestamp receiveTime) { int64_t message[2]; - if (buffer->readableBytes() >= frameLen) + while (buffer->readableBytes() >= frameLen) { memcpy(message, buffer->peek(), frameLen); buffer->retrieve(frameLen); diff --git a/muduo/net/TcpConnection.cc b/muduo/net/TcpConnection.cc index 7817a1ecb..5cc95299e 100644 --- a/muduo/net/TcpConnection.cc +++ b/muduo/net/TcpConnection.cc @@ -190,6 +190,11 @@ void TcpConnection::shutdownInLoop() } } +void TcpConnection::setTcpNoDelay(bool on) +{ + socket_->setTcpNoDelay(on); +} + void TcpConnection::connectEstablished() { loop_->assertInLoopThread(); diff --git a/muduo/net/TcpConnection.h b/muduo/net/TcpConnection.h index c47b0996b..d06e38a5b 100644 --- a/muduo/net/TcpConnection.h +++ b/muduo/net/TcpConnection.h @@ -63,6 +63,7 @@ class TcpConnection : public boost::enable_shared_from_this, // void send(const Buffer& message); void send(Buffer* message); // this one will swap data void shutdown(); // NOT thread safe, no simultaneous calling + void setTcpNoDelay(bool on); void setContext(const boost::any& context) { context_ = context; } From eeecca1160effddd12f6007034744f53acfd693b Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Tue, 31 Aug 2010 15:47:34 +0800 Subject: [PATCH 099/371] add simple chargen client example --- examples/netty/discard/client.cc | 5 +- examples/simple/CMakeLists.txt | 3 + .../simple/chargenclient/chargenclient.cc | 73 +++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 examples/simple/chargenclient/chargenclient.cc diff --git a/examples/netty/discard/client.cc b/examples/netty/discard/client.cc index b6daaba6b..4b454a76f 100644 --- a/examples/netty/discard/client.cc +++ b/examples/netty/discard/client.cc @@ -45,7 +45,10 @@ class DiscardClient : boost::noncopyable << conn->peerAddress().toHostPort() << " is " << (conn->connected() ? "UP" : "DOWN"); - conn->send(message_); + if (conn->connected()) + conn->send(message_); + else + loop_->quit(); } void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) diff --git a/examples/simple/CMakeLists.txt b/examples/simple/CMakeLists.txt index 9583ae52d..3fcfc6143 100644 --- a/examples/simple/CMakeLists.txt +++ b/examples/simple/CMakeLists.txt @@ -26,3 +26,6 @@ target_link_libraries(simple_allinone muduo_net) add_executable(simple_timeclient timeclient/timeclient.cc) target_link_libraries(simple_timeclient muduo_net) +add_executable(simple_chargenclient chargenclient/chargenclient.cc) +target_link_libraries(simple_chargenclient muduo_net) + diff --git a/examples/simple/chargenclient/chargenclient.cc b/examples/simple/chargenclient/chargenclient.cc new file mode 100644 index 000000000..d0c706a07 --- /dev/null +++ b/examples/simple/chargenclient/chargenclient.cc @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +class ChargenClient : boost::noncopyable +{ + public: + ChargenClient(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + client_(loop, listenAddr, "ChargenClient") + { + client_.setConnectionCallback( + boost::bind(&ChargenClient::onConnection, this, _1)); + client_.setMessageCallback( + boost::bind(&ChargenClient::onMessage, this, _1, _2, _3)); + // client_.enableRetry(); + } + + void connect() + { + client_.connect(); + } + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_INFO << conn->localAddress().toHostPort() << " -> " + << conn->peerAddress().toHostPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + + if (!conn->connected()) + loop_->quit(); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime) + { + buf->retrieveAll(); + } + + EventLoop* loop_; + TcpClient client_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid(); + if (argc > 1) + { + EventLoop loop; + InetAddress serverAddr(argv[1], 2019); + + ChargenClient timeClient(&loop, serverAddr); + timeClient.connect(); + loop.loop(); + } + else + { + printf("Usage: %s host_ip\n", argv[0]); + } +} + From 91aed4d982a503db908a11e824df889fd37e25ed Mon Sep 17 00:00:00 2001 From: Shuo Chen Date: Sat, 4 Sep 2010 11:44:57 +0800 Subject: [PATCH 100/371] Ping pong benchmark --- CMakeLists.txt | 2 +- ChangeLog | 4 + examples/CMakeLists.txt | 1 + examples/pingpong/CMakeLists.txt | 6 + examples/pingpong/client.cc | 209 +++++++++++++++++++++++++++++++ examples/pingpong/server.cc | 63 ++++++++++ muduo/base/Atomic.h | 7 +- muduo/base/Logging.h | 9 +- muduo/net/TcpServer.cc | 5 +- 9 files changed, 300 insertions(+), 6 deletions(-) create mode 100644 examples/pingpong/CMakeLists.txt create mode 100644 examples/pingpong/client.cc create mode 100644 examples/pingpong/server.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index b1945216e..2eb8d1ea7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") set(CMAKE_CXX_COMPILER "g++") #set(CMAKE_CXX_COMPILER "icpc") set(CMAKE_CXX_FLAGS_DEBUG "-O0") -set(CMAKE_CXX_FLAGS_RELEASE "-O2") # no NDEBUG in Release, keep asserting. +set(CMAKE_CXX_FLAGS_RELEASE "-O2 -finline-limit=1000") # no NDEBUG in Release, keep asserting. set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) diff --git a/ChangeLog b/ChangeLog index 31fb3a792..732f66a5a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2010-09-04 Shuo Chen + + * Ping-pong benchmark, version 0.1.1 + 2010-08-30 Shuo Chen * First pre-alpha release, version 0.1.0 diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 2103a7112..3509935ac 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(simple) add_subdirectory(roundtrip) add_subdirectory(hub) +add_subdirectory(pingpong) add_subdirectory(asio/tutorial) add_subdirectory(asio/chat) diff --git a/examples/pingpong/CMakeLists.txt b/examples/pingpong/CMakeLists.txt new file mode 100644 index 000000000..cb4fabf01 --- /dev/null +++ b/examples/pingpong/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(pingpong_client client.cc) +target_link_libraries(pingpong_client muduo_net) + +add_executable(pingpong_server server.cc) +target_link_libraries(pingpong_server muduo_net) + diff --git a/examples/pingpong/client.cc b/examples/pingpong/client.cc new file mode 100644 index 000000000..c84522453 --- /dev/null +++ b/examples/pingpong/client.cc @@ -0,0 +1,209 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +class Client; + +class Session : boost::noncopyable +{ + public: + Session(EventLoop* loop, const InetAddress& serverAddr, const string& name, Client* owner) + : client_(loop, serverAddr, name), + owner_(owner), + bytesRead_(0), + bytesWritten_(0), + messagesRead_(0) + { + client_.setConnectionCallback( + boost::bind(&Session::onConnection, this, _1)); + client_.setMessageCallback( + boost::bind(&Session::onMessage, this, _1, _2, _3)); + } + + void start() + { + client_.connect(); + } + + void stop() + { + client_.disconnect(); + } + + int64_t bytesRead() const + { + return bytesRead_; + } + + int64_t messagesRead() const + { + return messagesRead_; + } + + private: + + void onConnection(const TcpConnectionPtr& conn); + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) + { + ++messagesRead_; + bytesRead_ += buf->readableBytes(); + bytesWritten_ += buf->readableBytes(); + conn->send(buf); + } + + TcpClient client_; + Client* owner_; + int64_t bytesRead_; + int64_t bytesWritten_; + int64_t messagesRead_; +}; + +class Client : boost::noncopyable +{ + public: + Client(EventLoop* loop, + const InetAddress& serverAddr, + int blockSize, + int sessionCount, + int timeout, + int threadCount) + : loop_(loop), + threadPool_(loop), + sessionCount_(sessionCount), + timeout_(timeout) + { + loop->runAfter(timeout, boost::bind(&Client::handleTimeout, this)); + if (threadCount > 1) + { + threadPool_.setThreadNum(threadCount); + } + threadPool_.start(); + + for (int i = 0; i < blockSize; ++i) + { + message_.push_back(static_cast(i % 128)); + } + + for (int i = 0; i < sessionCount; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "C%05d", i); + Session* session = new Session(threadPool_.getNextLoop(), serverAddr, buf, this); + session->start(); + sessions_.push_back(session); + } + } + + const string& message() const + { + return message_; + } + + void onConnect() + { + if (numConnected_.incrementAndGet() == sessionCount_) + { + LOG_WARN << "all connected"; + } + } + + void onDisconnect() + { + if (numConnected_.decrementAndGet() == 0) + { + LOG_WARN << "all disconnected"; + + int64_t totalBytesRead = 0; + int64_t totalMessagesRead = 0; + for (boost::ptr_vector::iterator it = sessions_.begin(); + it != sessions_.end(); ++it) + { + totalBytesRead += it->bytesRead(); + totalMessagesRead += it->messagesRead(); + } + LOG_WARN << totalBytesRead << " total bytes read"; + LOG_WARN << totalMessagesRead << " total messages read"; + LOG_WARN << static_cast(totalBytesRead) / static_cast(totalMessagesRead) + << " average message size"; + LOG_WARN << static_cast(totalBytesRead) / (timeout_ * 1024 * 1024) + << " MiB/s throughput"; + loop_->quit(); + } + } + + private: + + void handleTimeout() + { + LOG_WARN << "stop"; + std::for_each(sessions_.begin(), sessions_.end(), + boost::mem_fn(&Session::stop)); + } + + EventLoop* loop_; + EventLoopThreadPool threadPool_; + int sessionCount_; + int timeout_; + boost::ptr_vector sessions_; + string message_; + AtomicInt32 numConnected_; +}; + +void Session::onConnection(const TcpConnectionPtr& conn) +{ + if (conn->connected()) + { + conn->setTcpNoDelay(true); + conn->send(owner_->message()); + owner_->onConnect(); + } + else + { + owner_->onDisconnect(); + } +} + +int main(int argc, char* argv[]) +{ + if (argc != 7) + { + fprintf(stderr, "Usage: client "); + fprintf(stderr, "