Changes in / [341bb80:8bdc1c36]
- Files:
-
- 1 deleted
- 2 edited
-
Jenkinsfile (modified) (6 diffs)
-
libcfa/src/heap.cfa (modified) (36 diffs)
-
tools/PrettyGitLogs.sh (deleted)
Legend:
- Unmodified
- Added
- Removed
-
Jenkinsfile
r341bb80 r8bdc1c36 6 6 node ('master'){ 7 7 8 // Globals 9 BuildDir = pwd tmp: true 10 SrcDir = pwd tmp: false 11 Settings = null 12 StageName = '' 13 14 // Local variables 8 boolean bIsSandbox = env.BRANCH_NAME == "jenkins-sandbox" 15 9 def err = null 16 10 def log_needed = false 11 12 stage_name = '' 13 14 compiler = null 15 arch_name = '' 16 architecture = '' 17 18 do_alltests = false 19 do_benchmark = false 20 do_doc = false 21 do_publish = false 22 do_sendemail = true 23 24 builddir = pwd tmp: true 25 srcdir = pwd tmp: false 17 26 18 27 currentBuild.result = "SUCCESS" … … 24 33 notify_server(0) 25 34 26 Settings =prepare_build()35 prepare_build() 27 36 28 37 clean() … … 52 61 err = caughtError 53 62 54 echo err.toString()55 56 63 //An error has occured, the build log is relevent 57 64 log_needed = true 58 65 59 66 //Store the result of the build log 60 currentBuild.result = "${ StageName} FAILURE".trim()67 currentBuild.result = "${stage_name} FAILURE".trim() 61 68 } 62 69 63 70 finally { 64 71 //Send email with final results if this is not a full build 65 if( Settings && !Settings.Silent ) { 66 email(log_needed, Settings.IsSandbox) 72 if( do_sendemail ) { 73 echo 'Notifying users of result' 74 email(currentBuild.result, log_needed, bIsSandbox) 67 75 } 68 76 … … 77 85 78 86 //=========================================================================================================== 79 // Main compilation routines80 //===========================================================================================================81 def clean() {82 build_stage('Cleanup') {83 // clean the build by wipping the build directory84 dir(BuildDir) {85 deleteDir()86 }87 }88 }89 90 //Compilation script is done here but environnement set-up and error handling is done in main loop91 def checkout() {92 build_stage('Checkout') {93 //checkout the source code and clean the repo94 final scmVars = checkout scm95 Settings.GitNewRef = scmVars.GIT_COMMIT96 Settings.GitOldRef = scmVars.GIT_PREVIOUS_COMMIT97 98 echo GitLogMessage()99 }100 }101 102 def build() {103 build_stage('Build') {104 // Build outside of the src tree to ease cleaning105 dir (BuildDir) {106 //Configure the conpilation (Output is not relevant)107 //Use the current directory as the installation target so nothing escapes the sandbox108 //Also specify the compiler by hand109 targets=""110 if( Settings.RunAllTests ) {111 targets="--with-target-hosts='host:debug,host:nodebug'"112 } else {113 targets="--with-target-hosts='host:debug'"114 }115 116 sh "${SrcDir}/configure CXX=${Settings.Compiler.cpp_cc} ${Settings.Architecture.flags} ${targets} --with-backend-compiler=${Settings.Compiler.cfa_cc} --quiet"117 118 //Compile the project119 sh 'make -j 8 --no-print-directory'120 }121 }122 }123 124 def test() {125 build_stage('Test') {126 127 dir (BuildDir) {128 //Run the tests from the tests directory129 if ( Settings.RunAllTests ) {130 sh 'make --no-print-directory -C tests all-tests debug=yes'131 sh 'make --no-print-directory -C tests all-tests debug=no '132 }133 else {134 sh 'make --no-print-directory -C tests'135 }136 }137 }138 }139 140 def benchmark() {141 build_stage('Benchmark') {142 143 if( !Settings.RunBenchmark ) return144 145 dir (BuildDir) {146 //Append bench results147 sh "make --no-print-directory -C benchmark jenkins githash=${Settings.GitNewRef} arch=${Settings.Architecture} | tee ${SrcDir}/bench.json"148 }149 }150 }151 152 def build_doc() {153 build_stage('Documentation') {154 155 if( !Settings.BuildDocumentation ) return156 157 dir ('doc/user') {158 make_doc()159 }160 161 dir ('doc/refrat') {162 make_doc()163 }164 }165 }166 167 def publish() {168 build_stage('Publish') {169 170 if( !Settings.Publish ) return171 172 //Then publish the results173 sh 'curl --silent --show-error -H \'Content-Type: application/json\' --data @bench.json https://cforall.uwaterloo.ca:8082/jenkins/publish > /dev/null || true'174 }175 }176 177 //===========================================================================================================178 //Routine responsible of sending the email notification once the build is completed179 //===========================================================================================================180 def GitLogMessage() {181 if (!Settings || !Settings.GitOldRef || !Settings.GitNewRef) return "\nERROR retrieveing git information!\n"182 183 sh "${SrcDir}/tools/PrettyGitLogs.sh ${BuildDir} ${Settings.GitOldRef} ${Settings.GitNewRef}"184 185 def gitUpdate = readFile("${BuildDir}/GIT_UPDATE")186 def gitLog = readFile("${BuildDir}/GIT_LOG")187 def gitDiff = readFile("${BuildDir}/GIT_DIFF")188 189 return """190 The branch ${env.BRANCH_NAME} has been updated.191 ${gitUpdate}192 193 Check console output at ${env.BUILD_URL} to view the results.194 195 - Status --------------------------------------------------------------196 197 BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}198 199 - Log -----------------------------------------------------------------200 ${gitLog}201 -----------------------------------------------------------------------202 Summary of changes:203 ${gitDiff}204 """205 }206 207 //Standard build email notification208 def email(boolean log, boolean bIsSandbox) {209 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line210 //Configurations for email format211 echo 'Notifying users of result'212 213 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase()214 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}"215 def email_body = """This is an automated email from the Jenkins build machine. It was216 generated because of a git hooks/post-receive script following217 a ref change which was pushed to the Cforall repository.218 """ + GitLogMessage()219 220 def email_to = "cforall@lists.uwaterloo.ca"221 222 if( Settings && !Settings.IsSandbox ) {223 //send email notification224 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log225 } else {226 echo "Would send email to: ${email_to}"227 echo "With title: ${email_subject}"228 echo "Content: \n${email_body}"229 }230 }231 232 //===========================================================================================================233 87 // Helper classes/variables/routines 234 88 //=========================================================================================================== 235 //Description of a compiler (Must be serializable since pipelines are persistent) 236 class CC_Desc implements Serializable { 237 public String cc_name 238 public String cpp_cc 239 public String cfa_cc 240 241 CC_Desc(String cc_name, String cpp_cc, String cfa_cc) { 242 this.cc_name = cc_name 243 this.cpp_cc = cpp_cc 244 this.cfa_cc = cfa_cc 245 } 246 } 247 248 //Description of an architecture (Must be serializable since pipelines are persistent) 249 class Arch_Desc implements Serializable { 250 public String name 251 public String flags 252 253 Arch_Desc(String name, String flags) { 254 this.name = name 255 this.flags = flags 256 } 257 } 258 259 class BuildSettings implements Serializable { 260 public final CC_Desc Compiler 261 public final Arch_Desc Architecture 262 public final Boolean RunAllTests 263 public final Boolean RunBenchmark 264 public final Boolean BuildDocumentation 265 public final Boolean Publish 266 public final Boolean Silent 267 public final Boolean IsSandbox 268 public final String DescLong 269 public final String DescShort 270 271 public String GitNewRef 272 public String GitOldRef 273 274 BuildSettings(java.util.Collections$UnmodifiableMap param, String branch) { 275 switch( param.Compiler ) { 276 case 'gcc-6': 277 this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6') 278 break 279 case 'gcc-5': 280 this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5') 281 break 282 case 'gcc-4.9': 283 this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9') 284 break 285 case 'clang': 286 this.Compiler = new CC_Desc('clang', 'clang++', 'gcc-6') 287 break 288 default : 289 error "Unhandled compiler : ${cc}" 290 } 291 292 switch( param.Architecture ) { 293 case 'x64': 294 this.Architecture = new Arch_Desc('x64', '--host=x86_64') 295 break 296 case 'x86': 297 this.Architecture = new Arch_Desc('x86', '--host=i386') 298 break 299 default : 300 error "Unhandled architecture : ${arch}" 301 } 302 303 this.RunAllTests = param.RunAllTests 304 this.RunBenchmark = param.RunBenchmark 305 this.BuildDocumentation = param.BuildDocumentation 306 this.Publish = param.Publish 307 this.Silent = param.Silent 308 this.IsSandbox = (branch == "jenkins-sandbox") 309 310 def full = param.RunAllTests ? " (Full)" : "" 311 this.DescShort = "${ this.Compiler.cc_name }:${ this.Architecture.name }${full}" 312 313 this.DescLong = """Compiler : ${ this.Compiler.cc_name } (${ this.Compiler.cpp_cc }/${ this.Compiler.cfa_cc }) 314 Architecture : ${ this.Architecture.name } 315 Arc Flags : ${ this.Architecture.flags } 316 Run All Tests : ${ this.RunAllTests.toString() } 317 Run Benchmark : ${ this.RunBenchmark.toString() } 318 Build Documentation : ${ this.BuildDocumentation.toString() } 319 Publish : ${ this.Publish.toString() } 320 Silent : ${ this.Silent.toString() } 321 """ 322 323 this.GitNewRef = '' 324 this.GitOldRef = '' 325 } 89 //Helper routine to collect information about the git history 90 def collect_git_info() { 91 92 checkout scm 93 94 //create the temporary output directory in case it doesn't already exist 95 def out_dir = pwd tmp: true 96 sh "mkdir -p ${out_dir}" 97 98 //parse git logs to find what changed 99 gitRefName = env.BRANCH_NAME 100 sh "git reflog > ${out_dir}/GIT_COMMIT" 101 git_reflog = readFile("${out_dir}/GIT_COMMIT") 102 gitRefOldValue = (git_reflog =~ /moving from (.+) to (.+)/)[0][1] 103 gitRefNewValue = (git_reflog =~ /moving from (.+) to (.+)/)[0][2] 326 104 } 327 105 328 106 def prepare_build() { 329 // prepare the properties330 107 properties ([ \ 331 108 [$class: 'ParametersDefinitionProperty', \ … … 371 148 ]]) 372 149 373 final settings = new BuildSettings(params, env.BRANCH_NAME) 374 375 currentBuild.description = settings.DescShort 376 echo settings.DescLong 377 378 return settings 150 compiler = compiler_from_params( params.Compiler ) 151 arch_name = params.Architecture 152 architecture = architecture_from_params( arch_name ) 153 154 do_alltests = (params.RunAllTests == 'true') 155 do_benchmark = (params.RunBenchmark == 'true') 156 do_doc = (params.BuildDocumentation == 'true') 157 do_publish = (params.Publish == 'true') 158 do_sendemail = ! (params.Silent == 'true') 159 160 collect_git_info() 161 162 def full = do_alltests ? " (Full)" : "" 163 currentBuild.description = "${compiler.cc_name}:${arch_name}${full}" 164 165 echo """Compiler : ${ compiler.cc_name } (${ compiler.cpp_cc }/${ compiler.cfa_cc }) 166 Architecture : ${ arch_name } 167 Arc Flags : ${ architecture } 168 Run All Tests : ${ params.RunAllTests.toString() } 169 Run Benchmark : ${ params.RunBenchmark.toString() } 170 Build Documentation : ${ params.BuildDocumentation.toString() } 171 Publish : ${ params.Publish.toString() } 172 Silent : ${ params.Silent.toString() } 173 """ 379 174 } 380 175 381 176 def build_stage(String name, Closure block ) { 382 StageName = name 383 echo " -------- ${StageName} -------- " 177 stage_name = name 384 178 stage(name, block) 385 179 } … … 404 198 } 405 199 } 200 201 //Description of a compiler (Must be serializable since pipelines are persistent) 202 class CC_Desc implements Serializable { 203 public String cc_name 204 public String cpp_cc 205 public String cfa_cc 206 207 CC_Desc(String cc_name, String cpp_cc, String cfa_cc) { 208 this.cc_name = cc_name 209 this.cpp_cc = cpp_cc 210 this.cfa_cc = cfa_cc 211 } 212 } 213 214 def compiler_from_params(cc) { 215 switch( cc ) { 216 case 'gcc-6': 217 return new CC_Desc('gcc-6', 'g++-6', 'gcc-6') 218 break 219 case 'gcc-5': 220 return new CC_Desc('gcc-5', 'g++-5', 'gcc-5') 221 break 222 case 'gcc-4.9': 223 return new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9') 224 break 225 case 'clang': 226 return new CC_Desc('clang', 'clang++', 'gcc-6') 227 break 228 default : 229 error "Unhandled compiler : ${cc}" 230 } 231 } 232 233 def architecture_from_params( arch ) { 234 switch( arch ) { 235 case 'x64': 236 return '--host=x86_64' 237 break 238 case 'x86': 239 return '--host=i386' 240 break 241 default : 242 error "Unhandled architecture : ${arch}" 243 } 244 } 245 246 //=========================================================================================================== 247 // Main compilation routines 248 //=========================================================================================================== 249 def clean() { 250 build_stage('Cleanup') { 251 // clean the build by wipping the build directory 252 dir(builddir) { 253 deleteDir() 254 } 255 256 //Clean all temporary files to make sure no artifacts of the previous build remain 257 sh 'git clean -fdqx' 258 259 //Reset the git repo so no local changes persist 260 sh 'git reset --hard' 261 } 262 } 263 264 //Compilation script is done here but environnement set-up and error handling is done in main loop 265 def checkout() { 266 build_stage('Checkout') { 267 //checkout the source code and clean the repo 268 checkout scm 269 } 270 } 271 272 def build() { 273 build_stage('Build') { 274 // Build outside of the src tree to ease cleaning 275 dir (builddir) { 276 //Configure the conpilation (Output is not relevant) 277 //Use the current directory as the installation target so nothing escapes the sandbox 278 //Also specify the compiler by hand 279 targets="" 280 if(do_alltests) { 281 targets="--with-target-hosts='host:debug,host:nodebug'" 282 } else { 283 targets="--with-target-hosts='host:debug'" 284 } 285 286 sh "${srcdir}/configure CXX=${compiler.cpp_cc} ${architecture} ${targets} --with-backend-compiler=${compiler.cfa_cc} --quiet" 287 288 //Compile the project 289 sh 'make -j 8 --no-print-directory' 290 } 291 } 292 } 293 294 def test() { 295 build_stage('Test') { 296 297 dir (builddir) { 298 //Run the tests from the tests directory 299 if ( do_alltests ) { 300 sh 'make --no-print-directory -C tests all-tests debug=yes' 301 sh 'make --no-print-directory -C tests all-tests debug=no ' 302 } 303 else { 304 sh 'make --no-print-directory -C tests' 305 } 306 } 307 } 308 } 309 310 def benchmark() { 311 build_stage('Benchmark') { 312 313 if( !do_benchmark ) return 314 315 dir (builddir) { 316 //Append bench results 317 sh "make --no-print-directory -C benchmark jenkins githash=${gitRefNewValue} arch=${arch_name} | tee ${srcdir}/bench.json" 318 } 319 } 320 } 321 322 def build_doc() { 323 build_stage('Documentation') { 324 325 if( !do_doc ) return 326 327 dir ('doc/user') { 328 make_doc() 329 } 330 331 dir ('doc/refrat') { 332 make_doc() 333 } 334 } 335 } 336 337 def publish() { 338 build_stage('Publish') { 339 340 if( !do_publish ) return 341 342 //Then publish the results 343 sh 'curl --silent --show-error -H \'Content-Type: application/json\' --data @bench.json https://cforall.uwaterloo.ca:8082/jenkins/publish > /dev/null || true' 344 } 345 } 346 347 //=========================================================================================================== 348 //Routine responsible of sending the email notification once the build is completed 349 //=========================================================================================================== 350 def gitBranchUpdate(String gitRefOldValue, String gitRefNewValue) { 351 def update = "" 352 sh "git rev-list ${gitRefOldValue}..${gitRefNewValue} > GIT_LOG"; 353 readFile('GIT_LOG').eachLine { rev -> 354 sh "git cat-file -t ${rev} > GIT_TYPE" 355 def type = readFile('GIT_TYPE') 356 357 update += " via ${rev} (${type})\n" 358 } 359 def rev = gitRefOldValue 360 sh "git cat-file -t ${rev} > GIT_TYPE" 361 def type = readFile('GIT_TYPE') 362 363 update += " from ${rev} (${type})\n" 364 return update 365 366 def output=readFile('result').trim() 367 echo "output=$output"; 368 } 369 370 //Standard build email notification 371 def email(String status, boolean log, boolean bIsSandbox) { 372 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line 373 //Configurations for email format 374 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase() 375 376 def gitLog = 'Error retrieving git logs' 377 def gitDiff = 'Error retrieving git diff' 378 def gitUpdate = 'Error retrieving update' 379 380 try { 381 gitUpdate = gitBranchUpdate(gitRefOldValue, gitRefNewValue) 382 383 sh "git rev-list --format=short ${gitRefOldValue}...${gitRefNewValue} > GIT_LOG" 384 gitLog = readFile('GIT_LOG') 385 386 sh "git diff --stat ${gitRefNewValue} ${gitRefOldValue} > GIT_DIFF" 387 gitDiff = readFile('GIT_DIFF') 388 } 389 catch (Exception error) { 390 echo error.toString() 391 echo error.getMessage() 392 } 393 394 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${status}] - branch ${env.BRANCH_NAME}" 395 def email_body = """This is an automated email from the Jenkins build machine. It was 396 generated because of a git hooks/post-receive script following 397 a ref change was pushed to the repository containing 398 the project "UNNAMED PROJECT". 399 400 The branch ${env.BRANCH_NAME} has been updated. 401 ${gitUpdate} 402 403 Check console output at ${env.BUILD_URL} to view the results. 404 405 - Status -------------------------------------------------------------- 406 407 BUILD# ${env.BUILD_NUMBER} - ${status} 408 409 - Log ----------------------------------------------------------------- 410 ${gitLog} 411 ----------------------------------------------------------------------- 412 Summary of changes: 413 ${gitDiff} 414 """ 415 416 def email_to = "cforall@lists.uwaterloo.ca" 417 418 if( !bIsSandbox ) { 419 //send email notification 420 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log 421 } else { 422 echo "Would send email to: ${email_to}" 423 echo "With title: ${email_subject}" 424 echo "Content: \n${email_body}" 425 } 426 } -
libcfa/src/heap.cfa
r341bb80 r8bdc1c36 1 // #comment TD : this file uses both spaces and tabs for indentation2 3 1 // 4 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo … … 24 22 } // extern "C" 25 23 26 // #comment TD : Many of these should be merged into math I believe27 24 #include "bits/align.hfa" // libPow2 28 25 #include "bits/defs.hfa" // likely, unlikely … … 39 36 40 37 size_t default_mmap_start() __attribute__(( weak )) { 41 return __CFA_DEFAULT_MMAP_START__;38 return __CFA_DEFAULT_MMAP_START__; 42 39 } // default_mmap_start 43 40 44 41 size_t default_heap_expansion() __attribute__(( weak )) { 45 return __CFA_DEFAULT_HEAP_EXPANSION__;42 return __CFA_DEFAULT_HEAP_EXPANSION__; 46 43 } // default_heap_expansion 47 44 … … 65 62 #endif // LOCKFREE 66 63 67 // #comment TD : This defined is significantly different from the __ALIGN__ define from locks.hfa68 64 #define ALIGN 16 69 65 … … 140 136 141 137 static void checkUnfreed() { 142 if ( allocFree != 0 ) {138 if ( allocFree != 0 ) { 143 139 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. 144 140 // char helpText[512]; … … 147 143 // (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid 148 144 // __cfaabi_dbg_bits_write( helpText, len ); 149 } // if145 } // if 150 146 } // checkUnfreed 151 147 … … 171 167 struct RealHeader { 172 168 union { 173 // #comment TD : this code use byte size but the comment uses bit size174 175 169 struct { // 32-bit word => 64-bit header, 64-bit word => 128-bit header 176 170 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4 … … 192 186 193 187 }; 194 195 // #comment TD : C++ code196 188 #if BUCKLOCK == LOCKFREE 197 189 Stack<Storage>::Link next; // freed block points next freed block of same size (double-wide) … … 223 215 Storage * freeList; 224 216 #elif BUCKLOCK == LOCKFREE 225 // #comment TD : C++ code226 217 StackLF<Storage> freeList; 227 218 #else … … 249 240 static unsigned int maxBucketsUsed; // maximum number of buckets in use 250 241 251 // #comment TD : This array is not const but it feels like it should be252 242 // Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size. 253 243 static unsigned int bucketSizes[NoBucketSizes] @= { // different bucket sizes 254 16, 32, 48, 64,255 64 + sizeof(HeapManager.Storage), 96, 112, 128, 128 + sizeof(HeapManager.Storage), 160, 192, 224,256 256 + sizeof(HeapManager.Storage), 320, 384, 448, 512 + sizeof(HeapManager.Storage), 640, 768, 896,257 1_024 + sizeof(HeapManager.Storage), 1_536, 2_048 + sizeof(HeapManager.Storage), 2_560, 3_072, 3_584, 4_096 + sizeof(HeapManager.Storage), 6_144,258 8_192 + sizeof(HeapManager.Storage), 9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360,259 16_384 + sizeof(HeapManager.Storage), 18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720,260 32_768 + sizeof(HeapManager.Storage), 36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440,261 65_536 + sizeof(HeapManager.Storage), 73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880,262 131_072 + sizeof(HeapManager.Storage), 147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760,263 262_144 + sizeof(HeapManager.Storage), 294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520,264 524_288 + sizeof(HeapManager.Storage), 655_360, 786_432, 917_504, 1_048_576 + sizeof(HeapManager.Storage), 1_179_648, 1_310_720, 1_441_792,265 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(HeapManager.Storage), 2_621_440, 3_145_728, 3_670_016,266 4_194_304 + sizeof(HeapManager.Storage)244 16, 32, 48, 64, 245 64 + sizeof(HeapManager.Storage), 96, 112, 128, 128 + sizeof(HeapManager.Storage), 160, 192, 224, 246 256 + sizeof(HeapManager.Storage), 320, 384, 448, 512 + sizeof(HeapManager.Storage), 640, 768, 896, 247 1_024 + sizeof(HeapManager.Storage), 1_536, 2_048 + sizeof(HeapManager.Storage), 2_560, 3_072, 3_584, 4_096 + sizeof(HeapManager.Storage), 6_144, 248 8_192 + sizeof(HeapManager.Storage), 9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 249 16_384 + sizeof(HeapManager.Storage), 18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 250 32_768 + sizeof(HeapManager.Storage), 36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 251 65_536 + sizeof(HeapManager.Storage), 73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 252 131_072 + sizeof(HeapManager.Storage), 147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 253 262_144 + sizeof(HeapManager.Storage), 294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 254 524_288 + sizeof(HeapManager.Storage), 655_360, 786_432, 917_504, 1_048_576 + sizeof(HeapManager.Storage), 1_179_648, 1_310_720, 1_441_792, 255 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(HeapManager.Storage), 2_621_440, 3_145_728, 3_670_016, 256 4_194_304 + sizeof(HeapManager.Storage) 267 257 }; 268 258 #ifdef FASTLOOKUP … … 277 267 static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing 278 268 279 // #comment TD : The return type of this function should be commented 269 280 270 static inline bool setMmapStart( size_t value ) { 281 if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;282 mmapStart = value; // set global283 284 // find the closest bucket size less than or equal to the mmapStart size285 maxBucketsUsed = bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search286 assert( maxBucketsUsed < NoBucketSizes ); // subscript failure ?287 assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?288 return false;271 if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true; 272 mmapStart = value; // set global 273 274 // find the closest bucket size less than or equal to the mmapStart size 275 maxBucketsUsed = bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search 276 assert( maxBucketsUsed < NoBucketSizes ); // subscript failure ? 277 assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ? 278 return false; 289 279 } // setMmapStart 290 280 291 281 292 282 static void ?{}( HeapManager & manager ) with ( manager ) { 293 pageSize = sysconf( _SC_PAGESIZE );294 295 for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists283 pageSize = sysconf( _SC_PAGESIZE ); 284 285 for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists 296 286 freeLists[i].blockSize = bucketSizes[i]; 297 } // for287 } // for 298 288 299 289 #ifdef FASTLOOKUP 300 unsigned int idx = 0;301 for ( unsigned int i = 0; i < LookupSizes; i += 1 ) {290 unsigned int idx = 0; 291 for ( unsigned int i = 0; i < LookupSizes; i += 1 ) { 302 292 if ( i > bucketSizes[idx] ) idx += 1; 303 293 lookup[i] = idx; 304 } // for294 } // for 305 295 #endif // FASTLOOKUP 306 296 307 if ( setMmapStart( default_mmap_start() ) ) {297 if ( setMmapStart( default_mmap_start() ) ) { 308 298 abort( "HeapManager : internal error, mmap start initialization failure." ); 309 } // if310 heapExpand = default_heap_expansion();311 312 char * End = (char *)sbrk( 0 );313 sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment314 heapBegin = heapEnd = sbrk( 0 ); // get new start point299 } // if 300 heapExpand = default_heap_expansion(); 301 302 char * End = (char *)sbrk( 0 ); 303 sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment 304 heapBegin = heapEnd = sbrk( 0 ); // get new start point 315 305 } // HeapManager 316 306 … … 336 326 #endif // __CFA_DEBUG__ 337 327 338 // #comment TD : This assertion seems redundent with the above code339 328 assert( heapManager.heapBegin == 0 ); 340 329 heapManager{}; … … 372 361 // Use "write" because streams may be shutdown when calls are made. 373 362 static void printStats() { 374 char helpText[512];363 char helpText[512]; 375 364 __cfaabi_dbg_bits_print_buffer( helpText, sizeof(helpText), 376 365 "\nHeap statistics:\n" … … 396 385 } // printStats 397 386 398 // #comment TD : Why do we have this? 387 399 388 static int printStatsXML( FILE * stream ) { 400 char helpText[512];401 int len = snprintf( helpText, sizeof(helpText),389 char helpText[512]; 390 int len = snprintf( helpText, sizeof(helpText), 402 391 "<malloc version=\"1\">\n" 403 392 "<heap nr=\"0\">\n" … … 424 413 sbrk_calls, sbrk_storage 425 414 ); 426 return write( fileno( stream ), helpText, len ); // -1 => error415 return write( fileno( stream ), helpText, len ); // -1 => error 427 416 } // printStatsXML 428 417 #endif // __STATISTICS__ 429 418 430 // #comment TD : Is this the samething as Out-of-Memory? 419 431 420 static inline void noMemory() { 432 abort( "Heap memory exhausted at %zu bytes.\n"421 abort( "Heap memory exhausted at %zu bytes.\n" 433 422 "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.", 434 423 ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) ); … … 437 426 438 427 static inline void checkAlign( size_t alignment ) { 439 if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) {428 if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) { 440 429 abort( "Alignment %zu for memory allocation is less than sizeof(void *) and/or not a power of 2.", alignment ); 441 } // if430 } // if 442 431 } // checkAlign 443 432 444 433 445 434 static inline bool setHeapExpand( size_t value ) { 446 if ( heapExpand < pageSize ) return true;447 heapExpand = value;448 return false;435 if ( heapExpand < pageSize ) return true; 436 heapExpand = value; 437 return false; 449 438 } // setHeapExpand 450 439 451 440 452 441 static inline void checkHeader( bool check, const char * name, void * addr ) { 453 if ( unlikely( check ) ) { // bad address ?442 if ( unlikely( check ) ) { // bad address ? 454 443 abort( "Attempt to %s storage %p with address outside the heap.\n" 455 444 "Possible cause is duplicate free on same block or overwriting of memory.", 456 445 name, addr ); 457 } // if446 } // if 458 447 } // checkHeader 459 448 460 // #comment TD : function should be commented and/or have a more evocative name 461 // this isn't either a check or a constructor which is what I would expect this function to be 449 462 450 static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & size, size_t & alignment ) { 463 if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?451 if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ? 464 452 size_t offset = header->kind.fake.offset; 465 453 alignment = header->kind.fake.alignment & -2; // remove flag from value … … 468 456 #endif // __CFA_DEBUG__ 469 457 header = (HeapManager.Storage.Header *)((char *)header - offset); 470 } // if458 } // if 471 459 } // fakeHeader 472 460 473 // #comment TD : Why is this a define 461 474 462 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) )) 475 463 476 464 static inline bool headers( const char * name, void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) { 477 header = headerAddr( addr );478 479 if ( unlikely( heapEnd < addr ) ) { // mmapped ?465 header = headerAddr( addr ); 466 467 if ( unlikely( heapEnd < addr ) ) { // mmapped ? 480 468 fakeHeader( header, size, alignment ); 481 469 size = header->kind.real.blockSize & -3; // mmap size 482 470 return true; 483 } // if471 } // if 484 472 485 473 #ifdef __CFA_DEBUG__ 486 checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?474 checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ? 487 475 #endif // __CFA_DEBUG__ 488 489 // #comment TD : This code looks weird... 490 // It's called as the first statement of both branches of the last if, with the same parameters in all cases 491 492 // header may be safe to dereference 493 fakeHeader( header, size, alignment ); 476 // header may be safe to dereference 477 fakeHeader( header, size, alignment ); 494 478 #ifdef __CFA_DEBUG__ 495 checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -)479 checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -) 496 480 #endif // __CFA_DEBUG__ 497 481 498 freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3);482 freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3); 499 483 #ifdef __CFA_DEBUG__ 500 if ( freeElem < &freeLists[0] || &freeLists[NoBucketSizes] <= freeElem ) {501 abort( "Attempt to %s storage %p with corrupted header.\n"502 "Possible cause is duplicate free on same block or overwriting of header information.",503 name, addr );504 } // if484 if ( freeElem < &freeLists[0] || &freeLists[NoBucketSizes] <= freeElem ) { 485 abort( "Attempt to %s storage %p with corrupted header.\n" 486 "Possible cause is duplicate free on same block or overwriting of header information.", 487 name, addr ); 488 } // if 505 489 #endif // __CFA_DEBUG__ 506 size = freeElem->blockSize;507 return false;490 size = freeElem->blockSize; 491 return false; 508 492 } // headers 509 493 510 494 511 495 static inline void * extend( size_t size ) with ( heapManager ) { 512 lock( extlock __cfaabi_dbg_ctx2 );513 ptrdiff_t rem = heapRemaining - size;514 if ( rem < 0 ) {496 lock( extlock __cfaabi_dbg_ctx2 ); 497 ptrdiff_t rem = heapRemaining - size; 498 if ( rem < 0 ) { 515 499 // If the size requested is bigger than the current remaining storage, increase the size of the heap. 516 500 … … 530 514 #endif // __CFA_DEBUG__ 531 515 rem = heapRemaining + increase - size; 532 } // if533 534 HeapManager.Storage * block = (HeapManager.Storage *)heapEnd;535 heapRemaining = rem;536 heapEnd = (char *)heapEnd + size;537 unlock( extlock );538 return block;516 } // if 517 518 HeapManager.Storage * block = (HeapManager.Storage *)heapEnd; 519 heapRemaining = rem; 520 heapEnd = (char *)heapEnd + size; 521 unlock( extlock ); 522 return block; 539 523 } // extend 540 524 541 525 542 526 static inline void * doMalloc( size_t size ) with ( heapManager ) { 543 HeapManager.Storage * block;544 545 // Look up size in the size list. Make sure the user request includes space for the header that must be allocated546 // along with the block and is a multiple of the alignment size.547 548 size_t tsize = size + sizeof(HeapManager.Storage);549 if ( likely( tsize < mmapStart ) ) { // small size => sbrk527 HeapManager.Storage * block; 528 529 // Look up size in the size list. Make sure the user request includes space for the header that must be allocated 530 // along with the block and is a multiple of the alignment size. 531 532 size_t tsize = size + sizeof(HeapManager.Storage); 533 if ( likely( tsize < mmapStart ) ) { // small size => sbrk 550 534 HeapManager.FreeHeader * freeElem = 551 535 #ifdef FASTLOOKUP … … 560 544 561 545 #if defined( SPINLOCK ) 562 lock( freeElem->lock __cfaabi_dbg_ctx2 );563 block = freeElem->freeList; // remove node from stack546 lock( freeElem->lock __cfaabi_dbg_ctx2 ); 547 block = freeElem->freeList; // remove node from stack 564 548 #else 565 block = freeElem->freeList.pop();549 block = freeElem->freeList.pop(); 566 550 #endif // SPINLOCK 567 551 if ( unlikely( block == 0 ) ) { // no free block ? … … 582 566 583 567 block->header.kind.real.home = freeElem; // pointer back to free list of apropriate size 584 } else { // large size => mmap568 } else { // large size => mmap 585 569 tsize = libCeiling( tsize, pageSize ); // must be multiple of page size 586 570 #ifdef __STATISTICS__ 587 __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST );588 __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST );571 __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST ); 572 __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST ); 589 573 #endif // __STATISTICS__ 590 574 block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 ); … … 598 582 #endif // __CFA_DEBUG__ 599 583 block->header.kind.real.blockSize = tsize; // storage size for munmap 600 } // if601 602 void * area = &(block->data); // adjust off header to user bytes584 } // if 585 586 void * area = &(block->data); // adjust off header to user bytes 603 587 604 588 #ifdef __CFA_DEBUG__ 605 assert( ((uintptr_t)area & (libAlign() - 1)) == 0 ); // minimum alignment ?606 __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );607 if ( traceHeap() ) {608 enum { BufferSize = 64 };609 char helpText[BufferSize];610 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", area, size, tsize );611 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", area, size );612 __cfaabi_dbg_bits_write( helpText, len );613 } // if589 assert( ((uintptr_t)area & (libAlign() - 1)) == 0 ); // minimum alignment ? 590 __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST ); 591 if ( traceHeap() ) { 592 enum { BufferSize = 64 }; 593 char helpText[BufferSize]; 594 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", area, size, tsize ); 595 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", area, size ); 596 __cfaabi_dbg_bits_write( helpText, len ); 597 } // if 614 598 #endif // __CFA_DEBUG__ 615 599 616 return area;600 return area; 617 601 } // doMalloc 618 602 … … 620 604 static inline void doFree( void * addr ) with ( heapManager ) { 621 605 #ifdef __CFA_DEBUG__ 622 if ( unlikely( heapManager.heapBegin == 0 ) ) {623 abort( "doFree( %p ) : internal error, called before heap is initialized.", addr );624 } // if606 if ( unlikely( heapManager.heapBegin == 0 ) ) { 607 abort( "doFree( %p ) : internal error, called before heap is initialized.", addr ); 608 } // if 625 609 #endif // __CFA_DEBUG__ 626 610 627 HeapManager.Storage.Header * header;628 HeapManager.FreeHeader * freeElem;629 size_t size, alignment; // not used (see realloc)630 631 if ( headers( "free", addr, header, freeElem, size, alignment ) ) { // mmapped ?632 #ifdef __STATISTICS__ 633 __atomic_add_fetch( &munmap_calls, 1, __ATOMIC_SEQ_CST );634 __atomic_add_fetch( &munmap_storage, size, __ATOMIC_SEQ_CST );611 HeapManager.Storage.Header * header; 612 HeapManager.FreeHeader * freeElem; 613 size_t size, alignment; // not used (see realloc) 614 615 if ( headers( "free", addr, header, freeElem, size, alignment ) ) { // mmapped ? 616 #ifdef __STATISTICS__ 617 __atomic_add_fetch( &munmap_calls, 1, __ATOMIC_SEQ_CST ); 618 __atomic_add_fetch( &munmap_storage, size, __ATOMIC_SEQ_CST ); 635 619 #endif // __STATISTICS__ 636 620 if ( munmap( header, size ) == -1 ) { … … 641 625 #endif // __CFA_DEBUG__ 642 626 } // if 643 } else {627 } else { 644 628 #ifdef __CFA_DEBUG__ 645 // Set free memory to garbage so subsequent usages might fail.646 memset( ((HeapManager.Storage *)header)->data, '\377', freeElem->blockSize - sizeof( HeapManager.Storage ) );629 // Set free memory to garbage so subsequent usages might fail. 630 memset( ((HeapManager.Storage *)header)->data, '\377', freeElem->blockSize - sizeof( HeapManager.Storage ) ); 647 631 #endif // __CFA_DEBUG__ 648 632 649 633 #ifdef __STATISTICS__ 650 free_storage += size;634 free_storage += size; 651 635 #endif // __STATISTICS__ 652 636 #if defined( SPINLOCK ) 653 lock( freeElem->lock __cfaabi_dbg_ctx2 ); // acquire spin lock654 header->kind.real.next = freeElem->freeList; // push on stack655 freeElem->freeList = (HeapManager.Storage *)header;656 unlock( freeElem->lock ); // release spin lock637 lock( freeElem->lock __cfaabi_dbg_ctx2 ); // acquire spin lock 638 header->kind.real.next = freeElem->freeList; // push on stack 639 freeElem->freeList = (HeapManager.Storage *)header; 640 unlock( freeElem->lock ); // release spin lock 657 641 #else 658 freeElem->freeList.push( *(HeapManager.Storage *)header );642 freeElem->freeList.push( *(HeapManager.Storage *)header ); 659 643 #endif // SPINLOCK 660 } // if644 } // if 661 645 662 646 #ifdef __CFA_DEBUG__ 663 __atomic_add_fetch( &allocFree, -size, __ATOMIC_SEQ_CST );664 if ( traceHeap() ) {665 char helpText[64];666 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );667 __cfaabi_dbg_bits_write( helpText, len );668 } // if647 __atomic_add_fetch( &allocFree, -size, __ATOMIC_SEQ_CST ); 648 if ( traceHeap() ) { 649 char helpText[64]; 650 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size ); 651 __cfaabi_dbg_bits_write( helpText, len ); 652 } // if 669 653 #endif // __CFA_DEBUG__ 670 654 } // doFree … … 672 656 673 657 size_t checkFree( HeapManager & manager ) with ( manager ) { 674 size_t total = 0;658 size_t total = 0; 675 659 #ifdef __STATISTICS__ 676 __cfaabi_dbg_bits_acquire();677 __cfaabi_dbg_bits_print_nolock( "\nBin lists (bin size : free blocks on list)\n" );660 __cfaabi_dbg_bits_acquire(); 661 __cfaabi_dbg_bits_print_nolock( "\nBin lists (bin size : free blocks on list)\n" ); 678 662 #endif // __STATISTICS__ 679 for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) {663 for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) { 680 664 size_t size = freeLists[i].blockSize; 681 665 #ifdef __STATISTICS__ 682 666 unsigned int N = 0; 683 667 #endif // __STATISTICS__ 684 685 668 #if defined( SPINLOCK ) 686 669 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0; p = p->header.kind.real.next ) { … … 692 675 N += 1; 693 676 #endif // __STATISTICS__ 694 } // for 695 696 #ifdef __STATISTICS__ 697 __cfaabi_dbg_bits_print_nolock( "%7zu, %-7u ", size, N ); 698 if ( (i + 1) % 8 == 0 ) __cfaabi_dbg_bits_print_nolock( "\n" ); 677 } // for 678 #ifdef __STATISTICS__ 679 __cfaabi_dbg_bits_print_nolock( "%7zu, %-7u ", size, N ); 680 if ( (i + 1) % 8 == 0 ) __cfaabi_dbg_bits_print_nolock( "\n" ); 699 681 #endif // __STATISTICS__ 700 682 } // for 701 683 #ifdef __STATISTICS__ 702 __cfaabi_dbg_bits_print_nolock( "\ntotal free blocks:%zu\n", total );703 __cfaabi_dbg_bits_release();684 __cfaabi_dbg_bits_print_nolock( "\ntotal free blocks:%zu\n", total ); 685 __cfaabi_dbg_bits_release(); 704 686 #endif // __STATISTICS__ 705 687 return (char *)heapEnd - (char *)heapBegin - total; 706 688 } // checkFree 707 689 708 // #comment TD : This is not a good name, plus this feels like it could easily be folded into doMalloc 690 709 691 static inline void * malloc2( size_t size ) { // necessary for malloc statistics 710 692 assert( heapManager.heapBegin != 0 ); 711 void * area = doMalloc( size );712 if ( unlikely( area == 0 ) ) errno = ENOMEM; // POSIX713 return area;693 void * area = doMalloc( size ); 694 if ( unlikely( area == 0 ) ) errno = ENOMEM; // POSIX 695 return area; 714 696 } // malloc2 715 697 … … 717 699 static inline void * memalign2( size_t alignment, size_t size ) { // necessary for malloc statistics 718 700 #ifdef __CFA_DEBUG__ 719 checkAlign( alignment ); // check alignment701 checkAlign( alignment ); // check alignment 720 702 #endif // __CFA_DEBUG__ 721 703 722 // if alignment <= default alignment, do normal malloc as two headers are unnecessary 723 if ( unlikely( alignment <= libAlign() ) ) return malloc2( size ); 724 725 // Allocate enough storage to guarantee an address on the alignment boundary, and sufficient space before it for 726 // administrative storage. NOTE, WHILE THERE ARE 2 HEADERS, THE FIRST ONE IS IMPLICITLY CREATED BY DOMALLOC. 727 // .-------------v-----------------v----------------v----------, 728 // | Real Header | ... padding ... | Fake Header | data ... | 729 // `-------------^-----------------^-+--------------^----------' 730 // |<--------------------------------' offset/align |<-- alignment boundary 731 732 // subtract libAlign() because it is already the minimum alignment 733 // add sizeof(Storage) for fake header 734 // #comment TD : this is the only place that calls doMalloc without calling malloc2, why ? 735 char * area = (char *)doMalloc( size + alignment - libAlign() + sizeof(HeapManager.Storage) ); 736 if ( unlikely( area == 0 ) ) return area; 737 738 // address in the block of the "next" alignment address 739 char * user = (char *)libCeiling( (uintptr_t)(area + sizeof(HeapManager.Storage)), alignment ); 740 741 // address of header from malloc 742 HeapManager.Storage.Header * realHeader = headerAddr( area ); 743 // address of fake header * before* the alignment location 744 HeapManager.Storage.Header * fakeHeader = headerAddr( user ); 745 // SKULLDUGGERY: insert the offset to the start of the actual storage block and remember alignment 746 fakeHeader->kind.fake.offset = (char *)fakeHeader - (char *)realHeader; 747 // SKULLDUGGERY: odd alignment imples fake header 748 fakeHeader->kind.fake.alignment = alignment | 1; 749 750 return user; 704 // if alignment <= default alignment, do normal malloc as two headers are unnecessary 705 if ( unlikely( alignment <= libAlign() ) ) return malloc2( size ); 706 707 // Allocate enough storage to guarantee an address on the alignment boundary, and sufficient space before it for 708 // administrative storage. NOTE, WHILE THERE ARE 2 HEADERS, THE FIRST ONE IS IMPLICITLY CREATED BY DOMALLOC. 709 // .-------------v-----------------v----------------v----------, 710 // | Real Header | ... padding ... | Fake Header | data ... | 711 // `-------------^-----------------^-+--------------^----------' 712 // |<--------------------------------' offset/align |<-- alignment boundary 713 714 // subtract libAlign() because it is already the minimum alignment 715 // add sizeof(Storage) for fake header 716 char * area = (char *)doMalloc( size + alignment - libAlign() + sizeof(HeapManager.Storage) ); 717 if ( unlikely( area == 0 ) ) return area; 718 719 // address in the block of the "next" alignment address 720 char * user = (char *)libCeiling( (uintptr_t)(area + sizeof(HeapManager.Storage)), alignment ); 721 722 // address of header from malloc 723 HeapManager.Storage.Header * realHeader = headerAddr( area ); 724 // address of fake header * before* the alignment location 725 HeapManager.Storage.Header * fakeHeader = headerAddr( user ); 726 // SKULLDUGGERY: insert the offset to the start of the actual storage block and remember alignment 727 fakeHeader->kind.fake.offset = (char *)fakeHeader - (char *)realHeader; 728 // SKULLDUGGERY: odd alignment imples fake header 729 fakeHeader->kind.fake.alignment = alignment | 1; 730 731 return user; 751 732 } // memalign2 752 733 753 734 754 735 extern "C" { 755 // The malloc() function allocates size bytes and returns a pointer to the 756 // allocated memory. The memory is not initialized. If size is 0, then malloc() 757 // returns either NULL, or a unique pointer value that can later be successfully 758 // passed to free(). 759 void * malloc( size_t size ) { 760 #ifdef __STATISTICS__ 761 __atomic_add_fetch( &malloc_calls, 1, __ATOMIC_SEQ_CST ); 762 __atomic_add_fetch( &malloc_storage, size, __ATOMIC_SEQ_CST ); 736 void * malloc( size_t size ) { 737 #ifdef __STATISTICS__ 738 __atomic_add_fetch( &malloc_calls, 1, __ATOMIC_SEQ_CST ); 739 __atomic_add_fetch( &malloc_storage, size, __ATOMIC_SEQ_CST ); 763 740 #endif // __STATISTICS__ 764 741 765 742 return malloc2( size ); 766 } // malloc 767 768 // The calloc() function allocates memory for an array of nmemb elements of 769 // size bytes each and returns a pointer to the allocated memory. The memory 770 // is set to zero. If nmemb or size is 0, then calloc() returns either NULL, 771 // or a unique pointer value that can later be successfully passed to free(). 772 void * calloc( size_t noOfElems, size_t elemSize ) { 743 } // malloc 744 745 746 void * calloc( size_t noOfElems, size_t elemSize ) { 773 747 size_t size = noOfElems * elemSize; 774 748 #ifdef __STATISTICS__ 775 __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );776 __atomic_add_fetch( &calloc_storage, size, __ATOMIC_SEQ_CST );749 __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST ); 750 __atomic_add_fetch( &calloc_storage, size, __ATOMIC_SEQ_CST ); 777 751 #endif // __STATISTICS__ 778 752 779 753 char * area = (char *)malloc2( size ); 780 754 if ( unlikely( area == 0 ) ) return 0; 781 782 755 HeapManager.Storage.Header * header; 783 756 HeapManager.FreeHeader * freeElem; … … 789 762 #endif // __CFA_DEBUG__ 790 763 memset( area, '\0', asize - sizeof(HeapManager.Storage) ); // set to zeros 791 792 764 header->kind.real.blockSize |= 2; // mark as zero filled 793 765 return area; 794 } // calloc795 796 // #comment TD : Document this function 797 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {766 } // calloc 767 768 769 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) { 798 770 size_t size = noOfElems * elemSize; 799 771 #ifdef __STATISTICS__ 800 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );801 __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );772 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST ); 773 __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST ); 802 774 #endif // __STATISTICS__ 803 775 … … 816 788 817 789 return area; 818 } // cmemalign 819 820 // The realloc() function changes the size of the memory block pointed to by 821 // ptr to size bytes. The contents will be unchanged in the range from the 822 // start of the region up to the minimum of the old and new sizes. If the new 823 // size is larger than the old size, the added memory will not be initialized. 824 // If ptr is NULL, then the call is equivalent to malloc(size), for all values 825 // of size; if size is equal to zero, and ptr is not NULL, then the call is 826 // equivalent to free(ptr). Unless ptr is NULL, it must have been returned by 827 // an earlier call to malloc(), calloc() or realloc(). If the area pointed to 828 // was moved, a free(ptr) is done. 829 void * realloc( void * addr, size_t size ) { 830 #ifdef __STATISTICS__ 831 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST ); 790 } // cmemalign 791 792 793 void * realloc( void * addr, size_t size ) { 794 #ifdef __STATISTICS__ 795 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST ); 832 796 #endif // __STATISTICS__ 833 797 … … 848 812 849 813 #ifdef __STATISTICS__ 850 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );814 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST ); 851 815 #endif // __STATISTICS__ 852 816 … … 871 835 free( addr ); 872 836 return area; 873 } // realloc 874 875 876 // The obsolete function memalign() allocates size bytes and returns 877 // a pointer to the allocated memory. The memory address will be a 878 // multiple of alignment, which must be a power of two. 879 void * memalign( size_t alignment, size_t size ) __attribute__ ((deprecated)); 880 void * memalign( size_t alignment, size_t size ) { 837 } // realloc 838 839 840 void * memalign( size_t alignment, size_t size ) { 881 841 #ifdef __STATISTICS__ 882 842 __atomic_add_fetch( &memalign_calls, 1, __ATOMIC_SEQ_CST ); … … 887 847 888 848 return area; 889 } // memalign 890 891 // The function aligned_alloc() is the same as memalign(), except for 892 // the added restriction that size should be a multiple of alignment. 893 void * aligned_alloc( size_t alignment, size_t size ) { 849 } // memalign 850 851 852 void * aligned_alloc( size_t alignment, size_t size ) { 894 853 return memalign( alignment, size ); 895 } // aligned_alloc 896 897 898 // The function posix_memalign() allocates size bytes and places the address 899 // of the allocated memory in *memptr. The address of the allocated memory 900 // will be a multiple of alignment, which must be a power of two and a multiple 901 // of sizeof(void *). If size is 0, then posix_memalign() returns either NULL, 902 // or a unique pointer value that can later be successfully passed to free(3). 903 int posix_memalign( void ** memptr, size_t alignment, size_t size ) { 854 } // aligned_alloc 855 856 857 int posix_memalign( void ** memptr, size_t alignment, size_t size ) { 904 858 if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment 905 859 * memptr = memalign( alignment, size ); 906 860 if ( unlikely( * memptr == 0 ) ) return ENOMEM; 907 861 return 0; 908 } // posix_memalign 909 910 // The obsolete function valloc() allocates size bytes and returns a pointer 911 // to the allocated memory. The memory address will be a multiple of the page size. 912 // It is equivalent to memalign(sysconf(_SC_PAGESIZE),size). 913 void * valloc( size_t size ) __attribute__ ((deprecated)); 914 void * valloc( size_t size ) { 862 } // posix_memalign 863 864 865 void * valloc( size_t size ) { 915 866 return memalign( pageSize, size ); 916 } // valloc 917 918 919 // The free() function frees the memory space pointed to by ptr, which must 920 // have been returned by a previous call to malloc(), calloc() or realloc(). 921 // Otherwise, or if free(ptr) has already been called before, undefined 922 // behavior occurs. If ptr is NULL, no operation is performed. 923 void free( void * addr ) { 924 #ifdef __STATISTICS__ 925 __atomic_add_fetch( &free_calls, 1, __ATOMIC_SEQ_CST ); 926 #endif // __STATISTICS__ 927 928 // #comment TD : To decrease nesting I would but the special case in the 929 // else instead, plus it reads more naturally to have the 930 // short / normal case instead 867 } // valloc 868 869 870 void free( void * addr ) { 871 #ifdef __STATISTICS__ 872 __atomic_add_fetch( &free_calls, 1, __ATOMIC_SEQ_CST ); 873 #endif // __STATISTICS__ 874 931 875 if ( unlikely( addr == 0 ) ) { // special case 932 876 #ifdef __CFA_DEBUG__ 933 if ( traceHeap() ) {934 #define nullmsg "Free( 0x0 ) size:0\n"935 // Do not debug print free( 0 ), as it can cause recursive entry from sprintf.936 __cfaabi_dbg_bits_write( nullmsg, sizeof(nullmsg) - 1 );937 } // if877 if ( traceHeap() ) { 878 #define nullmsg "Free( 0x0 ) size:0\n" 879 // Do not debug print free( 0 ), as it can cause recursive entry from sprintf. 880 __cfaabi_dbg_bits_write( nullmsg, sizeof(nullmsg) - 1 ); 881 } // if 938 882 #endif // __CFA_DEBUG__ 939 883 return; … … 941 885 942 886 doFree( addr ); 943 } // free 944 945 // The mallopt() function adjusts parameters that control the behavior of the 946 // memory-allocation functions (see malloc(3)). The param argument specifies 947 // the parameter to be modified, and value specifies the new value for that 948 // parameter. 949 int mallopt( int option, int value ) { 887 } // free 888 889 890 int mallopt( int option, int value ) { 950 891 choose( option ) { 951 case M_TOP_PAD: 952 if ( setHeapExpand( value ) ) fallthru default; 953 case M_MMAP_THRESHOLD: 954 if ( setMmapStart( value ) ) fallthru default; 955 default: 956 // #comment TD : 1 for unsopported feels wrong 957 return 1; // success, or unsupported 892 case M_TOP_PAD: 893 if ( setHeapExpand( value ) ) fallthru default; 894 case M_MMAP_THRESHOLD: 895 if ( setMmapStart( value ) ) fallthru default; 896 default: 897 return 1; // success, or unsupported 958 898 } // switch 959 899 return 0; // error 960 } // mallopt 961 962 // The malloc_trim() function attempts to release free memory at the top 963 // of the heap (by calling sbrk(2) with a suitable argument). 900 } // mallopt 901 902 964 903 int malloc_trim( size_t ) { 965 904 return 0; // => impossible to release memory 966 905 } // malloc_trim 967 906 968 // The malloc_usable_size() function returns the number of usable bytes in the 969 // block pointed to by ptr, a pointer to a block of memory allocated by 970 // malloc(3) or a related function. 971 size_t malloc_usable_size( void * addr ) { 907 size_t malloc_usable_size( void * addr ) { 972 908 if ( unlikely( addr == 0 ) ) return 0; // null allocation has 0 size 973 974 909 HeapManager.Storage.Header * header; 975 910 HeapManager.FreeHeader * freeElem; … … 979 914 size_t usize = size - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block 980 915 return usize; 981 } // malloc_usable_size 982 983 984 // #comment TD : Document this function 985 size_t malloc_alignment( void * addr ) { 916 } // malloc_usable_size 917 918 919 size_t malloc_alignment( void * addr ) { 986 920 if ( unlikely( addr == 0 ) ) return libAlign(); // minimum alignment 987 921 HeapManager.Storage.Header * header = (HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ); … … 991 925 return libAlign (); // minimum alignment 992 926 } // if 993 } // malloc_alignment 994 995 996 // #comment TD : Document this function 997 bool malloc_zero_fill( void * addr ) { 927 } // malloc_alignment 928 929 930 bool malloc_zero_fill( void * addr ) { 998 931 if ( unlikely( addr == 0 ) ) return false; // null allocation is not zero fill 999 1000 932 HeapManager.Storage.Header * header = (HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ); 1001 933 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ? … … 1003 935 } // if 1004 936 return (header->kind.real.blockSize & 2) != 0; // zero filled (calloc/cmemalign) ? 1005 } // malloc_zero_fill 1006 1007 1008 // #comment TD : Document this function 1009 void malloc_stats( void ) { 1010 #ifdef __STATISTICS__ 1011 printStats(); 1012 if ( checkFree() ) checkFree( heapManager ); 1013 #endif // __STATISTICS__ 1014 } // malloc_stats 1015 1016 // #comment TD : Document this function 1017 int malloc_stats_fd( int fd ) { 1018 #ifdef __STATISTICS__ 1019 int temp = statfd; 1020 statfd = fd; 1021 return temp; 937 } // malloc_zero_fill 938 939 940 void malloc_stats( void ) { 941 #ifdef __STATISTICS__ 942 printStats(); 943 if ( checkFree() ) checkFree( heapManager ); 944 #endif // __STATISTICS__ 945 } // malloc_stats 946 947 948 int malloc_stats_fd( int fd ) { 949 #ifdef __STATISTICS__ 950 int temp = statfd; 951 statfd = fd; 952 return temp; 1022 953 #else 1023 return -1; 1024 #endif // __STATISTICS__ 1025 } // malloc_stats_fd 1026 1027 1028 // #comment TD : Document this function 954 return -1; 955 #endif // __STATISTICS__ 956 } // malloc_stats_fd 957 958 1029 959 int malloc_info( int options, FILE * stream ) { 1030 960 return printStatsXML( stream ); … … 1032 962 1033 963 1034 // #comment TD : What are these two functions for?1035 964 void * malloc_get_state( void ) { 1036 965 return 0; 1037 966 } // malloc_get_state 967 1038 968 1039 969 int malloc_set_state( void * ptr ) {
Note:
See TracChangeset
for help on using the changeset viewer.