├── .clang-format ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE │ └── pull_request_template.md ├── .gitignore ├── .gitlab-ci.yml ├── .gitlab ├── git_commit_templates │ └── Commit_Template.md ├── issue_templates │ ├── Bug_Template.md │ └── Feature_Teamplate.md └── merge_request_templates │ └── PR_Template.md ├── Changelog.md ├── Contributing.md ├── Doc └── .gitkeep ├── LICENSE ├── MTAppenderFile.podspec ├── MTAppenderFileDemo ├── .gitkeep ├── MTAppenderFile.xcworkspace │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ ├── WorkspaceSettings.xcsettings │ │ └── xcschemes │ │ └── MTAppenderFileTests.xcscheme ├── MTAppenderFileDemo.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── MTAppenderFileDemo.xcscheme ├── MTAppenderFileDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── Supporting Files │ │ └── main.m │ ├── ViewController.h │ └── ViewController.mm ├── MTAppenderFileDemoTests │ ├── Info.plist │ └── MTAppenderFileDemoTests.m ├── Podfile.lock ├── ccache-clang ├── ccache-clang++ └── podfile ├── Readme.md ├── Scripts ├── Hooks │ ├── commit-msg │ ├── pre-commit │ ├── pre-commit-clang-format │ └── setup-hook.sh └── format-project-code-style-with-clang-format.sh ├── comm ├── __mtaf_assert.c ├── __mtaf_assert.h ├── comm.xcodeproj │ └── project.pbxproj ├── mtaf_atomic_oper.h ├── mtaf_autobuffer.cc ├── mtaf_autobuffer.h ├── mtaf_compiler_util.h ├── mtaf_condition.h ├── mtaf_lock.h ├── mtaf_mutex.h ├── mtaf_ptrbuffer.cc ├── mtaf_ptrbuffer.h ├── mtaf_runnable.h ├── mtaf_spinlock.h ├── mtaf_thread.h ├── mtaf_time_utils.c └── mtaf_time_utils.h ├── loglib ├── MTAppenderFile.h ├── MTAppenderFile.mm ├── loglib.xcodeproj │ └── project.pbxproj ├── mtaf_appender.cpp ├── mtaf_appender.h ├── mtaf_base.h ├── mtaf_formatter.cpp ├── mtaf_log_buffer.cpp ├── mtaf_log_buffer.h ├── mtaf_mmap_file.cpp ├── mtaf_mmap_file.h └── mtaf_platform_comm.mm └── setup.sh /.clang-format: -------------------------------------------------------------------------------- 1 | # .clang-format 2 | # clang 排版配置文件 3 | # 4 | # * 配置参数修改参考文档 5 | # http://clang.llvm.org/docs/ClangFormatStyleOptions.html 6 | # 7 | # * 使用步骤: 8 | # Xcode 8.0 之前可安装 ClangFormat-Xcode 插件(https://github.com/travisjeffery/ClangFormat-Xcode) 9 | # 配置快捷键,如有必要可设置保存文件时自动格式化 10 | # 11 | # 将此文件放入工程根目录下,命名为 .clang-format 12 | # 13 | # 14 | # * 若有不特殊的排版 clangformat 不支持,使用以下注释让 clang 跳过自动排版校验 15 | # // clang-format off 16 | # ... ... 17 | # // clang-format on 18 | # 19 | # 20 | 21 | --- 22 | # Language: Cpp # this format style is targeted at. Cpp for c, c++, oc, oc++. 23 | BasedOnStyle: LLVM 24 | AccessModifierOffset: -2 # 控制 @public ... 的左缩进,以 IndentWidth 为基准 25 | AlignAfterOpenBracket: false # 26 | # AlignConsecutiveAssignments: true # Xcode 6.3.2 还不支持此属性 27 | # AlignConsecutiveDeclarations: false 28 | AlignEscapedNewlinesLeft: true # If true, aligns escaped newlines as far left as possible. 29 | AlignOperands: true # 有操作符的多行语句,是否水平对齐 30 | AlignTrailingComments: true # 连续行,行尾注释对齐 31 | AllowAllParametersOfDeclarationOnNextLine: true # 即使 BinPackParameters 为 false, 仍允许方法声明的多个参数不在同一行 32 | AllowShortBlocksOnASingleLine: false # 允许简单 {} 语句单行 33 | AllowShortCaseLabelsOnASingleLine: true # 允许 case 单行 34 | AllowShortFunctionsOnASingleLine: Inline # 允许方法单行 int f() { return 0; }, 只在 inline 是允许 35 | AllowShortIfStatementsOnASingleLine: true # if 语句较短时不强制换行 36 | AllowShortLoopsOnASingleLine: true # 允许单行循环 while (true) continue; 37 | # AlwaysBreakAfterDefinitionReturnType: true # deprecated, c 方法定义返回值单起一行 38 | # AlwaysBreakAfterReturnType: # The function declaration return type breaking style to use. 39 | AlwaysBreakBeforeMultilineStrings: false # 40 | AlwaysBreakTemplateDeclarations: false # template<...> 后强制另起一行 41 | BinPackArguments: true # false 时表示 c 方法调用强制全部在同一行,或者每一行只能有一个参数 42 | BinPackParameters: true # false 时表示 c 方法声明强制全部在同一行,或者每一行只能有一个参数 43 | # BraceWrapping: # BreakBeforeBraces = BS_Custom 时此参数起作用,自定义不同语义下的 { 是否单起一行策略 44 | BraceWrapping: { 45 | AfterClass: true, # class { 的 { 不另起一行 46 | AfterControlStatement: false, # if { 的 { 不另起一行 47 | AfterEnum: false, # enum { 的 { 不另起一行 48 | AfterFunction: false, # aFunc { 的 { 不另起一行 49 | AfterNamespace: false # aNamespaece { 的 { 不另起一行 50 | } 51 | BreakBeforeBinaryOperators: All # All: Break before operators. 52 | BreakBeforeBraces: Custom # {} 换行风格, 自定义风格,由 BraceWrapping 配置 53 | # BreakBeforeInheritanceComma: false # class 继承后的多个类,不强制分成多行,暂不支持 54 | BreakBeforeTernaryOperators: true # ? : 如果换行时,强制 ? : 在行首 55 | BreakConstructorInitializersBeforeComma: true # cpp 构造函数变量构造强制对齐 56 | ColumnLimit: 0 # 单行最长字符限制,0不限制 57 | # CommentPragmas: '^ IWYU pragma:' # 正则表达式所匹配的注释有特殊意义,不要换行和修改 58 | ConstructorInitializerAllOnOneLineOrOnePerLine: false # 构造函数单行或强制多行 59 | ConstructorInitializerIndentWidth: 4 # 构造函数缩进 60 | ContinuationIndentWidth: 4 # [[AFNetworking share] xxx], xxx 单起一行时缩进 61 | Cpp11BracedListStyle: true # format braced lists as best suited for C++11 braced lists. 62 | DerivePointerAlignment: false # 是否将 PointerAlignment 置为备选 63 | ExperimentalAutoDetectBinPacking: false # 64 | # FixNamespaceComments: true # namespace a { ... } 后补充注释 // namespace a 暂不支持 65 | # ForEachMacros: # code FOREACH(, ...) 66 | IncludeCategories: # 头文件排序规则,<> , "" 按字母排序 67 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 68 | Priority: 2 69 | - Regex: '^(<|"(gtest|isl|json)/)' 70 | Priority: 2 71 | - Regex: '.\*' 72 | Priority: 1 73 | IndentCaseLabels: true # 强制将 switch case 的 case 进行缩进 74 | IndentWidth: 4 # 默认行缩进量 75 | IndentWrappedFunctionNames: false # Indent if a function definition or declaration is wrapped after the type. 76 | # JavaScriptQuotes: 77 | # JavaScriptWrapImports 78 | KeepEmptyLinesAtTheStartOfBlocks: true # 一个代码块开头如果是空行,是否保留 79 | #MacroBlockBegin: "^[A-Z_]+_BEGIN$" # block 宏开始正则匹配 80 | #MacroBlockEnd: "^[A-Z_]+_END$" # block 宏结束正则匹配 81 | MaxEmptyLinesToKeep: 3 # 最多允许几个连续空行 82 | NamespaceIndentation: None # namespace 是否缩进 83 | ObjCBlockIndentWidth: 4 # ObjC block 内缩进 84 | ObjCSpaceAfterProperty: true # @property (readonly) 中间强制一个空格 85 | ObjCSpaceBeforeProtocolList: true # Foo 中强制一个空格 86 | PenaltyBreakBeforeFirstCallParameter: 19 # The penalty for breaking a function call after `call(`. 87 | PenaltyBreakComment: 300 # The penalty for each line break introduced inside a comment. 88 | PenaltyBreakString: 1000 # The penalty for each line break introduced inside a string literal. 89 | PenaltyBreakFirstLessLess: 120 # The penalty for breaking before the first <<. 90 | PenaltyExcessCharacter: 1000000 # The penalty for each character outside of the column limit. 91 | PenaltyReturnTypeOnItsOwnLine: 60 # Penalty for putting the return type of a function onto its own line. 92 | PointerAlignment: Right # 指针、引用标识贴着变量名 int *a; <- int* a; 93 | ReflowComments: false # 多行时是否重排列 94 | SortIncludes: true # 是否对连续的 include 行进行排序 95 | SpaceAfterCStyleCast: false # c 式类型强转之后是否添加空格 (double)a <- (double) a 96 | # SpaceAfterTemplateKeyword: false # template, template 后不插入空格 97 | SpaceBeforeAssignmentOperators: true # = 号前是否加空格 98 | SpaceBeforeParens: ControlStatements # 什么时候在括号前插入空格,if (booleanValue), void f() , f() 99 | SpaceInEmptyParentheses: false # 空参数方法调用() 中是否插入空格 f() <- f( ) 100 | SpacesBeforeTrailingComments: 1 # 行尾注释 // 之前添加几个空格 ; // <- ;// 101 | SpacesInAngles: false # < 后 > 前是否插入空格, std::function fct; 102 | SpacesInCStyleCastParentheses: false # c 式类型强转之后是否添加空格 x = (int32)y <- x = ( int32 )y 103 | SpacesInContainerLiterals: true # @[], @{} 等容器前后是否插入空格 [ 1, 2, 3 ]; <- [1, 2, 3]; 104 | SpacesInParentheses: false # ( 后 ) 前是否插入空格, t f( Deleted & ) & = delete; -> t f(Deleted &) & = delete; 105 | SpacesInSquareBrackets: false # [ 后 ] 前是否插入空格 106 | Standard: Cpp11 # 语言标准 Cpp03 Cpp11 Auto 107 | TabWidth: 4 # Tab 宽度 108 | UseTab: Never # 保留 Tab 或者用空格替换 109 | PointerBindsToType: false 110 | IndentFunctionDeclarationAfterType: true 111 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Environment (please complete the following information):** 27 | - Device: [e.g. iPhone6] 28 | - OS: [e.g. iOS8.1] 29 | - Xcode Version: [e.g. 10.2] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Your checklist for this pull request 2 | 3 | Please check if your PR fullfills the following requirements: 4 | 5 | - [ ] Follow the branch management and code style under [Contributing](../../Contrubuting.md#branch-management). 6 | - [ ] Lint (`pod lib lint`) has passed locally. 7 | - [ ] The unit test all passed. 8 | - [ ] Extended the Readme / documentation, if necessary. 9 | 10 | ## Pull request type 11 | 12 | Please check the type of change your PR introduces: 13 | 14 | - [ ] Bugfix 15 | - [ ] Feature 16 | - [ ] Code style update (formatting, renaming) 17 | - [ ] Refactoring (no functional changes, no api changes) 18 | - [ ] Build related changes 19 | - [ ] Documentation content changes 20 | - [ ] Other (please describe): 21 | 22 | ## Description 23 | 24 | Please explain the changes you made here. 25 | 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/ruby,python,xcode,objective-c,swift,osx 3 | 4 | ### Ruby ### 5 | *.gem 6 | *.rbc 7 | /.config 8 | /coverage/ 9 | /InstalledFiles 10 | /pkg/ 11 | /spec/reports/ 12 | /spec/examples.txt 13 | /test/tmp/ 14 | /test/version_tmp/ 15 | /tmp/ 16 | 17 | ## Specific to RubyMotion: 18 | .dat* 19 | .repl_history 20 | build/ 21 | 22 | ## Documentation cache and generated files: 23 | /.yardoc/ 24 | /_yardoc/ 25 | /rdoc/ 26 | 27 | ## Environment normalization: 28 | /.bundle/ 29 | /vendor/bundle 30 | /lib/bundler/man/ 31 | 32 | # for a library or gem, you might want to ignore these files since the code is 33 | # intended to run in multiple environments; otherwise, check them in: 34 | # Gemfile.lock 35 | # .ruby-version 36 | # .ruby-gemset 37 | 38 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 39 | .rvmrc 40 | 41 | 42 | ### Xcode ### 43 | # Xcode 44 | # 45 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 46 | 47 | ## Build generated 48 | build/ 49 | DerivedData/ 50 | 51 | ## Various settings 52 | *.pbxuser 53 | !default.pbxuser 54 | *.mode1v3 55 | !default.mode1v3 56 | *.mode2v3 57 | !default.mode2v3 58 | *.perspectivev3 59 | !default.perspectivev3 60 | xcuserdata/ 61 | 62 | ## Other 63 | *.moved-aside 64 | *.xccheckout 65 | *.xcscmblueprint 66 | 67 | 68 | ### Objective-C ### 69 | # Xcode 70 | # 71 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 72 | 73 | ## Build generated 74 | build/ 75 | DerivedData/ 76 | 77 | ## Various settings 78 | *.pbxuser 79 | !default.pbxuser 80 | *.mode1v3 81 | !default.mode1v3 82 | *.mode2v3 83 | !default.mode2v3 84 | *.perspectivev3 85 | !default.perspectivev3 86 | xcuserdata/ 87 | 88 | ## Other 89 | *.moved-aside 90 | *.xcuserstate 91 | 92 | ## Obj-C/Swift specific 93 | *.hmap 94 | *.ipa 95 | 96 | # CocoaPods 97 | # 98 | # We recommend against adding the Pods directory to your .gitignore. However 99 | # you should judge for yourself, the pros and cons are mentioned at: 100 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 101 | # 102 | Pods/ 103 | 104 | # Carthage 105 | # 106 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 107 | # Carthage/Checkouts 108 | 109 | Carthage/Build 110 | 111 | # fastlane 112 | # 113 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 114 | # screenshots whenever they are needed. 115 | # For more information about the recommended setup visit: 116 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 117 | 118 | fastlane/report.xml 119 | fastlane/screenshots 120 | 121 | ### Objective-C Patch ### 122 | *.xcscmblueprint 123 | 124 | 125 | ### Swift ### 126 | # Xcode 127 | # 128 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 129 | 130 | ## Build generated 131 | build/ 132 | DerivedData/ 133 | 134 | ## Various settings 135 | *.pbxuser 136 | !default.pbxuser 137 | *.mode1v3 138 | !default.mode1v3 139 | *.mode2v3 140 | !default.mode2v3 141 | *.perspectivev3 142 | !default.perspectivev3 143 | xcuserdata/ 144 | 145 | ## Other 146 | *.moved-aside 147 | *.xcuserstate 148 | 149 | ## Obj-C/Swift specific 150 | *.hmap 151 | *.ipa 152 | 153 | ## Playgrounds 154 | timeline.xctimeline 155 | playground.xcworkspace 156 | 157 | # Swift Package Manager 158 | # 159 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 160 | # Packages/ 161 | .build/ 162 | 163 | # CocoaPods 164 | # 165 | # We recommend against adding the Pods directory to your .gitignore. However 166 | # you should judge for yourself, the pros and cons are mentioned at: 167 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 168 | # 169 | Pods/ 170 | 171 | # Carthage 172 | # 173 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 174 | # Carthage/Checkouts 175 | 176 | Carthage/Build 177 | 178 | # fastlane 179 | # 180 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 181 | # screenshots whenever they are needed. 182 | # For more information about the recommended setup visit: 183 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 184 | 185 | fastlane/report.xml 186 | fastlane/screenshots 187 | 188 | 189 | ### OSX ### 190 | .DS_Store 191 | .AppleDouble 192 | .LSOverride 193 | 194 | # Icon must end with two \r 195 | Icon 196 | 197 | 198 | # Thumbnails 199 | ._* 200 | 201 | # Files that might appear in the root of a volume 202 | .DocumentRevisions-V100 203 | .fseventsd 204 | .Spotlight-V100 205 | .TemporaryItems 206 | .Trashes 207 | .VolumeIcon.icns 208 | 209 | # Directories potentially created on remote AFP share 210 | .AppleDB 211 | .AppleDesktop 212 | Network Trash Folder 213 | Temporary Items 214 | .apdisk 215 | 216 | main.js 217 | contents.xcworkspacedata 218 | 219 | 220 | # VSCode 221 | .vscode/ -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | #before_script会在每个job之前先执行其中的命令,注意空格,不能缩进 2 | before_script: 3 | #打印根目录 4 | - echo ~ 5 | #打印当前路径 6 | - echo `pwd` 7 | - git submodule sync --recursive 8 | - git submodule update --init --recursive 9 | #安装 pod 依赖 10 | - cd ./MTAppenderFileDemo 11 | - pod install 12 | - cd .. 13 | 14 | #stages为构建的顺序,每个job加入其中的stage顺序执行,相同stage下的job平行执行 15 | stages: 16 | - pre 17 | - analysis 18 | - test 19 | - publish 20 | 21 | # 下面定义job,就是需要服务器跑的脚本任务 22 | # 自动关闭bug 23 | job-closebug: 24 | #将job加入到pre stage中 25 | stage: pre 26 | script: 27 | - closeBugs.rb 28 | tags: 29 | - ios 30 | only: 31 | - /.*develop$|^feature.*$|^release.*$/ 32 | when: always 33 | 34 | # faxuspas静态分析 35 | job-fauxpas: 36 | #将job加入到analysis stage中 37 | stage: analysis 38 | ################## 此处需要各自项目配置 ############################### 39 | #gitlab-ci-fauxpas脚本为静态编译脚本,使用faux pas实现,需要各自项目制定target 40 | #如target名为testCI,则gitlab-ci-fauxpas -t testCI 41 | #如海报工程工程的target名为HBGC,则gitlab-ci-fauxpas -t HBGC 42 | #fauxpas需要每个项目在根目录中配置一个名为:main.fauxpas.json的配置文本 43 | #如果没有配置该文件,则会使用服务器下的默认配置 44 | #这里是需要每个项目根据各自的工程名配置的,将下面的testCI改为各自项目中target名称即可 45 | script: 46 | - gitlab-ci-fauxpas -t MTAppenderFile 47 | #only 指定分支名称或者标识,使job在指定情况下构建.如下:只在master分支中的commit执行构建 48 | only: 49 | - /.*develop$|^feature.*$|^release.*$/ 50 | #tags指定执行的runner标识,服务器上已有个共享runner名为:ios 51 | tags: 52 | - ios 53 | when: always 54 | 55 | # 运行单元测试 56 | job-unittest: 57 | stage: test 58 | script: 59 | ################## 此处需要各自项目配置 ############################### 60 | # 这里有两个地方需要配置,一个是workspace的路径,一个是单元测试的scheme名称 61 | # xcodebuild test -workspace {workspace_path} -scheme {scehme_name} -destination 'platform=iOS Simulator,name=iPhone 7,OS=10.3' 62 | # 注意scheme需要设置为shared 63 | - xcodebuild test -workspace MTAppenderFileDemo/MTAppenderFile.xcworkspace -scheme MTAppenderFileTests -destination 'platform=iOS Simulator,name=iPhone 8,OS=latest' | xcpretty -s --color 64 | tags: 65 | - ios 66 | only: 67 | - /.*develop$|^feature.*$|^release.*$/ 68 | when: always 69 | 70 | job-publish: 71 | stage: publish 72 | script: 73 | ################## 此处需要各自项目配置 ############################### 74 | # 下面的 MTAnalyticsBase.podspec 需要改成各自项目的 .podspec 75 | # 注意,podspec里面对项目的引用方式必须是ssh,不能是http 76 | - pod repo push meitu-iosmodules-specs MTAppenderFile.podspec --allow-warnings --use-libraries --verbose 77 | tags: 78 | - ios 79 | only: 80 | - tags 81 | when: always 82 | -------------------------------------------------------------------------------- /.gitlab/git_commit_templates/Commit_Template.md: -------------------------------------------------------------------------------- 1 | 【提交分类】简洁描述修改摘要 2 | > 提交分类说明 3 | >【Bugfix-BugID】修复Bugfree提出的bug,带上Bug ID 4 | >【Bugfix】修复开发中自测出现的问题 5 | >【Feature】添加新的Feature 6 | >【Optimize】重构代码,优化结构等 7 | >【Resources】修改资源,替换翻译等,不涉及代码修改的 8 | >【Demo】只更新了Demo,未涉及源码修改。 9 | >【Doc】Readme、Changelog 等文档文件的整理和修改。 10 | >【Podspecs】podspecs文件修改,如果是版本封包需要带上-version 11 | > 如果提交 A 依赖于另一个提交 B,当提交时,应在提交 A 使用提交 B 的Hash在消息中说明该依赖项;同样地,如果提交一个由提交B引入的 bug,那么它应该在提交 A 中提出。 12 | 13 | 详细的描述你的修改。 14 | 并且解释了为什么需要这么修改,如何解决这个问题。它可能有什么副作用。 15 | 16 | 【影响范围】XXXXXX 17 | 【引入】引入这个bug的commit的 SHA,不需要完整的SHA,取前7位 18 | 【依赖】如果提交 A 依赖于另一个提交 B,当提交时,应在提交 A 使用提交 B 的SHA在消息中说明该依赖项,不需要完整的SHA,取前7位 19 | 【URL】引用 URL 或 Jira 的 URL 20 | 21 | > 更多细节参考[iOS Git Commit 规范](http://cf.meitu.com/confluence/pages/viewpage.action?pageId=4556189) 22 | -------------------------------------------------------------------------------- /.gitlab/issue_templates/Bug_Template.md: -------------------------------------------------------------------------------- 1 | ## 报告一个新 bug 之前 2 | - 确定在最新版本中该 bug 存在。一般不会持续维护所有的发布版本,所以请尽量使用最新版本验证。 3 | - 确认该 bug 是可以复现的,请尽量提供完整的重现步骤。 4 | - 请确定这不是一个重复的 bug,查看 issue page 列表,搜索您要提交的 bug 是否已经被报告过。如果是已有的 issue,直接在原 issue 上补充讨论内容。 5 | 6 | ## 在项目对应的 issue page 创建新的 issue 7 | - 使用一个清晰并有描述性的标题来定义 bug 8 | - 详细的描述复现 bug 的步骤。包括您的具体硬件环境、软件环境,如有需要可以添加详细的 trace 日志 9 | - 如果程序抛出异常,请附加完整的堆栈日志 10 | - 如有可能,请附上屏幕截图或动态的GIF图,这些图片能帮助演示整个问题的产生过程 11 | - 如果涉及性能问题,请附加上 CPU ,内存或网络磁盘 IO 等 Profile 截图 12 | - 说明适用的版本,只有 release 版本的 bug 才可以提交,并且应该是当前最新版本。 13 | - 使用 bug label 来标记这个 issue。 14 | 15 | ## Summary 16 | 17 | ## Steps to Reproduce 18 | 19 | ## Expected Results 20 | 21 | ## Observed Results 22 | -------------------------------------------------------------------------------- /.gitlab/issue_templates/Feature_Teamplate.md: -------------------------------------------------------------------------------- 1 | - 使用一个清晰并具有描述性的标题来定义增强建议 2 | - 详细描述增强功能的行为模式 3 | - 详细说明该功能的具体使用场景 4 | - 如有可能,可以列出其他第三方组件已经具备的类似功能 5 | -------------------------------------------------------------------------------- /.gitlab/merge_request_templates/PR_Template.md: -------------------------------------------------------------------------------- 1 | ## What does this PR do? 2 | 3 | (简单描述此次 PR 的改动内容) 4 | (每个 PR 尽量不要包含太多 commit,完整新功能例外情况处理,以便于 Review 和合并处理) 5 | 6 | - 标题简单概述本次 PR 改动的内容 7 | - 内容里简要罗列关键的变动点 8 | - 对于未完全开发完成不希望合并的 PR, 在 title 增加 WIP: 避免分支被手误合并掉 9 | 10 | ## Check list before PR 11 | 12 | - 编译以及单元测试通过 13 | - 功能测试通过 14 | - 代码风格符合项目统一的代码风格规范 15 | - 提交的代码没有多余的文件,代码,空格以及空行 16 | - Commit 信息是否需要 rebase 或者 amend 17 | - 先 Rebase 远程分支最新代码,本地解决冲突,再提交以避免创建 pull request 冲突 18 | 19 | @cqh 20 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | # MTAppenderFile 2 | 3 | ## 0.4.0 -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to MTAppenderFile 2 | 3 | Welcome to [report Issues](https://github.com/meitu/MTAppenderFile/issues) or [pull requests](https://github.com/meitu/MTAppenderFile/pulls). It's recommended to read the following Contributing Guide first before contributing. 4 | 5 | ## Issues 6 | 7 | We use Github Issues to track public bugs and feature requests. 8 | 9 | ### Search Known Issues First 10 | 11 | Please search the existing issues to see if any similar issue or feature request has already been filed. You should make sure your issue isn't redundant. 12 | 13 | ### Reporting New Issues 14 | 15 | If you open an issue, the more information the better. Such as detailed description, screenshot or video of your problem, logcat and xlog or code blocks for your crash. 16 | 17 | ## Pull Requests 18 | 19 | We strongly welcome your pull request to make MTAppenderFile better. 20 | 21 | ### Branch Management 22 | 23 | We use [Git Flow branching model](http://nvie.com/posts/a-successful-git-branching-model/) in this repository: 24 | 25 | * We use the `master` branch for bringing forth production releases 26 | * We use the `develop` branch for "next release" development. 27 | * We prefix `feature` branch names with `feature/`. 28 | * We prefix `release` branch names with `release/`. 29 | * We prefix `hotfix` branch names with `hotfix/`. 30 | 31 | Make commits of logical units of work. 32 | 33 | * Smaller / simpler commits are usually easier to review. 34 | * Ideally, lint the files to make sure they do not contain syntax errors before committing them. (`pod lib lint`). 35 | * Ideally, write good commit messages. 36 | 37 | ## Code Style Guide 38 | 39 | Run [Develop Setup Shell](./setup.sh) after clone to makesure `clang-format` git commit hook has installed. Each git commit submitted require verified by clang-format at least, see [.clang-format file](./.clang-format) for basic code style. 40 | 41 | ## License 42 | 43 | By contributing to MTAppenderFile, you agree that your contributions will be licensed 44 | under its [MIT LICENSE](./LICENSE) 45 | -------------------------------------------------------------------------------- /Doc/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meitu/MTAppenderFile/40230fce3ffc72ef3f7ed3f12be5e42d90a9b4a0/Doc/.gitkeep -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-present, Meitu, Inc. 2 | All rights reserved. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. -------------------------------------------------------------------------------- /MTAppenderFile.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "MTAppenderFile" 3 | s.version = "0.4.4" 4 | s.summary = "A simplified high-performance log component for *OS base on Tencent Mars xlog." 5 | 6 | s.description = <<-DESC 7 | simplified high-performance log component base on mmap, with C & Objective-C API. 8 | DESC 9 | 10 | s.homepage = "https://github.com/meitu/MTAppenderFile" 11 | s.license = { 12 | :type => 'Copyright', 13 | :text => <<-LICENSE 14 | © 2008 - present Meitu, Inc. All rights reserved. 15 | LICENSE 16 | } 17 | 18 | s.author = { "Euan Chan" => "cqh@meitu.com" } 19 | 20 | s.platform = :ios, "8.0" 21 | 22 | s.source = { :git => "https://github.com/meitu/MTAppenderFile.git", :tag => "#{s.version}" } 23 | 24 | s.public_header_files = "loglib/MTAppenderFile.h", "loglib/mtaf_base.h" "loglib/mtaf_appender.h" 25 | s.source_files = "loglib/**/*{h,hpp,m,mm,cpp,cc,c}", "comm/**/*.{h,hpp,m,mm,cpp,cc,c}" 26 | s.exclude_files = "MTAppenderFile/Exclude" 27 | 28 | s.requires_arc = false 29 | 30 | s.libraries = "z", "c++" 31 | 32 | s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-lc++' } 33 | 34 | end 35 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meitu/MTAppenderFile/40230fce3ffc72ef3f7ed3f12be5e42d90a9b4a0/MTAppenderFileDemo/.gitkeep -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFile.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFile.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFile.xcworkspace/xcshareddata/xcschemes/MTAppenderFileTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 48 | 49 | 51 | 52 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemo.xcodeproj/xcshareddata/xcschemes/MTAppenderFileDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MTAppenderFileDemo 4 | // 5 | // Created by cqh on 18/05/2017. 6 | // Copyright © 2017 Meitu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MTAppenderFileDemo 4 | // 5 | // Created by cqh on 18/05/2017. 6 | // Copyright © 2017 Meitu. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemo/Supporting Files/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MTAppenderFileDemo 4 | // 5 | // Created by cqh on 18/05/2017. 6 | // Copyright © 2017 Meitu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char *argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // MTAppenderFileDemo 4 | // 5 | // Created by cqh on 18/05/2017. 6 | // Copyright © 2017 Meitu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemo/ViewController.mm: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // MTAppenderFileDemo 4 | // 5 | // Created by cqh on 18/05/2017. 6 | // Copyright © 2017 Meitu. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import 11 | 12 | @interface ViewController () 13 | @property (nonatomic, strong) MTAppenderFile *logger; 14 | @property (nonatomic, strong) NSTimer *timer; 15 | @property (nonatomic, strong) NSMutableArray *loggers; 16 | @property (nonatomic, strong) MTAppenderFile *testLogger; 17 | @end 18 | 19 | @implementation ViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | NSString *logPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 24 | self.logger = [[MTAppenderFile alloc] initWithFileDir:logPath name:@"test"]; 25 | [self.logger open]; 26 | 27 | UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 40)]; 28 | [btn1 setTitle:@"new logger" forState:UIControlStateNormal]; 29 | [btn1 setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 30 | [btn1 addTarget:self action:@selector(addLog) forControlEvents:UIControlEventTouchUpInside]; 31 | [self.view addSubview:btn1]; 32 | 33 | UIButton *closeBtn = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 100, 40)]; 34 | [closeBtn setTitle:@"close" forState:UIControlStateNormal]; 35 | [closeBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; 36 | [closeBtn addTarget:self action:@selector(close) forControlEvents:UIControlEventTouchUpInside]; 37 | [self.view addSubview:closeBtn]; 38 | 39 | UIButton *writeSomeTestBtn = [[UIButton alloc] initWithFrame:CGRectMake(100, 250, 100, 40)]; 40 | [writeSomeTestBtn setTitle:@"writeFileTest" forState:UIControlStateNormal]; 41 | [writeSomeTestBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; 42 | [writeSomeTestBtn addTarget:self action:@selector(writeSomeTestEvent) forControlEvents:UIControlEventTouchUpInside]; 43 | [self.view addSubview:writeSomeTestBtn]; 44 | 45 | self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(test) userInfo:nil repeats:YES]; 46 | } 47 | 48 | - (MTAppenderFile *)testLogger { 49 | if (!_testLogger) { 50 | NSString *logPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 51 | _testLogger = [[MTAppenderFile alloc] initWithFileDir:logPath name:@"records"]; 52 | } 53 | return _testLogger; 54 | } 55 | 56 | - (NSMutableArray *)loggers { 57 | if (!_loggers) { 58 | _loggers = [[NSMutableArray alloc] init]; 59 | } 60 | return _loggers; 61 | } 62 | 63 | - (void)test { 64 | NSLog(@"填充Log"); 65 | @synchronized(self) { 66 | for (MTAppenderFile *logger in self.loggers) { 67 | [logger appendText:[NSString stringWithFormat:@"%lu: %s", (unsigned long)[self.loggers indexOfObject:logger], __PRETTY_FUNCTION__]]; 68 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { 69 | for (int i = 0; i < 1000; i++) { 70 | [logger appendText:@"dsajkdflsafkdslajfdlsafjdslkahfdklsa\n"]; 71 | } 72 | }); 73 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void) { 74 | for (int i = 0; i < 1000; i++) { 75 | [logger appendText:@"11132413501350\n"]; 76 | } 77 | }); 78 | } 79 | } 80 | } 81 | 82 | - (void)addLog { 83 | NSLog(@"添加一个MTAppenderFile"); 84 | @synchronized(self) { 85 | static int index = 0; 86 | NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 87 | NSString *logFileName = [NSString stringWithFormat:@"log_%i", index++]; 88 | MTAppenderFile *logger = [[MTAppenderFile alloc] initWithFileDir:documentPath name:logFileName]; 89 | [logger open]; 90 | [self.loggers addObject:logger]; 91 | } 92 | } 93 | 94 | - (void)close { 95 | NSLog(@"关闭所有MTAppenderFile"); 96 | @synchronized(self) { 97 | for (MTAppenderFile *logger in self.loggers) { 98 | [logger close]; 99 | } 100 | [self.loggers removeAllObjects]; 101 | } 102 | } 103 | 104 | - (void)writeSomeTestEvent { 105 | [self.testLogger open]; 106 | [self.testLogger appendText:@"11111111"]; 107 | [self.testLogger appendText:@"22222222"]; 108 | [self.testLogger appendText:@"33333333"]; 109 | [self.testLogger appendText:@"44444444"]; 110 | [self.testLogger appendText:@"55555555"]; 111 | [self.testLogger appendText:@"66666666"]; 112 | [self.testLogger appendText:@"77777777"]; 113 | [self.testLogger close]; 114 | NSLog(@"done"); 115 | } 116 | 117 | - (void)didReceiveMemoryWarning { 118 | [super didReceiveMemoryWarning]; 119 | // Dispose of any resources that can be recreated. 120 | } 121 | 122 | 123 | @end 124 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/MTAppenderFileDemoTests/MTAppenderFileDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MTAppenderFileDemoTests.m 3 | // MTAppenderFileDemoTests 4 | // 5 | // Created by cqh on 18/05/2017. 6 | // Copyright © 2017 Meitu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MTAppenderFileDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation MTAppenderFileDemoTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - MTAppenderFile (0.4.3) 3 | 4 | DEPENDENCIES: 5 | - MTAppenderFile (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | MTAppenderFile: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | MTAppenderFile: c7db8f33a8140ee2275a6200305fd11e609fae33 13 | 14 | PODFILE CHECKSUM: 3b1d41fd5c4fbf8fdffd123fce85fa19917bc300 15 | 16 | COCOAPODS: 1.6.1 17 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/ccache-clang: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if type -p ccache >/dev/null 2>&1; then 3 | export CCACHE_MAXSIZE=10G 4 | export CCACHE_CPP2=true 5 | export CCACHE_HARDLINK=true 6 | export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,file_stat_matches 7 | 8 | # 指定日志文件路径到桌面,等下排查集成问题有用,集成成功后删除,否则很占磁盘空间 9 | export CCACHE_LOGFILE='tmp/CCache.log' 10 | exec ccache /usr/bin/clang "$@" 11 | else 12 | exec clang "$@" 13 | fi 14 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/ccache-clang++: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if type -p ccache >/dev/null 2>&1; then 3 | export CCACHE_MAXSIZE=10G 4 | export CCACHE_CPP2=true 5 | export CCACHE_HARDLINK=true 6 | export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,file_stat_matches 7 | 8 | # 指定日志文件路径到桌面,等下排查集成问题有用,集成成功后删除,否则很占磁盘空间 9 | export CCACHE_LOGFILE='tmp/CCache.log' 10 | exec ccache /usr/bin/clang++ "$@" 11 | else 12 | exec clang++ "$@" 13 | fi 14 | -------------------------------------------------------------------------------- /MTAppenderFileDemo/podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | source 'http://techgit.meitu.com/iosmodules/specs.git' 3 | 4 | platform :ios, "8.0" 5 | 6 | workspace 'MTAppenderFile' 7 | 8 | target 'MTAppenderFileDemo' do 9 | 10 | project 'MTAppenderFileDemo' 11 | 12 | pod 'MTAppenderFile', :path => '../' 13 | 14 | 15 | target 'MTAppenderFileDemoTests' do 16 | end 17 | 18 | # 开启所有 pod 引入库的 ccache,加快重复编译速度 19 | post_install do |installer_representation| 20 | installer_representation.pods_project.targets.each do |target| 21 | target.build_configurations.each do |config| 22 | #关闭 Enable Modules 23 | # config.build_settings['CLANG_ENABLE_MODULES'] = 'NO' 24 | 25 | # 在生成的 Pods 项目文件中加入 CC 参数,路径的值根据你自己的项目来修改 26 | #config.build_settings['CC'] = '$(PODS_ROOT)/../ccache-clang' 27 | end 28 | end 29 | end 30 | 31 | end 32 | 33 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # MTAppenderFile 2 | 3 | A simplified high-performance log component for *OS base on Tencent Mars xlog, is used in [MTHawkeye](https://github.com/meitu/MTHawkeye) for performance record data persistance. 4 | 5 | ## Usage 6 | 7 | Creata a `AppenderFile` by using `Objective-C` API, 8 | 9 | ```objc 10 | MTAppenderFile *file = [[MTAppenderFile alloc] initWithFileDir:dirName name:fileName]; 11 | [file open]; 12 | ``` 13 | 14 | Then use `appendText:` or `appendUTF8Text:` to append line data. 15 | 16 | ```objc 17 | [file appendText:@"test line"]; 18 | [file appendUTF8Text:"test line"]; 19 | ``` 20 | 21 | ## Details 22 | 23 | Each `AppenderFile` contains two files with the same file name, and different extensions. The first one is mmap file for high speed cache with the extension `.mmap2`, it's size is 150KB. The other file a extension `.mtlog`, log data transfered to this file when the mmap file needs to be dumped. 24 | 25 | For example, if you create an `AppenderFile` whose name is records, the actual files are: `records.mmap2` and `records.mtlog`. You need to merge the two files when reading, which is the complete records. 26 | 27 | Attention for reading stored data: 28 | 29 | - Both files need to be read, first `*.mmap2`, then `*.mtlog`, and then put the content together. 30 | - When reading the `*.mmap2` file, only non-dirty data is needed. when the `\0\0\0` line is encountered, the complete content of `mmap` has been read, and the content after that is dirty data, which should be ignored. 31 | 32 | ## Contributing 33 | 34 | For more information about contributing issues or pull requests, see [Contributing Guide](./Contributing.md)。 35 | 36 | ## Base On 37 | 38 | 1. [Tencent-Mars](https://github.com/Tencent/mars) 39 | 2. [微信终端跨平台组件 mars 系列(一) - 高性能日志模块xlog](https://mp.weixin.qq.com/s/cnhuEodJGIbdodh0IxNeXQ) 40 | -------------------------------------------------------------------------------- /Scripts/Hooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | -------------------------------------------------------------------------------- /Scripts/Hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sh .git/hooks/pre-commit-clang-format 4 | -------------------------------------------------------------------------------- /Scripts/Hooks/pre-commit-clang-format: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # git pre-commit hook that runs an clang-format stylecheck. 4 | # Features: 5 | # - abort commit when commit does not comply with the style guidelines 6 | # - create a patch of the proposed style changes 7 | 8 | # modifications for clang-format by rene.milk@wwu.de 9 | # This file is part of a set of unofficial pre-commit hooks available 10 | # at github. 11 | # Link: https://github.com/githubbrowser/Pre-commit-hooks 12 | # Contact: David Martin, david.martin.mailbox@googlemail.com 13 | 14 | 15 | ################################################################## 16 | # SETTINGS 17 | # set path to clang-format binary 18 | CLANG_FORMAT="/usr/local/bin/clang-format" 19 | 20 | # remove any older patches from previous commits. Set to true or false. 21 | # DELETE_OLD_PATCHES=false 22 | DELETE_OLD_PATCHES=false 23 | 24 | # only parse files with the extensions in FILE_EXTS. Set to true or false. 25 | # if false every changed file in the commit will be parsed with clang-format. 26 | # if true only files matching one of the extensions are parsed with clang-format. 27 | # PARSE_EXTS=true 28 | PARSE_EXTS=true 29 | 30 | # file types to parse. Only effective when PARSE_EXTS is true. 31 | # FILE_EXTS=".c .h .cpp .hpp" 32 | FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm" 33 | 34 | ################################################################## 35 | # There should be no need to change anything below this line. 36 | 37 | # Reference: http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac 38 | canonicalize_filename () { 39 | local target_file=$1 40 | local physical_directory="" 41 | local result="" 42 | 43 | # Need to restore the working directory after work. 44 | pushd `pwd` > /dev/null 45 | 46 | cd "$(dirname "$target_file")" 47 | target_file=`basename $target_file` 48 | 49 | # Iterate down a (possible) chain of symlinks 50 | while [ -L "$target_file" ] 51 | do 52 | target_file=$(readlink "$target_file") 53 | cd "$(dirname "$target_file")" 54 | target_file=$(basename "$target_file") 55 | done 56 | 57 | # Compute the canonicalized name by finding the physical path 58 | # for the directory we're in and appending the target file. 59 | physical_directory=`pwd -P` 60 | result="$physical_directory"/"$target_file" 61 | 62 | # restore the working directory after work. 63 | popd > /dev/null 64 | 65 | echo "$result" 66 | } 67 | 68 | # exit on error 69 | set -e 70 | 71 | # check whether the given file matches any of the set extensions 72 | matches_extension() { 73 | local filename=$(basename "$1") 74 | local extension=".${filename##*.}" 75 | local ext 76 | 77 | for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done 78 | 79 | return 1 80 | } 81 | 82 | # necessary check for initial commit 83 | if git rev-parse --verify HEAD >/dev/null 2>&1 ; then 84 | against=HEAD 85 | else 86 | # Initial commit: diff against an empty tree object 87 | against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 88 | fi 89 | 90 | if [ ! -x "$CLANG_FORMAT" ] ; then 91 | printf "Error: clang-format executable not found.\n" 92 | printf "Set the correct path in $(canonicalize_filename "$0").\n" 93 | exit 1 94 | fi 95 | 96 | # create a random filename to store our generated patch 97 | prefix="pre-commit-clang-format" 98 | suffix="$(date +%s)" 99 | patch="/tmp/$prefix-$suffix.patch" 100 | 101 | # clean up any older clang-format patches 102 | $DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch 103 | 104 | # create one patch containing all changes to the files 105 | git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file; 106 | do 107 | # ignore file if we do check for file extensions and the file 108 | # does not match any of the extensions specified in $FILE_EXTS 109 | if $PARSE_EXTS && ! matches_extension "$file"; then 110 | continue; 111 | fi 112 | 113 | # clang-format our sourcefile, create a patch with diff and append it to our $patch 114 | # The sed call is necessary to transform the patch from 115 | # --- $file timestamp 116 | # +++ - timestamp 117 | # to both lines working on the same file and having a a/ and b/ prefix. 118 | # Else it can not be applied with 'git apply'. 119 | "$CLANG_FORMAT" -style=file "$file" | \ 120 | diff -u "$file" - | \ 121 | sed -e "1s|--- |--- a/|" -e "2s|+++ -|+++ b/$file|" >> "$patch" 122 | done 123 | 124 | # if no patch has been generated all is ok, clean up the file stub and exit 125 | if [ ! -s "$patch" ] ; then 126 | printf "Files in this commit comply with the clang-format rules.\n" 127 | rm -f "$patch" 128 | exit 0 129 | fi 130 | 131 | # a patch has been created, notify the user and exit 132 | printf "\nThe following differences were found between the code to commit " 133 | printf "and the clang-format rules:\n\n" 134 | cat "$patch" 135 | 136 | printf "\nYou can apply these changes with:\n git apply $patch\n" 137 | printf "(may need to be called from the root directory of your repository)\n" 138 | printf "Aborting commit. Apply changes and commit again or skip checking with" 139 | printf " --no-verify (not recommended).\n" 140 | 141 | exit 1 142 | -------------------------------------------------------------------------------- /Scripts/Hooks/setup-hook.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ROOT=$(git rev-parse --show-toplevel) 5 | BASE_DIR=$(dirname "$0") 6 | 7 | if [ ! -d $ROOT/.git/hooks ]; then 8 | mkdir $ROOT/.git/hooks 9 | fi 10 | 11 | if [ -f $ROOT/.git/hooks/commit-msg ];then 12 | echo "File .git/hooks/commit-msg already exists! Will not attempt to overwrite." 13 | else 14 | cp $BASE_DIR/commit-msg $ROOT/.git/hooks/commit-msg 15 | chmod +x $ROOT/.git/hooks/commit-msg 16 | fi 17 | 18 | if [ -f $ROOT/.git/hooks/pre-commit-clang-format ];then 19 | echo "File .git/hooks/pre-commit-clang-format already exists! Will not attempt to overwrite." 20 | else 21 | cp $BASE_DIR/pre-commit-clang-format $ROOT/.git/hooks/pre-commit-clang-format 22 | chmod +x $ROOT/.git/hooks/pre-commit-clang-format 23 | fi 24 | 25 | if [ -f $ROOT/.git/hooks/pre-commit ];then 26 | echo "File .git/hooks/pre-commit already exists! Will not attempt to overwrite." 27 | else 28 | cp $BASE_DIR/pre-commit $ROOT/.git/hooks/pre-commit 29 | chmod +x $ROOT/.git/hooks/pre-commit 30 | fi 31 | -------------------------------------------------------------------------------- /Scripts/format-project-code-style-with-clang-format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | BASE_DIR=$(dirname "$0") 5 | 6 | cd $BASE_DIR 7 | 8 | ROOT=$(git rev-parse --show-toplevel) 9 | 10 | find -E $ROOT -iregex ".*\.(h|m|c|mm|cpp|hpp|cc|hh|cxx)" -not -path '*/Pods/*' | xargs clang-format -style=file -i -sort-includes 11 | -------------------------------------------------------------------------------- /comm/__mtaf_assert.c: -------------------------------------------------------------------------------- 1 | /* 2 | * comm_assert.c 3 | * 4 | * Created on: 2012-9-5 5 | * Author: yerungui 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "mtaf_compiler_util.h" 15 | 16 | #ifndef XLOGGER_TAG 17 | #define XLOGGER_TAG "" 18 | #endif 19 | 20 | #if defined(__APPLE__) && (defined(NDEBUG)) 21 | void __assert_rtn(const char *, const char *, int, const char *) __dead2; 22 | #endif 23 | 24 | #ifdef DEBUG 25 | static int sg_enable_assert = 1; 26 | #else 27 | static int sg_enable_assert = 0; 28 | #endif 29 | 30 | void MTAF_ENABLE_ASSERT() { 31 | sg_enable_assert = 1; 32 | } 33 | void MTAF_DISABLE_ASSERT() { 34 | sg_enable_assert = 0; 35 | } 36 | int MTAF_IS_ASSERT_ENABLE() { 37 | return sg_enable_assert; 38 | } 39 | 40 | EXPORT_FUNC void __ASSERT(const char *_pfile, int _line, const char *_pfunc, const char *_pexpression) { 41 | if (MTAF_IS_ASSERT_ENABLE()) { 42 | __assert_rtn(_pfunc, _pfile, _line, _pexpression); 43 | } 44 | } 45 | 46 | void __ASSERTV2(const char *_pfile, int _line, const char *_pfunc, const char *_pexpression, const char *_format, va_list _list) { 47 | if (MTAF_IS_ASSERT_ENABLE()) { 48 | __assert_rtn(_pfunc, _pfile, _line, _pexpression); 49 | } 50 | } 51 | 52 | void __ASSERT2(const char *_pfile, int _line, const char *_pfunc, const char *_pexpression, const char *_format, ...) { 53 | va_list valist; 54 | va_start(valist, _format); 55 | __ASSERTV2(_pfile, _line, _pfunc, _pexpression, _format, valist); 56 | va_end(valist); 57 | } 58 | -------------------------------------------------------------------------------- /comm/__mtaf_assert.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | /* 15 | * assert.h 16 | * 17 | * Created on: 2012-8-6 18 | * Author: yerungui 19 | */ 20 | 21 | #ifndef MTAF_COMM_COMM_ASSERT_H_ 22 | #define MTAF_COMM_COMM_ASSERT_H_ 23 | 24 | #include 25 | #include 26 | 27 | #if (!__ISO_C_VISIBLE >= 1999) 28 | #error "C Version < C99" 29 | #endif 30 | 31 | #define MTAF_ASSERT(e) ((e) ? (void)0 : __ASSERT(__FILE__, __LINE__, __func__, #e)) 32 | #define MTAF_ASSERT2(e, fmt, ...) ((e) ? (void)0 : __ASSERT2(__FILE__, __LINE__, __func__, #e, fmt, ##__VA_ARGS__)) 33 | #define MTAF_ASSERTV2(e, fmt, valist) ((e) ? (void)0 : __ASSERTV2(__FILE__, __LINE__, __func__, #e, fmt, valist)) 34 | 35 | __BEGIN_DECLS 36 | void MTAF_ENABLE_ASSERT(); 37 | void MTAF_DISABLE_ASSERT(); 38 | int MTAF_IS_ASSERT_ENABLE(); 39 | 40 | __attribute__((__nonnull__(1, 3, 4))) void __ASSERT(const char *, int, const char *, const char *); 41 | __attribute__((__nonnull__(1, 3, 4, 5))) __attribute__((__format__(printf, 5, 6))) void __ASSERT2(const char *, int, const char *, const char *, const char *, ...); 42 | __attribute__((__nonnull__(1, 3, 4, 5))) __attribute__((__format__(printf, 5, 0))) void __ASSERTV2(const char *, int, const char *, const char *, const char *, va_list); 43 | __END_DECLS 44 | 45 | #endif /* MTAF_COMM_COMM_ASSERT_H_ */ 46 | -------------------------------------------------------------------------------- /comm/comm.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 209634FC20F4B41200207AD8 /* mtaf_time_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 209634E820F4B41200207AD8 /* mtaf_time_utils.c */; }; 11 | 209634FD20F4B41200207AD8 /* mtaf_ptrbuffer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 209634EF20F4B41200207AD8 /* mtaf_ptrbuffer.cc */; }; 12 | 209634FE20F4B41200207AD8 /* mtaf_autobuffer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 209634F120F4B41200207AD8 /* mtaf_autobuffer.cc */; }; 13 | 209634FF20F4B41200207AD8 /* __mtaf_assert.c in Sources */ = {isa = PBXBuildFile; fileRef = 209634FB20F4B41200207AD8 /* __mtaf_assert.c */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXCopyFilesBuildPhase section */ 17 | 20926E961FE509F4000DBD07 /* CopyFiles */ = { 18 | isa = PBXCopyFilesBuildPhase; 19 | buildActionMask = 2147483647; 20 | dstPath = "include/$(PRODUCT_NAME)"; 21 | dstSubfolderSpec = 16; 22 | files = ( 23 | ); 24 | runOnlyForDeploymentPostprocessing = 0; 25 | }; 26 | /* End PBXCopyFilesBuildPhase section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 20926E981FE509F4000DBD07 /* libcomm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcomm.a; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | 209634E820F4B41200207AD8 /* mtaf_time_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mtaf_time_utils.c; sourceTree = ""; }; 31 | 209634E920F4B41200207AD8 /* mtaf_compiler_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_compiler_util.h; sourceTree = ""; }; 32 | 209634EA20F4B41200207AD8 /* mtaf_spinlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_spinlock.h; sourceTree = ""; }; 33 | 209634EC20F4B41200207AD8 /* mtaf_condition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_condition.h; sourceTree = ""; }; 34 | 209634ED20F4B41200207AD8 /* mtaf_ptrbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_ptrbuffer.h; sourceTree = ""; }; 35 | 209634EE20F4B41200207AD8 /* mtaf_lock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_lock.h; sourceTree = ""; }; 36 | 209634EF20F4B41200207AD8 /* mtaf_ptrbuffer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mtaf_ptrbuffer.cc; sourceTree = ""; }; 37 | 209634F020F4B41200207AD8 /* __mtaf_assert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = __mtaf_assert.h; sourceTree = ""; }; 38 | 209634F120F4B41200207AD8 /* mtaf_autobuffer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mtaf_autobuffer.cc; sourceTree = ""; }; 39 | 209634F220F4B41200207AD8 /* mtaf_thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_thread.h; sourceTree = ""; }; 40 | 209634F320F4B41200207AD8 /* mtaf_time_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_time_utils.h; sourceTree = ""; }; 41 | 209634F420F4B41200207AD8 /* mtaf_atomic_oper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_atomic_oper.h; sourceTree = ""; }; 42 | 209634F620F4B41200207AD8 /* mtaf_autobuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_autobuffer.h; sourceTree = ""; }; 43 | 209634F720F4B41200207AD8 /* mtaf_mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_mutex.h; sourceTree = ""; }; 44 | 209634FB20F4B41200207AD8 /* __mtaf_assert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = __mtaf_assert.c; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 20926E951FE509F4000DBD07 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 20926E8F1FE509F4000DBD07 = { 59 | isa = PBXGroup; 60 | children = ( 61 | 209634E720F4B41200207AD8 /* comm */, 62 | 20926E991FE509F4000DBD07 /* Products */, 63 | ); 64 | sourceTree = ""; 65 | }; 66 | 20926E991FE509F4000DBD07 /* Products */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 20926E981FE509F4000DBD07 /* libcomm.a */, 70 | ); 71 | name = Products; 72 | sourceTree = ""; 73 | }; 74 | 209634E720F4B41200207AD8 /* comm */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 209634FB20F4B41200207AD8 /* __mtaf_assert.c */, 78 | 209634F020F4B41200207AD8 /* __mtaf_assert.h */, 79 | 209634F420F4B41200207AD8 /* mtaf_atomic_oper.h */, 80 | 209634F120F4B41200207AD8 /* mtaf_autobuffer.cc */, 81 | 209634F620F4B41200207AD8 /* mtaf_autobuffer.h */, 82 | 209634E920F4B41200207AD8 /* mtaf_compiler_util.h */, 83 | 209634EC20F4B41200207AD8 /* mtaf_condition.h */, 84 | 209634EE20F4B41200207AD8 /* mtaf_lock.h */, 85 | 209634F720F4B41200207AD8 /* mtaf_mutex.h */, 86 | 209634EF20F4B41200207AD8 /* mtaf_ptrbuffer.cc */, 87 | 209634ED20F4B41200207AD8 /* mtaf_ptrbuffer.h */, 88 | 209634EA20F4B41200207AD8 /* mtaf_spinlock.h */, 89 | 209634F220F4B41200207AD8 /* mtaf_thread.h */, 90 | 209634E820F4B41200207AD8 /* mtaf_time_utils.c */, 91 | 209634F320F4B41200207AD8 /* mtaf_time_utils.h */, 92 | ); 93 | name = comm; 94 | sourceTree = ""; 95 | }; 96 | /* End PBXGroup section */ 97 | 98 | /* Begin PBXNativeTarget section */ 99 | 20926E971FE509F4000DBD07 /* comm */ = { 100 | isa = PBXNativeTarget; 101 | buildConfigurationList = 20926EA11FE509F4000DBD07 /* Build configuration list for PBXNativeTarget "comm" */; 102 | buildPhases = ( 103 | 20926E941FE509F4000DBD07 /* Sources */, 104 | 20926E951FE509F4000DBD07 /* Frameworks */, 105 | 20926E961FE509F4000DBD07 /* CopyFiles */, 106 | ); 107 | buildRules = ( 108 | ); 109 | dependencies = ( 110 | ); 111 | name = comm; 112 | productName = comm; 113 | productReference = 20926E981FE509F4000DBD07 /* libcomm.a */; 114 | productType = "com.apple.product-type.library.static"; 115 | }; 116 | /* End PBXNativeTarget section */ 117 | 118 | /* Begin PBXProject section */ 119 | 20926E901FE509F4000DBD07 /* Project object */ = { 120 | isa = PBXProject; 121 | attributes = { 122 | LastUpgradeCheck = 1000; 123 | ORGANIZATIONNAME = meitu.com; 124 | TargetAttributes = { 125 | 20926E971FE509F4000DBD07 = { 126 | CreatedOnToolsVersion = 9.2; 127 | ProvisioningStyle = Automatic; 128 | }; 129 | }; 130 | }; 131 | buildConfigurationList = 20926E931FE509F4000DBD07 /* Build configuration list for PBXProject "comm" */; 132 | compatibilityVersion = "Xcode 8.0"; 133 | developmentRegion = en; 134 | hasScannedForEncodings = 0; 135 | knownRegions = ( 136 | en, 137 | ); 138 | mainGroup = 20926E8F1FE509F4000DBD07; 139 | productRefGroup = 20926E991FE509F4000DBD07 /* Products */; 140 | projectDirPath = ""; 141 | projectRoot = ""; 142 | targets = ( 143 | 20926E971FE509F4000DBD07 /* comm */, 144 | ); 145 | }; 146 | /* End PBXProject section */ 147 | 148 | /* Begin PBXSourcesBuildPhase section */ 149 | 20926E941FE509F4000DBD07 /* Sources */ = { 150 | isa = PBXSourcesBuildPhase; 151 | buildActionMask = 2147483647; 152 | files = ( 153 | 209634FD20F4B41200207AD8 /* mtaf_ptrbuffer.cc in Sources */, 154 | 209634FE20F4B41200207AD8 /* mtaf_autobuffer.cc in Sources */, 155 | 209634FF20F4B41200207AD8 /* __mtaf_assert.c in Sources */, 156 | 209634FC20F4B41200207AD8 /* mtaf_time_utils.c in Sources */, 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | }; 160 | /* End PBXSourcesBuildPhase section */ 161 | 162 | /* Begin XCBuildConfiguration section */ 163 | 20926E9F1FE509F4000DBD07 /* Debug */ = { 164 | isa = XCBuildConfiguration; 165 | buildSettings = { 166 | ALWAYS_SEARCH_USER_PATHS = NO; 167 | CLANG_ANALYZER_NONNULL = YES; 168 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 169 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 170 | CLANG_CXX_LIBRARY = "libc++"; 171 | CLANG_ENABLE_MODULES = YES; 172 | CLANG_ENABLE_OBJC_ARC = YES; 173 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 174 | CLANG_WARN_BOOL_CONVERSION = YES; 175 | CLANG_WARN_COMMA = YES; 176 | CLANG_WARN_CONSTANT_CONVERSION = YES; 177 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 178 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 179 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 180 | CLANG_WARN_EMPTY_BODY = YES; 181 | CLANG_WARN_ENUM_CONVERSION = YES; 182 | CLANG_WARN_INFINITE_RECURSION = YES; 183 | CLANG_WARN_INT_CONVERSION = YES; 184 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 185 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 186 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 187 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 188 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 189 | CLANG_WARN_STRICT_PROTOTYPES = YES; 190 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 191 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 192 | CLANG_WARN_UNREACHABLE_CODE = YES; 193 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 194 | CODE_SIGN_IDENTITY = "iPhone Developer"; 195 | COPY_PHASE_STRIP = NO; 196 | DEBUG_INFORMATION_FORMAT = dwarf; 197 | ENABLE_STRICT_OBJC_MSGSEND = YES; 198 | ENABLE_TESTABILITY = YES; 199 | GCC_C_LANGUAGE_STANDARD = "compiler-default"; 200 | GCC_DYNAMIC_NO_PIC = NO; 201 | GCC_NO_COMMON_BLOCKS = YES; 202 | GCC_OPTIMIZATION_LEVEL = 0; 203 | GCC_PREPROCESSOR_DEFINITIONS = ( 204 | "DEBUG=1", 205 | "$(inherited)", 206 | ); 207 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 208 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 209 | GCC_WARN_UNDECLARED_SELECTOR = YES; 210 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 211 | GCC_WARN_UNUSED_FUNCTION = YES; 212 | GCC_WARN_UNUSED_VARIABLE = YES; 213 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 214 | MTL_ENABLE_DEBUG_INFO = YES; 215 | ONLY_ACTIVE_ARCH = YES; 216 | SDKROOT = iphoneos; 217 | }; 218 | name = Debug; 219 | }; 220 | 20926EA01FE509F4000DBD07 /* Release */ = { 221 | isa = XCBuildConfiguration; 222 | buildSettings = { 223 | ALWAYS_SEARCH_USER_PATHS = NO; 224 | CLANG_ANALYZER_NONNULL = YES; 225 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 226 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 227 | CLANG_CXX_LIBRARY = "libc++"; 228 | CLANG_ENABLE_MODULES = YES; 229 | CLANG_ENABLE_OBJC_ARC = YES; 230 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 231 | CLANG_WARN_BOOL_CONVERSION = YES; 232 | CLANG_WARN_COMMA = YES; 233 | CLANG_WARN_CONSTANT_CONVERSION = YES; 234 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 236 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 237 | CLANG_WARN_EMPTY_BODY = YES; 238 | CLANG_WARN_ENUM_CONVERSION = YES; 239 | CLANG_WARN_INFINITE_RECURSION = YES; 240 | CLANG_WARN_INT_CONVERSION = YES; 241 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 242 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 243 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 244 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 245 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 246 | CLANG_WARN_STRICT_PROTOTYPES = YES; 247 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 248 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 249 | CLANG_WARN_UNREACHABLE_CODE = YES; 250 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 251 | CODE_SIGN_IDENTITY = "iPhone Developer"; 252 | COPY_PHASE_STRIP = NO; 253 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 254 | ENABLE_NS_ASSERTIONS = NO; 255 | ENABLE_STRICT_OBJC_MSGSEND = YES; 256 | GCC_C_LANGUAGE_STANDARD = "compiler-default"; 257 | GCC_NO_COMMON_BLOCKS = YES; 258 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 259 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 260 | GCC_WARN_UNDECLARED_SELECTOR = YES; 261 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 262 | GCC_WARN_UNUSED_FUNCTION = YES; 263 | GCC_WARN_UNUSED_VARIABLE = YES; 264 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 265 | MTL_ENABLE_DEBUG_INFO = NO; 266 | SDKROOT = iphoneos; 267 | VALIDATE_PRODUCT = YES; 268 | }; 269 | name = Release; 270 | }; 271 | 20926EA21FE509F4000DBD07 /* Debug */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | CODE_SIGN_STYLE = Automatic; 275 | OTHER_LDFLAGS = "-ObjC"; 276 | PRODUCT_NAME = "$(TARGET_NAME)"; 277 | SKIP_INSTALL = YES; 278 | TARGETED_DEVICE_FAMILY = "1,2"; 279 | }; 280 | name = Debug; 281 | }; 282 | 20926EA31FE509F4000DBD07 /* Release */ = { 283 | isa = XCBuildConfiguration; 284 | buildSettings = { 285 | CODE_SIGN_STYLE = Automatic; 286 | OTHER_LDFLAGS = "-ObjC"; 287 | PRODUCT_NAME = "$(TARGET_NAME)"; 288 | SKIP_INSTALL = YES; 289 | TARGETED_DEVICE_FAMILY = "1,2"; 290 | }; 291 | name = Release; 292 | }; 293 | /* End XCBuildConfiguration section */ 294 | 295 | /* Begin XCConfigurationList section */ 296 | 20926E931FE509F4000DBD07 /* Build configuration list for PBXProject "comm" */ = { 297 | isa = XCConfigurationList; 298 | buildConfigurations = ( 299 | 20926E9F1FE509F4000DBD07 /* Debug */, 300 | 20926EA01FE509F4000DBD07 /* Release */, 301 | ); 302 | defaultConfigurationIsVisible = 0; 303 | defaultConfigurationName = Release; 304 | }; 305 | 20926EA11FE509F4000DBD07 /* Build configuration list for PBXNativeTarget "comm" */ = { 306 | isa = XCConfigurationList; 307 | buildConfigurations = ( 308 | 20926EA21FE509F4000DBD07 /* Debug */, 309 | 20926EA31FE509F4000DBD07 /* Release */, 310 | ); 311 | defaultConfigurationIsVisible = 0; 312 | defaultConfigurationName = Release; 313 | }; 314 | /* End XCConfigurationList section */ 315 | }; 316 | rootObject = 20926E901FE509F4000DBD07 /* Project object */; 317 | } 318 | -------------------------------------------------------------------------------- /comm/mtaf_atomic_oper.h: -------------------------------------------------------------------------------- 1 | #ifndef MTAF_ATOMICOPER_H 2 | #define MTAF_ATOMICOPER_H 3 | 4 | #include 5 | 6 | #ifdef _WIN32 7 | #include 8 | extern "C" long __cdecl _InterlockedIncrement(long volatile *); 9 | extern "C" long __cdecl _InterlockedDecrement(long volatile *); 10 | extern "C" long __cdecl _InterlockedCompareExchange(long volatile *, long, long); 11 | extern "C" long __cdecl _InterlockedExchange(long volatile *, long); 12 | extern "C" long __cdecl _InterlockedExchangeAdd(long volatile *, long); 13 | 14 | #pragma intrinsic(_InterlockedIncrement) 15 | #pragma intrinsic(_InterlockedDecrement) 16 | #pragma intrinsic(_InterlockedCompareExchange) 17 | #pragma intrinsic(_InterlockedExchange) 18 | #pragma intrinsic(_InterlockedExchangeAdd) 19 | #endif 20 | 21 | //! Atomically increment an uint32_t by 1 22 | //! "mem": pointer to the object 23 | //! Returns the old value pointed to by mem 24 | inline uint32_t atomic_inc32(volatile uint32_t *mem); 25 | 26 | //! Atomically read an uint32_t from memory 27 | inline uint32_t atomic_read32(volatile uint32_t *mem); 28 | 29 | //! Atomically set an uint32_t in memory 30 | //! "mem": pointer to the object 31 | //! "param": val value that the object will assume 32 | inline void atomic_write32(volatile uint32_t *mem, uint32_t val); 33 | 34 | //! Compare an uint32_t's value with "cmp". 35 | //! If they are the same swap the value with "with" 36 | //! "mem": pointer to the value 37 | //! "with": what to swap it with 38 | //! "cmp": the value to compare it to 39 | //! Returns the old value of *mem 40 | inline uint32_t atomic_cas32(volatile uint32_t *mem, uint32_t with, uint32_t cmp); 41 | 42 | #ifdef _WIN32 43 | //! Atomically decrement an uint32_t by 1 44 | //! "mem": pointer to the atomic value 45 | //! Returns the old value pointed to by mem 46 | inline uint32_t atomic_dec32(volatile uint32_t *mem) { 47 | return ::_InterlockedDecrement(reinterpret_cast(mem)) + 1; 48 | } 49 | 50 | //! Atomically increment an apr_uint32_t by 1 51 | //! "mem": pointer to the object 52 | //! Returns the old value pointed to by mem 53 | inline uint32_t atomic_inc32(volatile uint32_t *mem) { 54 | return ::_InterlockedIncrement(reinterpret_cast(mem)) - 1; 55 | } 56 | 57 | //! Atomically read an uint32_t from memory 58 | inline uint32_t atomic_read32(volatile uint32_t *mem) { 59 | return *mem; 60 | } 61 | 62 | //! Atomically set an uint32_t in memory 63 | //! "mem": pointer to the object 64 | //! "param": val value that the object will assume 65 | inline void atomic_write32(volatile uint32_t *mem, uint32_t val) { 66 | ::_InterlockedExchange(reinterpret_cast(mem), val); 67 | } 68 | 69 | //! Compare an uint32_t's value with "cmp". 70 | //! If they are the same swap the value with "with" 71 | //! "mem": pointer to the value 72 | //! "with": what to swap it with 73 | //! "cmp": the value to compare it to 74 | //! Returns the old value of *mem 75 | inline uint32_t atomic_cas32(volatile uint32_t *mem, uint32_t with, uint32_t cmp) { 76 | return ::_InterlockedCompareExchange(reinterpret_cast(mem), with, cmp); 77 | } 78 | 79 | inline uint32_t atomic_add32(volatile uint32_t *mem, uint32_t val) { 80 | ::_InterlockedExchangeAdd(reinterpret_cast(mem), val); 81 | return *mem; 82 | } 83 | 84 | #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 85 | 86 | //! Compare an uint32_t's value with "cmp". 87 | //! If they are the same swap the value with "with" 88 | //! "mem": pointer to the value 89 | //! "with" what to swap it with 90 | //! "cmp": the value to compare it to 91 | //! Returns the old value of *mem 92 | inline uint32_t atomic_cas32(volatile uint32_t *mem, uint32_t with, uint32_t cmp) { 93 | uint32_t prev = cmp; 94 | // This version by Mans Rullgard of Pathscale 95 | __asm__ __volatile__("lock\n\t" 96 | "cmpxchg %2,%0" 97 | : "+m"(*mem), "+a"(prev) 98 | : "r"(with) 99 | : "cc"); 100 | 101 | return prev; 102 | } 103 | 104 | //! Atomically add 'val' to an uint32_t 105 | //! "mem": pointer to the object 106 | //! "val": amount to add 107 | //! Returns the old value pointed to by mem 108 | inline uint32_t atomic_add32(volatile uint32_t *mem, uint32_t val) { 109 | // int r = *pw; 110 | // *mem += val; 111 | // return r; 112 | int r; 113 | 114 | asm volatile( 115 | "lock\n\t" 116 | "xadd %1, %0" 117 | : "+m"(*mem), "=r"(r) 118 | : // outputs (%0, %1) 119 | "1"(val) 120 | : // inputs (%2 == %1) 121 | "memory", "cc" // clobbers 122 | ); 123 | 124 | return r; 125 | } 126 | 127 | //! Atomically increment an apr_uint32_t by 1 128 | //! "mem": pointer to the object 129 | //! Returns the old value pointed to by mem 130 | inline uint32_t atomic_inc32(volatile uint32_t *mem) { 131 | return atomic_add32(mem, 1); 132 | } 133 | 134 | //! Atomically decrement an uint32_t by 1 135 | //! "mem": pointer to the atomic value 136 | //! Returns the old value pointed to by mem 137 | inline uint32_t atomic_dec32(volatile uint32_t *mem) { 138 | return atomic_add32(mem, (uint32_t)-1); 139 | } 140 | 141 | //! Atomically read an uint32_t from memory 142 | inline uint32_t atomic_read32(volatile uint32_t *mem) { 143 | const uint32_t val = *mem; 144 | __asm__ __volatile__("" :: 145 | : "memory"); 146 | return val; 147 | } 148 | 149 | //! Atomically set an uint32_t in memory 150 | //! "mem": pointer to the object 151 | //! "param": val value that the object will assume 152 | inline void atomic_write32(volatile uint32_t *mem, uint32_t val) { 153 | __asm__ __volatile__( 154 | "xchgl %0, %1" 155 | : "+r"(val), "+m"(*mem)::"memory"); 156 | } 157 | 158 | #elif defined(__GNUC__) && (defined(__PPC__) || defined(__ppc__)) 159 | 160 | //! Atomically add 'val' to an uint32_t 161 | //! "mem": pointer to the object 162 | //! "val": amount to add 163 | //! Returns the old value pointed to by mem 164 | inline uint32_t atomic_add32(volatile uint32_t *mem, uint32_t val) { 165 | uint32_t prev, temp; 166 | 167 | asm volatile("1:\n\t" 168 | "lwarx %0,0,%2\n\t" 169 | "add %1,%0,%3\n\t" 170 | "stwcx. %1,0,%2\n\t" 171 | "bne- 1b" 172 | : "=&r"(prev), "=&r"(temp) 173 | : "b"(mem), "r"(val) 174 | : "cc", "memory"); 175 | return prev; 176 | } 177 | 178 | //! Compare an uint32_t's value with "cmp". 179 | //! If they are the same swap the value with "with" 180 | //! "mem": pointer to the value 181 | //! "with" what to swap it with 182 | //! "cmp": the value to compare it to 183 | //! Returns the old value of *mem 184 | inline uint32_t atomic_cas32(volatile uint32_t *mem, uint32_t with, uint32_t cmp) { 185 | uint32_t prev; 186 | 187 | asm volatile("1:\n\t" 188 | "lwarx %0,0,%1\n\t" 189 | "cmpw %0,%3\n\t" 190 | "bne- 2f\n\t" 191 | "stwcx. %2,0,%1\n\t" 192 | "bne- 1b\n\t" 193 | "2:" 194 | : "=&r"(prev) 195 | : "b"(mem), "r"(cmp), "r"(with) 196 | : "cc", "memory"); 197 | return prev; 198 | } 199 | 200 | //! Atomically increment an apr_uint32_t by 1 201 | //! "mem": pointer to the object 202 | //! Returns the old value pointed to by mem 203 | inline uint32_t atomic_inc32(volatile uint32_t *mem) { 204 | return atomic_add32(mem, 1); 205 | } 206 | 207 | //! Atomically decrement an uint32_t by 1 208 | //! "mem": pointer to the atomic value 209 | //! Returns the old value pointed to by mem 210 | inline uint32_t atomic_dec32(volatile uint32_t *mem) { 211 | return atomic_add32(mem, uint32_t(-1u)); 212 | } 213 | 214 | //! Atomically read an uint32_t from memory 215 | inline uint32_t atomic_read32(volatile uint32_t *mem) { 216 | const uint32_t val = *mem; 217 | __asm__ __volatile__("" :: 218 | : "memory"); 219 | return val; 220 | } 221 | 222 | //! Atomically set an uint32_t in memory 223 | //! "mem": pointer to the object 224 | //! "param": val value that the object will assume 225 | inline void atomic_write32(volatile uint32_t *mem, uint32_t val) { 226 | *mem = val; 227 | } 228 | 229 | 230 | #elif (defined(sun) || defined(__sun)) 231 | 232 | #include 233 | 234 | //! Atomically add 'val' to an uint32_t 235 | //! "mem": pointer to the object 236 | //! "val": amount to add 237 | //! Returns the old value pointed to by mem 238 | inline uint32_t atomic_add32(volatile uint32_t *mem, uint32_t val) { 239 | return atomic_add_32_nv(reinterpret_cast(mem), (int32_t)val) - val; 240 | } 241 | 242 | //! Compare an uint32_t's value with "cmp". 243 | //! If they are the same swap the value with "with" 244 | //! "mem": pointer to the value 245 | //! "with" what to swap it with 246 | //! "cmp": the value to compare it to 247 | //! Returns the old value of *mem 248 | inline uint32_t atomic_cas32(volatile uint32_t *mem, uint32_t with, uint32_t cmp) { 249 | return atomic_cas_32(reinterpret_cast(mem), cmp, with); 250 | } 251 | 252 | //! Atomically increment an apr_uint32_t by 1 253 | //! "mem": pointer to the object 254 | //! Returns the old value pointed to by mem 255 | inline uint32_t atomic_inc32(volatile uint32_t *mem) { 256 | return atomic_add_32_nv(reinterpret_cast(mem), 1) - 1; 257 | } 258 | 259 | //! Atomically decrement an uint32_t by 1 260 | //! "mem": pointer to the atomic value 261 | //! Returns the old value pointed to by mem 262 | inline uint32_t atomic_dec32(volatile uint32_t *mem) { 263 | return atomic_add_32_nv(reinterpret_cast(mem), (uint32_t)-1) + 1; 264 | } 265 | 266 | //! Atomically read an uint32_t from memory 267 | inline uint32_t atomic_read32(volatile uint32_t *mem) { 268 | return *mem; 269 | } 270 | 271 | //! Atomically set an uint32_t in memory 272 | //! "mem": pointer to the object 273 | //! "param": val value that the object will assume 274 | inline void atomic_write32(volatile uint32_t *mem, uint32_t val) { 275 | *mem = val; 276 | } 277 | 278 | #elif defined(__osf__) && defined(__DECCXX) 279 | 280 | #include 281 | #include 282 | 283 | //! Atomically decrement a uint32_t by 1 284 | //! "mem": pointer to the atomic value 285 | //! Returns the old value pointed to by mem 286 | //! Acquire, memory barrier after decrement. 287 | inline uint32_t atomic_dec32(volatile uint32_t *mem) { 288 | uint32_t old_val = __ATOMIC_DECREMENT_LONG(mem); 289 | __MB(); 290 | return old_val; 291 | } 292 | 293 | //! Atomically increment a uint32_t by 1 294 | //! "mem": pointer to the object 295 | //! Returns the old value pointed to by mem 296 | //! Release, memory barrier before increment. 297 | inline uint32_t atomic_inc32(volatile uint32_t *mem) { 298 | __MB(); 299 | return __ATOMIC_INCREMENT_LONG(mem); 300 | } 301 | 302 | // Rational for the implementation of the atomic read and write functions. 303 | // 304 | // 1. The Alpha Architecture Handbook requires that access to a byte, 305 | // an aligned word, an aligned longword, or an aligned quadword is 306 | // atomic. (See 'Alpha Architecture Handbook', version 4, chapter 5.2.2.) 307 | // 308 | // 2. The CXX User's Guide states that volatile quantities are accessed 309 | // with single assembler instructions, and that a compilation error 310 | // occurs when declaring a quantity as volatile which is not properly 311 | // aligned. 312 | 313 | //! Atomically read an uint32_t from memory 314 | //! Acquire, memory barrier after load. 315 | inline uint32_t atomic_read32(volatile uint32_t *mem) { 316 | uint32_t old_val = *mem; 317 | __MB(); 318 | return old_val; 319 | } 320 | 321 | //! Atomically set an uint32_t in memory 322 | //! "mem": pointer to the object 323 | //! "param": val value that the object will assume 324 | //! Release, memory barrier before store. 325 | inline void atomic_write32(volatile uint32_t *mem, uint32_t val) { 326 | __MB(); 327 | *mem = val; 328 | } 329 | 330 | //! Compare an uint32_t's value with "cmp". 331 | //! If they are the same swap the value with "with" 332 | //! "mem": pointer to the value 333 | //! "with" what to swap it with 334 | //! "cmp": the value to compare it to 335 | //! Returns the old value of *mem 336 | //! Memory barrier between load and store. 337 | inline uint32_t atomic_cas32( 338 | volatile uint32_t *mem, uint32_t with, uint32_t cmp) { 339 | // Note: 340 | // 341 | // Branch prediction prefers backward branches, and the Alpha Architecture 342 | // Handbook explicitely states that the loop should not be implemented like 343 | // it is below. (See chapter 4.2.5.) Therefore the code should probably look 344 | // like this: 345 | // 346 | // return asm( 347 | // "10: ldl_l %v0,(%a0) ;" 348 | // " cmpeq %v0,%a2,%t0 ;" 349 | // " beq %t0,20f ;" 350 | // " mb ;" 351 | // " mov %a1,%t0 ;" 352 | // " stl_c %t0,(%a0) ;" 353 | // " beq %t0,30f ;" 354 | // "20: ret ;" 355 | // "30: br 10b;", 356 | // mem, with, cmp); 357 | // 358 | // But as the compiler always transforms this into the form where a backward 359 | // branch is taken on failure, we can as well implement it in the straight 360 | // forward form, as this is what it will end up in anyway. 361 | 362 | return asm( 363 | "10: ldl_l %v0,(%a0) ;" // load prev value from mem and lock mem 364 | " cmpeq %v0,%a2,%t0 ;" // compare with given value 365 | " beq %t0,20f ;" // if not equal, we're done 366 | " mb ;" // memory barrier 367 | " mov %a1,%t0 ;" // load new value into scratch register 368 | " stl_c %t0,(%a0) ;" // store new value to locked mem (overwriting scratch) 369 | " beq %t0,10b ;" // store failed because lock has been stolen, retry 370 | "20: ", 371 | mem, with, cmp); 372 | } 373 | 374 | 375 | #elif defined(__IBMCPP__) && (__IBMCPP__ >= 800) && defined(_AIX) 376 | 377 | #include 378 | 379 | // first define uint32_t versions of __lwarx and __stwcx to avoid poluting 380 | // all the functions with casts 381 | 382 | //! From XLC documenation : 383 | //! This function can be used with a subsequent stwcxu call to implement a 384 | //! read-modify-write on a specified memory location. The two functions work 385 | //! together to ensure that if the store is successfully performed, no other 386 | //! processor or mechanism can modify the target doubleword between the time 387 | //! lwarxu function is executed and the time the stwcxu functio ncompletes. 388 | //! "mem" : pointer to the object 389 | //! Returns the value at pointed to by mem 390 | inline uint32_t lwarxu(volatile uint32_t *mem) { 391 | return static_cast(__lwarx(reinterpret_cast(mem))); 392 | } 393 | 394 | //! "mem" : pointer to the object 395 | //! "val" : the value to store 396 | //! Returns true if the update of mem is successful and false if it is 397 | // !unsuccessful 398 | inline bool stwcxu(volatile uint32_t *mem, uint32_t val) { 399 | return (__stwcx(reinterpret_cast(mem), static_cast(val)) != 0); 400 | } 401 | 402 | //! "mem": pointer to the object 403 | //! "val": amount to add 404 | //! Returns the old value pointed to by mem 405 | inline uint32_t atomic_add32(volatile uint32_t *mem, uint32_t val) { 406 | uint32_t oldValue; 407 | do { 408 | oldValue = lwarxu(mem); 409 | } while (!stwcxu(mem, oldValue + val)); 410 | return oldValue; 411 | } 412 | 413 | //! Atomically increment an apr_uint32_t by 1 414 | //! "mem": pointer to the object 415 | //! Returns the old value pointed to by mem 416 | inline uint32_t atomic_inc32(volatile uint32_t *mem) { 417 | return atomic_add32(mem, 1); 418 | } 419 | 420 | //! Atomically decrement an uint32_t by 1 421 | //! "mem": pointer to the atomic value 422 | //! Returns the old value pointed to by mem 423 | inline uint32_t atomic_dec32(volatile uint32_t *mem) { 424 | return atomic_add32(mem, (uint32_t)-1); 425 | } 426 | 427 | //! Atomically read an uint32_t from memory 428 | inline uint32_t atomic_read32(volatile uint32_t *mem) { 429 | return *mem; 430 | } 431 | 432 | //! Compare an uint32_t's value with "cmp". 433 | //! If they are the same swap the value with "with" 434 | //! "mem": pointer to the value 435 | //! "with" what to swap it with 436 | //! "cmp": the value to compare it to 437 | //! Returns the old value of *mem 438 | inline uint32_t atomic_cas32(volatile uint32_t *mem, uint32_t with, uint32_t cmp) { 439 | uint32_t oldValue; 440 | uint32_t valueToStore; 441 | do { 442 | oldValue = lwarxu(mem); 443 | } while (!stwcxu(mem, (oldValue == with) ? cmp : oldValue)); 444 | 445 | return oldValue; 446 | } 447 | 448 | //! Atomically set an uint32_t in memory 449 | //! "mem": pointer to the object 450 | //! "param": val value that the object will assume 451 | inline void atomic_write32(volatile uint32_t *mem, uint32_t val) { 452 | *mem = val; 453 | } 454 | 455 | #elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) 456 | 457 | //! Atomically add 'val' to an uint32_t 458 | //! "mem": pointer to the object 459 | //! "val": amount to add 460 | //! Returns the old value pointed to by mem 461 | inline uint32_t atomic_add32(volatile uint32_t *mem, uint32_t val) { 462 | return __sync_fetch_and_add(const_cast(mem), val); 463 | } 464 | 465 | //! Atomically increment an apr_uint32_t by 1 466 | //! "mem": pointer to the object 467 | //! Returns the old value pointed to by mem 468 | inline uint32_t atomic_inc32(volatile uint32_t *mem) { 469 | return atomic_add32(mem, 1); 470 | } 471 | 472 | //! Atomically decrement an uint32_t by 1 473 | //! "mem": pointer to the atomic value 474 | //! Returns the old value pointed to by mem 475 | inline uint32_t atomic_dec32(volatile uint32_t *mem) { 476 | return atomic_add32(mem, (uint32_t)-1); 477 | } 478 | 479 | //! Atomically read an uint32_t from memory 480 | inline uint32_t atomic_read32(volatile uint32_t *mem) { 481 | uint32_t old_val = *mem; 482 | __sync_synchronize(); 483 | return old_val; 484 | } 485 | 486 | //! Compare an uint32_t's value with "cmp". 487 | //! If they are the same swap the value with "with" 488 | //! "mem": pointer to the value 489 | //! "with" what to swap it with 490 | //! "cmp": the value to compare it to 491 | //! Returns the old value of *mem 492 | inline uint32_t atomic_cas32(volatile uint32_t *mem, uint32_t with, uint32_t cmp) { 493 | return __sync_val_compare_and_swap(const_cast(mem), cmp, with); 494 | } 495 | 496 | //! Atomically set an uint32_t in memory 497 | //! "mem": pointer to the object 498 | //! "param": val value that the object will assume 499 | inline void atomic_write32(volatile uint32_t *mem, uint32_t val) { 500 | __sync_synchronize(); 501 | *mem = val; 502 | } 503 | 504 | 505 | #else 506 | 507 | #error No atomic operations implemented for this platform, sorry! 508 | 509 | #endif 510 | 511 | //inline bool atomic_add_unless32(volatile uint32_t *mem, uint32_t value, uint32_t unless_this) { 512 | // uint32_t old, c(atomic_read32(mem)); 513 | // while (c != unless_this && (old = atomic_cas32(mem, c + value, c)) != c) { 514 | // c = old; 515 | // } 516 | // return c != unless_this; 517 | //} 518 | 519 | 520 | #endif 521 | -------------------------------------------------------------------------------- /comm/mtaf_autobuffer.cc: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | #include "mtaf_autobuffer.h" 15 | #include 16 | #include 17 | 18 | #include "__mtaf_assert.h" 19 | using namespace MTAppenderFile; 20 | 21 | const AutoBuffer KNullAtuoBuffer; 22 | 23 | #ifndef max 24 | #define max(a, b) (((a) > (b)) ? (a) : (b)) 25 | #endif 26 | #ifndef min 27 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 28 | #endif 29 | 30 | AutoBuffer::AutoBuffer(size_t _nSize) 31 | : parray_(NULL) 32 | , pos_(0) 33 | , length_(0) 34 | , capacity_(0) 35 | , malloc_unitsize_(_nSize) {} 36 | 37 | 38 | AutoBuffer::AutoBuffer(void *_pbuffer, size_t _len, size_t _nSize) 39 | : parray_(NULL) 40 | , pos_(0) 41 | , length_(0) 42 | , capacity_(0) 43 | , malloc_unitsize_(_nSize) { 44 | Attach(_pbuffer, _len); 45 | } 46 | 47 | AutoBuffer::AutoBuffer(const void *_pbuffer, size_t _len, size_t _nSize) 48 | : parray_(NULL) 49 | , pos_(0) 50 | , length_(0) 51 | , capacity_(0) 52 | , malloc_unitsize_(_nSize) { 53 | Write(0, _pbuffer, _len); 54 | } 55 | 56 | 57 | AutoBuffer::~AutoBuffer() { 58 | Reset(); 59 | } 60 | 61 | void AutoBuffer::AllocWrite(size_t _readytowrite, bool _changelength) { 62 | size_t nLen = (size_t)(Pos() + _readytowrite); 63 | __FitSize(nLen); 64 | 65 | if (_changelength) length_ = max(nLen, length_); 66 | } 67 | 68 | void AutoBuffer::AddCapacity(size_t _len) { 69 | __FitSize(Capacity() + _len); 70 | } 71 | 72 | void AutoBuffer::Write(const void *_pbuffer, size_t _len) { 73 | Write(Pos(), _pbuffer, _len); 74 | Seek(_len, ESeekCur); 75 | } 76 | 77 | void AutoBuffer::Write(off_t &_pos, const void *_pbuffer, size_t _len) { 78 | Write((const off_t &)_pos, _pbuffer, _len); 79 | _pos += _len; 80 | } 81 | 82 | void AutoBuffer::Write(const off_t &_pos, const void *_pbuffer, size_t _len) { 83 | MTAF_ASSERT(NULL != _pbuffer || 0 == _len); 84 | MTAF_ASSERT(0 <= _pos); 85 | MTAF_ASSERT((size_t)_pos <= Length()); 86 | size_t nLen = (size_t)(_pos + _len); 87 | __FitSize(nLen); 88 | length_ = max(nLen, length_); 89 | memcpy((unsigned char *)Ptr() + _pos, _pbuffer, _len); 90 | } 91 | 92 | void AutoBuffer::Write(TSeek _seek, const void *_pbuffer, size_t _len) { 93 | off_t pos = 0; 94 | switch (_seek) { 95 | case ESeekStart: 96 | pos = 0; 97 | break; 98 | case ESeekCur: 99 | pos = pos_; 100 | break; 101 | case ESeekEnd: 102 | pos = length_; 103 | break; 104 | default: 105 | MTAF_ASSERT(false); 106 | break; 107 | } 108 | 109 | Write(pos, _pbuffer, _len); 110 | } 111 | 112 | size_t AutoBuffer::Read(void *_pbuffer, size_t _len) { 113 | size_t readlen = Read(Pos(), _pbuffer, _len); 114 | Seek(readlen, ESeekCur); 115 | return readlen; 116 | } 117 | 118 | size_t AutoBuffer::Read(AutoBuffer &_rhs, size_t _len) { 119 | size_t readlen = Read(Pos(), _rhs, _len); 120 | Seek(readlen, ESeekCur); 121 | return readlen; 122 | } 123 | 124 | size_t AutoBuffer::Read(off_t &_pos, void *_pbuffer, size_t _len) const { 125 | size_t readlen = Read((const off_t &)_pos, _pbuffer, _len); 126 | _pos += readlen; 127 | return readlen; 128 | } 129 | 130 | size_t AutoBuffer::Read(off_t &_pos, AutoBuffer &_rhs, size_t _len) const { 131 | size_t readlen = Read((const off_t &)_pos, _rhs, _len); 132 | _pos += readlen; 133 | return readlen; 134 | } 135 | 136 | size_t AutoBuffer::Read(const off_t &_pos, void *_pbuffer, size_t _len) const { 137 | MTAF_ASSERT(NULL != _pbuffer); 138 | MTAF_ASSERT(0 <= _pos); 139 | MTAF_ASSERT((size_t)_pos <= Length()); 140 | 141 | size_t readlen = (size_t)(Length() - _pos); 142 | readlen = min(readlen, _len); 143 | memcpy(_pbuffer, PosPtr(), readlen); 144 | return readlen; 145 | } 146 | 147 | size_t AutoBuffer::Read(const off_t &_pos, AutoBuffer &_rhs, size_t _len) const { 148 | size_t readlen = (size_t)(Length() - _pos); 149 | readlen = min(readlen, _len); 150 | _rhs.Write(PosPtr(), readlen); 151 | return readlen; 152 | } 153 | 154 | off_t AutoBuffer::Move(off_t _move_len) { 155 | if (0 < _move_len) { 156 | if (__FitSize((size_t)(Length() + _move_len))) { 157 | memmove(parray_ + _move_len, parray_, Length()); 158 | memset(parray_, 0, (size_t)_move_len); 159 | Length(Pos() + _move_len, (size_t)(Length() + _move_len)); 160 | } 161 | } else { 162 | size_t move_len = (size_t)-_move_len; 163 | 164 | if (move_len > Length()) move_len = Length(); 165 | 166 | memmove(parray_, parray_ + move_len, Length() - move_len); 167 | Length(move_len < (size_t)Pos() ? Pos() - move_len : 0, Length() - move_len); 168 | } 169 | 170 | return Length(); 171 | } 172 | 173 | void AutoBuffer::Seek(off_t _offset, TSeek _eorigin) { 174 | switch (_eorigin) { 175 | case ESeekStart: 176 | pos_ = _offset; 177 | break; 178 | 179 | case ESeekCur: 180 | pos_ += _offset; 181 | break; 182 | 183 | case ESeekEnd: 184 | pos_ = length_ + _offset; 185 | break; 186 | 187 | default: 188 | MTAF_ASSERT(false); 189 | break; 190 | } 191 | 192 | if (pos_ < 0) 193 | pos_ = 0; 194 | 195 | if ((size_t)pos_ > length_) 196 | pos_ = length_; 197 | } 198 | 199 | void AutoBuffer::Length(off_t _pos, size_t _lenght) { 200 | MTAF_ASSERT(0 <= _pos); 201 | MTAF_ASSERT((size_t)_pos <= _lenght); 202 | MTAF_ASSERT(_lenght <= Capacity()); 203 | length_ = _lenght; 204 | Seek(_pos, ESeekStart); 205 | } 206 | 207 | void *AutoBuffer::Ptr(off_t _offset) { 208 | return (char *)parray_ + _offset; 209 | } 210 | 211 | const void *AutoBuffer::Ptr(off_t _offset) const { 212 | return (const char *)parray_ + _offset; 213 | } 214 | 215 | void *AutoBuffer::PosPtr() { 216 | return ((unsigned char *)Ptr()) + Pos(); 217 | } 218 | 219 | const void *AutoBuffer::PosPtr() const { 220 | return ((unsigned char *)Ptr()) + Pos(); 221 | } 222 | 223 | off_t AutoBuffer::Pos() const { 224 | return pos_; 225 | } 226 | 227 | size_t AutoBuffer::PosLength() const { 228 | return (size_t)(length_ - pos_); 229 | } 230 | 231 | size_t AutoBuffer::Length() const { 232 | return length_; 233 | } 234 | 235 | size_t AutoBuffer::Capacity() const { 236 | return capacity_; 237 | } 238 | 239 | void AutoBuffer::Attach(void *_pbuffer, size_t _len) { 240 | Reset(); 241 | parray_ = (unsigned char *)_pbuffer; 242 | length_ = _len; 243 | capacity_ = _len; 244 | } 245 | 246 | void AutoBuffer::Attach(AutoBuffer &_rhs) { 247 | Reset(); 248 | parray_ = _rhs.parray_; 249 | pos_ = _rhs.pos_; 250 | length_ = _rhs.length_; 251 | capacity_ = _rhs.capacity_; 252 | 253 | _rhs.parray_ = NULL; 254 | _rhs.Reset(); 255 | } 256 | 257 | void *AutoBuffer::Detach(size_t *_plen) { 258 | unsigned char *ret = parray_; 259 | parray_ = NULL; 260 | size_t nLen = Length(); 261 | 262 | if (NULL != _plen) 263 | *_plen = nLen; 264 | 265 | Reset(); 266 | return ret; 267 | } 268 | 269 | void AutoBuffer::Reset() { 270 | if (NULL != parray_) 271 | free(parray_); 272 | 273 | parray_ = NULL; 274 | pos_ = 0; 275 | length_ = 0; 276 | capacity_ = 0; 277 | } 278 | 279 | bool AutoBuffer::__FitSize(size_t _len) { 280 | if (_len > capacity_) { 281 | size_t mallocsize = ((_len + malloc_unitsize_ - 1) / malloc_unitsize_) * malloc_unitsize_; 282 | 283 | void *p = realloc(parray_, mallocsize); 284 | 285 | if (NULL == p) { 286 | MTAF_ASSERT2(p, "_len=%lld, m_nMallocUnitSize=%lld, nMallocSize=%lld, m_nCapacity=%lld", 287 | (uint64_t)_len, (uint64_t)malloc_unitsize_, (uint64_t)mallocsize, (uint64_t)capacity_); 288 | free(parray_); 289 | parray_ = NULL; 290 | return false; 291 | } 292 | 293 | parray_ = (unsigned char *)p; 294 | 295 | MTAF_ASSERT2(_len <= 10 * 1024 * 1024, "%u", (uint32_t)_len); 296 | MTAF_ASSERT(parray_); 297 | 298 | memset(parray_ + capacity_, 0, mallocsize - capacity_); 299 | capacity_ = mallocsize; 300 | return true; 301 | } 302 | return true; 303 | } 304 | -------------------------------------------------------------------------------- /comm/mtaf_autobuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | 15 | #ifndef MTAF_COMM_AUTOBUFFER_H_ 16 | #define MTAF_COMM_AUTOBUFFER_H_ 17 | 18 | #include 19 | #include 20 | 21 | namespace MTAppenderFile { 22 | class AutoBuffer; 23 | } 24 | 25 | class MTAppenderFile::AutoBuffer 26 | { 27 | public: 28 | enum TSeek { 29 | ESeekStart, 30 | ESeekCur, 31 | ESeekEnd, 32 | }; 33 | 34 | public: 35 | explicit AutoBuffer(size_t _size = 128); 36 | explicit AutoBuffer(void *_pbuffer, size_t _len, size_t _size = 128); 37 | explicit AutoBuffer(const void *_pbuffer, size_t _len, size_t _size = 128); 38 | ~AutoBuffer(); 39 | 40 | void AllocWrite(size_t _readytowrite, bool _changelength = true); 41 | void AddCapacity(size_t _len); 42 | 43 | template 44 | void Write(const T &_val) { Write(&_val, sizeof(_val)); } 45 | 46 | template 47 | void Write(off_t &_pos, const T &_val) { Write(_pos, &_val, sizeof(_val)); } 48 | 49 | template 50 | void Write(const off_t &_pos, const T &_val) { Write(_pos, &_val, sizeof(_val)); } 51 | 52 | void Write(const char *const _val) { Write(_val, strlen(_val)); } 53 | 54 | void Write(off_t &_pos, const char *const _val) { Write(_pos, _val, strlen(_val)); } 55 | 56 | void Write(const off_t &_pos, const char *const _val) { Write(_pos, _val, strlen(_val)); } 57 | 58 | void Write(const void *_pbuffer, size_t _len); 59 | void Write(off_t &_pos, const void *_pbuffer, size_t _len); 60 | void Write(const off_t &_pos, const void *_pbuffer, size_t _len); 61 | void Write(TSeek _seek, const void *_pbuffer, size_t _len); 62 | 63 | template 64 | size_t Read(T &_val) { return Read(&_val, sizeof(_val)); } 65 | 66 | template 67 | size_t Read(off_t &_pos, T &_val) const { return Read(_pos, &_val, sizeof(_val)); } 68 | 69 | template 70 | size_t Read(const off_t &_pos, T &_val) const { return Read(_pos, &_val, sizeof(_val)); } 71 | 72 | size_t Read(void *_pbuffer, size_t _len); 73 | size_t Read(AutoBuffer &_rhs, size_t _len); 74 | 75 | size_t Read(off_t &_pos, void *_pbuffer, size_t _len) const; 76 | size_t Read(off_t &_pos, AutoBuffer &_rhs, size_t _len) const; 77 | 78 | size_t Read(const off_t &_pos, void *_pbuffer, size_t _len) const; 79 | size_t Read(const off_t &_pos, AutoBuffer &_rhs, size_t _len) const; 80 | 81 | off_t Move(off_t _move_len); 82 | 83 | void Seek(off_t _offset, TSeek _eorigin); 84 | void Length(off_t _pos, size_t _lenght); 85 | 86 | void *Ptr(off_t _offset = 0); 87 | void *PosPtr(); 88 | const void *Ptr(off_t _offset = 0) const; 89 | const void *PosPtr() const; 90 | 91 | off_t Pos() const; 92 | size_t PosLength() const; 93 | size_t Length() const; 94 | size_t Capacity() const; 95 | 96 | void Attach(void *_pbuffer, size_t _len); 97 | void Attach(AutoBuffer &_rhs); 98 | void *Detach(size_t *_plen = NULL); 99 | 100 | void Reset(); 101 | 102 | private: 103 | bool __FitSize(size_t _len); 104 | 105 | private: 106 | AutoBuffer(const AutoBuffer &_rhs); 107 | AutoBuffer &operator=(const AutoBuffer &_rhs); 108 | 109 | private: 110 | unsigned char *parray_; 111 | off_t pos_; 112 | size_t length_; 113 | size_t capacity_; 114 | size_t malloc_unitsize_; 115 | }; 116 | 117 | extern const MTAppenderFile::AutoBuffer KNullAtuoBuffer; 118 | 119 | namespace MTAppenderFile { 120 | template 121 | class copy_wrapper_helper; 122 | } 123 | 124 | template <> 125 | class MTAppenderFile::copy_wrapper_helper 126 | { 127 | public: 128 | static void copy_constructor(MTAppenderFile::AutoBuffer &_lhs, MTAppenderFile::AutoBuffer &_rhs) { _lhs.Attach(_rhs); } 129 | 130 | static void copy_constructor(MTAppenderFile::AutoBuffer &_lhs, const MTAppenderFile::AutoBuffer &_rhs) { _lhs.Attach(const_cast(_rhs)); } 131 | 132 | static void destructor(MTAppenderFile::AutoBuffer &_delobj) {} 133 | }; 134 | 135 | #endif // MTAF_COMM_AUTOBUFFER_H_ 136 | -------------------------------------------------------------------------------- /comm/mtaf_compiler_util.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | /* 15 | * mtaf_compiler_util.h 16 | * 17 | * Created on: 2013-11-15 18 | * Author: yerungui 19 | */ 20 | 21 | #ifndef MTAF_COMM_COMPILER_UTIL_H_ 22 | #define MTAF_COMM_COMPILER_UTIL_H_ 23 | 24 | #if defined(__GNUC__) 25 | #define WEAK_FUNC __attribute__((weak)) 26 | #elif defined(_MSC_VER) && !defined(_LIB) 27 | #define WEAK_FUNC __declspec(selectany) 28 | #else 29 | #define WEAK_FUNC 30 | #endif 31 | 32 | #if defined(__GNUC__) 33 | #define EXPORT_FUNC __attribute__((visibility("default"))) 34 | #elif defined(_MSC_VER) 35 | #define EXPORT_FUNC __declspec(dllexport) 36 | #else 37 | #error "export" 38 | #endif 39 | 40 | #ifndef VARIABLE_IS_NOT_USED 41 | #ifdef __GNUC__ 42 | #define VARIABLE_IS_NOT_USED __attribute__((unused)) 43 | #else 44 | #define VARIABLE_IS_NOT_USED 45 | #endif 46 | #endif 47 | 48 | #endif /* MTAF_COMM_COMPILER_UTIL_H_ */ 49 | -------------------------------------------------------------------------------- /comm/mtaf_condition.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | 15 | #ifndef MTAF_CONDITION_H_ 16 | #define MTAF_CONDITION_H_ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "__mtaf_assert.h" 23 | #include "mtaf_atomic_oper.h" 24 | #include "mtaf_lock.h" 25 | 26 | namespace MTAppenderFile { 27 | class Condition; 28 | } 29 | 30 | class MTAppenderFile::Condition 31 | { 32 | public: 33 | Condition() 34 | : condition_() 35 | , mutex_() 36 | , anyway_notify_(0) { 37 | int ret = pthread_cond_init(&condition_, 0); 38 | 39 | if (EAGAIN == ret) 40 | MTAF_ASSERT(0 == EAGAIN); 41 | else if (ENOMEM == ret) 42 | MTAF_ASSERT(0 == ENOMEM); 43 | else if (EBUSY == ret) 44 | MTAF_ASSERT(0 == EBUSY); 45 | else if (EINVAL == ret) 46 | MTAF_ASSERT(0 == EINVAL); 47 | else if (0 != ret) 48 | MTAF_ASSERT2(0 == ret, "%d", ret); 49 | } 50 | 51 | ~Condition() { 52 | int ret = pthread_cond_destroy(&condition_); 53 | 54 | if (EBUSY == ret) 55 | MTAF_ASSERT(0 == EBUSY); 56 | else if (EINVAL == ret) 57 | MTAF_ASSERT(0 == EINVAL); 58 | else if (0 != ret) 59 | MTAF_ASSERT2(0 == ret, "%d", ret); 60 | } 61 | 62 | void wait(ScopedLock &lock) { 63 | MTAF_ASSERT(lock.islocked()); 64 | 65 | int ret = 0; 66 | 67 | if (!atomic_cas32(&anyway_notify_, 0, 1)) { 68 | ret = pthread_cond_wait(&condition_, &(lock.internal().internal())); 69 | } 70 | 71 | anyway_notify_ = 0; 72 | 73 | if (EPERM == ret) 74 | MTAF_ASSERT(0 == EPERM); 75 | else if (EINVAL == ret) 76 | MTAF_ASSERT(0 == EINVAL); 77 | else if (0 != ret) 78 | MTAF_ASSERT2(0 == ret, "%d", ret); 79 | } 80 | 81 | int wait(ScopedLock &lock, long millisecond) { 82 | MTAF_ASSERT(lock.islocked()); 83 | struct timespec ts; 84 | makeTimeout(&ts, millisecond); 85 | 86 | int ret = 0; 87 | 88 | if (!atomic_cas32(&anyway_notify_, 0, 1)) { 89 | ret = pthread_cond_timedwait(&condition_, &(lock.internal().internal()), &ts); 90 | } 91 | 92 | anyway_notify_ = 0; 93 | 94 | if (ETIMEDOUT == ret || 0 == ret) return ret; 95 | 96 | if (EPERM == ret) 97 | MTAF_ASSERT(0 == EPERM); 98 | else if (EINVAL == ret) 99 | MTAF_ASSERT(0 == EINVAL); 100 | else if (0 != ret) 101 | MTAF_ASSERT2(0 == ret, "%d", ret); 102 | 103 | return ret; 104 | } 105 | 106 | void wait() { 107 | ScopedLock scopedLock(mutex_); 108 | wait(scopedLock); 109 | } 110 | 111 | int wait(long millisecond) { 112 | ScopedLock scopedLock(mutex_); 113 | return wait(scopedLock, millisecond); 114 | } 115 | 116 | void notifyOne() { 117 | int ret = pthread_cond_signal(&condition_); 118 | 119 | if (EINVAL == ret) 120 | MTAF_ASSERT(0 == EINVAL); 121 | else if (0 != ret) 122 | MTAF_ASSERT2(0 == ret, "%d", ret); 123 | } 124 | 125 | void notifyOne(ScopedLock &lock) { 126 | MTAF_ASSERT(lock.islocked()); 127 | notifyOne(); 128 | } 129 | 130 | void notifyAll(bool anywaynotify = false) { 131 | if (anywaynotify) anyway_notify_ = 1; 132 | 133 | int ret = pthread_cond_broadcast(&condition_); 134 | 135 | if (EINVAL == ret) 136 | MTAF_ASSERT(0 == EINVAL); 137 | else if (0 != ret) 138 | MTAF_ASSERT2(0 == ret, "%d", ret); 139 | } 140 | 141 | void notifyAll(ScopedLock &lock, bool anywaynotify = false) { 142 | MTAF_ASSERT(lock.islocked()); 143 | notifyAll(anywaynotify); 144 | } 145 | 146 | void cancelAnyWayNotify() { anyway_notify_ = 0; } 147 | 148 | private: 149 | static void makeTimeout(struct timespec *pts, long millisecond) { 150 | struct timeval tv; 151 | gettimeofday(&tv, 0); 152 | pts->tv_sec = millisecond / 1000 + tv.tv_sec; 153 | pts->tv_nsec = (millisecond % 1000) * 1000 * 1000 + tv.tv_usec * 1000; 154 | 155 | pts->tv_sec += pts->tv_nsec / (1000 * 1000 * 1000); 156 | pts->tv_nsec = pts->tv_nsec % (1000 * 1000 * 1000); 157 | } 158 | 159 | private: 160 | Condition(const Condition &); 161 | Condition &operator=(const Condition &); 162 | 163 | private: 164 | pthread_cond_t condition_; 165 | Mutex mutex_; 166 | volatile unsigned int anyway_notify_; 167 | }; 168 | 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /comm/mtaf_lock.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | 15 | #ifndef MTAF_LOCK_H_ 16 | #define MTAF_LOCK_H_ 17 | 18 | #include 19 | 20 | #include "__mtaf_assert.h" 21 | #include "mtaf_mutex.h" 22 | #include "mtaf_spinlock.h" 23 | #include "mtaf_time_utils.h" 24 | 25 | namespace MTAppenderFile { 26 | template 27 | class BaseScopedLock; 28 | } 29 | 30 | template 31 | class MTAppenderFile::BaseScopedLock 32 | { 33 | public: 34 | explicit BaseScopedLock(MutexType &mtaf_mtaf_mutex, bool initiallyLocked = true) 35 | : mutex_(mtaf_mtaf_mutex) 36 | , islocked_(false) { 37 | if (!initiallyLocked) return; 38 | 39 | lock(); 40 | } 41 | 42 | explicit BaseScopedLock(MutexType &mtaf_mtaf_mutex, long _millisecond) 43 | : mutex_(mtaf_mtaf_mutex) 44 | , islocked_(false) { 45 | timedlock(_millisecond); 46 | } 47 | 48 | ~BaseScopedLock() { 49 | if (islocked_) unlock(); 50 | } 51 | 52 | bool islocked() const { 53 | return islocked_; 54 | } 55 | 56 | void lock() { 57 | MTAF_ASSERT(!islocked_); 58 | 59 | if (!islocked_ && mutex_.lock()) { 60 | islocked_ = true; 61 | } 62 | 63 | MTAF_ASSERT(islocked_); 64 | } 65 | 66 | void unlock() { 67 | MTAF_ASSERT(islocked_); 68 | 69 | if (islocked_) { 70 | mutex_.unlock(); 71 | islocked_ = false; 72 | } 73 | } 74 | 75 | bool trylock() { 76 | if (islocked_) return false; 77 | 78 | islocked_ = mutex_.trylock(); 79 | return islocked_; 80 | } 81 | 82 | #ifdef __linux__ 83 | bool timedlock(long _millisecond) { 84 | MTAF_ASSERT(!islocked_); 85 | 86 | if (islocked_) return true; 87 | 88 | islocked_ = mtaf_mutex.timedlock(_millisecond); 89 | return islocked_; 90 | } 91 | #else 92 | bool timedlock(long _millisecond) { 93 | MTAF_ASSERT(!islocked_); 94 | 95 | if (islocked_) return true; 96 | 97 | unsigned long start = mtaf_gettickcount(); 98 | unsigned long cur = start; 99 | 100 | while (cur <= start + _millisecond) { 101 | if (trylock()) break; 102 | 103 | usleep(50 * 1000); 104 | cur = mtaf_gettickcount(); 105 | } 106 | 107 | return islocked_; 108 | } 109 | #endif 110 | 111 | MutexType &internal() { 112 | return mutex_; 113 | } 114 | 115 | private: 116 | MutexType &mutex_; 117 | bool islocked_; 118 | }; 119 | 120 | typedef MTAppenderFile::BaseScopedLock ScopedLock; 121 | typedef MTAppenderFile::BaseScopedLock ScopedSpinLock; 122 | 123 | #endif /* MTAF_LOCK_H_ */ 124 | -------------------------------------------------------------------------------- /comm/mtaf_mutex.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | 15 | #ifndef MTAF_MUTEX_H_ 16 | #define MTAF_MUTEX_H_ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "__mtaf_assert.h" 24 | #include "mtaf_time_utils.h" 25 | namespace MTAppenderFile { 26 | class Mutex; 27 | } 28 | 29 | class MTAppenderFile::Mutex 30 | { 31 | public: 32 | typedef pthread_mutex_t handle_type; 33 | Mutex(bool _recursive = false) 34 | : magic_(reinterpret_cast(this)) 35 | , mutex_() 36 | , attr_() { 37 | //禁止重复加锁 38 | int ret = pthread_mutexattr_init(&attr_); 39 | 40 | if (ENOMEM == ret) 41 | MTAF_ASSERT(0 == ENOMEM); 42 | else if (0 != ret) 43 | MTAF_ASSERT(0 == ret); 44 | 45 | ret = pthread_mutexattr_settype(&attr_, _recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_ERRORCHECK); 46 | 47 | if (EINVAL == ret) 48 | MTAF_ASSERT(0 == EINVAL); 49 | else if (0 != ret) 50 | MTAF_ASSERT(0 == ret); 51 | 52 | ret = pthread_mutex_init(&mutex_, &attr_); 53 | 54 | if (EAGAIN == ret) 55 | MTAF_ASSERT(0 == EAGAIN); 56 | else if (ENOMEM == ret) 57 | MTAF_ASSERT(0 == ENOMEM); 58 | else if (EPERM == ret) 59 | MTAF_ASSERT(0 == EPERM); 60 | else if (EBUSY == ret) 61 | MTAF_ASSERT(0 == EBUSY); 62 | else if (EINVAL == ret) 63 | MTAF_ASSERT(0 == EINVAL); 64 | else if (0 != ret) 65 | MTAF_ASSERT(0 == ret); 66 | } 67 | 68 | ~Mutex() { 69 | magic_ = 0; 70 | int ret = pthread_mutex_destroy(&mutex_); 71 | 72 | if (EBUSY == ret) 73 | MTAF_ASSERT(0 == EBUSY); 74 | else if (EINVAL == ret) 75 | MTAF_ASSERT(0 == EINVAL); 76 | else if (0 != ret) 77 | MTAF_ASSERT(0 == ret); 78 | 79 | ret = pthread_mutexattr_destroy(&attr_); 80 | 81 | if (EINVAL == ret) 82 | MTAF_ASSERT(0 == EINVAL); 83 | else if (0 != ret) 84 | MTAF_ASSERT(0 == ret); 85 | } 86 | 87 | bool lock() { 88 | // 成功返回0,失败返回错误码 89 | MTAF_ASSERT2(reinterpret_cast(this) == magic_ && 0 != magic_, "this:%p != mageic:%p", this, (void *)magic_); 90 | 91 | if (reinterpret_cast(this) != magic_) return false; 92 | 93 | int ret = pthread_mutex_lock(&mutex_); 94 | 95 | if (EINVAL == ret) 96 | MTAF_ASSERT(0 == EINVAL); 97 | else if (EAGAIN == ret) 98 | MTAF_ASSERT(0 == EAGAIN); 99 | else if (EDEADLK == ret) 100 | MTAF_ASSERT(0 == EDEADLK); 101 | else if (0 != ret) 102 | MTAF_ASSERT(0 == ret); 103 | 104 | return 0 == ret; 105 | } 106 | 107 | bool unlock() { 108 | MTAF_ASSERT2(reinterpret_cast(this) == magic_ && 0 != magic_, "this:%p != mageic:%p", this, (void *)magic_); 109 | 110 | int ret = pthread_mutex_unlock(&mutex_); 111 | 112 | if (EINVAL == ret) 113 | MTAF_ASSERT(0 == EINVAL); 114 | else if (EAGAIN == ret) 115 | MTAF_ASSERT(0 == EAGAIN); 116 | else if (EPERM == ret) 117 | MTAF_ASSERT(0 == EPERM); 118 | else if (0 != ret) 119 | MTAF_ASSERT(0 == ret); 120 | 121 | return 0 == ret; 122 | } 123 | 124 | bool trylock() { 125 | MTAF_ASSERT2(reinterpret_cast(this) == magic_ && 0 != magic_, "this:%p != mageic:%p", this, (void *)magic_); 126 | 127 | if (reinterpret_cast(this) != magic_) return false; 128 | 129 | int ret = pthread_mutex_trylock(&mutex_); 130 | 131 | if (EBUSY == ret) return false; 132 | 133 | if (EINVAL == ret) 134 | MTAF_ASSERT(0 == EINVAL); 135 | else if (EAGAIN == ret) 136 | MTAF_ASSERT(0 == EAGAIN); 137 | else if (EDEADLK == ret) 138 | MTAF_ASSERT(0 == EDEADLK); 139 | else if (0 != ret) 140 | MTAF_ASSERT(0 == ret); 141 | 142 | return 0 == ret; 143 | } 144 | 145 | bool islocked() { 146 | MTAF_ASSERT(reinterpret_cast(this) == magic_); 147 | 148 | int ret = pthread_mutex_trylock(&mutex_); 149 | 150 | if (0 == ret) unlock(); 151 | 152 | return 0 != ret; 153 | } 154 | 155 | handle_type &internal() { return mutex_; } 156 | 157 | private: 158 | Mutex(const Mutex &); 159 | Mutex &operator=(const Mutex &); 160 | 161 | private: 162 | static void MakeTimeout(struct timespec *pts, long millisecond) { 163 | struct timeval tv; 164 | gettimeofday(&tv, 0); 165 | pts->tv_sec = millisecond / 1000 + tv.tv_sec; 166 | pts->tv_nsec = (millisecond % 1000) * 1000 * 1000 + tv.tv_usec * 1000; 167 | 168 | pts->tv_sec += pts->tv_nsec / (1000 * 1000 * 1000); 169 | pts->tv_nsec = pts->tv_nsec % (1000 * 1000 * 1000); 170 | } 171 | 172 | private: 173 | uintptr_t magic_; // Dangling pointer will dead lock, so check it!!! 174 | pthread_mutex_t mutex_; 175 | pthread_mutexattr_t attr_; 176 | }; 177 | 178 | 179 | #endif /* MTAF_MUTEX_H_ */ 180 | -------------------------------------------------------------------------------- /comm/mtaf_ptrbuffer.cc: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | // 14 | // ptrbuffer.cc 15 | // 16 | // Created by yerungui on 13-4-4. 17 | // 18 | 19 | #include "mtaf_ptrbuffer.h" 20 | 21 | #include 22 | #include 23 | 24 | #include "__mtaf_assert.h" 25 | 26 | using namespace MTAppenderFile; 27 | 28 | const PtrBuffer KNullPtrBuffer(0, 0, 0); 29 | 30 | #ifndef max 31 | #define max(a, b) (((a) > (b)) ? (a) : (b)) 32 | #endif 33 | #ifndef min 34 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 35 | #endif 36 | 37 | PtrBuffer::PtrBuffer(void *_ptr, size_t _len, size_t _maxlen) 38 | : parray_((unsigned char *)_ptr) 39 | , pos_(0) 40 | , length_(_len) 41 | , max_length_(_maxlen) { 42 | MTAF_ASSERT(length_ <= max_length_); 43 | } 44 | 45 | PtrBuffer::PtrBuffer(void *_ptr, size_t _len) 46 | : parray_((unsigned char *)_ptr) 47 | , pos_(0) 48 | , length_(_len) 49 | , max_length_(_len) { 50 | MTAF_ASSERT(length_ <= max_length_); 51 | } 52 | 53 | PtrBuffer::PtrBuffer() { 54 | Reset(); 55 | } 56 | 57 | PtrBuffer::~PtrBuffer() { 58 | } 59 | 60 | void PtrBuffer::Write(const void *_pBuffer, size_t _nLen) { 61 | Write(_pBuffer, _nLen, Pos()); 62 | Seek(_nLen, kSeekCur); 63 | } 64 | 65 | void PtrBuffer::Write(const void *_pBuffer, size_t _nLen, off_t _nPos) { 66 | MTAF_ASSERT(NULL != _pBuffer); 67 | MTAF_ASSERT(0 <= _nPos); 68 | MTAF_ASSERT((unsigned int)_nPos <= Length()); 69 | size_t copylen = (size_t)min(_nLen, max_length_.load() - _nPos); 70 | length_.store((size_t)max(length_.load(), copylen + _nPos)); 71 | memcpy((unsigned char *)Ptr() + _nPos, _pBuffer, copylen); 72 | 73 | if (length_.load() < max_length_.load() - 4) { 74 | memset((unsigned char *)Ptr() + _nPos + copylen, 0, sizeof(char) * 3); 75 | memset((unsigned char *)Ptr() + _nPos + copylen + 3, '\r', sizeof(char)); 76 | } 77 | } 78 | 79 | size_t PtrBuffer::Read(void *_pBuffer, size_t _nLen) { 80 | size_t nRead = Read(_pBuffer, _nLen, Pos()); 81 | Seek(nRead, kSeekCur); 82 | return nRead; 83 | } 84 | 85 | size_t PtrBuffer::Read(void *_pBuffer, size_t _nLen, off_t _nPos) const { 86 | MTAF_ASSERT(NULL != _pBuffer); 87 | MTAF_ASSERT(0 <= _nPos); 88 | MTAF_ASSERT((unsigned int)_nPos < Length()); 89 | 90 | size_t nRead = (size_t)(Length() - _nPos); 91 | nRead = min(nRead, _nLen); 92 | memcpy(_pBuffer, PosPtr(), nRead); 93 | return nRead; 94 | } 95 | 96 | void PtrBuffer::Seek(off_t _nOffset, TSeek _eOrigin) { 97 | switch (_eOrigin) { 98 | case kSeekStart: 99 | pos_.store(_nOffset); 100 | break; 101 | 102 | case kSeekCur: 103 | pos_.store(pos_.load() + _nOffset); 104 | break; 105 | 106 | case kSeekEnd: 107 | pos_.store(length_.load() + _nOffset); 108 | break; 109 | 110 | default: 111 | MTAF_ASSERT(false); 112 | break; 113 | } 114 | 115 | if (pos_.load() < 0) 116 | pos_.store(0); 117 | 118 | if ((unsigned int)pos_.load() > length_.load()) 119 | pos_.store(length_.load()); 120 | } 121 | 122 | void PtrBuffer::Length(off_t _nPos, size_t _nLenght) { 123 | MTAF_ASSERT(0 <= _nPos); 124 | MTAF_ASSERT((size_t)_nPos <= _nLenght); 125 | MTAF_ASSERT(_nLenght <= MaxLength()); 126 | 127 | length_.store(max_length_.load() < _nLenght ? max_length_.load() : _nLenght); 128 | Seek(_nPos, kSeekStart); 129 | } 130 | 131 | void *PtrBuffer::Ptr() { 132 | return parray_; 133 | } 134 | 135 | const void *PtrBuffer::Ptr() const { 136 | return parray_; 137 | } 138 | 139 | void *PtrBuffer::PosPtr() { 140 | return ((unsigned char *)Ptr()) + Pos(); 141 | } 142 | 143 | const void *PtrBuffer::PosPtr() const { 144 | return ((unsigned char *)Ptr()) + Pos(); 145 | } 146 | 147 | off_t PtrBuffer::Pos() const { 148 | return pos_.load(); 149 | } 150 | 151 | size_t PtrBuffer::PosLength() const { 152 | return (size_t)(length_.load() - pos_.load()); 153 | } 154 | 155 | size_t PtrBuffer::Length() const { 156 | return length_.load(); 157 | } 158 | 159 | size_t PtrBuffer::MaxLength() const { 160 | return max_length_.load(); 161 | } 162 | 163 | void PtrBuffer::Attach(void *_pBuffer, size_t _nLen, size_t _maxlen) { 164 | Reset(); 165 | parray_ = (unsigned char *)_pBuffer; 166 | length_.store(_nLen); 167 | max_length_.store(_maxlen); 168 | } 169 | 170 | void PtrBuffer::Attach(void *_pBuffer, size_t _nLen) { 171 | Attach(_pBuffer, _nLen, _nLen); 172 | } 173 | 174 | void PtrBuffer::Reset() { 175 | parray_ = NULL; 176 | pos_.store(0); 177 | length_.store(0); 178 | max_length_.store(0); 179 | } 180 | -------------------------------------------------------------------------------- /comm/mtaf_ptrbuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | // 14 | // ptrbuffer.h 15 | // 16 | // Created by yerungui on 13-4-4. 17 | // 18 | 19 | #ifndef MTAF_COMM_PTRBUFFER_H_ 20 | #define MTAF_COMM_PTRBUFFER_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace MTAppenderFile { 27 | class PtrBuffer; 28 | } 29 | 30 | class MTAppenderFile::PtrBuffer 31 | { 32 | public: 33 | enum TSeek { 34 | kSeekStart, 35 | kSeekCur, 36 | kSeekEnd, 37 | }; 38 | 39 | public: 40 | PtrBuffer(void *_ptr, size_t _len, size_t _maxlen); 41 | PtrBuffer(void *_ptr, size_t _len); 42 | PtrBuffer(); 43 | ~PtrBuffer(); 44 | 45 | template 46 | void Write(const T &_val) { Write(&_val, sizeof(_val)); } 47 | 48 | template 49 | void Write(int _nPos, const T &_val) { Write(&_val, sizeof(_val), _nPos); } 50 | 51 | void Write(const char *const _val) { Write(_val, (unsigned int)strlen(_val)); } 52 | 53 | void Write(int _nPos, const char *const _val) { Write(_val, (unsigned int)strlen(_val), _nPos); } 54 | 55 | void Write(const void *_pBuffer, size_t _nLen); 56 | void Write(const void *_pBuffer, size_t _nLen, off_t _nPos); 57 | 58 | template 59 | void Read(T &_val) { Read(&_val, sizeof(_val)); } 60 | 61 | template 62 | void Read(int _nPos, const T &_val) const { Read(&_val, sizeof(_val), _nPos); } 63 | 64 | size_t Read(void *_pBuffer, size_t _nLen); 65 | size_t Read(void *_pBuffer, size_t _nLen, off_t _nPos) const; 66 | 67 | void Seek(off_t _nOffset, TSeek _eOrigin = kSeekCur); 68 | void Length(off_t _nPos, size_t _nLenght); 69 | 70 | void *Ptr(); 71 | void *PosPtr(); 72 | const void *Ptr() const; 73 | const void *PosPtr() const; 74 | 75 | off_t Pos() const; 76 | size_t PosLength() const; 77 | size_t Length() const; 78 | size_t MaxLength() const; 79 | 80 | void Attach(void *_pBuffer, size_t _nLen, size_t _maxlen); 81 | void Attach(void *_pBuffer, size_t _nLen); 82 | void Reset(); 83 | 84 | private: 85 | PtrBuffer(const PtrBuffer &_rhs); 86 | PtrBuffer &operator=(const PtrBuffer &_rhs); 87 | 88 | private: 89 | unsigned char *parray_; 90 | std::atomic pos_; 91 | std::atomic_size_t length_; 92 | std::atomic_size_t max_length_; 93 | }; 94 | 95 | extern const MTAppenderFile::PtrBuffer KNullPtrBuffer; 96 | 97 | 98 | #endif // COMM_PTRBUFFER_H_ 99 | -------------------------------------------------------------------------------- /comm/mtaf_runnable.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | 15 | #ifndef RUNNABLE_H_ 16 | #define RUNNABLE_H_ 17 | 18 | struct Runnable { 19 | virtual ~Runnable() {} 20 | virtual void run(void *) = 0; 21 | }; 22 | 23 | namespace detail { 24 | 25 | template 26 | class RunnableFunctor : public Runnable 27 | { 28 | public: 29 | RunnableFunctor(const T &f) 30 | : func_(f) {} 31 | virtual void run(void *) { func_(); } 32 | 33 | private: 34 | T func_; 35 | }; 36 | 37 | template 38 | class RunnableFunctor : public Runnable 39 | { 40 | public: 41 | RunnableFunctor(T *f) 42 | : func_(f) {} 43 | virtual void run(void *) { (*func_)(); } 44 | 45 | private: 46 | RunnableFunctor(const RunnableFunctor &); 47 | RunnableFunctor &operator=(const RunnableFunctor &); 48 | 49 | private: 50 | T *func_; 51 | }; 52 | 53 | template <> 54 | class RunnableFunctor : public Runnable 55 | { 56 | RunnableFunctor(); 57 | }; 58 | 59 | template <> 60 | class RunnableFunctor : public Runnable 61 | { 62 | public: 63 | RunnableFunctor(Runnable *f) 64 | : func_(f) {} 65 | virtual void run(void *arg) { static_cast(func_)->run(arg); } 66 | 67 | private: 68 | RunnableFunctor(const RunnableFunctor &); 69 | RunnableFunctor &operator=(const RunnableFunctor &); 70 | 71 | private: 72 | Runnable *func_; 73 | }; 74 | 75 | class RunnableArgFunctor : public Runnable 76 | { 77 | public: 78 | RunnableArgFunctor(void (*fn)(void *)) 79 | : func_f(fn) {} 80 | virtual void run(void *arg) { func_f(arg); } 81 | 82 | private: 83 | void (*func_f)(void *); 84 | }; 85 | 86 | // base template for no argument functor 87 | template 88 | struct TransformImplement { 89 | static Runnable *transform(const T &t) { 90 | return new RunnableFunctor(t); 91 | } 92 | }; 93 | 94 | template 95 | inline Runnable *transform(const T &t) { 96 | return TransformImplement::transform(t); 97 | } 98 | 99 | inline Runnable *transform(void (*fn)(void *)) { 100 | return new RunnableArgFunctor(fn); 101 | } 102 | } // namespace detail 103 | 104 | 105 | #endif /* RUNNABLE_H_ */ 106 | -------------------------------------------------------------------------------- /comm/mtaf_spinlock.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | // 15 | // spinlock.h 16 | // 17 | // 18 | 19 | #ifndef MTAF_spinlock_h 20 | #define MTAF_spinlock_h 21 | 22 | #ifdef __APPLE__ 23 | #include 24 | 25 | #define splock OSSpinLock 26 | #define splockinit(lock) \ 27 | { *lock = OS_SPINLOCK_INIT; } 28 | #define splocklock OSSpinLockLock 29 | #define splockunlock OSSpinLockUnlock 30 | #define splocktrylock OSSpinLockTry 31 | 32 | namespace MTAppenderFile { 33 | class SpinLock; 34 | } 35 | 36 | class MTAppenderFile::SpinLock 37 | { 38 | public: 39 | typedef splock handle_type; 40 | 41 | public: 42 | SpinLock() { splockinit(&lock_); } 43 | 44 | bool lock() { 45 | splocklock(&lock_); 46 | return true; 47 | } 48 | 49 | bool unlock() { 50 | splockunlock(&lock_); 51 | return true; 52 | } 53 | 54 | bool trylock() { 55 | return splocktrylock(&lock_); 56 | } 57 | 58 | splock *internal() { return &lock_; } 59 | 60 | private: 61 | SpinLock(const SpinLock &); 62 | SpinLock &operator=(const SpinLock &); 63 | 64 | private: 65 | splock lock_; 66 | }; 67 | 68 | #endif // __APPLE__ 69 | #endif 70 | -------------------------------------------------------------------------------- /comm/mtaf_thread.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | #ifndef MTAF_THREAD_H_ 15 | #define MTAF_THREAD_H_ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "__mtaf_assert.h" 25 | #include "mtaf_condition.h" 26 | #include "mtaf_runnable.h" 27 | 28 | typedef pthread_t thread_tid; 29 | //注意!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 30 | // 如果在pthread_join途中,其他线程进行pthread_detach, 会出现join函数不能退出的情况 31 | namespace MTAppenderFile { 32 | class ThreadUtil; 33 | class Thread; 34 | } // namespace MTAppenderFile 35 | 36 | class MTAppenderFile::ThreadUtil 37 | { 38 | public: 39 | static void yield() { 40 | ::sched_yield(); 41 | } 42 | 43 | static void sleep(unsigned int _sec) { 44 | ::sleep(_sec); 45 | } 46 | 47 | static void usleep(unsigned int _usec) { 48 | ::usleep(_usec); 49 | } 50 | 51 | static thread_tid currentthreadid() { 52 | return pthread_self(); 53 | } 54 | 55 | static bool isruning(thread_tid _id) { 56 | MTAF_ASSERT(0 != _id); 57 | int ret = pthread_kill(_id, 0); 58 | 59 | if (0 == ret) 60 | return true; 61 | else if (ESRCH == ret) 62 | return false; 63 | else if (EINVAL == ret) 64 | MTAF_ASSERT(false); 65 | 66 | return false; 67 | } 68 | 69 | static int join(thread_tid _id) { 70 | if (_id == ThreadUtil::currentthreadid()) return EDEADLK; 71 | int ret = pthread_join(_id, 0); 72 | MTAF_ASSERT2(0 == ret || ESRCH == ret, "pthread_join err:%d", ret); 73 | return ret; 74 | } 75 | }; 76 | 77 | class MTAppenderFile::Thread 78 | { 79 | private: 80 | class RunnableReference 81 | { 82 | public: 83 | RunnableReference(Runnable *_target) 84 | : target(_target) 85 | , count(0) 86 | , tid(0) 87 | , isjoined(false) 88 | , isended(true) 89 | , aftertime(LONG_MAX) 90 | , periodictime(LONG_MAX) 91 | , iscanceldelaystart(false) 92 | , condtime() 93 | , splock() 94 | , isinthread(false) 95 | , killsig(0) { 96 | memset(thread_name, 0, sizeof(thread_name)); 97 | } 98 | 99 | ~RunnableReference() { 100 | delete target; 101 | MTAF_ASSERT(0 == count); 102 | MTAF_ASSERT(isended); 103 | } 104 | 105 | void AddRef() { count++; } 106 | void RemoveRef(ScopedSpinLock &_lock) { 107 | MTAF_ASSERT(0 < count); 108 | MTAF_ASSERT(_lock.islocked()); 109 | 110 | bool willdel = false; 111 | count--; 112 | 113 | if (0 == count) willdel = true; 114 | 115 | _lock.unlock(); 116 | 117 | if (willdel) delete this; 118 | } 119 | 120 | private: 121 | RunnableReference(const RunnableReference &); 122 | RunnableReference &operator=(const RunnableReference &); 123 | 124 | public: 125 | Runnable *target; 126 | void *arg; 127 | int count; 128 | thread_tid tid; 129 | bool isjoined; 130 | bool isended; 131 | long aftertime; 132 | long periodictime; 133 | bool iscanceldelaystart; 134 | Condition condtime; 135 | SpinLock splock; 136 | bool isinthread; // 猥琐的东西,是为了解决线程还没有起来的时就发送信号出现crash的问题 137 | int killsig; 138 | char thread_name[128]; 139 | }; 140 | 141 | public: 142 | Thread(void (*fn)(void *), void *arg, const char *_thread_name = NULL) 143 | : runable_ref_(NULL) { 144 | runable_ref_ = new RunnableReference(detail::transform(fn)); 145 | ScopedSpinLock lock(runable_ref_->splock); 146 | runable_ref_->AddRef(); 147 | runable_ref_->arg = arg; 148 | 149 | int res = pthread_attr_init(&attr_); 150 | MTAF_ASSERT2(0 == res, "res=%d", res); 151 | if (_thread_name) strncpy(runable_ref_->thread_name, _thread_name, sizeof(runable_ref_->thread_name)); 152 | } 153 | 154 | template 155 | explicit Thread(const T &op, const char *_thread_name = NULL) 156 | : runable_ref_(NULL) { 157 | runable_ref_ = new RunnableReference(detail::transform(op)); 158 | ScopedSpinLock lock(runable_ref_->splock); 159 | runable_ref_->AddRef(); 160 | runable_ref_->arg = NULL; 161 | 162 | int res = pthread_attr_init(&attr_); 163 | MTAF_ASSERT2(0 == res, "res=%d", res); 164 | if (_thread_name) strncpy(runable_ref_->thread_name, _thread_name, sizeof(runable_ref_->thread_name)); 165 | } 166 | 167 | Thread(const char *_thread_name = NULL) 168 | : runable_ref_(NULL) { 169 | runable_ref_ = new RunnableReference(NULL); 170 | ScopedSpinLock lock(runable_ref_->splock); 171 | runable_ref_->AddRef(); 172 | runable_ref_->arg = NULL; 173 | 174 | int res = pthread_attr_init(&attr_); 175 | MTAF_ASSERT2(0 == res, "res=%d", res); 176 | if (_thread_name) strncpy(runable_ref_->thread_name, _thread_name, sizeof(runable_ref_->thread_name)); 177 | } 178 | 179 | virtual ~Thread() { 180 | int res = pthread_attr_destroy(&attr_); 181 | MTAF_ASSERT2(0 == res, "res=%d", res); 182 | ScopedSpinLock lock(runable_ref_->splock); 183 | runable_ref_->RemoveRef(lock); 184 | } 185 | 186 | int start(bool *_newone = NULL) { 187 | ScopedSpinLock lock(runable_ref_->splock); 188 | 189 | if (_newone) *_newone = false; 190 | 191 | if (isruning()) return 0; 192 | 193 | MTAF_ASSERT(runable_ref_->target); 194 | runable_ref_->isended = false; 195 | runable_ref_->AddRef(); 196 | 197 | int ret = pthread_create(reinterpret_cast(&runable_ref_->tid), &attr_, start_routine, runable_ref_); 198 | MTAF_ASSERT(0 == ret); 199 | 200 | if (_newone) *_newone = true; 201 | 202 | if (0 != ret) { 203 | runable_ref_->isended = true; 204 | runable_ref_->RemoveRef(lock); 205 | } 206 | 207 | return ret; 208 | } 209 | 210 | template 211 | int start(const T &op, bool *_newone = NULL) { 212 | ScopedSpinLock lock(runable_ref_->splock); 213 | 214 | if (_newone) *_newone = false; 215 | 216 | if (isruning()) return 0; 217 | 218 | delete runable_ref_->target; 219 | runable_ref_->target = detail::transform(op); 220 | 221 | runable_ref_->isended = false; 222 | runable_ref_->AddRef(); 223 | 224 | int ret = pthread_create(reinterpret_cast(&runable_ref_->tid), &attr_, start_routine, runable_ref_); 225 | MTAF_ASSERT(0 == ret); 226 | 227 | if (_newone) *_newone = true; 228 | 229 | if (0 != ret) { 230 | runable_ref_->isended = true; 231 | runable_ref_->RemoveRef(lock); 232 | } 233 | 234 | return ret; 235 | } 236 | 237 | int start_after(long after) { 238 | ScopedSpinLock lock(runable_ref_->splock); 239 | 240 | if (isruning()) return 0; 241 | 242 | MTAF_ASSERT(runable_ref_->target); 243 | runable_ref_->condtime.cancelAnyWayNotify(); 244 | runable_ref_->iscanceldelaystart = false; 245 | runable_ref_->isended = false; 246 | runable_ref_->aftertime = after; 247 | runable_ref_->AddRef(); 248 | 249 | int ret = pthread_create(reinterpret_cast(&runable_ref_->tid), &attr_, start_routine_after, runable_ref_); 250 | MTAF_ASSERT(0 == ret); 251 | 252 | if (0 != ret) { 253 | runable_ref_->isended = true; 254 | runable_ref_->aftertime = LONG_MAX; 255 | runable_ref_->RemoveRef(lock); 256 | } 257 | 258 | return ret; 259 | } 260 | 261 | void cancel_after() { 262 | ScopedSpinLock lock(runable_ref_->splock); 263 | 264 | if (!isruning()) return; 265 | 266 | runable_ref_->iscanceldelaystart = true; 267 | runable_ref_->condtime.notifyAll(true); 268 | } 269 | 270 | int start_periodic(long after, long periodic) { // ms 271 | ScopedSpinLock lock(runable_ref_->splock); 272 | 273 | if (isruning()) return 0; 274 | 275 | MTAF_ASSERT(runable_ref_->target); 276 | runable_ref_->condtime.cancelAnyWayNotify(); 277 | runable_ref_->iscanceldelaystart = false; 278 | runable_ref_->isended = false; 279 | runable_ref_->aftertime = after; 280 | runable_ref_->periodictime = periodic; 281 | runable_ref_->AddRef(); 282 | 283 | int ret = pthread_create(reinterpret_cast(&runable_ref_->tid), &attr_, start_routine_periodic, runable_ref_); 284 | MTAF_ASSERT(0 == ret); 285 | 286 | if (0 != ret) { 287 | runable_ref_->isended = true; 288 | runable_ref_->aftertime = LONG_MAX; 289 | runable_ref_->periodictime = LONG_MAX; 290 | runable_ref_->RemoveRef(lock); 291 | } 292 | 293 | return ret; 294 | } 295 | 296 | void cancel_periodic() { 297 | ScopedSpinLock lock(runable_ref_->splock); 298 | 299 | if (!isruning()) return; 300 | 301 | runable_ref_->iscanceldelaystart = true; 302 | runable_ref_->condtime.notifyAll(true); 303 | } 304 | 305 | int join() const { 306 | int ret = 0; 307 | ScopedSpinLock lock(runable_ref_->splock); 308 | MTAF_ASSERT(!runable_ref_->isjoined); 309 | 310 | if (tid() == MTAppenderFile::ThreadUtil::currentthreadid()) return EDEADLK; 311 | 312 | if (isruning()) { 313 | runable_ref_->isjoined = true; 314 | lock.unlock(); 315 | ret = pthread_join(tid(), 0); 316 | MTAF_ASSERT2(0 == ret || ESRCH == ret, "pthread_join err:%d", ret); 317 | } 318 | 319 | return ret; 320 | } 321 | 322 | void outside_join() const { 323 | ScopedSpinLock lock(runable_ref_->splock); 324 | MTAF_ASSERT(!runable_ref_->isjoined); 325 | MTAF_ASSERT(!isruning()); 326 | if (runable_ref_->isjoined || isruning()) return; 327 | 328 | runable_ref_->isjoined = true; 329 | } 330 | 331 | int kill(int sig) const { 332 | ScopedSpinLock lock(runable_ref_->splock); 333 | 334 | if (!isruning()) return ESRCH; 335 | 336 | if (!runable_ref_->isinthread) { 337 | runable_ref_->killsig = sig; 338 | return 0; 339 | } 340 | 341 | lock.unlock(); 342 | 343 | int ret = pthread_kill(tid(), sig); 344 | return ret; 345 | } 346 | 347 | int unsafe_exit() const { 348 | return pthread_cancel(tid()); 349 | } 350 | 351 | thread_tid tid() const { 352 | return runable_ref_->tid; 353 | } 354 | 355 | bool isruning() const { 356 | return !runable_ref_->isended; 357 | } 358 | 359 | void stack_size(size_t _stacksize) { 360 | if (_stacksize == 0) return; 361 | 362 | int res = pthread_attr_setstacksize(&attr_, _stacksize); 363 | MTAF_ASSERT2(0 == res, "res=%d", res); 364 | } 365 | 366 | size_t stack_size() const { 367 | size_t _stacksize = 0; 368 | int res = pthread_attr_getstacksize(&attr_, &_stacksize); 369 | MTAF_ASSERT2(0 == res, "res=%d", res); 370 | return _stacksize; 371 | } 372 | 373 | const char *thread_name() const { 374 | return runable_ref_->thread_name; 375 | } 376 | 377 | private: 378 | static void init(void *arg) { 379 | volatile RunnableReference *runableref = static_cast(arg); 380 | ScopedSpinLock lock((const_cast(runableref))->splock); 381 | MTAF_ASSERT(runableref != 0); 382 | MTAF_ASSERT(runableref->target != 0); 383 | MTAF_ASSERT(!runableref->isinthread); 384 | 385 | runableref->isinthread = true; 386 | 387 | if (0 < strnlen((const char *)runableref->thread_name, sizeof(runableref->thread_name))) { 388 | pthread_setname_np((const char *)runableref->thread_name); 389 | } 390 | 391 | if (!(0 < runableref->killsig && runableref->killsig <= 32)) 392 | return; 393 | 394 | lock.unlock(); 395 | pthread_kill(pthread_self(), runableref->killsig); 396 | } 397 | 398 | static void cleanup(void *arg) { 399 | volatile RunnableReference *runableref = static_cast(arg); 400 | ScopedSpinLock lock((const_cast(runableref))->splock); 401 | 402 | MTAF_ASSERT(runableref != 0); 403 | MTAF_ASSERT(runableref->target != 0); 404 | MTAF_ASSERT(runableref->tid != 0); 405 | MTAF_ASSERT(runableref->isinthread); 406 | 407 | runableref->isinthread = false; 408 | runableref->killsig = 0; 409 | runableref->isended = true; 410 | 411 | if (!runableref->isjoined) pthread_detach(pthread_self()); 412 | 413 | runableref->isjoined = false; 414 | (const_cast(runableref))->RemoveRef(lock); 415 | } 416 | 417 | static void *start_routine(void *arg) { 418 | init(arg); 419 | volatile RunnableReference *runableref = static_cast(arg); 420 | pthread_cleanup_push(&cleanup, arg); 421 | runableref->target->run(runableref->arg); 422 | pthread_cleanup_pop(1); 423 | return 0; 424 | } 425 | 426 | static void *start_routine_after(void *arg) { 427 | init(arg); 428 | volatile RunnableReference *runableref = static_cast(arg); 429 | pthread_cleanup_push(&cleanup, arg); 430 | 431 | if (!runableref->iscanceldelaystart) { 432 | (const_cast(runableref))->condtime.wait(runableref->aftertime); 433 | 434 | if (!runableref->iscanceldelaystart) { 435 | runableref->target->run(runableref->arg); 436 | } 437 | } 438 | 439 | pthread_cleanup_pop(1); 440 | return 0; 441 | } 442 | 443 | static void *start_routine_periodic(void *arg) { 444 | init(arg); 445 | volatile RunnableReference *runableref = static_cast(arg); 446 | pthread_cleanup_push(&cleanup, arg); 447 | 448 | if (!runableref->iscanceldelaystart) { 449 | (const_cast(runableref))->condtime.wait(runableref->aftertime); 450 | 451 | while (!runableref->iscanceldelaystart) { 452 | 453 | runableref->target->run(runableref->arg); 454 | 455 | if (!runableref->iscanceldelaystart) 456 | (const_cast(runableref))->condtime.wait(runableref->periodictime); 457 | } 458 | } 459 | 460 | pthread_cleanup_pop(1); 461 | return 0; 462 | } 463 | 464 | private: 465 | Thread(const Thread &); 466 | Thread &operator=(const Thread &); 467 | 468 | private: 469 | RunnableReference *runable_ref_; 470 | pthread_attr_t attr_; 471 | }; 472 | 473 | 474 | inline bool operator==(const MTAppenderFile::Thread &lhs, const MTAppenderFile::Thread &rhs) { 475 | return pthread_equal(lhs.tid(), rhs.tid()) != 0; 476 | } 477 | 478 | inline bool operator!=(const MTAppenderFile::Thread &lhs, const MTAppenderFile::Thread &rhs) { 479 | return pthread_equal(lhs.tid(), rhs.tid()) == 0; 480 | } 481 | 482 | #endif /* MTAF_THREAD_H_ */ 483 | -------------------------------------------------------------------------------- /comm/mtaf_time_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * utils.c 3 | * 4 | * Created on: 2012-7-18 5 | * Author: yerungui 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #ifdef ANDROID 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #if __ANDROID_API__ < 21 && !defined(__LP64__) 18 | #include 19 | #else 20 | #include 21 | #endif 22 | 23 | #include 24 | #include 25 | 26 | uint64_t mtaf_gettickcount() { 27 | static int s_fd = -1; 28 | static int errcode = 0; 29 | if (s_fd == -1 && EACCES != errcode) { 30 | int fd = open("/dev/alarm", O_RDONLY); 31 | if (-1 == fd) errcode = errno; 32 | #if __ANDROID_API__ < 21 && !defined(__LP64__) 33 | if (__atomic_cmpxchg(-1, fd, &s_fd)) { 34 | close(fd); 35 | } 36 | #else 37 | atomic_int x = ATOMIC_VAR_INIT(s_fd); 38 | int expect = -1; 39 | if (!atomic_compare_exchange_strong(&x, &expect, fd)) { 40 | close(fd); 41 | } 42 | s_fd = atomic_load(&x); 43 | #endif 44 | } 45 | 46 | struct timespec ts; 47 | int result = ioctl(s_fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts); 48 | 49 | if (result != 0) { 50 | // XXX: there was an error, probably because the driver didn't 51 | // exist ... this should return 52 | // a real error, like an exception! 53 | clock_gettime(CLOCK_BOOTTIME, &ts); 54 | } 55 | return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; 56 | } 57 | 58 | uint64_t mtaf_clock_app_monotonic() { 59 | struct timespec ts; 60 | clock_gettime(CLOCK_MONOTONIC_RAW, &ts); 61 | return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; 62 | } 63 | 64 | #elif defined __APPLE__ 65 | 66 | #include 67 | #include 68 | 69 | uint64_t mtaf_gettickcount() { 70 | static mach_timebase_info_data_t timebase_info = {0}; 71 | 72 | // Convert to nanoseconds - if this is the first time we've run, get the timebase. 73 | if (timebase_info.denom == 0) { 74 | (void)mach_timebase_info(&timebase_info); 75 | } 76 | 77 | // Convert the mach time to milliseconds 78 | uint64_t mach_time = mach_absolute_time(); 79 | uint64_t millis = (mach_time * timebase_info.numer) / (timebase_info.denom * 1000000); 80 | return millis; 81 | } 82 | 83 | uint64_t mtaf_clock_app_monotonic() { 84 | return mtaf_gettickcount(); 85 | } 86 | 87 | #else 88 | #error "not support" 89 | #endif 90 | 91 | int64_t mtaf_gettickspan(uint64_t _old_tick) { 92 | uint64_t cur_tick = mtaf_gettickcount(); 93 | if (_old_tick > cur_tick) return 0; 94 | 95 | return cur_tick - _old_tick; 96 | } 97 | 98 | uint64_t mtaf_timeMs() { 99 | struct timeval tv; 100 | gettimeofday(&tv, NULL); 101 | return (uint64_t)tv.tv_sec * 1000 + (uint64_t)tv.tv_usec / 1000; 102 | } 103 | -------------------------------------------------------------------------------- /comm/mtaf_time_utils.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | /* 15 | * mtaf_time_utils.h 16 | * 17 | * Created on: 2012-7-18 18 | * Author: yerungui 19 | */ 20 | 21 | #ifndef MTAF_COMM_UTILS_H_ 22 | #define MTAF_COMM_UTILS_H_ 23 | 24 | #include 25 | #include 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | uint64_t mtaf_gettickcount(); // ms 32 | int64_t mtaf_gettickspan(uint64_t _old_tick); // ms 33 | uint64_t mtaf_timeMs(); 34 | 35 | uint64_t mtaf_clock_app_monotonic(); // ms 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | 42 | #endif /* MTAF_COMM_UTILS_H_ */ 43 | -------------------------------------------------------------------------------- /loglib/MTAppenderFile.h: -------------------------------------------------------------------------------- 1 | // 2 | // MTAppenderFile.h 3 | // MTAppenderFile 4 | // 5 | // Created by EuanC on 16/12/2017. 6 | // Copyright © 2017 meitu.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #define kMTAppenderFileVersion 0.2.4 13 | 14 | 15 | @interface MTAppenderFile : NSObject 16 | 17 | - (instancetype)initWithFileDir:(NSString *)fileDir name:(NSString *)name; 18 | 19 | - (void)open; 20 | - (void)close; 21 | 22 | - (void)appendText:(NSString *)text; 23 | 24 | - (void)appendUTF8Text:(const char *)utf8Text; 25 | 26 | /** 27 | @param format format content to write, length limit 3000. 28 | */ 29 | - (void)appendFormat:(const char *)format, ...; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /loglib/MTAppenderFile.mm: -------------------------------------------------------------------------------- 1 | // 2 | // MTAppenderFile.m 3 | // MTAppenderFile 4 | // 5 | // Created by EuanC on 16/12/2017. 6 | // Copyright © 2017 meitu.com. All rights reserved. 7 | // 8 | 9 | #import "MTAppenderFile.h" 10 | #import 11 | #include "mtaf_appender.h" 12 | 13 | 14 | @interface MTAppenderFile () { 15 | mtaf_log_appender *_appender; 16 | } 17 | 18 | @property (nonatomic, copy) NSString *fileDir; 19 | @property (nonatomic, copy) NSString *fileName; 20 | 21 | @end 22 | 23 | @implementation MTAppenderFile 24 | 25 | - (void)dealloc { 26 | [self close]; 27 | 28 | [_fileDir release]; 29 | [_fileName release]; 30 | 31 | [super dealloc]; 32 | } 33 | 34 | - (instancetype)initWithFileDir:(NSString *)fileDir name:(NSString *)name { 35 | if (self = [super init]) { 36 | self.fileDir = fileDir; 37 | self.fileName = name; 38 | _appender = nil; 39 | } 40 | return self; 41 | } 42 | 43 | - (void)open { 44 | if (_appender) { 45 | NSAssert(NO, @"[appender] you should close previous appender firstly"); 46 | return; 47 | } 48 | 49 | const char *filedir = [_fileDir UTF8String]; 50 | const char *filename = [_fileName UTF8String]; 51 | 52 | bool useShareThread = true; 53 | _appender = mtaf_log_appender_create(useShareThread); 54 | mtaf_log_appender_open(_appender, mtaf_append_mode_async, filedir, filename); 55 | } 56 | 57 | - (void)appendText:(NSString *)text { 58 | NSAssert(_appender, @"[appender] you should open appender first"); 59 | mtaf_log_appender_append(_appender, [text UTF8String]); 60 | } 61 | 62 | - (void)appendUTF8Text:(const char *)utf8Text { 63 | NSAssert(_appender, @"[appender] you should open appender first"); 64 | mtaf_log_appender_append(_appender, utf8Text); 65 | } 66 | 67 | #define kLogBufSize 3000 68 | 69 | - (void)appendFormat:(const char *)str, ... { 70 | if (str == NULL) 71 | return; 72 | 73 | va_list args; 74 | va_start(args, str); 75 | 76 | char buf[kLogBufSize]; 77 | vsnprintf(buf, kLogBufSize, str, args); 78 | va_end(args); 79 | 80 | mtaf_log_appender_append(_appender, buf); 81 | } 82 | 83 | - (void)close { 84 | if (_appender) { 85 | mtaf_log_appender_close(_appender); 86 | mtaf_log_appender_destroy(_appender); 87 | _appender = nil; 88 | } 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /loglib/loglib.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 209634E020F4B3DE00207AD8 /* mtaf_log_buffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 209634CF20F4B3DE00207AD8 /* mtaf_log_buffer.cpp */; }; 11 | 209634E220F4B3DE00207AD8 /* MTAppenderFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 209634D620F4B3DE00207AD8 /* MTAppenderFile.mm */; }; 12 | 209634E320F4B3DE00207AD8 /* mtaf_platform_comm.mm in Sources */ = {isa = PBXBuildFile; fileRef = 209634D720F4B3DE00207AD8 /* mtaf_platform_comm.mm */; }; 13 | 209634E420F4B3DE00207AD8 /* mtaf_appender.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 209634D820F4B3DE00207AD8 /* mtaf_appender.cpp */; }; 14 | 209634E520F4B3DE00207AD8 /* mtaf_formatter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 209634DC20F4B3DE00207AD8 /* mtaf_formatter.cpp */; }; 15 | 209634E620F4B3DE00207AD8 /* mtaf_mmap_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 209634DE20F4B3DE00207AD8 /* mtaf_mmap_file.cpp */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 20926EC01FE50BF5000DBD07 /* CopyFiles */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = "include/$(PRODUCT_NAME)"; 23 | dstSubfolderSpec = 16; 24 | files = ( 25 | ); 26 | runOnlyForDeploymentPostprocessing = 0; 27 | }; 28 | /* End PBXCopyFilesBuildPhase section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 205E59141FE8E6CF0004D8BA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 32 | 208895061FE8E9410031DB01 /* libz.1.1.3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.1.1.3.tbd; path = usr/lib/libz.1.1.3.tbd; sourceTree = SDKROOT; }; 33 | 20926EC21FE50BF5000DBD07 /* libloglib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libloglib.a; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 209634CF20F4B3DE00207AD8 /* mtaf_log_buffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mtaf_log_buffer.cpp; sourceTree = ""; }; 35 | 209634D020F4B3DE00207AD8 /* mtaf_mmap_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_mmap_file.h; sourceTree = ""; }; 36 | 209634D520F4B3DE00207AD8 /* mtaf_log_buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_log_buffer.h; sourceTree = ""; }; 37 | 209634D620F4B3DE00207AD8 /* MTAppenderFile.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTAppenderFile.mm; sourceTree = ""; }; 38 | 209634D720F4B3DE00207AD8 /* mtaf_platform_comm.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtaf_platform_comm.mm; sourceTree = ""; }; 39 | 209634D820F4B3DE00207AD8 /* mtaf_appender.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mtaf_appender.cpp; sourceTree = ""; }; 40 | 209634DA20F4B3DE00207AD8 /* mtaf_base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_base.h; sourceTree = ""; }; 41 | 209634DB20F4B3DE00207AD8 /* MTAppenderFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTAppenderFile.h; sourceTree = ""; }; 42 | 209634DC20F4B3DE00207AD8 /* mtaf_formatter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mtaf_formatter.cpp; sourceTree = ""; }; 43 | 209634DD20F4B3DE00207AD8 /* mtaf_appender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtaf_appender.h; sourceTree = ""; }; 44 | 209634DE20F4B3DE00207AD8 /* mtaf_mmap_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mtaf_mmap_file.cpp; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 20926EBF1FE50BF5000DBD07 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 205E59131FE8E6CF0004D8BA /* Frameworks */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 208895061FE8E9410031DB01 /* libz.1.1.3.tbd */, 62 | 205E59141FE8E6CF0004D8BA /* libz.tbd */, 63 | ); 64 | name = Frameworks; 65 | sourceTree = ""; 66 | }; 67 | 20926EB91FE50BF5000DBD07 = { 68 | isa = PBXGroup; 69 | children = ( 70 | 209634CD20F4B3DE00207AD8 /* loglib */, 71 | 20926EC31FE50BF5000DBD07 /* Products */, 72 | 205E59131FE8E6CF0004D8BA /* Frameworks */, 73 | ); 74 | sourceTree = ""; 75 | }; 76 | 20926EC31FE50BF5000DBD07 /* Products */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 20926EC21FE50BF5000DBD07 /* libloglib.a */, 80 | ); 81 | name = Products; 82 | sourceTree = ""; 83 | }; 84 | 209634CD20F4B3DE00207AD8 /* loglib */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 209634D820F4B3DE00207AD8 /* mtaf_appender.cpp */, 88 | 209634DD20F4B3DE00207AD8 /* mtaf_appender.h */, 89 | 209634DA20F4B3DE00207AD8 /* mtaf_base.h */, 90 | 209634DC20F4B3DE00207AD8 /* mtaf_formatter.cpp */, 91 | 209634CF20F4B3DE00207AD8 /* mtaf_log_buffer.cpp */, 92 | 209634D520F4B3DE00207AD8 /* mtaf_log_buffer.h */, 93 | 209634DE20F4B3DE00207AD8 /* mtaf_mmap_file.cpp */, 94 | 209634D020F4B3DE00207AD8 /* mtaf_mmap_file.h */, 95 | 209634D720F4B3DE00207AD8 /* mtaf_platform_comm.mm */, 96 | 209634DB20F4B3DE00207AD8 /* MTAppenderFile.h */, 97 | 209634D620F4B3DE00207AD8 /* MTAppenderFile.mm */, 98 | ); 99 | name = loglib; 100 | sourceTree = ""; 101 | }; 102 | /* End PBXGroup section */ 103 | 104 | /* Begin PBXNativeTarget section */ 105 | 20926EC11FE50BF5000DBD07 /* loglib */ = { 106 | isa = PBXNativeTarget; 107 | buildConfigurationList = 20926ECB1FE50BF5000DBD07 /* Build configuration list for PBXNativeTarget "loglib" */; 108 | buildPhases = ( 109 | 20926EBE1FE50BF5000DBD07 /* Sources */, 110 | 20926EBF1FE50BF5000DBD07 /* Frameworks */, 111 | 20926EC01FE50BF5000DBD07 /* CopyFiles */, 112 | ); 113 | buildRules = ( 114 | ); 115 | dependencies = ( 116 | ); 117 | name = loglib; 118 | productName = loglib; 119 | productReference = 20926EC21FE50BF5000DBD07 /* libloglib.a */; 120 | productType = "com.apple.product-type.library.static"; 121 | }; 122 | /* End PBXNativeTarget section */ 123 | 124 | /* Begin PBXProject section */ 125 | 20926EBA1FE50BF5000DBD07 /* Project object */ = { 126 | isa = PBXProject; 127 | attributes = { 128 | LastUpgradeCheck = 1000; 129 | ORGANIZATIONNAME = meitu.com; 130 | TargetAttributes = { 131 | 20926EC11FE50BF5000DBD07 = { 132 | CreatedOnToolsVersion = 9.2; 133 | ProvisioningStyle = Automatic; 134 | }; 135 | }; 136 | }; 137 | buildConfigurationList = 20926EBD1FE50BF5000DBD07 /* Build configuration list for PBXProject "loglib" */; 138 | compatibilityVersion = "Xcode 8.0"; 139 | developmentRegion = en; 140 | hasScannedForEncodings = 0; 141 | knownRegions = ( 142 | en, 143 | ); 144 | mainGroup = 20926EB91FE50BF5000DBD07; 145 | productRefGroup = 20926EC31FE50BF5000DBD07 /* Products */; 146 | projectDirPath = ""; 147 | projectRoot = ""; 148 | targets = ( 149 | 20926EC11FE50BF5000DBD07 /* loglib */, 150 | ); 151 | }; 152 | /* End PBXProject section */ 153 | 154 | /* Begin PBXSourcesBuildPhase section */ 155 | 20926EBE1FE50BF5000DBD07 /* Sources */ = { 156 | isa = PBXSourcesBuildPhase; 157 | buildActionMask = 2147483647; 158 | files = ( 159 | 209634E520F4B3DE00207AD8 /* mtaf_formatter.cpp in Sources */, 160 | 209634E620F4B3DE00207AD8 /* mtaf_mmap_file.cpp in Sources */, 161 | 209634E020F4B3DE00207AD8 /* mtaf_log_buffer.cpp in Sources */, 162 | 209634E320F4B3DE00207AD8 /* mtaf_platform_comm.mm in Sources */, 163 | 209634E220F4B3DE00207AD8 /* MTAppenderFile.mm in Sources */, 164 | 209634E420F4B3DE00207AD8 /* mtaf_appender.cpp in Sources */, 165 | ); 166 | runOnlyForDeploymentPostprocessing = 0; 167 | }; 168 | /* End PBXSourcesBuildPhase section */ 169 | 170 | /* Begin XCBuildConfiguration section */ 171 | 20926EC91FE50BF5000DBD07 /* Debug */ = { 172 | isa = XCBuildConfiguration; 173 | buildSettings = { 174 | ALWAYS_SEARCH_USER_PATHS = NO; 175 | CLANG_ANALYZER_NONNULL = YES; 176 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 177 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 178 | CLANG_CXX_LIBRARY = "libc++"; 179 | CLANG_ENABLE_MODULES = YES; 180 | CLANG_ENABLE_OBJC_ARC = YES; 181 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 182 | CLANG_WARN_BOOL_CONVERSION = YES; 183 | CLANG_WARN_COMMA = YES; 184 | CLANG_WARN_CONSTANT_CONVERSION = YES; 185 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 186 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 187 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 188 | CLANG_WARN_EMPTY_BODY = YES; 189 | CLANG_WARN_ENUM_CONVERSION = YES; 190 | CLANG_WARN_INFINITE_RECURSION = YES; 191 | CLANG_WARN_INT_CONVERSION = YES; 192 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 193 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 194 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 195 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 196 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 197 | CLANG_WARN_STRICT_PROTOTYPES = YES; 198 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 199 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 200 | CLANG_WARN_UNREACHABLE_CODE = YES; 201 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 202 | CODE_SIGN_IDENTITY = "iPhone Developer"; 203 | COPY_PHASE_STRIP = NO; 204 | DEBUG_INFORMATION_FORMAT = dwarf; 205 | ENABLE_STRICT_OBJC_MSGSEND = YES; 206 | ENABLE_TESTABILITY = YES; 207 | GCC_C_LANGUAGE_STANDARD = gnu11; 208 | GCC_DYNAMIC_NO_PIC = NO; 209 | GCC_NO_COMMON_BLOCKS = YES; 210 | GCC_OPTIMIZATION_LEVEL = 0; 211 | GCC_PREPROCESSOR_DEFINITIONS = ( 212 | "DEBUG=1", 213 | "$(inherited)", 214 | ); 215 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 216 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 217 | GCC_WARN_UNDECLARED_SELECTOR = YES; 218 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 219 | GCC_WARN_UNUSED_FUNCTION = YES; 220 | GCC_WARN_UNUSED_VARIABLE = YES; 221 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 222 | MTL_ENABLE_DEBUG_INFO = YES; 223 | ONLY_ACTIVE_ARCH = YES; 224 | SDKROOT = iphoneos; 225 | }; 226 | name = Debug; 227 | }; 228 | 20926ECA1FE50BF5000DBD07 /* Release */ = { 229 | isa = XCBuildConfiguration; 230 | buildSettings = { 231 | ALWAYS_SEARCH_USER_PATHS = NO; 232 | CLANG_ANALYZER_NONNULL = YES; 233 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 234 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 235 | CLANG_CXX_LIBRARY = "libc++"; 236 | CLANG_ENABLE_MODULES = YES; 237 | CLANG_ENABLE_OBJC_ARC = YES; 238 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 239 | CLANG_WARN_BOOL_CONVERSION = YES; 240 | CLANG_WARN_COMMA = YES; 241 | CLANG_WARN_CONSTANT_CONVERSION = YES; 242 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 243 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 244 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 245 | CLANG_WARN_EMPTY_BODY = YES; 246 | CLANG_WARN_ENUM_CONVERSION = YES; 247 | CLANG_WARN_INFINITE_RECURSION = YES; 248 | CLANG_WARN_INT_CONVERSION = YES; 249 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 250 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 251 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 252 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 253 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 254 | CLANG_WARN_STRICT_PROTOTYPES = YES; 255 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 256 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 257 | CLANG_WARN_UNREACHABLE_CODE = YES; 258 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 259 | CODE_SIGN_IDENTITY = "iPhone Developer"; 260 | COPY_PHASE_STRIP = NO; 261 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 262 | ENABLE_NS_ASSERTIONS = NO; 263 | ENABLE_STRICT_OBJC_MSGSEND = YES; 264 | GCC_C_LANGUAGE_STANDARD = gnu11; 265 | GCC_NO_COMMON_BLOCKS = YES; 266 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 267 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 268 | GCC_WARN_UNDECLARED_SELECTOR = YES; 269 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 270 | GCC_WARN_UNUSED_FUNCTION = YES; 271 | GCC_WARN_UNUSED_VARIABLE = YES; 272 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 273 | MTL_ENABLE_DEBUG_INFO = NO; 274 | SDKROOT = iphoneos; 275 | VALIDATE_PRODUCT = YES; 276 | }; 277 | name = Release; 278 | }; 279 | 20926ECC1FE50BF5000DBD07 /* Debug */ = { 280 | isa = XCBuildConfiguration; 281 | buildSettings = { 282 | CLANG_WARN_ASSIGN_ENUM = YES; 283 | CLANG_WARN_CXX0X_EXTENSIONS = YES; 284 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 285 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; 286 | CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; 287 | CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; 288 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 289 | CLANG_WARN_OBJC_INTERFACE_IVARS = YES; 290 | CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; 291 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; 292 | CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES; 293 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; 294 | CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; 295 | CODE_SIGN_STYLE = Automatic; 296 | GCC_C_LANGUAGE_STANDARD = "compiler-default"; 297 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; 298 | GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; 299 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; 300 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 301 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 302 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; 303 | GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; 304 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; 305 | GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; 306 | GCC_WARN_SHADOW = YES; 307 | GCC_WARN_SIGN_COMPARE = YES; 308 | GCC_WARN_STRICT_SELECTOR_MATCH = YES; 309 | GCC_WARN_UNKNOWN_PRAGMAS = YES; 310 | GCC_WARN_UNUSED_LABEL = YES; 311 | GCC_WARN_UNUSED_PARAMETER = YES; 312 | HEADER_SEARCH_PATHS = $SOURCE_ROOT/../comm; 313 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 314 | OTHER_LDFLAGS = "-ObjC"; 315 | PRODUCT_NAME = "$(TARGET_NAME)"; 316 | SKIP_INSTALL = YES; 317 | TARGETED_DEVICE_FAMILY = "1,2"; 318 | }; 319 | name = Debug; 320 | }; 321 | 20926ECD1FE50BF5000DBD07 /* Release */ = { 322 | isa = XCBuildConfiguration; 323 | buildSettings = { 324 | CLANG_WARN_ASSIGN_ENUM = YES; 325 | CLANG_WARN_CXX0X_EXTENSIONS = YES; 326 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 327 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; 328 | CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; 329 | CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; 330 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 331 | CLANG_WARN_OBJC_INTERFACE_IVARS = YES; 332 | CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; 333 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; 334 | CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES; 335 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; 336 | CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; 337 | CODE_SIGN_STYLE = Automatic; 338 | GCC_C_LANGUAGE_STANDARD = "compiler-default"; 339 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; 340 | GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; 341 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; 342 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 343 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 344 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; 345 | GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; 346 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; 347 | GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; 348 | GCC_WARN_SHADOW = YES; 349 | GCC_WARN_SIGN_COMPARE = YES; 350 | GCC_WARN_STRICT_SELECTOR_MATCH = YES; 351 | GCC_WARN_UNKNOWN_PRAGMAS = YES; 352 | GCC_WARN_UNUSED_LABEL = YES; 353 | GCC_WARN_UNUSED_PARAMETER = YES; 354 | HEADER_SEARCH_PATHS = $SOURCE_ROOT/../comm; 355 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 356 | OTHER_LDFLAGS = "-ObjC"; 357 | PRODUCT_NAME = "$(TARGET_NAME)"; 358 | SKIP_INSTALL = YES; 359 | TARGETED_DEVICE_FAMILY = "1,2"; 360 | }; 361 | name = Release; 362 | }; 363 | /* End XCBuildConfiguration section */ 364 | 365 | /* Begin XCConfigurationList section */ 366 | 20926EBD1FE50BF5000DBD07 /* Build configuration list for PBXProject "loglib" */ = { 367 | isa = XCConfigurationList; 368 | buildConfigurations = ( 369 | 20926EC91FE50BF5000DBD07 /* Debug */, 370 | 20926ECA1FE50BF5000DBD07 /* Release */, 371 | ); 372 | defaultConfigurationIsVisible = 0; 373 | defaultConfigurationName = Release; 374 | }; 375 | 20926ECB1FE50BF5000DBD07 /* Build configuration list for PBXNativeTarget "loglib" */ = { 376 | isa = XCConfigurationList; 377 | buildConfigurations = ( 378 | 20926ECC1FE50BF5000DBD07 /* Debug */, 379 | 20926ECD1FE50BF5000DBD07 /* Release */, 380 | ); 381 | defaultConfigurationIsVisible = 0; 382 | defaultConfigurationName = Release; 383 | }; 384 | /* End XCConfigurationList section */ 385 | }; 386 | rootObject = 20926EBA1FE50BF5000DBD07 /* Project object */; 387 | } 388 | -------------------------------------------------------------------------------- /loglib/mtaf_appender.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by meitu on 2017/3/23. 3 | // 4 | 5 | #include "mtaf_condition.h" 6 | #include "mtaf_lock.h" 7 | #include "mtaf_thread.h" 8 | 9 | #include "mtaf_appender.h" 10 | #include "mtaf_base.h" 11 | #include "mtaf_log_buffer.h" 12 | #include "mtaf_mmap_file.h" 13 | 14 | #define __STDC_FORMAT_MACROS 15 | #include 16 | #include 17 | #include 18 | 19 | #define LOG_EXT "mtlog" 20 | 21 | using namespace MTAppenderFile; 22 | 23 | #define kBufferBlockLength 150 * 1024 // default 150KB. 24 | 25 | static void __async_log_thread_operation(void *arg); 26 | 27 | static void __log2file(mtaf_log_appender *mlog, const void *_data, size_t _len); 28 | 29 | extern void mtaf_log_formater(const mtaf_log_info *_info, const char *_logbody, PtrBuffer &_log); 30 | 31 | extern void mtaf_console_log(const char *_log); 32 | 33 | extern void mtaf_console_log(const mtaf_log_info *_info, const char *_log); 34 | 35 | struct mtaf_log_appender_t { 36 | 37 | std::string sg_logdir; 38 | 39 | std::string sg_logfilename; 40 | 41 | int sg_bufferblock_length; // default 150 * 1024 byte 42 | 43 | Mutex sg_mutex_log_file; 44 | 45 | std::atomic_bool sg_log_close; 46 | 47 | mtaf_mmapped_file *sg_mmap_file; 48 | 49 | MTAppenderFileLogBuffer *sg_log_buff; 50 | 51 | FILE *sg_logfile; 52 | 53 | time_t sg_openfiletime; 54 | 55 | std::string sg_current_dir; 56 | 57 | Mutex sg_mutex_buffer_async; 58 | 59 | Condition sg_cond_buffer_async; 60 | 61 | Thread *sg_thread_async; 62 | 63 | mtaf_append_mode sg_mode; 64 | 65 | uint8_t sg_security; 66 | 67 | bool sg_consolelog_open; 68 | 69 | bool sg_custom_name; 70 | }; 71 | 72 | 73 | #pragma mark - 74 | 75 | static void __async_log_shared_thread_operation(); 76 | 77 | // objc load() run before global cpp static variable inilization, 78 | // so use the function instead of global static variable. 79 | static Condition *__private_shared_condition = nullptr; 80 | void _initialize_share_condition() { 81 | __private_shared_condition = new Condition(); 82 | } 83 | Condition *shared_condition() { 84 | static std::once_flag initFlag; 85 | std::call_once(initFlag, _initialize_share_condition); 86 | return __private_shared_condition; 87 | } 88 | 89 | static SpinLock *__private_shared_spinlock; 90 | void _initialize_shared_spinlock() { 91 | __private_shared_spinlock = new SpinLock(); 92 | } 93 | SpinLock *shared_spinlock() { 94 | static std::once_flag initFlag; 95 | std::call_once(initFlag, _initialize_shared_spinlock); 96 | return __private_shared_spinlock; 97 | } 98 | 99 | static Thread *__private_shared_thread; 100 | void _initialize_shared_thread() { 101 | __private_shared_thread = new Thread("com.meitu.log.share_appender_file"); 102 | } 103 | Thread *shared_thread() { 104 | static std::once_flag initFlag; 105 | std::call_once(initFlag, _initialize_shared_thread); 106 | return __private_shared_thread; 107 | } 108 | 109 | static std::vector *p_shared_appenders; 110 | void _initialize_shared_appenders() { 111 | p_shared_appenders = new std::vector; 112 | } 113 | std::vector *shared_appenders() { 114 | static std::once_flag initFlag; 115 | std::call_once(initFlag, _initialize_shared_appenders); 116 | return p_shared_appenders; 117 | } 118 | 119 | #pragma mark - 120 | mtaf_log_appender *mtaf_log_appender_create(bool use_share_thread) { 121 | mtaf_log_appender *mlog = new mtaf_log_appender(); 122 | if (!mlog) { 123 | return NULL; 124 | } 125 | 126 | mlog->sg_log_close.store(true); 127 | mlog->sg_log_buff = NULL; 128 | mlog->sg_logfile = NULL; 129 | mlog->sg_openfiletime = 0; 130 | mlog->sg_thread_async = use_share_thread ? shared_thread() : new Thread(__async_log_thread_operation, mlog, "com.meitu.log.appender_file"); 131 | mlog->sg_mode = mtaf_append_mode_async; 132 | mlog->sg_consolelog_open = false; 133 | 134 | if (use_share_thread) { 135 | shared_spinlock()->lock(); 136 | shared_appenders()->push_back(mlog); 137 | shared_spinlock()->unlock(); 138 | } 139 | return mlog; 140 | } 141 | 142 | void mtaf_log_appender_destroy(mtaf_log_appender *mlog) { 143 | if (!mlog) { 144 | return; 145 | } 146 | 147 | mtaf_log_appender_close(mlog); 148 | if (mlog->sg_thread_async && mlog->sg_thread_async != shared_thread()) { 149 | delete mlog->sg_thread_async; 150 | } 151 | mlog->sg_thread_async = NULL; 152 | 153 | shared_spinlock()->lock(); 154 | for (auto it = shared_appenders()->begin(); it != shared_appenders()->end(); it++) { 155 | if (*it == mlog) { 156 | it = shared_appenders()->erase(it); 157 | break; 158 | } 159 | } 160 | 161 | shared_spinlock()->unlock(); 162 | 163 | delete mlog; 164 | } 165 | 166 | void mtaf_log_appender_open(mtaf_log_appender *mlog, mtaf_append_mode _mode, const char *filedir, const char *filename) { 167 | assert(filedir); 168 | assert(filename); 169 | if (!mlog) { 170 | printf("mt_appender_open : MTLogAppender is NULL\n"); 171 | return; 172 | } 173 | if (!mlog->sg_log_close.load()) { 174 | printf("appender has already been opened. _dir:%s _name:%s\n", filedir, filename); 175 | return; 176 | } 177 | if (mlog->sg_bufferblock_length <= 0) { 178 | mlog->sg_bufferblock_length = kBufferBlockLength; 179 | } 180 | 181 | char mmap_file_path[512] = {0}; 182 | snprintf(mmap_file_path, sizeof(mmap_file_path), "%s/%s.mmap2", filedir, filename); 183 | 184 | if (!mlog->sg_mmap_file) { 185 | mlog->sg_mmap_file = (mtaf_mmapped_file *)malloc(sizeof(mtaf_mmapped_file)); 186 | mlog->sg_mmap_file->isOpen = false; 187 | } 188 | bool use_mmap; 189 | if (mtaf_open_mmap(mlog->sg_mmap_file, mmap_file_path, mlog->sg_bufferblock_length, false) >= 0) { 190 | mlog->sg_log_buff = new MTAppenderFileLogBuffer(mlog->sg_mmap_file->start, mlog->sg_bufferblock_length); 191 | use_mmap = true; 192 | } else { 193 | char *buffer = new char[mlog->sg_bufferblock_length]; 194 | mlog->sg_log_buff = new MTAppenderFileLogBuffer(buffer, mlog->sg_bufferblock_length); 195 | use_mmap = false; 196 | } 197 | if (NULL == mlog->sg_log_buff->GetData().Ptr()) { 198 | if (use_mmap && mlog->sg_mmap_file->isOpen) 199 | mtaf_close_mmap(mlog->sg_mmap_file); 200 | return; 201 | } 202 | 203 | AutoBuffer buffer; 204 | mlog->sg_log_buff->Flush(buffer); 205 | ScopedLock lock(mlog->sg_mutex_log_file); 206 | mlog->sg_logdir = filedir; 207 | mlog->sg_logfilename = filename; 208 | mlog->sg_log_close.store(false); 209 | mtaf_log_appender_setmode(mlog, _mode); 210 | lock.unlock(); 211 | 212 | // 上次的缓存回写到文件 213 | if (buffer.Ptr()) { 214 | __log2file(mlog, buffer.Ptr(), buffer.Length()); 215 | } 216 | } 217 | 218 | static void __make_logfilename(const timeval &_tv, const std::string &_logdir, const char *_filename, 219 | const std::string &_fileext, char *_filepath, unsigned int _len) { 220 | 221 | std::string logfilepath = _logdir; 222 | logfilepath += "/"; 223 | logfilepath += _filename; 224 | logfilepath += "."; 225 | logfilepath += _fileext; 226 | strncpy(_filepath, logfilepath.c_str(), _len - 1); 227 | _filepath[_len - 1] = '\0'; 228 | } 229 | 230 | static bool __writefile(const void *_data, size_t _len, FILE *_file) { 231 | if (NULL == _file) { 232 | return false; 233 | } 234 | 235 | long before_len = ftell(_file); 236 | if (before_len < 0) return false; 237 | 238 | if (1 != fwrite(_data, _len, 1, _file)) { 239 | int err = ferror(_file); 240 | 241 | printf("write file error:%d\n", err); 242 | 243 | return false; 244 | } 245 | 246 | return true; 247 | } 248 | 249 | static bool __openlogfile(mtaf_log_appender *mlog, const std::string &_log_dir) { 250 | if (mlog->sg_logdir.empty()) return false; 251 | 252 | struct timeval tv; 253 | gettimeofday(&tv, NULL); 254 | 255 | if (NULL != mlog->sg_logfile) { 256 | time_t sec = tv.tv_sec; 257 | tm tcur = *localtime((const time_t *)&sec); 258 | tm filetm = *localtime(&mlog->sg_openfiletime); 259 | 260 | if (filetm.tm_year == tcur.tm_year && filetm.tm_mon == tcur.tm_mon && filetm.tm_mday == tcur.tm_mday && mlog->sg_current_dir == _log_dir) 261 | return true; 262 | 263 | fclose(mlog->sg_logfile); 264 | mlog->sg_logfile = NULL; 265 | } 266 | 267 | mlog->sg_openfiletime = tv.tv_sec; 268 | mlog->sg_current_dir = _log_dir; 269 | 270 | char logfilepath[1024] = {0}; 271 | __make_logfilename(tv, _log_dir, mlog->sg_logfilename.c_str(), LOG_EXT, logfilepath, 1024); 272 | 273 | mlog->sg_logfile = fopen(logfilepath, "ab"); 274 | 275 | if (NULL == mlog->sg_logfile) { 276 | printf("open file error:%d %s, path:%s", errno, strerror(errno), logfilepath); 277 | } 278 | 279 | return NULL != mlog->sg_logfile; 280 | } 281 | 282 | static void __closelogfile(mtaf_log_appender *mlog) { 283 | if (NULL == mlog->sg_logfile) return; 284 | 285 | mlog->sg_openfiletime = 0; 286 | fclose(mlog->sg_logfile); 287 | mlog->sg_logfile = NULL; 288 | } 289 | 290 | static void __log2file(mtaf_log_appender *mlog, const void *_data, size_t _len) { 291 | if (NULL == _data || 0 == _len || mlog->sg_logdir.empty()) { 292 | return; 293 | } 294 | 295 | ScopedLock lock_file(mlog->sg_mutex_log_file); 296 | 297 | bool write_sucess = false; 298 | bool open_success = __openlogfile(mlog, mlog->sg_logdir); 299 | if (open_success) { 300 | write_sucess = __writefile(_data, _len, mlog->sg_logfile); 301 | if (mtaf_append_mode_async == mlog->sg_mode) { 302 | __closelogfile(mlog); 303 | } 304 | } 305 | 306 | if (!write_sucess) { 307 | if (open_success && mtaf_append_mode_sync == mlog->sg_mode) { 308 | __closelogfile(mlog); 309 | } 310 | } 311 | } 312 | 313 | static void __log_thread_task(mtaf_log_appender *mlog) { 314 | if (NULL == mlog->sg_log_buff) return; 315 | 316 | ScopedLock lock_buffer(mlog->sg_mutex_buffer_async); 317 | AutoBuffer tmp; 318 | mlog->sg_log_buff->Flush(tmp); 319 | lock_buffer.unlock(); 320 | 321 | if (NULL != tmp.Ptr()) { 322 | __log2file(mlog, tmp.Ptr(), tmp.Length()); 323 | } 324 | } 325 | 326 | static void __async_log_shared_thread_operation() { 327 | while (true) { 328 | shared_spinlock()->lock(); 329 | 330 | if (shared_appenders()->empty()) { 331 | shared_spinlock()->unlock(); 332 | break; 333 | } 334 | 335 | for (auto it = shared_appenders()->begin(); it != shared_appenders()->end(); it++) { 336 | mtaf_log_appender *mlog = *it; 337 | if (mlog->sg_log_close.load()) { 338 | continue; 339 | } 340 | 341 | __log_thread_task(mlog); 342 | } 343 | 344 | shared_spinlock()->unlock(); 345 | 346 | shared_condition()->wait(15 * 60 * 1000); 347 | } 348 | } 349 | 350 | static void __async_log_thread_operation(void *arg) { 351 | mtaf_log_appender *mlog = (mtaf_log_appender *)arg; 352 | while (true) { 353 | if (NULL == mlog->sg_log_buff) { 354 | break; 355 | } 356 | 357 | __log_thread_task(mlog); 358 | 359 | if (mlog->sg_log_close.load()) { 360 | break; 361 | } 362 | 363 | mlog->sg_cond_buffer_async.wait(15 * 60 * 1000); 364 | } 365 | } 366 | 367 | static void __appender_sync(mtaf_log_appender *mlog, const mtaf_log_info *_info, const char *_log) { 368 | char temp[16 * 1024] = {0}; // tell perry,ray if you want modify size. 369 | PtrBuffer log(temp, 0, sizeof(temp)); 370 | mtaf_log_formater(_info, _log, log); 371 | char buffer_crypt[16 * 1024] = {0}; 372 | size_t len = 16 * 1024; 373 | if (!MTAppenderFileLogBuffer::Write(log.Ptr(), log.Length(), buffer_crypt, len)) 374 | return; 375 | __log2file(mlog, buffer_crypt, len); 376 | } 377 | 378 | static void __appender_async(mtaf_log_appender *mlog, const mtaf_log_info *_info, const char *_log) { 379 | ScopedLock lock(mlog->sg_mutex_buffer_async); 380 | if (NULL == mlog->sg_log_buff) return; 381 | 382 | char temp[16 * 1024] = {0}; //tell perry,ray if you want modify size. 383 | PtrBuffer log_buff(temp, 0, sizeof(temp)); 384 | mtaf_log_formater(_info, _log, log_buff); 385 | 386 | if (mlog->sg_log_buff->GetData().Length() >= mlog->sg_bufferblock_length * 4 / 5) { 387 | int ret = snprintf(temp, sizeof(temp), 388 | "[F][ sg_buffer_async.Length() >= BUFFER_BLOCK_LENTH*4/5, len: %d\n", 389 | (int)mlog->sg_log_buff->GetData().Length()); 390 | log_buff.Length(ret, ret); 391 | } 392 | 393 | if (!mlog->sg_log_buff->Write(log_buff.Ptr(), (unsigned int)log_buff.Length())) return; 394 | 395 | // mmap/内存超出一定限度就写通知异步线程写回到文件中 396 | if (mlog->sg_log_buff->GetData().Length() >= mlog->sg_bufferblock_length * 1 / 3 || (NULL != _info && LOG_LEVEL_FATAL == _info->level)) { 397 | mlog->sg_cond_buffer_async.notifyAll(); 398 | } 399 | 400 | // 共享线程在有数据输入的时候才启动 401 | if (!shared_thread()->isruning()) { 402 | shared_thread()->start(&__async_log_shared_thread_operation, NULL); 403 | } 404 | 405 | for (auto it = shared_appenders()->begin(); it != shared_appenders()->end(); it++) { 406 | mtaf_log_appender *mlog = *it; 407 | if (mlog->sg_log_close.load()) 408 | continue; 409 | 410 | if (mlog->sg_log_buff->GetData().Length() >= mlog->sg_bufferblock_length * 1 / 3 || (NULL != _info && LOG_LEVEL_FATAL == _info->level)) { 411 | shared_condition()->notifyAll(); 412 | break; 413 | } 414 | } 415 | } 416 | 417 | void mtaf_log_appender_append(mtaf_log_appender *mlog, const char *log) { 418 | if (mlog->sg_log_close.load()) return; 419 | 420 | if (mlog->sg_consolelog_open) mtaf_console_log(log); 421 | 422 | if (mtaf_append_mode_sync == mlog->sg_mode) 423 | __appender_sync(mlog, NULL, log); 424 | else 425 | __appender_async(mlog, NULL, log); 426 | } 427 | 428 | void mtaf_log_appender_append_ex(mtaf_log_appender *mlog, const char *log, const mtaf_log_info *mLogInfo) { 429 | if (mlog->sg_log_close.load()) return; 430 | 431 | if (mlog->sg_consolelog_open) mtaf_console_log(mLogInfo, log); 432 | 433 | if (mtaf_append_mode_sync == mlog->sg_mode) 434 | __appender_sync(mlog, mLogInfo, log); 435 | else 436 | __appender_async(mlog, mLogInfo, log); 437 | } 438 | 439 | void mtaf_log_appender_close(mtaf_log_appender *mlog) { 440 | if (mlog->sg_log_close.load()) return; 441 | 442 | mlog->sg_log_close = true; 443 | 444 | // 使用独立的线程 445 | mlog->sg_cond_buffer_async.notifyAll(); 446 | if (mlog->sg_thread_async->isruning() && mlog->sg_thread_async != shared_thread()) { 447 | mlog->sg_thread_async->join(); 448 | } 449 | 450 | // 使用共享线程 451 | shared_condition()->notifyAll(); 452 | if (mlog->sg_thread_async == shared_thread()) { 453 | __log_thread_task(mlog); 454 | } 455 | 456 | ScopedLock buffer_lock(mlog->sg_mutex_buffer_async); 457 | if (mlog->sg_mmap_file->isOpen) { 458 | memset(mlog->sg_mmap_file->start, 0, mlog->sg_bufferblock_length); 459 | mtaf_close_mmap(mlog->sg_mmap_file); 460 | } else { 461 | delete[](char *)((mlog->sg_log_buff->GetData()).Ptr()); 462 | } 463 | 464 | free(mlog->sg_mmap_file); 465 | mlog->sg_mmap_file = NULL; 466 | delete mlog->sg_log_buff; 467 | mlog->sg_log_buff = NULL; 468 | buffer_lock.unlock(); 469 | 470 | ScopedLock lock(mlog->sg_mutex_log_file); 471 | __closelogfile(mlog); 472 | } 473 | 474 | void mtaf_log_appender_setmode(mtaf_log_appender *mlog, mtaf_append_mode _mode) { 475 | mlog->sg_mode = _mode; 476 | mlog->sg_cond_buffer_async.notifyAll(); 477 | shared_condition()->notifyAll(); 478 | 479 | if (mtaf_append_mode_async == mlog->sg_mode && !mlog->sg_thread_async->isruning() && mlog->sg_thread_async != shared_thread()) { 480 | mlog->sg_thread_async->start(); 481 | } 482 | } 483 | 484 | void mtaf_log_appender_flush(mtaf_log_appender *mlog) { 485 | mlog->sg_cond_buffer_async.notifyAll(); 486 | shared_condition()->notifyAll(); 487 | } 488 | 489 | void mtaf_log_appender_flush_sync(mtaf_log_appender *mlog) { 490 | if (mtaf_append_mode_sync == mlog->sg_mode) { 491 | return; 492 | } 493 | ScopedLock lock_buffer(mlog->sg_mutex_buffer_async); 494 | 495 | if (NULL == mlog->sg_log_buff) return; 496 | 497 | AutoBuffer tmp; 498 | mlog->sg_log_buff->Flush(tmp); 499 | 500 | lock_buffer.unlock(); 501 | 502 | if (tmp.Ptr()) __log2file(mlog, tmp.Ptr(), tmp.Length()); 503 | } 504 | 505 | void mtaf_log_appender_set_console_log(mtaf_log_appender *mlog, bool _is_open) { 506 | mlog->sg_consolelog_open = _is_open; 507 | } 508 | -------------------------------------------------------------------------------- /loglib/mtaf_appender.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by meitu on 2017/3/24. 3 | // 4 | 5 | #ifndef MTAF_APPENDER_FILE_H 6 | #define MTAF_APPENDER_FILE_H 7 | 8 | #include 9 | #include 10 | 11 | #include "mtaf_base.h" 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | enum mtaf_append_mode { 18 | mtaf_append_mode_async, 19 | mtaf_append_mode_sync, 20 | }; 21 | 22 | typedef struct mtaf_log_appender_t mtaf_log_appender; 23 | 24 | mtaf_log_appender *mtaf_log_appender_create(bool shared_thread); 25 | 26 | void mtaf_log_appender_destroy(mtaf_log_appender *mlog); 27 | 28 | void mtaf_log_appender_open(mtaf_log_appender *mlog, mtaf_append_mode _mode, const char *filedir, const char *filename); 29 | 30 | void mtaf_log_appender_append(mtaf_log_appender *mlog, const char *log); 31 | 32 | void mtaf_log_appender_append_ex(mtaf_log_appender *mlog, const char *log, const mtaf_log_info *mLogInfo); 33 | 34 | void mtaf_log_appender_close(mtaf_log_appender *mlog); 35 | 36 | void mtaf_log_appender_setmode(mtaf_log_appender *mlog, mtaf_append_mode _mode); 37 | 38 | void mtaf_log_appender_set_console_log(mtaf_log_appender *mlog, bool _is_open); 39 | 40 | void mtaf_log_appender_flush(mtaf_log_appender *mlog); 41 | 42 | void mtaf_log_appender_flush_sync(mtaf_log_appender *mlog); 43 | 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | 49 | #endif // MTAF_APPENDER_FILE_H 50 | -------------------------------------------------------------------------------- /loglib/mtaf_base.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by meitu on 2017/3/24. 3 | // 4 | 5 | #ifndef MTAF_BASE_H 6 | #define MTAF_BASE_H 7 | 8 | #include 9 | #include 10 | 11 | #define LOG_LEVEL_ALL 0 12 | #define LOG_LEVEL_VERBOSE 0 13 | #define LOG_LEVEL_DEBUG 1 14 | #define LOG_LEVEL_INFO 2 15 | #define LOG_LEVEL_WARN 3 16 | #define LOG_LEVEL_ERROR 4 17 | #define LOG_LEVEL_FATAL 5 18 | #define LOG_LEVEL_NONE 6 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | typedef struct mtaf_log_info_t { 25 | int level; 26 | const char *tag; 27 | struct timeval timeval; 28 | } mtaf_log_info; 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | 34 | #endif // MTAF_BASE_H 35 | -------------------------------------------------------------------------------- /loglib/mtaf_formatter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mtaf_base.h" 4 | #include "mtaf_ptrbuffer.h" 5 | 6 | #define __STDC_FORMAT_MACROS 7 | #include 8 | 9 | // 10 | // Created by meitu on 2017/3/24. 11 | // 12 | void mtaf_log_formater(const mtaf_log_info *_info, const char *_logbody, MTAppenderFile::PtrBuffer &_log) { 13 | static const char *levelStrings[] = { 14 | "V", 15 | "D", // debug 16 | "I", // info 17 | "W", // warn 18 | "E", // error 19 | "F" // fatal 20 | }; 21 | 22 | assert((unsigned int)_log.Pos() == _log.Length()); 23 | 24 | static int error_count = 0; 25 | static int error_size = 0; 26 | 27 | if (_log.MaxLength() <= _log.Length() + 5 * 1024) { // allowd len(_log) <= 11K(16K - 5K) 28 | ++error_count; 29 | error_size = (int)strnlen(_logbody, 1024 * 1024); 30 | 31 | if (_log.MaxLength() >= _log.Length() + 128) { 32 | int ret = snprintf((char *)_log.PosPtr(), 1024, "[F]log_size <= 5*1024, err(%d, %d)\n", 33 | error_count, error_size); // **CPPLINT SKIP** 34 | _log.Length(_log.Pos() + ret, _log.Length() + ret); 35 | _log.Write(""); 36 | 37 | error_count = 0; 38 | error_size = 0; 39 | } 40 | 41 | return; 42 | } 43 | 44 | if (NULL != _info) { 45 | char temp_time[64] = {0}; 46 | 47 | if (0 != _info->timeval.tv_sec) { 48 | time_t sec = _info->timeval.tv_sec; 49 | tm tm = *localtime((const time_t *)&sec); 50 | snprintf(temp_time, sizeof(temp_time), "%d-%02d-%02d %+.1f %02d:%02d:%02d.%.3d", 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, 51 | tm.tm_gmtoff / 3600.0, tm.tm_hour, tm.tm_min, tm.tm_sec, _info->timeval.tv_usec / 1000); 52 | } 53 | 54 | int ret = snprintf((char *)_log.PosPtr(), 1024, "[%s][%s][%s]: ", // **CPPLINT SKIP** 55 | _logbody ? levelStrings[_info->level] : levelStrings[LOG_LEVEL_FATAL], 56 | temp_time, _info->tag ? _info->tag : ""); 57 | assert(0 <= ret); 58 | _log.Length(_log.Pos() + ret, _log.Length() + ret); 59 | 60 | assert((unsigned int)_log.Pos() == _log.Length()); 61 | } 62 | 63 | if (NULL != _logbody) { 64 | // in android 64bit, in strnlen memchr, const unsigned char* end = p + n; > 4G!!!!! in stack array 65 | 66 | size_t bodylen = _log.MaxLength() - _log.Length() > 130 ? _log.MaxLength() - _log.Length() - 130 : 0; 67 | bodylen = bodylen > 0xFFFFU ? 0xFFFFU : bodylen; 68 | bodylen = strnlen(_logbody, bodylen); 69 | bodylen = bodylen > 0xFFFFU ? 0xFFFFU : bodylen; 70 | _log.Write(_logbody, bodylen); 71 | } else { 72 | _log.Write("error!! NULL==_logbody"); 73 | } 74 | 75 | char nextline = '\n'; 76 | 77 | if (*((char *)_log.PosPtr() - 1) != nextline) _log.Write(&nextline, 1); 78 | } 79 | -------------------------------------------------------------------------------- /loglib/mtaf_log_buffer.cpp: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | /* 14 | * log_buffer.cpp 15 | * 16 | * Created on: 2015-7-28 17 | * Author: yanguoyue 18 | */ 19 | 20 | #include "mtaf_log_buffer.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace MTAppenderFile; 27 | 28 | bool MTAppenderFileLogBuffer::Write(const void *_data, size_t _input_len, void *_output, size_t &_output_len) { 29 | if (NULL == _data || NULL == _output || 0 == _input_len) { 30 | return false; 31 | } 32 | 33 | memcpy(_output, _data, _input_len); 34 | _output_len = _input_len; 35 | 36 | return true; 37 | } 38 | 39 | MTAppenderFileLogBuffer::MTAppenderFileLogBuffer(void *_pbuffer, size_t _len) { 40 | buff_.Attach(_pbuffer, _len); 41 | __Fix(); 42 | 43 | memset(&cstream_, 0, sizeof(cstream_)); 44 | } 45 | 46 | MTAppenderFileLogBuffer::~MTAppenderFileLogBuffer() { 47 | if (Z_NULL != cstream_.state) { 48 | deflateEnd(&cstream_); 49 | } 50 | } 51 | 52 | PtrBuffer &MTAppenderFileLogBuffer::GetData() { 53 | return buff_; 54 | } 55 | 56 | void MTAppenderFileLogBuffer::Flush(AutoBuffer &_buff) { 57 | if (Z_NULL != cstream_.state) { 58 | deflateEnd(&cstream_); 59 | } 60 | 61 | if ((uint32_t)strnlen((char *)buff_.Ptr(), buff_.Length()) == 0) { 62 | __Clear(); 63 | return; 64 | } 65 | 66 | __Flush(); 67 | _buff.Write(buff_.Ptr(), buff_.Length()); 68 | __Clear(); 69 | } 70 | 71 | bool MTAppenderFileLogBuffer::Write(const void *_data, size_t _length) { 72 | if (NULL == _data || 0 == _length) { 73 | return false; 74 | } 75 | 76 | if (buff_.Length() == 0) { 77 | if (!__Reset()) return false; 78 | } 79 | 80 | buff_.Write(_data, _length); 81 | 82 | return true; 83 | } 84 | 85 | bool MTAppenderFileLogBuffer::__Reset() { 86 | __Clear(); 87 | return true; 88 | } 89 | 90 | void MTAppenderFileLogBuffer::__Flush() { 91 | } 92 | 93 | void MTAppenderFileLogBuffer::__Clear() { 94 | // 有游标控制数据位置,理论上只需将第一个字节置空即可 95 | memset(buff_.Ptr(), 0, 1); 96 | buff_.Length(0, 0); 97 | } 98 | 99 | 100 | void MTAppenderFileLogBuffer::__Fix() { 101 | } 102 | -------------------------------------------------------------------------------- /loglib/mtaf_log_buffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making GAutomator available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | /* 14 | * log_buffer.h 15 | * 16 | * Created on: 2015-7-28 17 | * Author: yanguoyue 18 | */ 19 | 20 | #ifndef MTAF_LOGBUFFER_H_ 21 | #define MTAF_LOGBUFFER_H_ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "mtaf_autobuffer.h" 27 | #include "mtaf_ptrbuffer.h" 28 | 29 | class MTAppenderFileLogCrypt; 30 | 31 | class MTAppenderFileLogBuffer 32 | { 33 | public: 34 | MTAppenderFileLogBuffer(void *_pbuffer, size_t _len); 35 | ~MTAppenderFileLogBuffer(); 36 | 37 | public: 38 | static bool Write(const void *_data, size_t _inputlen, void *_output, size_t &_len); 39 | 40 | public: 41 | MTAppenderFile::PtrBuffer &GetData(); 42 | 43 | void Flush(MTAppenderFile::AutoBuffer &_buff); 44 | bool Write(const void *_data, size_t _length); 45 | 46 | private: 47 | bool __Reset(); 48 | void __Flush(); 49 | void __Clear(); 50 | 51 | void __Fix(); 52 | 53 | private: 54 | MTAppenderFile::PtrBuffer buff_; 55 | z_stream cstream_; 56 | }; 57 | 58 | 59 | #endif /* MTAF_LOGBUFFER_H_ */ 60 | -------------------------------------------------------------------------------- /loglib/mtaf_mmap_file.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by meitu on 2017/3/24. 3 | // 4 | #include "mtaf_mmap_file.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "fcntl.h" 11 | 12 | int mtaf_open_mmap(mtaf_mmapped_file *mt, const char *filePath, int mapSize, bool isRead) { 13 | if (!mt) { 14 | printf("[error] try to open MMap while mtaf_mmapped_file is null"); 15 | return -1; 16 | } 17 | 18 | if (mt && mt->isOpen) { 19 | mtaf_close_mmap(mt); 20 | } 21 | if (isRead) { 22 | mt->mmapFd = open(filePath, O_RDWR); 23 | } else { 24 | mt->mmapFd = open(filePath, O_CREAT | O_RDWR, 0666); 25 | } 26 | if (mt->mmapFd < 0) { 27 | int code = errno; // EINVAL 28 | printf("[error] mmap open failed, code: %d, filepath: %s\n", code, filePath); 29 | if (code == ENOENT) { 30 | printf("[error] please check the directory\n"); 31 | } 32 | return -1; 33 | } 34 | mt->isOpen = true; 35 | ftruncate(mt->mmapFd, mapSize); 36 | mt->start = (unsigned char *)mmap(0, (size_t)mapSize, PROT_WRITE, MAP_SHARED, mt->mmapFd, 0); 37 | mt->offset = 0; 38 | mt->size = mapSize; 39 | return 0; 40 | } 41 | 42 | void mtaf_write_mmap(mtaf_mmapped_file *mt, const char *data, int len) { 43 | memcpy(mt->start + mt->offset, data, len); 44 | mt->offset += len; 45 | } 46 | 47 | void mtaf_read_mmap(mtaf_mmapped_file *mt, const char *data, int len) { 48 | memcpy((void *)data, mt->start + mt->offset, len); 49 | mt->offset += len; 50 | } 51 | 52 | void mtaf_close_mmap(mtaf_mmapped_file *mt) { 53 | mt->offset = 0; 54 | munmap(mt->start, (size_t)mt->size); 55 | close(mt->mmapFd); 56 | mt->mmapFd = -1; 57 | mt->isOpen = false; 58 | } 59 | -------------------------------------------------------------------------------- /loglib/mtaf_mmap_file.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by meitu on 2017/3/24. 3 | // 4 | 5 | #ifndef MTAF_MMAPPED_FILE_H 6 | #define MTAF_MMAPPED_FILE_H 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | typedef struct mtaf_mmapped_file { 13 | int mmapFd; 14 | int offset; 15 | int size; 16 | bool isOpen; 17 | unsigned char *start; 18 | } mtaf_mmapped_file; 19 | 20 | int mtaf_open_mmap(struct mtaf_mmapped_file *mt, const char *filePath, int mapSize, bool isRead); 21 | 22 | void mtaf_write_mmap(struct mtaf_mmapped_file *mt, const char *data, int len); 23 | 24 | void mtaf_read_mmap(struct mtaf_mmapped_file *mt, const char *data, int len); 25 | 26 | void mtaf_close_mmap(struct mtaf_mmapped_file *mt); 27 | 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif // MTAF_MMAPPED_FILE_H 34 | -------------------------------------------------------------------------------- /loglib/mtaf_platform_comm.mm: -------------------------------------------------------------------------------- 1 | // 2 | // platform_comm.mm 3 | // loglib 4 | // 5 | // Created by EuanC on 19/12/2017. 6 | // Copyright © 2017 meitu.com. All rights reserved. 7 | // 8 | 9 | #ifndef mtaf_platform_comm_h 10 | #define mtaf_platform_comm_h 11 | 12 | #import 13 | #include "mtaf_base.h" 14 | 15 | void mtaf_console_log(const char *_log) { 16 | NSLog(@"[appender_file] %s", _log); 17 | } 18 | 19 | void mtaf_console_log(const mtaf_log_info *_info, const char *_log) { 20 | NSLog(@"[appender_file] %s", _log); 21 | } 22 | 23 | #endif /* mtaf_platform_comm_h */ 24 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | BASE_DIR=$(dirname "$0") 6 | 7 | sh $BASE_DIR/Scripts/Hooks/setup-hook.sh 8 | 9 | git config commit.template $BASE_DIR/.gitlab/git_commit_templates/Commit_Template.md 10 | --------------------------------------------------------------------------------