├── .cvsignore ├── .gitignore ├── AUTHORS ├── COPYING ├── COPYRIGHT ├── ChangeLog ├── Doxyfile.in ├── Makefile.am ├── NEWS ├── OPENSOLARIS.LICENSE ├── README ├── README-alpha ├── TODO ├── autogen.sh ├── configure.ac ├── envvar.c ├── gdb-macros ├── getpcstack.c ├── hello.c ├── i386_subr_sol.s ├── init_lib.c ├── init_stand.c ├── linktest_stand.c ├── m4 ├── libtool.m4 ├── ltoptions.m4 ├── ltsugar.m4 ├── ltversion.m4 └── lt~obsolete.m4 ├── malloc.c ├── misc.c ├── misc.h ├── sol_compat.h ├── sparc_subr_sol.s ├── stand_mapfile ├── stub_stand.c ├── sys ├── vmem.h └── vmem_impl_user.h ├── test.c ├── umem.c ├── umem.h ├── umem.spec.in ├── umem_agent_support.c ├── umem_alloc.3 ├── umem_base.h ├── umem_cache_create.3 ├── umem_debug.3 ├── umem_fail.c ├── umem_fork.c ├── umem_impl.h ├── umem_test.c ├── umem_test2.c ├── umem_test3.c ├── umem_test4 ├── umem_update_thread.c ├── vmem.c ├── vmem_base.c ├── vmem_base.h ├── vmem_mmap.c ├── vmem_sbrk.c ├── vmem_stand.c └── vmem_stand.h /.cvsignore: -------------------------------------------------------------------------------- 1 | *.lo 2 | *.la 3 | .deps 4 | .libs 5 | *.loT 6 | Makefile 7 | Makefile.in 8 | aclocal.m4 9 | autom4te.cache 10 | config.h 11 | config.h.in 12 | config.log 13 | config.status 14 | configure 15 | libtool 16 | stamp-h 17 | stamp-h.in 18 | stamp-h1 19 | umem_test 20 | umem_test2 21 | umem_test3 22 | Doxyfile 23 | umem.spec 24 | *.tar.gz 25 | *.tar.bz2 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.lo 3 | *.la 4 | *.o 5 | *.libs 6 | INSTALL 7 | Makefile.in 8 | aclocal.m4 9 | autom4te.cache 10 | compile 11 | config.guess 12 | config.h.in 13 | config.sub 14 | configure 15 | depcomp 16 | install-sh 17 | ltmain.sh 18 | missing 19 | .deps 20 | Doxyfile 21 | Makefile 22 | config.h 23 | config.log 24 | config.status 25 | libtool 26 | stamp-h1 27 | test-driver 28 | umem.spec 29 | umem_test 30 | umem_test1 31 | umem_test2 32 | umem_test3 33 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gburd/libumem/c4b96af8293a1196b77e8245f779573a71773f00/AUTHORS -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Please see COPYRIGHT and OPENSOLARIS.LICENSE for the copyright 2 | and license details. 3 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | The bulk of the library is Copyright 2004 Sun Microsystems, Inc. 2 | Portions are Copyright 2006-2008 Message Systems, Inc. 3 | 4 | The library is distributed under the terms of the CDDL. 5 | See the file OPENSOLARIS.LICENSE for more information. 6 | 7 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gburd/libumem/c4b96af8293a1196b77e8245f779573a71773f00/ChangeLog -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libumem.la libumem_malloc.la 2 | noinst_PROGRAMS = umem_test umem_test2 umem_test3 3 | 4 | libumem_la_LDFLAGS = -lpthread 5 | 6 | umem_test_SOURCES = umem_test.c 7 | umem_test_LDADD = -lumem 8 | 9 | umem_test2_SOURCES = umem_test2.c 10 | umem_test2_LDADD = -lumem 11 | 12 | umem_test3_SOURCES = umem_test3.c 13 | umem_test3_LDADD = -lumem -lumem_malloc 14 | 15 | libumem_la_SOURCES = init_lib.c \ 16 | umem_agent_support.c \ 17 | umem_fail.c \ 18 | umem_fork.c \ 19 | umem_update_thread.c \ 20 | vmem_mmap.c \ 21 | vmem_sbrk.c \ 22 | envvar.c \ 23 | getpcstack.c \ 24 | misc.c \ 25 | misc.h \ 26 | vmem_base.c \ 27 | vmem_base.h \ 28 | vmem_stand.h \ 29 | umem.c \ 30 | umem.h \ 31 | umem_base.h \ 32 | umem_impl.h \ 33 | sol_compat.h \ 34 | vmem.c \ 35 | sys/vmem.h \ 36 | sys/vmem_impl_user.h 37 | 38 | libumem_malloc_la_SOURCES = malloc.c 39 | libumem_malloc_la_LDFLAGS = -lpthread -R$(libdir) -lumem 40 | 41 | AM_CFLAGS = -fno-builtin-calloc 42 | ACLOCAL_AMFLAGS = -I m4 43 | 44 | man3_MANS = umem_alloc.3 umem_cache_create.3 umem_debug.3 45 | EXTRA_DIST = COPYRIGHT OPENSOLARIS.LICENSE umem.spec Doxyfile umem_test4 \ 46 | $(man3_MANS) 47 | 48 | nobase_include_HEADERS = umem.h sys/vmem.h 49 | 50 | TESTS = umem_test umem_test2 umem_test3 umem_test4 51 | 52 | html-local: 53 | mkdir -p docs 54 | doxygen Doxyfile 55 | 56 | clean-local: 57 | rm -rf docs 58 | 59 | .PHONY: rpm 60 | rpm: dist-bzip2 61 | rpmbuild -ta $(distdir).tar.bz2 62 | 63 | # XXX: Non-i386: SPARC asm. x86_64? 64 | # Convert this to GNU as format: i386_subr_sol.s 65 | # 66 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gburd/libumem/c4b96af8293a1196b77e8245f779573a71773f00/NEWS -------------------------------------------------------------------------------- /OPENSOLARIS.LICENSE: -------------------------------------------------------------------------------- 1 | Unless otherwise noted, all files in this distribution are released 2 | under the Common Development and Distribution License (CDDL), 3 | Version 1.0 only. Exceptions are noted within the associated 4 | source files. 5 | 6 | -------------------------------------------------------------------- 7 | 8 | 9 | COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0 10 | 11 | 1. Definitions. 12 | 13 | 1.1. "Contributor" means each individual or entity that creates 14 | or contributes to the creation of Modifications. 15 | 16 | 1.2. "Contributor Version" means the combination of the Original 17 | Software, prior Modifications used by a Contributor (if any), 18 | and the Modifications made by that particular Contributor. 19 | 20 | 1.3. "Covered Software" means (a) the Original Software, or (b) 21 | Modifications, or (c) the combination of files containing 22 | Original Software with files containing Modifications, in 23 | each case including portions thereof. 24 | 25 | 1.4. "Executable" means the Covered Software in any form other 26 | than Source Code. 27 | 28 | 1.5. "Initial Developer" means the individual or entity that first 29 | makes Original Software available under this License. 30 | 31 | 1.6. "Larger Work" means a work which combines Covered Software or 32 | portions thereof with code not governed by the terms of this 33 | License. 34 | 35 | 1.7. "License" means this document. 36 | 37 | 1.8. "Licensable" means having the right to grant, to the maximum 38 | extent possible, whether at the time of the initial grant or 39 | subsequently acquired, any and all of the rights conveyed 40 | herein. 41 | 42 | 1.9. "Modifications" means the Source Code and Executable form of 43 | any of the following: 44 | 45 | A. Any file that results from an addition to, deletion from or 46 | modification of the contents of a file containing Original 47 | Software or previous Modifications; 48 | 49 | B. Any new file that contains any part of the Original 50 | Software or previous Modifications; or 51 | 52 | C. Any new file that is contributed or otherwise made 53 | available under the terms of this License. 54 | 55 | 1.10. "Original Software" means the Source Code and Executable 56 | form of computer software code that is originally released 57 | under this License. 58 | 59 | 1.11. "Patent Claims" means any patent claim(s), now owned or 60 | hereafter acquired, including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by 62 | grantor. 63 | 64 | 1.12. "Source Code" means (a) the common form of computer software 65 | code in which modifications are made and (b) associated 66 | documentation included in or with such code. 67 | 68 | 1.13. "You" (or "Your") means an individual or a legal entity 69 | exercising rights under, and complying with all of the terms 70 | of, this License. For legal entities, "You" includes any 71 | entity which controls, is controlled by, or is under common 72 | control with You. For purposes of this definition, 73 | "control" means (a) the power, direct or indirect, to cause 74 | the direction or management of such entity, whether by 75 | contract or otherwise, or (b) ownership of more than fifty 76 | percent (50%) of the outstanding shares or beneficial 77 | ownership of such entity. 78 | 79 | 2. License Grants. 80 | 81 | 2.1. The Initial Developer Grant. 82 | 83 | Conditioned upon Your compliance with Section 3.1 below and 84 | subject to third party intellectual property claims, the Initial 85 | Developer hereby grants You a world-wide, royalty-free, 86 | non-exclusive license: 87 | 88 | (a) under intellectual property rights (other than patent or 89 | trademark) Licensable by Initial Developer, to use, 90 | reproduce, modify, display, perform, sublicense and 91 | distribute the Original Software (or portions thereof), 92 | with or without Modifications, and/or as part of a Larger 93 | Work; and 94 | 95 | (b) under Patent Claims infringed by the making, using or 96 | selling of Original Software, to make, have made, use, 97 | practice, sell, and offer for sale, and/or otherwise 98 | dispose of the Original Software (or portions thereof). 99 | 100 | (c) The licenses granted in Sections 2.1(a) and (b) are 101 | effective on the date Initial Developer first distributes 102 | or otherwise makes the Original Software available to a 103 | third party under the terms of this License. 104 | 105 | (d) Notwithstanding Section 2.1(b) above, no patent license is 106 | granted: (1) for code that You delete from the Original 107 | Software, or (2) for infringements caused by: (i) the 108 | modification of the Original Software, or (ii) the 109 | combination of the Original Software with other software 110 | or devices. 111 | 112 | 2.2. Contributor Grant. 113 | 114 | Conditioned upon Your compliance with Section 3.1 below and 115 | subject to third party intellectual property claims, each 116 | Contributor hereby grants You a world-wide, royalty-free, 117 | non-exclusive license: 118 | 119 | (a) under intellectual property rights (other than patent or 120 | trademark) Licensable by Contributor to use, reproduce, 121 | modify, display, perform, sublicense and distribute the 122 | Modifications created by such Contributor (or portions 123 | thereof), either on an unmodified basis, with other 124 | Modifications, as Covered Software and/or as part of a 125 | Larger Work; and 126 | 127 | (b) under Patent Claims infringed by the making, using, or 128 | selling of Modifications made by that Contributor either 129 | alone and/or in combination with its Contributor Version 130 | (or portions of such combination), to make, use, sell, 131 | offer for sale, have made, and/or otherwise dispose of: 132 | (1) Modifications made by that Contributor (or portions 133 | thereof); and (2) the combination of Modifications made by 134 | that Contributor with its Contributor Version (or portions 135 | of such combination). 136 | 137 | (c) The licenses granted in Sections 2.2(a) and 2.2(b) are 138 | effective on the date Contributor first distributes or 139 | otherwise makes the Modifications available to a third 140 | party. 141 | 142 | (d) Notwithstanding Section 2.2(b) above, no patent license is 143 | granted: (1) for any code that Contributor has deleted 144 | from the Contributor Version; (2) for infringements caused 145 | by: (i) third party modifications of Contributor Version, 146 | or (ii) the combination of Modifications made by that 147 | Contributor with other software (except as part of the 148 | Contributor Version) or other devices; or (3) under Patent 149 | Claims infringed by Covered Software in the absence of 150 | Modifications made by that Contributor. 151 | 152 | 3. Distribution Obligations. 153 | 154 | 3.1. Availability of Source Code. 155 | 156 | Any Covered Software that You distribute or otherwise make 157 | available in Executable form must also be made available in Source 158 | Code form and that Source Code form must be distributed only under 159 | the terms of this License. You must include a copy of this 160 | License with every copy of the Source Code form of the Covered 161 | Software You distribute or otherwise make available. You must 162 | inform recipients of any such Covered Software in Executable form 163 | as to how they can obtain such Covered Software in Source Code 164 | form in a reasonable manner on or through a medium customarily 165 | used for software exchange. 166 | 167 | 3.2. Modifications. 168 | 169 | The Modifications that You create or to which You contribute are 170 | governed by the terms of this License. You represent that You 171 | believe Your Modifications are Your original creation(s) and/or 172 | You have sufficient rights to grant the rights conveyed by this 173 | License. 174 | 175 | 3.3. Required Notices. 176 | 177 | You must include a notice in each of Your Modifications that 178 | identifies You as the Contributor of the Modification. You may 179 | not remove or alter any copyright, patent or trademark notices 180 | contained within the Covered Software, or any notices of licensing 181 | or any descriptive text giving attribution to any Contributor or 182 | the Initial Developer. 183 | 184 | 3.4. Application of Additional Terms. 185 | 186 | You may not offer or impose any terms on any Covered Software in 187 | Source Code form that alters or restricts the applicable version 188 | of this License or the recipients' rights hereunder. You may 189 | choose to offer, and to charge a fee for, warranty, support, 190 | indemnity or liability obligations to one or more recipients of 191 | Covered Software. However, you may do so only on Your own behalf, 192 | and not on behalf of the Initial Developer or any Contributor. 193 | You must make it absolutely clear that any such warranty, support, 194 | indemnity or liability obligation is offered by You alone, and You 195 | hereby agree to indemnify the Initial Developer and every 196 | Contributor for any liability incurred by the Initial Developer or 197 | such Contributor as a result of warranty, support, indemnity or 198 | liability terms You offer. 199 | 200 | 3.5. Distribution of Executable Versions. 201 | 202 | You may distribute the Executable form of the Covered Software 203 | under the terms of this License or under the terms of a license of 204 | Your choice, which may contain terms different from this License, 205 | provided that You are in compliance with the terms of this License 206 | and that the license for the Executable form does not attempt to 207 | limit or alter the recipient's rights in the Source Code form from 208 | the rights set forth in this License. If You distribute the 209 | Covered Software in Executable form under a different license, You 210 | must make it absolutely clear that any terms which differ from 211 | this License are offered by You alone, not by the Initial 212 | Developer or Contributor. You hereby agree to indemnify the 213 | Initial Developer and every Contributor for any liability incurred 214 | by the Initial Developer or such Contributor as a result of any 215 | such terms You offer. 216 | 217 | 3.6. Larger Works. 218 | 219 | You may create a Larger Work by combining Covered Software with 220 | other code not governed by the terms of this License and 221 | distribute the Larger Work as a single product. In such a case, 222 | You must make sure the requirements of this License are fulfilled 223 | for the Covered Software. 224 | 225 | 4. Versions of the License. 226 | 227 | 4.1. New Versions. 228 | 229 | Sun Microsystems, Inc. is the initial license steward and may 230 | publish revised and/or new versions of this License from time to 231 | time. Each version will be given a distinguishing version number. 232 | Except as provided in Section 4.3, no one other than the license 233 | steward has the right to modify this License. 234 | 235 | 4.2. Effect of New Versions. 236 | 237 | You may always continue to use, distribute or otherwise make the 238 | Covered Software available under the terms of the version of the 239 | License under which You originally received the Covered Software. 240 | If the Initial Developer includes a notice in the Original 241 | Software prohibiting it from being distributed or otherwise made 242 | available under any subsequent version of the License, You must 243 | distribute and make the Covered Software available under the terms 244 | of the version of the License under which You originally received 245 | the Covered Software. Otherwise, You may also choose to use, 246 | distribute or otherwise make the Covered Software available under 247 | the terms of any subsequent version of the License published by 248 | the license steward. 249 | 250 | 4.3. Modified Versions. 251 | 252 | When You are an Initial Developer and You want to create a new 253 | license for Your Original Software, You may create and use a 254 | modified version of this License if You: (a) rename the license 255 | and remove any references to the name of the license steward 256 | (except to note that the license differs from this License); and 257 | (b) otherwise make it clear that the license contains terms which 258 | differ from this License. 259 | 260 | 5. DISCLAIMER OF WARRANTY. 261 | 262 | COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" 263 | BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 264 | INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED 265 | SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR 266 | PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND 267 | PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY 268 | COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE 269 | INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY 270 | NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF 271 | WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF 272 | ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS 273 | DISCLAIMER. 274 | 275 | 6. TERMINATION. 276 | 277 | 6.1. This License and the rights granted hereunder will terminate 278 | automatically if You fail to comply with terms herein and fail to 279 | cure such breach within 30 days of becoming aware of the breach. 280 | Provisions which, by their nature, must remain in effect beyond 281 | the termination of this License shall survive. 282 | 283 | 6.2. If You assert a patent infringement claim (excluding 284 | declaratory judgment actions) against Initial Developer or a 285 | Contributor (the Initial Developer or Contributor against whom You 286 | assert such claim is referred to as "Participant") alleging that 287 | the Participant Software (meaning the Contributor Version where 288 | the Participant is a Contributor or the Original Software where 289 | the Participant is the Initial Developer) directly or indirectly 290 | infringes any patent, then any and all rights granted directly or 291 | indirectly to You by such Participant, the Initial Developer (if 292 | the Initial Developer is not the Participant) and all Contributors 293 | under Sections 2.1 and/or 2.2 of this License shall, upon 60 days 294 | notice from Participant terminate prospectively and automatically 295 | at the expiration of such 60 day notice period, unless if within 296 | such 60 day period You withdraw Your claim with respect to the 297 | Participant Software against such Participant either unilaterally 298 | or pursuant to a written agreement with Participant. 299 | 300 | 6.3. In the event of termination under Sections 6.1 or 6.2 above, 301 | all end user licenses that have been validly granted by You or any 302 | distributor hereunder prior to termination (excluding licenses 303 | granted to You by any distributor) shall survive termination. 304 | 305 | 7. LIMITATION OF LIABILITY. 306 | 307 | UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT 308 | (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE 309 | INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF 310 | COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE 311 | LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR 312 | CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT 313 | LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK 314 | STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER 315 | COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN 316 | INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF 317 | LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL 318 | INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT 319 | APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO 320 | NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR 321 | CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT 322 | APPLY TO YOU. 323 | 324 | 8. U.S. GOVERNMENT END USERS. 325 | 326 | The Covered Software is a "commercial item," as that term is 327 | defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial 328 | computer software" (as that term is defined at 48 329 | C.F.R. 252.227-7014(a)(1)) and "commercial computer software 330 | documentation" as such terms are used in 48 C.F.R. 12.212 331 | (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 332 | C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all 333 | U.S. Government End Users acquire Covered Software with only those 334 | rights set forth herein. This U.S. Government Rights clause is in 335 | lieu of, and supersedes, any other FAR, DFAR, or other clause or 336 | provision that addresses Government rights in computer software 337 | under this License. 338 | 339 | 9. MISCELLANEOUS. 340 | 341 | This License represents the complete agreement concerning subject 342 | matter hereof. If any provision of this License is held to be 343 | unenforceable, such provision shall be reformed only to the extent 344 | necessary to make it enforceable. This License shall be governed 345 | by the law of the jurisdiction specified in a notice contained 346 | within the Original Software (except to the extent applicable law, 347 | if any, provides otherwise), excluding such jurisdiction's 348 | conflict-of-law provisions. Any litigation relating to this 349 | License shall be subject to the jurisdiction of the courts located 350 | in the jurisdiction and venue specified in a notice contained 351 | within the Original Software, with the losing party responsible 352 | for costs, including, without limitation, court costs and 353 | reasonable attorneys' fees and expenses. The application of the 354 | United Nations Convention on Contracts for the International Sale 355 | of Goods is expressly excluded. Any law or regulation which 356 | provides that the language of a contract shall be construed 357 | against the drafter shall not apply to this License. You agree 358 | that You alone are responsible for compliance with the United 359 | States export administration regulations (and the export control 360 | laws and regulation of any other countries) when You use, 361 | distribute or otherwise make available any Covered Software. 362 | 363 | 10. RESPONSIBILITY FOR CLAIMS. 364 | 365 | As between Initial Developer and the Contributors, each party is 366 | responsible for claims and damages arising, directly or 367 | indirectly, out of its utilization of rights under this License 368 | and You agree to work with Initial Developer and Contributors to 369 | distribute such responsibility on an equitable basis. Nothing 370 | herein is intended or shall be deemed to constitute any admission 371 | of liability. 372 | 373 | -------------------------------------------------------------------- 374 | 375 | NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND 376 | DISTRIBUTION LICENSE (CDDL) 377 | 378 | For Covered Software in this distribution, this License shall 379 | be governed by the laws of the State of California (excluding 380 | conflict-of-law provisions). 381 | 382 | Any litigation relating to this License shall be subject to the 383 | jurisdiction of the Federal Courts of the Northern District of 384 | California and the state courts of the State of California, with 385 | venue lying in Santa Clara County, California. 386 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Portable libumem. 2 | ================ 3 | 4 | This is a port of Solaris libumem to non-Solaris systems. 5 | 6 | The port was made while integrating libumem with our Ecelerity MTA product, so 7 | your initial experience will not be 100% out-of-the-box, because there is no 8 | standalone configure script for the library at this time. (patches welcome!) 9 | 10 | In addition, since our deployment is threaded, we force the library into 11 | threaded mode. 12 | 13 | While the library is itself stable (it's the memory allocator used by the 14 | Solaris OS), the port may have a few rough edges. We're shipping umem with 15 | Linux and Windows versions of our product as we have found it to be stable. 16 | 17 | We will continue to update this project as and when we make improvements, and 18 | welcome third-party patches that improve the usability for everyone. 19 | 20 | 21 | Wez Furlong, 22 | Message Systems, Inc. 23 | wez (at) messagesystems (dot) com 24 | 25 | -------------------------------------------------------------------------------- /README-alpha: -------------------------------------------------------------------------------- 1 | This is the libumem package. 2 | This document describes the actions needed to build the pre-release 3 | or subversion version of the package. See end of file for copying conditions. 4 | 5 | * Introduction 6 | 7 | This is a *pre-release* version, and not ready for production use yet. If 8 | you are taking source from subversion, you will need to have libtool, automake, 9 | and autoconf installed to help contribute. See the chapter `Building' for the 10 | detailed instructions. The script autogen.sh is provided to help autoconfigure 11 | libumem from the cvs src. After you run autogen.sh, there should be a file 12 | 'INSTALL' with (generic) installation instructions. Package-specific 13 | installation instructions are set forth in the file README. 14 | 15 | Please, note that the accompanying documentation may be inaccurate or 16 | incomplete. The subversion history is the authoritative documentation of all 17 | recent changes. 18 | 19 | Report bugs at https://github.com/gburd/libumem/issues 20 | 21 | * Checking Out the Sources 22 | 23 | The following instructions apply if you wish to obtain sources from 24 | the subversion repository: 25 | 26 | To checkout the source tree from subversion issue the following command: 27 | 28 | svn co https://labs.omniti.com/portableumem/trunk portable-umem 29 | 30 | * Building 31 | 32 | In order to build this you will first need to have right versions 33 | of autotools and some auxiliary GNU programs. At the time of this 34 | writing these are: 35 | 36 | Package Version (>=) 37 | ======== ============ 38 | automake 1.4 39 | autoconf 2.50 40 | libtool 1.5.0 41 | 42 | To prepare the package for building run autogen.sh. Then run 43 | ./configure with the desired options (See INSTALL and README for the 44 | detailed instructions). Finally, run make. Notice that the first make 45 | of the package should be made in the source directory. Subsequent 46 | makes can use build directory different from the source one. 47 | 48 | * Use 49 | 50 | To use link with both umem and umem_malloc (e.g. '-lumem -lumem_malloc'). 51 | 52 | * Testing 53 | 54 | There are two basic test files included, test.c and hello.c, with 55 | basic instructions within those files at the end. Basic performance 56 | testing was done using hyperfine. 57 | 58 | * Copyright information: 59 | 60 | Please see COPYRIGHT and OPENSOLARIS.LICENSE for the copyright 61 | and license details. 62 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | To-do List for the Linux port of umem 2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | 4 | * Autconf'ery for in "sol_compat.h". 5 | 6 | * Fix #define wreakage for THR_RETURN, THR_API in "sol_compat.h". 7 | 8 | * Replace use of Ecelerity's portable atomic locking header with something 9 | equivalent in "sol_compat.h". 10 | 11 | * ec_debug_vprintf -> something else? 12 | 13 | * test suite. 14 | 15 | * static library support. 16 | 17 | * doxygen'ate the headers/code, to produce reference docs. 18 | 19 | * HAVE_DOT in Doxyfile.in should be detected by configure. 20 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf -i -s 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([umem], [1.0.2], [], [umem]) 2 | AM_INIT_AUTOMAKE([dist-bzip2]) 3 | AC_CONFIG_MACRO_DIRS([m4]) 4 | 5 | AC_PROG_CC 6 | AM_PROG_AS 7 | AC_PROG_LIBTOOL 8 | 9 | AC_C_INLINE 10 | 11 | AC_MSG_CHECKING([whether pthread_mutex_t is larger than 24 bytes]) 12 | AC_TRY_RUN( 13 | [ 14 | #include 15 | int main(void){return (sizeof(pthread_mutex_t) > 24);} 16 | ], 17 | [AC_MSG_RESULT(yes)], 18 | [ 19 | AC_MSG_RESULT(no) 20 | AC_DEFINE(UMEM_PTHREAD_MUTEX_TOO_BIG, [1], [need bigger cache]) 21 | AC_MSG_WARN([*** increasing umem cpu cache size to compensate.]) 22 | ] 23 | ) 24 | 25 | AC_CHECK_LIB(dl,dlopen) 26 | 27 | AC_CHECK_HEADERS([sys/mman.h sys/sysmacros.h sys/time.h malloc.h]) 28 | AC_CHECK_FUNCS([issetugid mallinfo malloc_stats]) 29 | 30 | AC_CONFIG_HEADERS([config.h]) 31 | AC_CONFIG_FILES([Makefile Doxyfile umem.spec]) 32 | 33 | AC_OUTPUT 34 | -------------------------------------------------------------------------------- /gdb-macros: -------------------------------------------------------------------------------- 1 | # vim:ft=gdb:ts=2:sw=2:et: 2 | 3 | set $UMF_AUDIT = 1 4 | set $UMF_DEADBEEF = 2 5 | set $UMF_REDZONE = 4 6 | set $UMF_CONTENTS = 8 7 | set $UMF_CHECKSIGNAL = 16 8 | set $UMF_NOMAGAZINE = 32 9 | set $UMF_FIREWALL = 64 10 | set $UMF_LITE = 128 11 | set $UMF_HASH = 256 12 | set $UMF_RANDOMIZE = 512 13 | 14 | define umastat_cache 15 | set $cp = $arg0 16 | set $meminuse = ($cp->cache_slab_create - $cp->cache_slab_destroy) * $cp->cache_slabsize 17 | 18 | if (($cp->cache_cpu[0].cc_magsize != 0) || ($cp->cache_flags & $UMF_NOMAGAZINE)) 19 | set $magsize = $cp->cache_cpu[0].cc_magsize 20 | else 21 | set $magsize = $cp->cache_magtype->mt_magsize 22 | end 23 | 24 | set $alloc = $cp->cache_slab_alloc + $cp->cache_full.ml_alloc 25 | set $avail = $cp->cache_full.ml_total * $magsize 26 | set $total = $cp->cache_buftotal 27 | 28 | # walk the cpu caches 29 | set $cpu_current = 0 30 | while $cpu_current < umem_max_ncpus 31 | set $cpu = umem_cpus[$cpu_current] 32 | set $cpu_cache = (umem_cpu_cache_t*)((char*)$cp + $cpu->cpu_cache_offset) 33 | 34 | if $cpu_cache->cc_rounds > 0 35 | set $avail = $avail + $cpu_cache->cc_rounds 36 | end 37 | if $cpu_cache->cc_prounds > 0 38 | set $avail = $avail + $cpu_cache->cc_prounds 39 | end 40 | set $alloc = $alloc + $cpu_cache->cc_alloc 41 | 42 | set $cpu_current = $cpu_current + 1 43 | end 44 | 45 | # walk some slabs 46 | set $slab = $cp->cache_nullslab.slab_next 47 | while $slab != &$cp->cache_nullslab 48 | set $avail = $avail + $slab->slab_chunks - $slab->slab_refcnt 49 | set $slab = $slab->slab_next 50 | end 51 | 52 | printf "%-25s %6u %6u %6u %9u %9u %5llu\n", $cp->cache_name, $cp->cache_bufsize, $total - $avail, $total, $meminuse, $alloc, $cp->cache_alloc_fail 53 | end 54 | 55 | document umastat 56 | umem allocator stats 57 | end 58 | 59 | define umastat 60 | printf "cache buf buf buf memory alloc alloc\n" 61 | printf "name size in use total in use succeed fail\n" 62 | printf "---------------------------- ------ ------ ------ --------- --------- -----\n" 63 | set $cp = umem_null_cache->cache_next 64 | while $cp != &umem_null_cache 65 | umastat_cache $cp 66 | set $cp = $cp->cache_next 67 | end 68 | printf "---------------------------- ------ ------ ------ --------- --------- -----\n" 69 | set $vmem = vmem_list 70 | while $vmem != 0 71 | set $meminuse = 0 72 | set $alloc = 0 73 | set $fail = 0 74 | set $cp = umem_null_cache->cache_next 75 | while $cp != &umem_null_cache 76 | if $cp->cache_arena == $vmem 77 | set $meminuse = $meminuse + (($cp->cache_slab_create - $cp->cache_slab_destroy) * $cp->cache_slabsize) 78 | 79 | if (($cp->cache_cpu[0].cc_magsize != 0) || ($cp->cache_flags & $UMF_NOMAGAZINE)) 80 | set $magsize = $cp->cache_cpu[0].cc_magsize 81 | else 82 | set $magsize = $cp->cache_magtype->mt_magsize 83 | end 84 | 85 | set $alloc = $alloc + ($cp->cache_slab_alloc + $cp->cache_full.ml_alloc) 86 | set $avail = $avail + ($cp->cache_full.ml_total * $magsize) 87 | end 88 | set $cp = $cp->cache_next 89 | end 90 | printf "Total %-25s %9u %9u %5u\n", $vmem->vm_name, $meminuse, $alloc, $fail 91 | set $vmem = $vmem->vm_next 92 | end 93 | end 94 | 95 | define umem_status 96 | printf "Concurrency:\t%d\n", umem_max_ncpus 97 | printf "Logs\t\t" 98 | if umem_transaction_log != 0 99 | printf "transaction=%d ", umem_transaction_log->lh_chunksize * umem_transaction_log->lh_nchunks 100 | end 101 | if umem_content_log != 0 102 | printf "content=%d ", umem_content_log->lh_chunksize * umem_content_log->lh_nchunks 103 | end 104 | if umem_failure_log != 0 105 | printf "fail=%d ", umem_failure_log->lh_chunksize * umem_failure_log->lh_nchunks 106 | end 107 | if umem_slab_log != 0 108 | printf "slab=%d ", umem_slab_log->lh_chunksize * umem_slab_log->lh_nchunks 109 | end 110 | if umem_logging == 0 111 | printf "(inactive)" 112 | end 113 | printf "\nMessage buffer:\n" 114 | set $msg = &umem_error_buffer + umem_error_begin 115 | printf "%s", $msg 116 | end 117 | 118 | -------------------------------------------------------------------------------- /getpcstack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | */ 26 | /* 27 | * Portions Copyright 2006-2008 Message Systems, Inc. 28 | */ 29 | 30 | /* #pragma ident "@(#)getpcstack.c 1.5 05/06/08 SMI" */ 31 | 32 | #include "config.h" 33 | #include "misc.h" 34 | 35 | #if HAVE_UCONTEXT_H 36 | #include 37 | #endif 38 | 39 | #if HAVE_SYS_FRAME_H 40 | #include 41 | #endif 42 | #if HAVE_SYS_STACK_H 43 | #include 44 | #endif 45 | 46 | #include 47 | 48 | #if defined(__MACH__) 49 | /* 50 | * Darwin doesn't have any exposed frame info, so give it some space. 51 | */ 52 | #define UMEM_FRAMESIZE (2 * sizeof(long long)) 53 | 54 | #elif defined(__sparc) || defined(__sparcv9) 55 | extern void flush_windows(void); 56 | #define UMEM_FRAMESIZE MINFRAME 57 | 58 | #elif defined(__i386) || defined(__amd64) 59 | /* 60 | * On x86, MINFRAME is defined to be 0, but we want to be sure we can 61 | * dereference the entire frame structure. 62 | */ 63 | #define UMEM_FRAMESIZE (sizeof (struct frame)) 64 | 65 | #elif !defined(EC_UMEM_DUMMY_PCSTACK) 66 | #error needs update for new architecture 67 | #endif 68 | 69 | /* 70 | * Get a pc-only stacktrace. Used for kmem_alloc() buffer ownership tracking. 71 | * Returns MIN(current stack depth, pcstack_limit). 72 | */ 73 | /*ARGSUSED*/ 74 | int 75 | getpcstack(uintptr_t *pcstack, int pcstack_limit, int check_signal) 76 | { 77 | #ifdef EC_UMEM_DUMMY_PCSTACK 78 | return 0; 79 | #else 80 | struct frame *fp; 81 | struct frame *nextfp, *minfp; 82 | int depth = 0; 83 | uintptr_t base = 0; 84 | size_t size = 0; 85 | #ifndef UMEM_STANDALONE 86 | int on_altstack = 0; 87 | uintptr_t sigbase = 0; 88 | size_t sigsize = 0; 89 | 90 | stack_t st; 91 | 92 | if (stack_getbounds(&st) != 0) { 93 | if (thr_stksegment(&st) != 0 || 94 | (uintptr_t)st.ss_sp < st.ss_size) { 95 | return (0); /* unable to get stack bounds */ 96 | } 97 | /* 98 | * thr_stksegment(3C) has a slightly different interface than 99 | * stack_getbounds(3C) -- correct it 100 | */ 101 | st.ss_sp = (void *)(((uintptr_t)st.ss_sp) - st.ss_size); 102 | st.ss_flags = 0; /* can't be on-stack */ 103 | } 104 | on_altstack = (st.ss_flags & SS_ONSTACK); 105 | 106 | if (st.ss_size != 0) { 107 | base = (uintptr_t)st.ss_sp; 108 | size = st.ss_size; 109 | } else { 110 | /* 111 | * If size == 0, then ss_sp is the *top* of the stack. 112 | * 113 | * Since we only allow increasing frame pointers, and we 114 | * know our caller set his up correctly, we can treat ss_sp 115 | * as an upper bound safely. 116 | */ 117 | base = 0; 118 | size = (uintptr_t)st.ss_sp; 119 | } 120 | 121 | if (check_signal != 0) { 122 | void (*sigfunc)() = NULL; 123 | int sigfuncsize = 0; 124 | extern void thr_sighndlrinfo(void (**)(), int *); 125 | 126 | thr_sighndlrinfo(&sigfunc, &sigfuncsize); 127 | sigbase = (uintptr_t)sigfunc; 128 | sigsize = sigfuncsize; 129 | } 130 | #else /* UMEM_STANDALONE */ 131 | base = (uintptr_t)umem_min_stack; 132 | size = umem_max_stack - umem_min_stack; 133 | #endif 134 | 135 | /* 136 | * shorten size so that fr_savfp and fr_savpc will be within the stack 137 | * bounds. 138 | */ 139 | if (size >= UMEM_FRAMESIZE - 1) 140 | size -= (UMEM_FRAMESIZE - 1); 141 | else 142 | size = 0; 143 | 144 | #if defined(__sparc) || defined(__sparcv9) 145 | flush_windows(); 146 | #endif 147 | 148 | /* LINTED alignment */ 149 | fp = (struct frame *)((caddr_t)getfp() + STACK_BIAS); 150 | 151 | minfp = fp; 152 | 153 | if (((uintptr_t)fp - base) >= size) 154 | return (0); /* the frame pointer isn't in our stack */ 155 | 156 | while (depth < pcstack_limit) { 157 | uintptr_t tmp; 158 | 159 | /* LINTED alignment */ 160 | nextfp = (struct frame *)((caddr_t)fp->fr_savfp + STACK_BIAS); 161 | tmp = (uintptr_t)nextfp; 162 | 163 | /* 164 | * Check nextfp for validity. It must be properly aligned, 165 | * increasing compared to the last %fp (or the top of the 166 | * stack we just switched to), and it must be inside 167 | * [base, base + size). 168 | */ 169 | if (tmp != SA(tmp)) 170 | break; 171 | else if (nextfp <= minfp || (tmp - base) >= size) { 172 | #ifndef UMEM_STANDALONE 173 | if (tmp == NULL || !on_altstack) 174 | break; 175 | /* 176 | * If we're on an alternate signal stack, try jumping 177 | * to the main thread stack. 178 | * 179 | * If the main thread stack has an unlimited size, we 180 | * punt, since we don't know where the frame pointer's 181 | * been. 182 | * 183 | * (thr_stksegment() returns the *top of stack* 184 | * in ss_sp, not the bottom) 185 | */ 186 | if (thr_stksegment(&st) == 0) { 187 | if (st.ss_size >= (uintptr_t)st.ss_sp || 188 | st.ss_size < UMEM_FRAMESIZE - 1) 189 | break; 190 | 191 | on_altstack = 0; 192 | base = (uintptr_t)st.ss_sp - st.ss_size; 193 | size = st.ss_size - (UMEM_FRAMESIZE - 1); 194 | minfp = (struct frame *)base; 195 | continue; /* try again */ 196 | } 197 | #endif 198 | break; 199 | } 200 | 201 | #ifndef UMEM_STANDALONE 202 | if (check_signal && (fp->fr_savpc - sigbase) <= sigsize) 203 | umem_panic("called from signal handler"); 204 | #endif 205 | pcstack[depth++] = fp->fr_savpc; 206 | fp = nextfp; 207 | minfp = fp; 208 | } 209 | return (depth); 210 | #endif 211 | } 212 | -------------------------------------------------------------------------------- /hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char *ptr = (char *)malloc(4096); 6 | snprintf(ptr, 4096, "%s", "Hello, World!"); 7 | printf("%s 0x%p\n", ptr, ptr); 8 | return 0; 9 | } 10 | 11 | /* 12 | * Local variables: 13 | * tab-width:4 14 | * compile-command: "gcc -fpic -Wall -Werror -Ofast -march=native -mtune=native hello.c -o hello" 15 | * End: 16 | */ 17 | 18 | -------------------------------------------------------------------------------- /i386_subr_sol.s: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | */ 26 | 27 | #pragma ident "@(#)asm_subr.s 1.4 05/06/08 SMI" 28 | 29 | #include 30 | 31 | #if defined(lint) 32 | 33 | void * 34 | getfp(void) 35 | { 36 | return (NULL); 37 | } 38 | 39 | #ifndef UMEM_STANDALONE 40 | void 41 | _breakpoint(void) 42 | { 43 | return; 44 | } 45 | #endif 46 | 47 | #else /* lint */ 48 | 49 | #if defined(__amd64) 50 | 51 | ENTRY(getfp) 52 | movq %rbp, %rax 53 | ret 54 | SET_SIZE(getfp) 55 | 56 | #else /* __i386 */ 57 | 58 | ENTRY(getfp) 59 | movl %ebp, %eax 60 | ret 61 | SET_SIZE(getfp) 62 | 63 | #endif 64 | 65 | #ifndef UMEM_STANDALONE 66 | ENTRY(_breakpoint) 67 | int $3 68 | ret 69 | SET_SIZE(_breakpoint) 70 | #endif 71 | 72 | #endif /* lint */ 73 | -------------------------------------------------------------------------------- /init_lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | 23 | /* 24 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 25 | * Use is subject to license terms. 26 | * 27 | * Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved. 28 | */ 29 | 30 | /* #pragma ident "@(#)init_lib.c 1.2 05/06/08 SMI" */ 31 | 32 | /* 33 | * Initialization routines for the library version of libumem. 34 | */ 35 | 36 | #include "config.h" 37 | #include "umem_base.h" 38 | #include "vmem_base.h" 39 | 40 | #if HAVE_UNISTD_H 41 | #include 42 | #endif 43 | #if HAVE_DLFCN_H 44 | #include 45 | #endif 46 | 47 | #include 48 | #include 49 | 50 | #ifdef __FreeBSD__ 51 | #include 52 | #endif 53 | 54 | void 55 | vmem_heap_init(void) 56 | { 57 | #ifdef _WIN32 58 | vmem_backend = VMEM_BACKEND_MMAP; 59 | (void) vmem_sbrk_arena(NULL, NULL); 60 | #else 61 | # if defined(sun) 62 | void *handle = dlopen("libmapmalloc.so.1", RTLD_NOLOAD); 63 | 64 | if (handle != NULL) { 65 | log_message("sbrk backend disabled\n"); 66 | vmem_backend = VMEM_BACKEND_MMAP; 67 | } 68 | # else 69 | if (vmem_backend == 0) { 70 | /* prefer mmap, as sbrk() seems to have problems wither working 71 | * with other allocators or has some Solaris specific assumptions. */ 72 | vmem_backend = VMEM_BACKEND_MMAP; 73 | } 74 | # endif 75 | 76 | if ((vmem_backend & VMEM_BACKEND_MMAP) != 0) { 77 | vmem_backend = VMEM_BACKEND_MMAP; 78 | (void) vmem_mmap_arena(NULL, NULL); 79 | } else { 80 | vmem_backend = VMEM_BACKEND_SBRK; 81 | (void) vmem_sbrk_arena(NULL, NULL); 82 | } 83 | #endif 84 | } 85 | 86 | /*ARGSUSED*/ 87 | void 88 | umem_type_init(caddr_t start, size_t len, size_t pgsize) 89 | { 90 | #ifdef _WIN32 91 | SYSTEM_INFO info; 92 | GetSystemInfo(&info); 93 | pagesize = info.dwPageSize; 94 | #elif !defined(__FreeBSD__) 95 | pagesize = _sysconf(_SC_PAGESIZE); 96 | #else 97 | pagesize = PAGE_SIZE; 98 | #endif 99 | } 100 | 101 | int 102 | umem_get_max_ncpus(void) 103 | { 104 | #ifdef linux 105 | /* 106 | * HACK: sysconf() will invoke malloc() on Linux as part of reading 107 | * in /proc/stat. To avoid recursion in the malloc replacement 108 | * version of libumem, read /proc/stat into a static buffer. 109 | */ 110 | static int ncpus = 0; 111 | 112 | if (ncpus == 0) { 113 | char proc_stat[8192]; 114 | int fd; 115 | 116 | ncpus = 1; 117 | fd = open("/proc/stat", O_RDONLY); 118 | if (fd >= 0) { 119 | const ssize_t n = read(fd, proc_stat, sizeof(proc_stat) - 1); 120 | if (n >= 0) { 121 | const char *cur; 122 | const char *next; 123 | 124 | proc_stat[n] = '\0'; 125 | cur = proc_stat; 126 | while (*cur && (next = strstr(cur + 3, "cpu"))) { 127 | cur = next; 128 | } 129 | 130 | if (*cur) 131 | ncpus = atoi(cur + 3) + 1; 132 | } 133 | 134 | close(fd); 135 | } 136 | } 137 | 138 | return ncpus; 139 | 140 | #else /* !linux */ 141 | 142 | #if _SC_NPROCESSORS_ONLN 143 | return (2 * sysconf(_SC_NPROCESSORS_ONLN)); 144 | #elif defined(_SC_NPROCESSORS_CONF) 145 | return (2 * sysconf(_SC_NPROCESSORS_CONF)); 146 | #elif defined(_WIN32) 147 | SYSTEM_INFO info; 148 | GetSystemInfo(&info); 149 | return info.dwNumberOfProcessors; 150 | #else 151 | /* XXX: determine CPU count on other platforms */ 152 | return (1); 153 | #endif 154 | 155 | #endif /* linux */ 156 | } 157 | -------------------------------------------------------------------------------- /init_stand.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | */ 26 | 27 | #pragma ident "@(#)init_stand.c 1.3 05/06/08 SMI" 28 | 29 | /* 30 | * Initialization routines for the standalone version of libumem. 31 | */ 32 | 33 | #include "config.h" 34 | #include "umem_base.h" 35 | #include "vmem_base.h" 36 | 37 | #include "vmem_stand.h" 38 | 39 | void 40 | vmem_heap_init(void) 41 | { 42 | vmem_backend = VMEM_BACKEND_STAND; 43 | (void) vmem_stand_arena(NULL, NULL); 44 | } 45 | 46 | void 47 | umem_type_init(caddr_t base, size_t len, size_t pgsize) 48 | { 49 | pagesize = pgsize; 50 | 51 | vmem_stand_init(); 52 | (void) vmem_stand_add(base, len); 53 | } 54 | 55 | int 56 | umem_get_max_ncpus(void) 57 | { 58 | return (1); 59 | } 60 | 61 | int 62 | umem_add(caddr_t base, size_t len) 63 | { 64 | return (vmem_stand_add(base, len)); 65 | } 66 | -------------------------------------------------------------------------------- /linktest_stand.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | 23 | /* 24 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 25 | * Use is subject to license terms. 26 | */ 27 | 28 | #pragma ident "@(#)linktest_stand.c 1.3 05/06/08 SMI" 29 | 30 | /* 31 | * This file is used to verify that the standalone's external dependencies 32 | * haven't changed in a way that'll break things that use it. 33 | */ 34 | 35 | void __umem_assert_failed(void) {} 36 | void _atomic_add_64(void) {} 37 | void _atomic_add_32_nv(void) {} 38 | void bcopy(void) {} 39 | void bzero(void) {} 40 | void dladdr1(void) {} 41 | void exit(void) {} 42 | void getenv(void) {} 43 | void gethrtime(void) {} 44 | void membar_producer(void) {} 45 | void memcpy(void) {} 46 | void memset(void) {} 47 | void snprintf(void) {} 48 | void strchr(void) {} 49 | void strcmp(void) {} 50 | void strlen(void) {} 51 | void strncpy(void) {} 52 | void strrchr(void) {} 53 | void strtoul(void) {} 54 | void umem_err_recoverable(void) {} 55 | void umem_panic(void) {} 56 | void vsnprintf(void) {} 57 | 58 | #ifdef __i386 59 | void __mul64(void) {} 60 | void __rem64(void) {} 61 | void __div64(void) {} 62 | 63 | #ifdef __GNUC__ 64 | void __divdi3(void) {} 65 | void __moddi3(void) {} 66 | #endif /* __GNUC__ */ 67 | 68 | #endif /* __i386 */ 69 | 70 | int __ctype; 71 | int errno; 72 | -------------------------------------------------------------------------------- /m4/libtool.m4: -------------------------------------------------------------------------------- 1 | /usr/share/aclocal/libtool.m4 -------------------------------------------------------------------------------- /m4/ltoptions.m4: -------------------------------------------------------------------------------- 1 | /usr/share/aclocal/ltoptions.m4 -------------------------------------------------------------------------------- /m4/ltsugar.m4: -------------------------------------------------------------------------------- 1 | /usr/share/aclocal/ltsugar.m4 -------------------------------------------------------------------------------- /m4/ltversion.m4: -------------------------------------------------------------------------------- 1 | /usr/share/aclocal/ltversion.m4 -------------------------------------------------------------------------------- /m4/lt~obsolete.m4: -------------------------------------------------------------------------------- 1 | /usr/share/aclocal/lt~obsolete.m4 -------------------------------------------------------------------------------- /malloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | 23 | /* 24 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 25 | * Use is subject to license terms. 26 | */ 27 | 28 | #pragma ident "@(#)malloc.c 1.5 05/06/08 SMI" 29 | 30 | #include "config.h" 31 | #include 32 | 33 | #include 34 | 35 | #include 36 | 37 | #ifdef HAVE_SYS_SYSMACROS_H 38 | #include 39 | #endif 40 | 41 | #include "umem_base.h" 42 | 43 | #include "misc.h" 44 | 45 | /* 46 | * malloc_data_t is an 8-byte structure which is located "before" the pointer 47 | * returned from {m,c,re}alloc and memalign. The first four bytes give 48 | * information about the buffer, and the second four bytes are a status byte. 49 | * 50 | * See umem_impl.h for the various magic numbers used, and the size 51 | * encode/decode macros. 52 | * 53 | * The 'size' of the buffer includes the tags. That is, we encode the 54 | * argument to umem_alloc(), not the argument to malloc(). 55 | */ 56 | 57 | typedef struct malloc_data { 58 | uint32_t malloc_size; 59 | uint32_t malloc_stat; /* = UMEM_MALLOC_ENCODE(state, malloc_size) */ 60 | } malloc_data_t; 61 | 62 | void * 63 | malloc(size_t size_arg) 64 | { 65 | #ifdef _LP64 66 | uint32_t high_size = 0; 67 | #endif 68 | size_t size; 69 | 70 | malloc_data_t *ret; 71 | size = size_arg + sizeof (malloc_data_t); 72 | 73 | #ifdef _LP64 74 | if (size > UMEM_SECOND_ALIGN) { 75 | size += sizeof (malloc_data_t); 76 | high_size = (size >> 32); 77 | } 78 | #endif 79 | if (size < size_arg) { 80 | errno = ENOMEM; /* overflow */ 81 | return (NULL); 82 | } 83 | ret = (malloc_data_t *)_umem_alloc(size, UMEM_DEFAULT); 84 | if (ret == NULL) { 85 | if (size <= UMEM_MAXBUF) 86 | errno = EAGAIN; 87 | else 88 | errno = ENOMEM; 89 | return (NULL); 90 | #ifdef _LP64 91 | } else if (high_size > 0) { 92 | uint32_t low_size = (uint32_t)size; 93 | 94 | /* 95 | * uses different magic numbers to make it harder to 96 | * undetectably corrupt 97 | */ 98 | ret->malloc_size = high_size; 99 | ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_MAGIC, high_size); 100 | ret++; 101 | 102 | ret->malloc_size = low_size; 103 | ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_OVERSIZE_MAGIC, 104 | low_size); 105 | ret++; 106 | } else if (size > UMEM_SECOND_ALIGN) { 107 | uint32_t low_size = (uint32_t)size; 108 | 109 | ret++; /* leave the first 8 bytes alone */ 110 | 111 | ret->malloc_size = low_size; 112 | ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_SECOND_MAGIC, 113 | low_size); 114 | ret++; 115 | #endif 116 | } else { 117 | ret->malloc_size = size; 118 | ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_MAGIC, size); 119 | ret++; 120 | } 121 | return ((void *)ret); 122 | } 123 | 124 | void * 125 | calloc(size_t nelem, size_t elsize) 126 | { 127 | size_t size = nelem * elsize; 128 | void *retval; 129 | 130 | if (nelem > 0 && elsize > 0 && size/nelem != elsize) { 131 | errno = ENOMEM; /* overflow */ 132 | return (NULL); 133 | } 134 | 135 | retval = malloc(size); 136 | if (retval == NULL) 137 | return (NULL); 138 | 139 | (void) memset(retval, 0, size); 140 | return (retval); 141 | } 142 | 143 | /* 144 | * memalign uses vmem_xalloc to do its work. 145 | * 146 | * in 64-bit, the memaligned buffer always has two tags. This simplifies the 147 | * code. 148 | */ 149 | 150 | void * 151 | memalign(size_t align, size_t size_arg) 152 | { 153 | size_t size; 154 | uintptr_t phase; 155 | 156 | void *buf; 157 | malloc_data_t *ret; 158 | 159 | size_t overhead; 160 | 161 | if (size_arg == 0 || align == 0 || (align & (align - 1)) != 0) { 162 | errno = EINVAL; 163 | return (NULL); 164 | } 165 | 166 | /* 167 | * if malloc provides the required alignment, use it. 168 | */ 169 | if (align <= UMEM_ALIGN || 170 | (align <= UMEM_SECOND_ALIGN && size_arg >= UMEM_SECOND_ALIGN)) 171 | return (malloc(size_arg)); 172 | 173 | #ifdef _LP64 174 | overhead = 2 * sizeof (malloc_data_t); 175 | #else 176 | overhead = sizeof (malloc_data_t); 177 | #endif 178 | 179 | ASSERT(overhead <= align); 180 | 181 | size = size_arg + overhead; 182 | phase = align - overhead; 183 | 184 | if (umem_memalign_arena == NULL && umem_init() == 0) { 185 | errno = ENOMEM; 186 | return (NULL); 187 | } 188 | 189 | if (size < size_arg) { 190 | errno = ENOMEM; /* overflow */ 191 | return (NULL); 192 | } 193 | 194 | buf = vmem_xalloc(umem_memalign_arena, size, align, phase, 195 | 0, NULL, NULL, VM_NOSLEEP); 196 | 197 | if (buf == NULL) { 198 | if ((size_arg + align) <= UMEM_MAXBUF) 199 | errno = EAGAIN; 200 | else 201 | errno = ENOMEM; 202 | 203 | return (NULL); 204 | } 205 | 206 | ret = (malloc_data_t *)buf; 207 | { 208 | uint32_t low_size = (uint32_t)size; 209 | 210 | #ifdef _LP64 211 | uint32_t high_size = (uint32_t)(size >> 32); 212 | 213 | ret->malloc_size = high_size; 214 | ret->malloc_stat = UMEM_MALLOC_ENCODE(MEMALIGN_MAGIC, 215 | high_size); 216 | ret++; 217 | #endif 218 | 219 | ret->malloc_size = low_size; 220 | ret->malloc_stat = UMEM_MALLOC_ENCODE(MEMALIGN_MAGIC, low_size); 221 | ret++; 222 | } 223 | 224 | ASSERT(P2PHASE((uintptr_t)ret, align) == 0); 225 | ASSERT((void *)((uintptr_t)ret - overhead) == buf); 226 | 227 | return ((void *)ret); 228 | } 229 | 230 | int 231 | posix_memalign(void **memptr, size_t alignment, size_t size) 232 | { 233 | *memptr = memalign(alignment, size); 234 | if (*memptr) { 235 | return 0; 236 | } 237 | return errno; 238 | } 239 | 240 | void * 241 | valloc(size_t size) 242 | { 243 | return (memalign(pagesize, size)); 244 | } 245 | 246 | /* 247 | * process_free: 248 | * 249 | * Pulls information out of a buffer pointer, and optionally free it. 250 | * This is used by free() and realloc() to process buffers. 251 | * 252 | * On failure, calls umem_err_recoverable() with an appropriate message 253 | * On success, returns the data size through *data_size_arg, if (!is_free). 254 | * 255 | * Preserves errno, since free()'s semantics require it. 256 | */ 257 | 258 | static int 259 | process_free(void *buf_arg, 260 | int do_free, /* free the buffer, or just get its size? */ 261 | size_t *data_size_arg) /* output: bytes of data in buf_arg */ 262 | { 263 | malloc_data_t *buf; 264 | 265 | void *base; 266 | size_t size; 267 | size_t data_size; 268 | 269 | const char *message; 270 | int old_errno = errno; 271 | 272 | buf = (malloc_data_t *)buf_arg; 273 | 274 | buf--; 275 | size = buf->malloc_size; 276 | 277 | switch (UMEM_MALLOC_DECODE(buf->malloc_stat, size)) { 278 | 279 | case MALLOC_MAGIC: 280 | base = (void *)buf; 281 | data_size = size - sizeof (malloc_data_t); 282 | 283 | if (do_free) 284 | buf->malloc_stat = UMEM_FREE_PATTERN_32; 285 | 286 | goto process_malloc; 287 | 288 | #ifdef _LP64 289 | case MALLOC_SECOND_MAGIC: 290 | base = (void *)(buf - 1); 291 | data_size = size - 2 * sizeof (malloc_data_t); 292 | 293 | if (do_free) 294 | buf->malloc_stat = UMEM_FREE_PATTERN_32; 295 | 296 | goto process_malloc; 297 | 298 | case MALLOC_OVERSIZE_MAGIC: { 299 | size_t high_size; 300 | 301 | buf--; 302 | high_size = buf->malloc_size; 303 | 304 | if (UMEM_MALLOC_DECODE(buf->malloc_stat, high_size) != 305 | MALLOC_MAGIC) { 306 | message = "invalid or corrupted buffer"; 307 | break; 308 | } 309 | 310 | size += high_size << 32; 311 | 312 | base = (void *)buf; 313 | data_size = size - 2 * sizeof (malloc_data_t); 314 | 315 | if (do_free) { 316 | buf->malloc_stat = UMEM_FREE_PATTERN_32; 317 | (buf + 1)->malloc_stat = UMEM_FREE_PATTERN_32; 318 | } 319 | 320 | goto process_malloc; 321 | } 322 | #endif 323 | 324 | case MEMALIGN_MAGIC: { 325 | size_t overhead = sizeof (malloc_data_t); 326 | 327 | #ifdef _LP64 328 | size_t high_size; 329 | 330 | overhead += sizeof (malloc_data_t); 331 | 332 | buf--; 333 | high_size = buf->malloc_size; 334 | 335 | if (UMEM_MALLOC_DECODE(buf->malloc_stat, high_size) != 336 | MEMALIGN_MAGIC) { 337 | message = "invalid or corrupted buffer"; 338 | break; 339 | } 340 | size += high_size << 32; 341 | 342 | /* 343 | * destroy the main tag's malloc_stat 344 | */ 345 | if (do_free) 346 | (buf + 1)->malloc_stat = UMEM_FREE_PATTERN_32; 347 | #endif 348 | 349 | base = (void *)buf; 350 | data_size = size - overhead; 351 | 352 | if (do_free) 353 | buf->malloc_stat = UMEM_FREE_PATTERN_32; 354 | 355 | goto process_memalign; 356 | } 357 | default: 358 | if (buf->malloc_stat == UMEM_FREE_PATTERN_32) 359 | message = "double-free or invalid buffer"; 360 | else 361 | message = "invalid or corrupted buffer"; 362 | break; 363 | } 364 | 365 | umem_err_recoverable("%s(%p): %s\n", 366 | do_free? "free" : "realloc", buf_arg, message); 367 | 368 | errno = old_errno; 369 | return (0); 370 | 371 | process_malloc: 372 | if (do_free) 373 | _umem_free(base, size); 374 | else 375 | *data_size_arg = data_size; 376 | 377 | errno = old_errno; 378 | return (1); 379 | 380 | process_memalign: 381 | if (do_free) 382 | vmem_xfree(umem_memalign_arena, base, size); 383 | else 384 | *data_size_arg = data_size; 385 | 386 | errno = old_errno; 387 | return (1); 388 | } 389 | 390 | void 391 | free(void *buf) 392 | { 393 | if (buf == NULL) 394 | return; 395 | 396 | /* 397 | * Process buf, freeing it if it is not corrupt. 398 | */ 399 | (void) process_free(buf, 1, NULL); 400 | } 401 | 402 | void * 403 | realloc(void *buf_arg, size_t newsize) 404 | { 405 | size_t oldsize; 406 | void *buf; 407 | 408 | if (buf_arg == NULL) 409 | return (malloc(newsize)); 410 | 411 | if (newsize == 0) { 412 | free(buf_arg); 413 | return (NULL); 414 | } 415 | 416 | /* 417 | * get the old data size without freeing the buffer 418 | */ 419 | if (process_free(buf_arg, 0, &oldsize) == 0) { 420 | errno = EINVAL; 421 | return (NULL); 422 | } 423 | 424 | if (newsize == oldsize) /* size didn't change */ 425 | return (buf_arg); 426 | 427 | buf = malloc(newsize); 428 | if (buf == NULL) 429 | return (NULL); 430 | 431 | (void) memcpy(buf, buf_arg, MIN(newsize, oldsize)); 432 | free(buf_arg); 433 | return (buf); 434 | } 435 | -------------------------------------------------------------------------------- /misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | 23 | /* 24 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 25 | * Use is subject to license terms. 26 | * 27 | * Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved. 28 | */ 29 | 30 | /* #pragma ident "@(#)misc.c 1.6 05/06/08 SMI" */ 31 | 32 | #define _BUILDING_UMEM_MISC_C 33 | #include "config.h" 34 | /* #include "mtlib.h" */ 35 | #if HAVE_UNISTD_H 36 | #include 37 | #endif 38 | #if HAVE_DLFCN_H 39 | #include 40 | #endif 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #if HAVE_SYS_MACHELF_H 47 | #include 48 | #endif 49 | 50 | #include 51 | #include "misc.h" 52 | 53 | #define UMEM_ERRFD 2 /* goes to standard error */ 54 | #define UMEM_MAX_ERROR_SIZE 4096 /* error messages are truncated to this */ 55 | 56 | /* 57 | * This is a circular buffer for holding error messages. 58 | * umem_error_enter appends to the buffer, adding "..." to the beginning 59 | * if data has been lost. 60 | */ 61 | 62 | #define ERR_SIZE 8192 /* must be a power of 2 */ 63 | 64 | static mutex_t umem_error_lock = DEFAULTMUTEX; 65 | #ifdef NEED_64_LOCK 66 | pthread_mutex_t umem_ppc_64inc_lock = PTHREAD_MUTEX_INITIALIZER; 67 | #endif 68 | 69 | static char umem_error_buffer[ERR_SIZE] = ""; 70 | static uint_t umem_error_begin = 0; 71 | static uint_t umem_error_end = 0; 72 | 73 | #define WRITE_AND_INC(var, value) { \ 74 | umem_error_buffer[(var)++] = (value); \ 75 | var = P2PHASE((var), ERR_SIZE); \ 76 | } 77 | 78 | static void 79 | umem_log_enter(const char *error_str) 80 | { 81 | int looped; 82 | char c; 83 | 84 | looped = 0; 85 | 86 | (void) mutex_lock(&umem_error_lock); 87 | 88 | while ((c = *error_str++) != '\0') { 89 | WRITE_AND_INC(umem_error_end, c); 90 | if (umem_error_end == umem_error_begin) 91 | looped = 1; 92 | } 93 | 94 | umem_error_buffer[umem_error_end] = 0; 95 | 96 | if (looped) { 97 | uint_t idx; 98 | umem_error_begin = P2PHASE(umem_error_end + 1, ERR_SIZE); 99 | 100 | idx = umem_error_begin; 101 | WRITE_AND_INC(idx, '.'); 102 | WRITE_AND_INC(idx, '.'); 103 | WRITE_AND_INC(idx, '.'); 104 | } 105 | 106 | (void) mutex_unlock(&umem_error_lock); 107 | } 108 | 109 | void 110 | umem_error_enter(const char *error_str) 111 | { 112 | #ifndef UMEM_STANDALONE 113 | if (umem_output && !issetugid()) 114 | (void) write(UMEM_ERRFD, error_str, strlen(error_str)); 115 | #endif 116 | 117 | umem_log_enter(error_str); 118 | } 119 | 120 | int 121 | highbit(ulong_t i) 122 | { 123 | register int h = 1; 124 | 125 | if (i == 0) 126 | return (0); 127 | #ifdef _LP64 128 | if (i & 0xffffffff00000000ul) { 129 | h += 32; i >>= 32; 130 | } 131 | #endif 132 | if (i & 0xffff0000) { 133 | h += 16; i >>= 16; 134 | } 135 | if (i & 0xff00) { 136 | h += 8; i >>= 8; 137 | } 138 | if (i & 0xf0) { 139 | h += 4; i >>= 4; 140 | } 141 | if (i & 0xc) { 142 | h += 2; i >>= 2; 143 | } 144 | if (i & 0x2) { 145 | h += 1; 146 | } 147 | return (h); 148 | } 149 | 150 | int 151 | lowbit(ulong_t i) 152 | { 153 | register int h = 1; 154 | 155 | if (i == 0) 156 | return (0); 157 | #ifdef _LP64 158 | if (!(i & 0xffffffff)) { 159 | h += 32; i >>= 32; 160 | } 161 | #endif 162 | if (!(i & 0xffff)) { 163 | h += 16; i >>= 16; 164 | } 165 | if (!(i & 0xff)) { 166 | h += 8; i >>= 8; 167 | } 168 | if (!(i & 0xf)) { 169 | h += 4; i >>= 4; 170 | } 171 | if (!(i & 0x3)) { 172 | h += 2; i >>= 2; 173 | } 174 | if (!(i & 0x1)) { 175 | h += 1; 176 | } 177 | return (h); 178 | } 179 | 180 | void 181 | hrt2ts(hrtime_t hrt, timestruc_t *tsp) 182 | { 183 | tsp->tv_sec = hrt / NANOSEC; 184 | tsp->tv_nsec = hrt % NANOSEC; 185 | } 186 | 187 | void 188 | log_message(const char *format, ...) 189 | { 190 | char buf[UMEM_MAX_ERROR_SIZE] = ""; 191 | 192 | va_list va; 193 | 194 | va_start(va, format); 195 | (void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va); 196 | va_end(va); 197 | 198 | #ifndef UMEM_STANDALONE 199 | if (umem_output > 1) 200 | (void) write(UMEM_ERRFD, buf, strlen(buf)); 201 | #endif 202 | 203 | umem_log_enter(buf); 204 | } 205 | 206 | #ifndef UMEM_STANDALONE 207 | void 208 | debug_printf(const char *format, ...) 209 | { 210 | char buf[UMEM_MAX_ERROR_SIZE] = ""; 211 | 212 | va_list va; 213 | 214 | va_start(va, format); 215 | (void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va); 216 | va_end(va); 217 | 218 | (void) write(UMEM_ERRFD, buf, strlen(buf)); 219 | } 220 | #endif 221 | 222 | void 223 | umem_vprintf(const char *format, va_list va) 224 | { 225 | char buf[UMEM_MAX_ERROR_SIZE] = ""; 226 | 227 | (void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va); 228 | 229 | umem_error_enter(buf); 230 | } 231 | 232 | void 233 | umem_printf(const char *format, ...) 234 | { 235 | va_list va; 236 | 237 | va_start(va, format); 238 | umem_vprintf(format, va); 239 | va_end(va); 240 | } 241 | 242 | /*ARGSUSED*/ 243 | void 244 | umem_printf_warn(void *ignored, const char *format, ...) 245 | { 246 | va_list va; 247 | 248 | va_start(va, format); 249 | umem_vprintf(format, va); 250 | va_end(va); 251 | } 252 | 253 | /* 254 | * print_sym tries to print out the symbol and offset of a pointer 255 | */ 256 | int 257 | print_sym(void *pointer) 258 | { 259 | #if HAVE_SYS_MACHELF_H 260 | int result; 261 | Dl_info sym_info; 262 | 263 | uintptr_t end = NULL; 264 | 265 | Sym *ext_info = NULL; 266 | 267 | result = dladdr1(pointer, &sym_info, (void **)&ext_info, 268 | RTLD_DL_SYMENT); 269 | 270 | if (result != 0) { 271 | const char *endpath; 272 | 273 | end = (uintptr_t)sym_info.dli_saddr + ext_info->st_size; 274 | 275 | endpath = strrchr(sym_info.dli_fname, '/'); 276 | if (endpath) 277 | endpath++; 278 | else 279 | endpath = sym_info.dli_fname; 280 | umem_printf("%s'", endpath); 281 | } 282 | 283 | if (result == 0 || (uintptr_t)pointer > end) { 284 | umem_printf("?? (0x%p)", pointer); 285 | return (0); 286 | } else { 287 | umem_printf("%s+0x%p", sym_info.dli_sname, 288 | (char *)pointer - (char *)sym_info.dli_saddr); 289 | return (1); 290 | } 291 | #else 292 | umem_printf("?? (0x%p)", pointer); 293 | return 0; 294 | #endif 295 | } 296 | -------------------------------------------------------------------------------- /misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | 23 | /* 24 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 25 | * Use is subject to license terms. 26 | * 27 | * Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved. 28 | */ 29 | 30 | #ifndef _MISC_H 31 | #define _MISC_H 32 | 33 | /* #pragma ident "@(#)misc.h 1.6 05/06/08 SMI" */ 34 | 35 | #include "config.h" 36 | #include 37 | #ifndef _WIN32 38 | #include 39 | #endif 40 | #ifdef HAVE_THREAD_H 41 | # include 42 | #else 43 | # include "sol_compat.h" 44 | #endif 45 | #include 46 | 47 | #ifdef __cplusplus 48 | extern "C" { 49 | #endif 50 | 51 | extern uint_t umem_abort; /* abort when errors occur */ 52 | extern uint_t umem_output; /* output error messages to stderr */ 53 | extern caddr_t umem_min_stack; /* max stack address for audit log */ 54 | extern caddr_t umem_max_stack; /* min stack address for audit log */ 55 | 56 | /* 57 | * various utility functions 58 | * These are globally implemented. 59 | */ 60 | 61 | #undef offsetof 62 | #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 63 | 64 | /* 65 | * a safe printf -- do not use for error messages. 66 | */ 67 | void debug_printf(const char *format, ...); 68 | 69 | /* 70 | * adds a message to the log without writing it out. 71 | */ 72 | void log_message(const char *format, ...); 73 | 74 | /* 75 | * returns the index of the (high/low) bit + 1 76 | */ 77 | int highbit(ulong_t) __attribute__ ((pure)); 78 | int lowbit(ulong_t) __attribute__ ((pure)); 79 | /* #pragma no_side_effect(highbit, lowbit) */ 80 | 81 | /* 82 | * Converts a hrtime_t to a timestruc_t 83 | */ 84 | void hrt2ts(hrtime_t hrt, timestruc_t *tsp); 85 | 86 | /* 87 | * tries to print out the symbol and offset of a pointer using umem_error_info 88 | */ 89 | int print_sym(void *pointer); 90 | 91 | /* 92 | * Information about the current error. Can be called multiple times, should 93 | * be followed eventually with a call to umem_err or umem_err_recoverable. 94 | */ 95 | void umem_printf(const char *format, ...); 96 | void umem_vprintf(const char *format, va_list); 97 | 98 | void umem_printf_warn(void *ignored, const char *format, ...); 99 | 100 | void umem_error_enter(const char *); 101 | 102 | /* 103 | * prints error message and stack trace, then aborts. Cannot return. 104 | */ 105 | void umem_panic(const char *format, ...) __attribute__((noreturn)); 106 | /* #pragma does_not_return(umem_panic) */ 107 | /* #pragma rarely_called(umem_panic) */ 108 | 109 | /* 110 | * like umem_err, but only aborts if umem_abort > 0 111 | */ 112 | void umem_err_recoverable(const char *format, ...); 113 | 114 | /* 115 | * We define our own assertion handling since libc's assert() calls malloc() 116 | */ 117 | #ifdef NDEBUG 118 | #define ASSERT(assertion) (void)0 119 | #else 120 | #define ASSERT(assertion) (void)((assertion) || \ 121 | __umem_assert_failed(#assertion, __FILE__, __LINE__)) 122 | #endif 123 | 124 | int __umem_assert_failed(const char *assertion, const char *file, int line) __attribute__ ((noreturn)); 125 | /* #pragma does_not_return(__umem_assert_failed) */ 126 | /* #pragma rarely_called(__umem_assert_failed) */ 127 | /* 128 | * These have architecture-specific implementations. 129 | */ 130 | 131 | /* 132 | * Returns the current function's frame pointer. 133 | */ 134 | extern void *getfp(void); 135 | 136 | /* 137 | * puts a pc-only stack trace of up to pcstack_limit frames into pcstack. 138 | * Returns the number of stacks written. 139 | * 140 | * if check_sighandler != 0, and we are in a signal context, calls 141 | * umem_err_recoverable. 142 | */ 143 | extern int getpcstack(uintptr_t *pcstack, int pcstack_limit, 144 | int check_sighandler); 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif 149 | 150 | #endif /* _MISC_H */ 151 | -------------------------------------------------------------------------------- /sol_compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2008 Message Systems, Inc. All rights reserved 3 | * This header file distributed under the terms of the CDDL. 4 | * Portions Copyright 2004 Sun Microsystems, Inc. All Rights reserved. 5 | */ 6 | #ifndef _EC_UMEM_SOL_COMPAT_H_ 7 | #define _EC_UMEM_SOL_COMPAT_H_ 8 | 9 | #include "config.h" 10 | 11 | #include 12 | #include 13 | 14 | #ifdef HAVE_SYS_TIME_H 15 | #include 16 | #endif 17 | 18 | #ifdef _WIN32 19 | # define THR_RETURN DWORD 20 | # define THR_API WINAPI 21 | # define INLINE __inline 22 | #else 23 | # define THR_RETURN void * 24 | # define THR_API 25 | # define INLINE inline 26 | #endif 27 | 28 | #if defined(__MACH__) || defined(_WIN32) 29 | #define NO_WEAK_SYMBOLS 30 | #define _umem_cache_alloc(a,b) umem_cache_alloc(a,b) 31 | #define _umem_cache_free(a,b) umem_cache_free(a,b) 32 | #define _umem_zalloc(a,b) umem_zalloc(a,b) 33 | #define _umem_alloc(a,b) umem_alloc(a,b) 34 | #define _umem_alloc_align(a,b,c) umem_alloc_align(a,b,c) 35 | #define _umem_free(a,b) umem_free(a,b) 36 | #define _umem_free_align(a,b) umem_free_align(a,b) 37 | #endif 38 | 39 | #ifdef _WIN32 40 | #define bcopy(s, d, n) memcpy(d, s, n) 41 | #define bzero(m, s) memset(m, 0, s) 42 | #endif 43 | 44 | typedef pthread_t thread_t; 45 | typedef pthread_mutex_t mutex_t; 46 | typedef pthread_cond_t cond_t; 47 | typedef u_int64_t hrtime_t; 48 | typedef uint32_t uint_t; 49 | typedef unsigned long ulong_t; 50 | typedef struct timespec timestruc_t; 51 | typedef long long longlong_t; 52 | typedef struct timespec timespec_t; 53 | static INLINE hrtime_t gethrtime(void) { 54 | struct timeval tv; 55 | gettimeofday(&tv, NULL); 56 | return (((u_int64_t)tv.tv_sec) << 32) | tv.tv_usec; 57 | } 58 | # define thr_self() pthread_self() 59 | static INLINE thread_t _thr_self(void) { 60 | return thr_self(); 61 | } 62 | #if defined(__MACH__) 63 | #define CPUHINT() (pthread_mach_thread_np(pthread_self())) 64 | #endif 65 | # define thr_sigsetmask pthread_sigmask 66 | 67 | #define THR_BOUND 1 68 | #define THR_DETACHED 2 69 | #define THR_DAEMON 4 70 | 71 | static INLINE int thr_create(void *stack_base, 72 | size_t stack_size, THR_RETURN (THR_API *start_func)(void*), 73 | void *arg, long flags, thread_t *new_thread_ID) 74 | { 75 | int ret; 76 | pthread_attr_t attr; 77 | 78 | pthread_attr_init(&attr); 79 | 80 | if (flags & THR_DETACHED) { 81 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 82 | } 83 | ret = pthread_create(new_thread_ID, &attr, start_func, arg); 84 | pthread_attr_destroy(&attr); 85 | return ret; 86 | } 87 | 88 | 89 | # define mutex_init(mp, type, arg) pthread_mutex_init(mp, NULL) 90 | # define mutex_lock(mp) pthread_mutex_lock(mp) 91 | # define mutex_unlock(mp) pthread_mutex_unlock(mp) 92 | # define mutex_destroy(mp) pthread_mutex_destroy(mp) 93 | # define mutex_trylock(mp) pthread_mutex_trylock(mp) 94 | # define DEFAULTMUTEX PTHREAD_MUTEX_INITIALIZER 95 | # define DEFAULTCV PTHREAD_COND_INITIALIZER 96 | # define MUTEX_HELD(mp) 1 /* not really, but only used in an assert */ 97 | 98 | # define cond_init(c, type, arg) pthread_cond_init(c, NULL) 99 | # define cond_wait(c, m) pthread_cond_wait(c, m) 100 | # define _cond_wait(c, m) pthread_cond_wait(c, m) 101 | # define cond_signal(c) pthread_cond_signal(c) 102 | # define cond_broadcast(c) pthread_cond_broadcast(c) 103 | # define cond_destroy(c) pthread_cond_destroy(c) 104 | # define cond_timedwait pthread_cond_timedwait 105 | # define _cond_timedwait pthread_cond_timedwait 106 | 107 | #ifndef RTLD_FIRST 108 | # define RTLD_FIRST 0 109 | #endif 110 | 111 | #ifdef ECELERITY 112 | # include "umem_atomic.h" 113 | #else 114 | # ifdef _WIN32 115 | # define umem_atomic_inc(a) InterlockedIncrement(a) 116 | # define umem_atomic_inc64(a) InterlockedIncrement64(a) 117 | # elif defined(__MACH__) 118 | # include 119 | # define umem_atomic_inc(x) OSAtomicIncrement32Barrier((int32_t*)x) 120 | # if !defined(__ppc__) 121 | # define umem_atomic_inc64(x) OSAtomicIncrement64Barrier((int64_t*)x) 122 | # endif 123 | # elif (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) 124 | static INLINE uint_t umem_atomic_cas(uint_t *mem, uint_t with, uint_t cmp) 125 | { 126 | uint_t prev; 127 | asm volatile ("lock; cmpxchgl %1, %2" 128 | : "=a" (prev) 129 | : "r" (with), "m" (*(mem)), "0" (cmp) 130 | : "memory"); 131 | return prev; 132 | } 133 | static INLINE uint64_t umem_atomic_cas64(uint64_t *mem, uint64_t with, 134 | uint64_t cmp) 135 | { 136 | uint64_t prev; 137 | # if defined(__x86_64__) 138 | __asm__ volatile ("lock; cmpxchgq %1, %2" 139 | : "=a" (prev) 140 | : "r" (with), "m" (*(mem)), "0" (cmp) 141 | : "memory"); 142 | # else 143 | __asm__ volatile ( 144 | "pushl %%ebx;" 145 | "mov 4+%1,%%ecx;" 146 | "mov %1,%%ebx;" 147 | "lock;" 148 | "cmpxchg8b (%3);" 149 | "popl %%ebx" 150 | : "=A" (prev) 151 | : "m" (with), "A" (cmp), "r" (mem) 152 | : "%ecx", "memory"); 153 | # endif 154 | return prev; 155 | } 156 | static INLINE uint64_t umem_atomic_inc64(uint64_t *mem) 157 | { 158 | register uint64_t last; 159 | do { 160 | last = *mem; 161 | } while (umem_atomic_cas64(mem, last+1, last) != last); 162 | return ++last; 163 | } 164 | # define umem_atomic_inc64 umem_atomic_inc64 165 | # else 166 | # error no atomic solution for your platform 167 | # endif 168 | 169 | # ifndef umem_atomic_inc 170 | static INLINE uint_t umem_atomic_inc(uint_t *mem) 171 | { 172 | register uint_t last; 173 | do { 174 | last = *mem; 175 | } while (umem_atomic_cas(mem, last+1, last) != last); 176 | return ++last; 177 | } 178 | # endif 179 | # ifndef umem_atomic_inc64 180 | /* yeah, it's not great. It's only used to bump failed allocation 181 | * counts, so it is not critical right now. */ 182 | extern pthread_mutex_t umem_ppc_64inc_lock; 183 | static INLINE uint64_t umem_atomic_inc64(uint64_t *val) 184 | { 185 | uint64_t rval; 186 | pthread_mutex_lock(&umem_ppc_64inc_lock); 187 | rval = *val + 1; 188 | *val = rval; 189 | pthread_mutex_unlock(&umem_ppc_64inc_lock); 190 | return rval; 191 | } 192 | # define umem_atomic_inc64 umem_atomic_inc64 193 | # define NEED_64_LOCK 1 194 | # endif 195 | 196 | #endif 197 | 198 | #define P2PHASE(x, align) ((x) & ((align) - 1)) 199 | #define P2ALIGN(x, align) ((x) & -(align)) 200 | #define P2NPHASE(x, align) (-(x) & ((align) - 1)) 201 | #define P2ROUNDUP(x, align) (-(-(x) & -(align))) 202 | #define P2END(x, align) (-(~(x) & -(align))) 203 | #define P2PHASEUP(x, align, phase) ((phase) - (((phase) - (x)) & -(align))) 204 | #define P2CROSS(x, y, align) (((x) ^ (y)) > (align) - 1) 205 | #define P2SAMEHIGHBIT(x, y) (((x) ^ (y)) < ((x) & (y))) 206 | #define IS_P2ALIGNED(v, a) ((((uintptr_t)(v)) & ((uintptr_t)(a) - 1)) == 0) 207 | #define ISP2(x) (((x) & ((x) - 1)) == 0) 208 | /* 209 | * return TRUE if adding len to off would cause it to cross an align 210 | * boundary. 211 | * eg, P2BOUNDARY(0x1234, 0xe0, 0x100) == TRUE (0x1234 + 0xe0 == 0x1314) 212 | * eg, P2BOUNDARY(0x1234, 0x50, 0x100) == FALSE (0x1234 + 0x50 == 0x1284) 213 | */ 214 | #define P2BOUNDARY(off, len, align) \ 215 | (((off) ^ ((off) + (len) - 1)) > (align) - 1) 216 | 217 | /* beware! umem only uses these atomic adds for incrementing by 1 */ 218 | #define atomic_add_64(lvalptr, delta) umem_atomic_inc64(lvalptr) 219 | #define atomic_add_32_nv(a, b) umem_atomic_inc(a) 220 | 221 | #ifndef NANOSEC 222 | #define NANOSEC 1000000000 223 | #endif 224 | 225 | #ifdef _WIN32 226 | #define issetugid() 0 227 | #elif !HAVE_ISSETUGID 228 | #define issetugid() (geteuid() == 0) 229 | #endif 230 | 231 | #define _sysconf(a) sysconf(a) 232 | #define __NORETURN __attribute__ ((noreturn)) 233 | 234 | #define EC_UMEM_DUMMY_PCSTACK 1 235 | static INLINE int __nthreads(void) 236 | { 237 | /* or more; just to force multi-threaded mode */ 238 | return 2; 239 | } 240 | 241 | #if (SIZEOF_VOID_P == 8) 242 | # define _LP64 1 243 | #endif 244 | 245 | #ifndef MIN 246 | # define MIN(a,b) ((a) < (b) ? (a) : (b)) 247 | #endif 248 | #ifndef MAX 249 | # define MAX(a,b) ((a) > (b) ? (a) : (b)) 250 | #endif 251 | 252 | 253 | #endif 254 | -------------------------------------------------------------------------------- /sparc_subr_sol.s: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | */ 26 | 27 | #pragma ident "@(#)asm_subr.s 1.3 05/06/08 SMI" 28 | 29 | #include 30 | 31 | #if defined(lint) 32 | 33 | void * 34 | getfp(void) 35 | { 36 | return (NULL); 37 | } 38 | 39 | void 40 | flush_windows(void) 41 | { 42 | 43 | } 44 | 45 | #ifndef UMEM_STANDALONE 46 | void 47 | _breakpoint(void) 48 | { 49 | return; 50 | } 51 | #endif 52 | 53 | #else /* lint */ 54 | 55 | ENTRY(getfp) 56 | retl 57 | mov %fp, %o0 58 | SET_SIZE(getfp) 59 | 60 | #ifdef UMEM_STANDALONE 61 | #ifdef __sparcv9 62 | 63 | /* 64 | * The caller doesn't need the top window to be flushed, so this 65 | * is sufficient. 66 | */ 67 | ENTRY(flush_windows) 68 | retl 69 | flushw 70 | SET_SIZE(flush_windows) 71 | 72 | #else /* !__sparcv9 */ 73 | #error "This file does not provide a pre-v9 standalone flush_windows" 74 | #endif /* __sparcv9 */ 75 | 76 | #else /* !UMEM_STANDALONE */ 77 | 78 | ENTRY(flush_windows) 79 | retl 80 | ta 0x3 81 | SET_SIZE(flush_windows) 82 | 83 | #endif /* UMEM_STANDALONE */ 84 | 85 | #ifndef UMEM_STANDALONE 86 | ENTRY(_breakpoint) 87 | retl 88 | ta 0x1 89 | SET_SIZE(_breakpoint) 90 | #endif 91 | 92 | #endif /* lint */ 93 | -------------------------------------------------------------------------------- /stand_mapfile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 | # Use is subject to license terms. 4 | # 5 | # CDDL HEADER START 6 | # 7 | # The contents of this file are subject to the terms of the 8 | # Common Development and Distribution License, Version 1.0 only 9 | # (the "License"). You may not use this file except in compliance 10 | # with the License. 11 | # 12 | # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 13 | # or http://www.opensolaris.org/os/licensing. 14 | # See the License for the specific language governing permissions 15 | # and limitations under the License. 16 | # 17 | # When distributing Covered Code, include this CDDL HEADER in each 18 | # file and include the License file at usr/src/OPENSOLARIS.LICENSE. 19 | # If applicable, add the following below this CDDL HEADER, with the 20 | # fields enclosed by brackets "[]" replaced with your own identifying 21 | # information: Portions Copyright [yyyy] [name of copyright owner] 22 | # 23 | # CDDL HEADER END 24 | # 25 | #ident "@(#)stand_mapfile 1.3 05/06/08 SMI" 26 | # 27 | 28 | # 29 | # This is a supplemental mapfile, used in addition to the standard one 30 | # produced by the spec tools. This mapfile exposes an additional 31 | # symbol (umem_startup) that is only present in the standalone version 32 | # of libumem. 33 | # 34 | 35 | SUNWprivate1.1 { 36 | global: 37 | umem_startup; 38 | umem_add; 39 | }; 40 | -------------------------------------------------------------------------------- /stub_stand.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | 23 | /* 24 | * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 25 | * Use is subject to license terms. 26 | */ 27 | 28 | #pragma ident "@(#)stub_stand.c 1.3 05/06/08 SMI" 29 | 30 | /* 31 | * Stubs for the standalone to reduce the dependence on external libraries 32 | */ 33 | 34 | #include "config.h" 35 | #include 36 | #include 37 | 38 | #include "misc.h" 39 | 40 | /*ARGSUSED*/ 41 | int 42 | _cond_init(cond_t *cvp, int type, void *arg) 43 | { 44 | return (0); 45 | } 46 | 47 | /*ARGSUSED*/ 48 | int 49 | _cond_destroy(cond_t *cvp) 50 | { 51 | return (0); 52 | } 53 | 54 | /*ARGSUSED*/ 55 | int 56 | _cond_wait(cond_t *cv, mutex_t *mutex) 57 | { 58 | umem_panic("attempt to wait on standumem cv %p", cv); 59 | 60 | /*NOTREACHED*/ 61 | return (0); 62 | } 63 | 64 | /*ARGSUSED*/ 65 | int 66 | _cond_broadcast(cond_t *cvp) 67 | { 68 | return (0); 69 | } 70 | 71 | thread_t 72 | _thr_self(void) 73 | { 74 | return ((thread_t)1); 75 | } 76 | 77 | static mutex_t _mp = DEFAULTMUTEX; 78 | 79 | /*ARGSUSED*/ 80 | int 81 | __mutex_init(mutex_t *mp, int type, void *arg) 82 | { 83 | (void) memcpy(mp, &_mp, sizeof (mutex_t)); 84 | return (0); 85 | } 86 | 87 | /*ARGSUSED*/ 88 | int 89 | __mutex_destroy(mutex_t *mp) 90 | { 91 | return (0); 92 | } 93 | 94 | /*ARGSUSED*/ 95 | int 96 | __mutex_held(mutex_t *mp) 97 | { 98 | return (1); 99 | } 100 | 101 | /*ARGSUSED*/ 102 | int 103 | __mutex_lock(mutex_t *mp) 104 | { 105 | return (0); 106 | } 107 | 108 | /*ARGSUSED*/ 109 | int 110 | __mutex_trylock(mutex_t *mp) 111 | { 112 | return (0); 113 | } 114 | 115 | /*ARGSUSED*/ 116 | int 117 | __mutex_unlock(mutex_t *mp) 118 | { 119 | return (0); 120 | } 121 | 122 | int 123 | issetugid(void) 124 | { 125 | return (1); 126 | } 127 | -------------------------------------------------------------------------------- /sys/vmem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | */ 26 | 27 | #ifndef _SYS_VMEM_H 28 | #define _SYS_VMEM_H 29 | 30 | /* #pragma ident "@(#)vmem.h 1.13 05/06/08 SMI" */ 31 | 32 | #include 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | 39 | /* 40 | * Per-allocation flags 41 | */ 42 | #define VM_SLEEP 0x00000000 /* same as KM_SLEEP */ 43 | #define VM_NOSLEEP 0x00000001 /* same as KM_NOSLEEP */ 44 | #define VM_PANIC 0x00000002 /* same as KM_PANIC */ 45 | #define VM_PUSHPAGE 0x00000004 /* same as KM_PUSHPAGE */ 46 | #define VM_KMFLAGS 0x000000ff /* flags that must match KM_* flags */ 47 | 48 | #define VM_BESTFIT 0x00000100 49 | #define VM_FIRSTFIT 0x00000200 50 | #define VM_NEXTFIT 0x00000400 51 | 52 | /* 53 | * The following flags are restricted for use only within the kernel. 54 | * VM_MEMLOAD is for use by the HAT to avoid infinite recursion. 55 | * VM_NORELOC is used by the kernel when static VA->PA mappings are required. 56 | */ 57 | #define VM_MEMLOAD 0x00000800 58 | #define VM_NORELOC 0x00001000 59 | /* 60 | * VM_ABORT requests that vmem_alloc() *ignore* the VM_SLEEP/VM_NOSLEEP flags 61 | * and forgo reaping if the allocation or attempted import, fails. This 62 | * flag is a segkmem-specific flag, and should not be used by anyone else. 63 | */ 64 | #define VM_ABORT 0x00002000 65 | 66 | #define VM_FLAGS 0x0000FFFF 67 | 68 | /* 69 | * Arena creation flags 70 | */ 71 | #define VMC_POPULATOR 0x00010000 72 | #define VMC_NO_QCACHE 0x00020000 /* cannot use quantum caches */ 73 | #define VMC_IDENTIFIER 0x00040000 /* not backed by memory */ 74 | /* 75 | * internal use only; the import function uses the vmem_ximport_t interface 76 | * and may increase the request size if it so desires 77 | */ 78 | #define VMC_XALLOC 0x00080000 79 | #define VMC_FLAGS 0xFFFF0000 80 | 81 | /* 82 | * Public segment types 83 | */ 84 | #define VMEM_ALLOC 0x01 85 | #define VMEM_FREE 0x02 86 | 87 | /* 88 | * Implementation-private segment types 89 | */ 90 | #define VMEM_SPAN 0x10 91 | #define VMEM_ROTOR 0x20 92 | #define VMEM_WALKER 0x40 93 | 94 | /* 95 | * VMEM_REENTRANT indicates to vmem_walk() that the callback routine may 96 | * call back into the arena being walked, so vmem_walk() must drop the 97 | * arena lock before each callback. The caveat is that since the arena 98 | * isn't locked, its state can change. Therefore it is up to the callback 99 | * routine to handle cases where the segment isn't of the expected type. 100 | * For example, we use this to walk heap_arena when generating a crash dump; 101 | * see segkmem_dump() for sample usage. 102 | */ 103 | #define VMEM_REENTRANT 0x80000000 104 | 105 | typedef struct vmem vmem_t; 106 | typedef void *(vmem_alloc_t)(vmem_t *, size_t, int); 107 | typedef void (vmem_free_t)(vmem_t *, void *, size_t); 108 | 109 | /* 110 | * Alternate import style; the requested size is passed in a pointer, 111 | * which can be increased by the import function if desired. 112 | */ 113 | typedef void *(vmem_ximport_t)(vmem_t *, size_t *, int); 114 | 115 | #ifdef _KERNEL 116 | extern vmem_t *vmem_init(const char *, void *, size_t, size_t, 117 | vmem_alloc_t *, vmem_free_t *); 118 | extern void vmem_update(void *); 119 | extern int vmem_is_populator(); 120 | extern size_t vmem_seg_size; 121 | #endif 122 | 123 | extern vmem_t *vmem_create(const char *, void *, size_t, size_t, 124 | vmem_alloc_t *, vmem_free_t *, vmem_t *, size_t, int); 125 | extern vmem_t *vmem_xcreate(const char *, void *, size_t, size_t, 126 | vmem_ximport_t *, vmem_free_t *, vmem_t *, size_t, int); 127 | extern void vmem_destroy(vmem_t *); 128 | extern void *vmem_alloc(vmem_t *, size_t, int); 129 | extern void *vmem_xalloc(vmem_t *, size_t, size_t, size_t, size_t, 130 | void *, void *, int); 131 | extern void vmem_free(vmem_t *, void *, size_t); 132 | extern void vmem_xfree(vmem_t *, void *, size_t); 133 | extern void *vmem_add(vmem_t *, void *, size_t, int); 134 | extern int vmem_contains(vmem_t *, void *, size_t); 135 | extern void vmem_walk(vmem_t *, int, void (*)(void *, void *, size_t), void *); 136 | extern size_t vmem_size(vmem_t *, int); 137 | 138 | #ifdef __cplusplus 139 | } 140 | #endif 141 | 142 | #endif /* _SYS_VMEM_H */ 143 | -------------------------------------------------------------------------------- /sys/vmem_impl_user.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | * 26 | * Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved. 27 | */ 28 | 29 | #ifndef _SYS_VMEM_IMPL_USER_H 30 | #define _SYS_VMEM_IMPL_USER_H 31 | 32 | /* #pragma ident "@(#)vmem_impl_user.h 1.2 05/06/08 SMI" */ 33 | 34 | #if HAVE_SYS_KSTAT 35 | #include 36 | #endif 37 | #ifndef _WIN32 38 | #include 39 | #endif 40 | #include 41 | #if HAVE_THREAD_H 42 | #include 43 | #else 44 | # include "sol_compat.h" 45 | #endif 46 | #if HAVE_SYNC_H 47 | #include 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | extern "C" { 52 | #endif 53 | 54 | typedef struct vmem_seg vmem_seg_t; 55 | 56 | #define VMEM_STACK_DEPTH 20 57 | 58 | struct vmem_seg { 59 | /* 60 | * The first four fields must match vmem_freelist_t exactly. 61 | */ 62 | uintptr_t vs_start; /* start of segment (inclusive) */ 63 | uintptr_t vs_end; /* end of segment (exclusive) */ 64 | vmem_seg_t *vs_knext; /* next of kin (alloc, free, span) */ 65 | vmem_seg_t *vs_kprev; /* prev of kin */ 66 | 67 | vmem_seg_t *vs_anext; /* next in arena */ 68 | vmem_seg_t *vs_aprev; /* prev in arena */ 69 | uint8_t vs_type; /* alloc, free, span */ 70 | uint8_t vs_import; /* non-zero if segment was imported */ 71 | uint8_t vs_depth; /* stack depth if UMF_AUDIT active */ 72 | /* 73 | * The following fields are present only when UMF_AUDIT is set. 74 | */ 75 | thread_t vs_thread; 76 | hrtime_t vs_timestamp; 77 | uintptr_t vs_stack[VMEM_STACK_DEPTH]; 78 | }; 79 | 80 | typedef struct vmem_freelist { 81 | uintptr_t vs_start; /* always zero */ 82 | uintptr_t vs_end; /* segment size */ 83 | vmem_seg_t *vs_knext; /* next of kin */ 84 | vmem_seg_t *vs_kprev; /* prev of kin */ 85 | } vmem_freelist_t; 86 | 87 | #define VS_SIZE(vsp) ((vsp)->vs_end - (vsp)->vs_start) 88 | 89 | /* 90 | * Segment hashing 91 | */ 92 | #define VMEM_HASH_INDEX(a, s, q, m) \ 93 | ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m)) 94 | 95 | #define VMEM_HASH(vmp, addr) \ 96 | (&(vmp)->vm_hash_table[VMEM_HASH_INDEX(addr, \ 97 | (vmp)->vm_hash_shift, (vmp)->vm_qshift, (vmp)->vm_hash_mask)]) 98 | 99 | #define VMEM_NAMELEN 30 100 | #define VMEM_HASH_INITIAL 16 101 | #define VMEM_NQCACHE_MAX 16 102 | #define VMEM_FREELISTS (sizeof (void *) * 8) 103 | 104 | typedef struct vmem_kstat { 105 | uint64_t vk_mem_inuse; /* memory in use */ 106 | uint64_t vk_mem_import; /* memory imported */ 107 | uint64_t vk_mem_total; /* total memory in arena */ 108 | uint32_t vk_source_id; /* vmem id of vmem source */ 109 | uint64_t vk_alloc; /* number of allocations */ 110 | uint64_t vk_free; /* number of frees */ 111 | uint64_t vk_wait; /* number of allocations that waited */ 112 | uint64_t vk_fail; /* number of allocations that failed */ 113 | uint64_t vk_lookup; /* hash lookup count */ 114 | uint64_t vk_search; /* freelist search count */ 115 | uint64_t vk_populate_wait; /* populates that waited */ 116 | uint64_t vk_populate_fail; /* populates that failed */ 117 | uint64_t vk_contains; /* vmem_contains() calls */ 118 | uint64_t vk_contains_search; /* vmem_contains() search cnt */ 119 | } vmem_kstat_t; 120 | 121 | struct vmem { 122 | char vm_name[VMEM_NAMELEN]; /* arena name */ 123 | cond_t vm_cv; /* cv for blocking allocations */ 124 | mutex_t vm_lock; /* arena lock */ 125 | uint32_t vm_id; /* vmem id */ 126 | uint32_t vm_mtbf; /* induced alloc failure rate */ 127 | int vm_cflags; /* arena creation flags */ 128 | int vm_qshift; /* log2(vm_quantum) */ 129 | size_t vm_quantum; /* vmem quantum */ 130 | size_t vm_qcache_max; /* maximum size to front by umem */ 131 | vmem_alloc_t *vm_source_alloc; 132 | vmem_free_t *vm_source_free; 133 | vmem_t *vm_source; /* vmem source for imported memory */ 134 | vmem_t *vm_next; /* next in vmem_list */ 135 | ssize_t vm_nsegfree; /* number of free vmem_seg_t's */ 136 | vmem_seg_t *vm_segfree; /* free vmem_seg_t list */ 137 | vmem_seg_t **vm_hash_table; /* allocated-segment hash table */ 138 | size_t vm_hash_mask; /* hash_size - 1 */ 139 | size_t vm_hash_shift; /* log2(vm_hash_mask + 1) */ 140 | ulong_t vm_freemap; /* bitmap of non-empty freelists */ 141 | vmem_seg_t vm_seg0; /* anchor segment */ 142 | vmem_seg_t vm_rotor; /* rotor for VM_NEXTFIT allocations */ 143 | vmem_seg_t *vm_hash0[VMEM_HASH_INITIAL]; /* initial hash table */ 144 | void *vm_qcache[VMEM_NQCACHE_MAX]; /* quantum caches */ 145 | vmem_freelist_t vm_freelist[VMEM_FREELISTS + 1]; /* power-of-2 flists */ 146 | vmem_kstat_t vm_kstat; /* kstat data */ 147 | }; 148 | 149 | /* 150 | * We cannot use a mutex_t and MUTEX_HELD, since that will not work 151 | * when libthread is not linked. 152 | */ 153 | typedef struct vmem_populate_lock { 154 | mutex_t vmpl_mutex; 155 | thread_t vmpl_thr; 156 | } vmem_populate_lock_t; 157 | 158 | #define VM_UMFLAGS VM_KMFLAGS 159 | 160 | #ifdef __cplusplus 161 | } 162 | #endif 163 | 164 | #endif /* _SYS_VMEM_IMPL_USER_H */ 165 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /* malloc-test.c 2 | * by Wolfram Gloger 1995, 1996 3 | * 4 | * This program is provided `as is', there is no warranty. 5 | * https://raw.githubusercontent.com/emeryberger/Malloc-Implementations/master/allocators/CAMA/malloc-test.c 6 | */ 7 | 8 | #if !defined(__STDC__) 9 | #define __STDC__ 1 10 | #endif 11 | 12 | #include 13 | #include 14 | 15 | #if !defined(_WIN32) 16 | #include 17 | #include 18 | #include 19 | #include 20 | #endif 21 | 22 | #ifndef MEMORY 23 | #define MEMORY 4000000l 24 | #endif 25 | #ifndef BINS_MAX 26 | #define BINS_MAX 32768 27 | #endif 28 | #define SBINS_MAX 1024 29 | #define SIZE 4024 30 | #define I_MAX 5000 31 | #ifndef I_AVERAGE 32 | #define I_AVERAGE 200 33 | #endif 34 | #define ACTIONS_MAX 50 35 | #ifndef SBRK_AVG 36 | #define SBRK_AVG 0 37 | #endif 38 | #ifndef MMAP_THRESH 39 | #define MMAP_THRESH 0 40 | #endif 41 | #ifndef TEST 42 | #define TEST 4 /* minimal testing */ 43 | #endif 44 | #ifndef TEST_INC 45 | #define TEST_INC 2047 46 | #endif 47 | #if defined(__i386__) || defined(__sparc__) || defined(mips) || defined(_WIN32) 48 | #define PAGE_SIZE 4096 49 | #elif defined(__alpha__) 50 | #define PAGE_SIZE 8192 51 | #elif defined(__SVR4) 52 | #define PAGE_SIZE 8192 53 | #else 54 | #define PAGE_SIZE 4096 /* default */ 55 | #endif 56 | #define RANDOM(s) (lran2(0) % (s)) 57 | 58 | /* All probabilities are parts in 1024. */ 59 | #ifndef PROB_MEMALIGN 60 | #define PROB_MEMALIGN 0 61 | #endif 62 | #ifndef PROB_REALLOC 63 | #define PROB_REALLOC 48 64 | #endif 65 | #ifndef PROB_CALLOC 66 | #define PROB_CALLOC 0 67 | #endif 68 | 69 | struct bin { 70 | unsigned char *ptr; 71 | unsigned long size; 72 | } m[BINS_MAX], sm[SBINS_MAX]; 73 | 74 | unsigned long size = SIZE, bins=0, sbins=0; 75 | unsigned long total_size=0, total_size_max=0; 76 | unsigned char *base_ptr; 77 | unsigned long base_save; 78 | 79 | long 80 | #if __STDC__ 81 | lran2(long seed) 82 | #else 83 | lran2(seed) long seed; 84 | #endif 85 | #define LRAN2_MAX 714025l /* constants for portable */ 86 | #define IA 1366l /* random number generator */ 87 | #define IC 150889l /* (see Numerical Recipes p. 211) */ 88 | { 89 | static int first = 1; 90 | static long x, y, v[97]; 91 | int j; 92 | 93 | if(seed || first) { 94 | first = 0; 95 | x = (IC - seed) % LRAN2_MAX; 96 | if(x < 0) x = -x; 97 | for(j=0; j<97; j++) { 98 | x = (IA*x + IC) % LRAN2_MAX; 99 | v[j] = x; 100 | } 101 | x = (IA*x + IC) % LRAN2_MAX; 102 | y = x; 103 | } 104 | j = y % 97; 105 | y = v[j]; 106 | x = (IA*x + IC) % LRAN2_MAX; 107 | v[j] = x; 108 | return y; 109 | } 110 | #undef IA 111 | #undef IC 112 | 113 | void 114 | #if __STDC__ 115 | mem_init(unsigned char *ptr, unsigned long size) 116 | #else 117 | mem_init(ptr, size) unsigned char *ptr; unsigned long size; 118 | #endif 119 | { 120 | unsigned long i, j; 121 | 122 | if(size == 0) return; 123 | if(size > sizeof(unsigned long)) { 124 | /* Try the complete initial word. */ 125 | *(unsigned long *)ptr = (unsigned long)ptr ^ size; 126 | i = TEST_INC; 127 | } else 128 | i = 0; 129 | for(; i>8)) & 0xFF); 132 | } 133 | j = (unsigned long)ptr ^ (size-1); 134 | ptr[size-1] = ((j ^ (j>>8)) & 0xFF); 135 | } 136 | 137 | int 138 | #if __STDC__ 139 | mem_check(unsigned char *ptr, unsigned long size) 140 | #else 141 | mem_check(ptr, size) unsigned char *ptr; unsigned long size; 142 | #endif 143 | { 144 | unsigned long i, j; 145 | 146 | if(size == 0) return 0; 147 | if(size > sizeof(unsigned long)) { 148 | if(*(unsigned long *)ptr != ((unsigned long)ptr ^ size)) { 149 | printf ("failed size check: expected %lx, found %lx!\n", 150 | ((unsigned long) ptr ^ size), *(unsigned long *) ptr); 151 | return 1; 152 | } 153 | i = TEST_INC; 154 | } else 155 | i = 0; 156 | for(; i>8)) & 0xFF)) return 2; 159 | } 160 | j = (unsigned long)ptr ^ (size-1); 161 | if(ptr[size-1] != ((j ^ (j>>8)) & 0xFF)) { 162 | printf ("failed last byte check: expected %lx, found %x!\n", 163 | ((unsigned long) ((j ^ (j>>8)) & 0xFF)), ptr[size-1]); 164 | return 3; 165 | } 166 | return 0; 167 | } 168 | 169 | long 170 | #if __STDC__ 171 | random_size(long max) 172 | #else 173 | random_size(max) long max; 174 | #endif 175 | { 176 | long r1, r2, r, max_pages; 177 | 178 | max_pages = max/PAGE_SIZE; 179 | if(max_pages > 0) { 180 | r1 = RANDOM(1024); 181 | r2 = (r1 & 7)*4; 182 | if(r1 < 512) { 183 | /* small value near power of two */ 184 | r = (1L << (r1 >> 6)) + r2; 185 | } else if(r1 < 512+20) { 186 | /* value near a multiple of the page size */ 187 | r = (RANDOM(max_pages)+1)*PAGE_SIZE + r2 - 16; 188 | /*printf("r = %4lx\n", r);*/ 189 | } else r = RANDOM(max) + 1; 190 | } else r = RANDOM(max) + 1; 191 | /*if(r <= 0) exit(-1);*/ 192 | return r; 193 | } 194 | 195 | void 196 | #if __STDC__ 197 | bin_alloc(struct bin *m) 198 | #else 199 | bin_alloc(m) struct bin *m; 200 | #endif 201 | { 202 | long r, key; 203 | unsigned long sz; 204 | 205 | #if TEST > 0 206 | if(mem_check(m->ptr, m->size)) { 207 | printf("bin_alloc: memory corrupt at %p, size=%lu!\n", m->ptr, m->size); 208 | exit(1); 209 | } 210 | #endif 211 | total_size -= m->size; 212 | r = RANDOM(1024); 213 | if(r < PROB_MEMALIGN) { 214 | #if !defined(_WIN32) 215 | if(m->size > 0) free(m->ptr); 216 | m->size = random_size(size); 217 | #if PROB_MEMALIGN 218 | m->ptr = (unsigned char *)memalign(4 << RANDOM(8), m->size); 219 | #endif 220 | 221 | #endif 222 | } else if(r < (PROB_MEMALIGN + PROB_REALLOC)) { 223 | if(m->size == 0) { 224 | #ifndef __sparc__ 225 | m->ptr = NULL; 226 | #else 227 | /* SunOS4 does not realloc() a NULL pointer */ 228 | m->ptr = (unsigned char *)malloc(1); 229 | #endif 230 | } 231 | #if TEST > 2 232 | key = RANDOM(256); 233 | sz = m->size; 234 | for(r=0; rptr[r] = (r ^ key) & 0xFF; 235 | #endif 236 | m->size = random_size(size); 237 | /*printf("realloc %d\n", (int)m->size);*/ 238 | m->ptr = (unsigned char *)realloc(m->ptr, m->size); 239 | #if TEST > 2 240 | if(m->size < sz) sz = m->size; 241 | for(r=0; rptr[r] != ((r ^ key) & 0xFF)) { 243 | printf("realloc bug !\n"); 244 | exit(1); 245 | } 246 | #endif 247 | } else if(r < (PROB_MEMALIGN + PROB_REALLOC + PROB_CALLOC)) { 248 | if(m->size > 0) free(m->ptr); 249 | m->size = random_size(size); 250 | m->ptr = (unsigned char *)calloc(m->size, 1); 251 | #if TEST > 2 252 | for(r=0; rsize; r++) 253 | if(m->ptr[r] != '\0') { 254 | printf("calloc bug !\n"); 255 | exit(1); 256 | } 257 | #endif 258 | } else { /* normal malloc call */ 259 | if(m->size > 0) free(m->ptr); 260 | m->size = random_size(size); 261 | m->ptr = (unsigned char *)malloc(m->size); 262 | } 263 | if(!m->ptr) { 264 | printf("out of memory!\n"); 265 | exit(1); 266 | } 267 | total_size += m->size; 268 | if(total_size > total_size_max) total_size_max = total_size; 269 | #if TEST > 0 270 | mem_init(m->ptr, m->size); 271 | #endif 272 | if(m->ptr < base_ptr) { 273 | #ifdef VERBOSE 274 | printf("hmmm, allocating below brk...\n"); 275 | #endif 276 | base_ptr = m->ptr; 277 | } 278 | } 279 | 280 | void 281 | #if __STDC__ 282 | bin_free(struct bin *m) 283 | #else 284 | bin_free(m) struct bin *m; 285 | #endif 286 | { 287 | if(m->size == 0) return; 288 | #if TEST > 0 289 | if(mem_check(m->ptr, m->size)) { 290 | printf("bin_free: memory corrupt!\n"); 291 | exit(1); 292 | } 293 | #endif 294 | total_size -= m->size; 295 | free(m->ptr); 296 | m->size = 0; 297 | } 298 | 299 | void 300 | bin_test() 301 | { 302 | unsigned int b; 303 | int v; 304 | // printf ("bin_test.\n"); 305 | 306 | for(b=0; b= 1000000) { 338 | total_usec -= 1000000; 339 | total_sec++; 340 | } 341 | printf(" t=%ld.%06ldsec", total_sec, total_usec); 342 | #endif 343 | } 344 | 345 | int 346 | #if __STDC__ 347 | main(int argc, char *argv[]) 348 | #else 349 | main(argc, argv) int argc; char *argv[]; 350 | #endif 351 | { 352 | int i, j, next_i, count, max=I_MAX, actions; 353 | unsigned int b; 354 | long sbrk_max, sum; 355 | double sbrk_used_sum, total_size_sum; 356 | 357 | if(argc > 1) max = atoi(argv[1]); 358 | if(argc > 2) size = atoi(argv[2]); 359 | lran2((long)max ^ size); 360 | bins = (MEMORY/size)*4; 361 | if(bins > BINS_MAX) bins = BINS_MAX; 362 | #if 0 // FIX ME? Disable sbrk... 363 | base_ptr = (unsigned char *)sbrk(0); 364 | sum = (long)base_ptr % PAGE_SIZE; 365 | if(sum > 0) { 366 | if((char *)sbrk((long)PAGE_SIZE - sum) == (char *)-1) exit(1); 367 | base_ptr += (long)PAGE_SIZE - sum; 368 | /*printf("base_ptr = %lx\n", (long)base_ptr);*/ 369 | } 370 | /* attempt to fill up the region below the initial brk */ 371 | void* dummy = 0; 372 | for(i=0; i<10000; i++) { 373 | dummy = malloc(1); 374 | if(dummy >= (void*)base_ptr) break; 375 | } 376 | free(dummy); 377 | base_save = ((unsigned long)base_ptr >> 24) << 24; 378 | #endif 379 | 380 | #if MMAP_THRESH > 0 381 | if(!mallopt(-3, MMAP_THRESH)) printf("mallopt failed!\n"); 382 | if(!mallopt(-4, 200)) printf("mallopt failed!\n"); 383 | #endif 384 | #ifdef VERBOSE 385 | printf("# mmap_thresh=%d\n", MMAP_THRESH); 386 | printf("# bins=%d max=%d size=%d\n", bins, max, size); 387 | printf("# base=%lx\n", base_save); 388 | #endif 389 | for(b=0; b 1 397 | bin_test(); 398 | #endif 399 | #ifdef MSTATS 400 | malloc_stats(); 401 | #endif 402 | actions = RANDOM(ACTIONS_MAX); 403 | for(j=0; j 3 407 | bin_test(); 408 | #endif 409 | } 410 | i += actions; 411 | #ifdef AFTER_FREE 412 | AFTER_FREE; 413 | #endif 414 | #if SBRK_AVG > 0 415 | if(sbins0 && sm[sbins].ptr==(sm[sbins-1].ptr+sm[sbins-1].size)) { 420 | sm[sbins-1].size += sm[sbins].size; 421 | sbins--; 422 | } 423 | #ifdef VERBOSE 424 | printf("sbrk #%d %p %ld\n", sbins, sm[sbins].ptr, sm[sbins].size); 425 | #endif 426 | #if TEST > 0 427 | mem_init(sm[sbins].ptr, sm[sbins].size); 428 | #endif 429 | sbins++; 430 | } 431 | #endif 432 | actions = RANDOM(ACTIONS_MAX); 433 | for(j=0; j 3 437 | bin_test(); 438 | #endif 439 | } 440 | i += actions; 441 | if(i >= next_i) { /* gather statistics */ 442 | count++; 443 | #if !defined(_WIN32) 444 | sum = (long)sbrk(0); 445 | #else 446 | sum = 0; 447 | #endif 448 | if(sum > sbrk_max) sbrk_max = sum; 449 | sbrk_used_sum += sum; 450 | total_size_sum += (double)total_size; 451 | #ifdef VERBOSE 452 | printf("%8d %7lu\n", i, total_size); 453 | #endif 454 | next_i += I_AVERAGE; 455 | } 456 | } 457 | 458 | /* Correct sbrk values. */ 459 | sbrk_max -= (long)base_ptr; 460 | sbrk_used_sum -= (double)count*(long)base_ptr; 461 | #ifdef VERBOSE 462 | printf("# initial brk: %lx\n", (long)base_ptr); 463 | printf("# max. sbrk()'ed memory: %ld bytes\n", sbrk_max); 464 | printf("# avg. sbrk()'ed memory: %ld bytes\n", 465 | (long)(sbrk_used_sum/count)); 466 | printf("# current size allocated: %ld bytes\n", total_size); 467 | printf("# maximum size allocated: %ld bytes\n", total_size_max); 468 | printf("# average size allocated: %.1f bytes\n", total_size_sum/count); 469 | printf("# current heap waste: %.2f%%\n", 470 | (1.0 - (double)total_size_max/sbrk_max)*100.0); 471 | printf("# average heap waste: %.2f%%\n", 472 | (1.0 - (double)total_size_sum/sbrk_used_sum)*100.0); 473 | printf("# total sbrk calls performed: %d\n", sbins); 474 | #else 475 | printf("size=%7ld waste=%7.3f%%", size, 476 | /* (1.0 - (double)total_size_max/sbrk_max)*100.0, */ 477 | (1.0 - (double)total_size_sum/sbrk_used_sum)*100.0); 478 | print_times(); 479 | printf("\n"); 480 | #endif 481 | return 0; 482 | } 483 | 484 | /* testing: 485 | * gcc -Wall -Werror -fpic -march=native -mtune=native -Ofast test.c -o test 486 | * gcc -Wall -Werror -fpic -march=native -mtune=native -Ofast test.c -o test -lumem -lumem_malloc 487 | * 488 | * https://github.com/sharkdp/hyperfine 489 | * 490 | 491 | $ ldd test 492 | linux-vdso.so.1 (0x00007ffc607de000) 493 | libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb619a4d000) 494 | /lib64/ld-linux-x86-64.so.2 (0x00007fb619ce9000) 495 | $ ldd test_umem 496 | linux-vdso.so.1 (0x00007ffd1ff59000) 497 | libumem_malloc.so.0 => /usr/local/lib/libumem_malloc.so.0 (0x00007fe885b18000) 498 | libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe885926000) 499 | libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe885903000) 500 | libumem.so.0 => /usr/local/lib/libumem.so.0 (0x00007fe88585b000) 501 | /lib64/ld-linux-x86-64.so.2 (0x00007fe885bc7000) 502 | libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fe885855000) 503 | 504 | $ hyperfine --warmup 3 --min-runs 10 ./test 505 | Benchmark #1: ./test 506 | Time (mean ± σ): 82.1 ms ± 1.1 ms [User: 81.0 ms, System: 0.9 ms] 507 | Range (min … max): 79.3 ms … 84.4 ms 35 runs 508 | 509 | $ hyperfine --warmup 3 --min-runs 10 ./test_umem 510 | Benchmark #1: ./test_umem 511 | Time (mean ± σ): 85.7 ms ± 1.5 ms [User: 83.2 ms, System: 2.5 ms] 512 | Range (min … max): 81.8 ms … 89.2 ms 34 runs 513 | 514 | */ 515 | 516 | /* 517 | * Local variables: 518 | * tab-width:4 519 | * compile-command: "gcc -fpic -Wall -Werror -Ofast -march=native -mtune=native test.c -o test" 520 | * End: 521 | */ 522 | -------------------------------------------------------------------------------- /umem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | */ 26 | 27 | #ifndef _UMEM_H 28 | #define _UMEM_H 29 | 30 | /* #pragma ident "@(#)umem.h 1.3 05/06/08 SMI" */ 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | #define UMEM_DEFAULT 0x0000 /* normal -- may fail */ 41 | #define UMEM_NOFAIL 0x0100 /* Never fails -- may call exit(2) */ 42 | 43 | #define UMEM_FLAGS 0xffff /* all settable umem flags */ 44 | 45 | extern void *umem_alloc(size_t, int); 46 | extern void *umem_alloc_align(size_t, size_t, int); 47 | extern void *umem_zalloc(size_t, int); 48 | extern void umem_free(void *, size_t); 49 | extern void umem_free_align(void *, size_t); 50 | 51 | /*! 52 | * Flags for umem_cache_create() 53 | */ 54 | /*@{*/ 55 | #define UMC_NOTOUCH 0x00010000 56 | #define UMC_NODEBUG 0x00020000 57 | #define UMC_NOMAGAZINE 0x00040000 58 | #define UMC_NOHASH 0x00080000 59 | /*@}*/ 60 | 61 | struct umem_cache; /* cache structure is opaque to umem clients */ 62 | 63 | typedef struct umem_cache umem_cache_t; 64 | typedef int umem_constructor_t(void *, void *, int); 65 | typedef void umem_destructor_t(void *, void *); 66 | typedef void umem_reclaim_t(void *); 67 | 68 | typedef int umem_nofail_callback_t(void); 69 | #define UMEM_CALLBACK_RETRY 0 70 | #define UMEM_CALLBACK_EXIT(status) (0x100 | ((status) & 0xFF)) 71 | 72 | extern void umem_nofail_callback(umem_nofail_callback_t *); 73 | 74 | extern umem_cache_t *umem_cache_create(char *, size_t, 75 | size_t, umem_constructor_t *, umem_destructor_t *, umem_reclaim_t *, 76 | void *, vmem_t *, int); 77 | extern void umem_cache_destroy(umem_cache_t *); 78 | 79 | extern void *umem_cache_alloc(umem_cache_t *, int); 80 | extern void umem_cache_free(umem_cache_t *, void *); 81 | 82 | extern void umem_reap(void); 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif /* _UMEM_H */ 89 | -------------------------------------------------------------------------------- /umem.spec.in: -------------------------------------------------------------------------------- 1 | Name: @PACKAGE_NAME@ 2 | Version: @PACKAGE_VERSION@ 3 | Release: 2%{?dist} 4 | Summary: Port of Solaris's slab allocator. 5 | 6 | Group: System Environment/Libraries 7 | License: CDDL 8 | URL: https://labs.omniti.com/trac/portableumem/ 9 | Source0: %{name}-%{version}.tar.bz2 10 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 11 | 12 | BuildRequires: autoconf >= 2.50 13 | BuildRequires: automake >= 1.4 14 | BuildRequires: libtool >= 1.4.2 15 | BuildRequires: doxygen 16 | BuildRequires: gcc 17 | BuildRequires: binutils 18 | BuildRequires: make 19 | BuildRequires: mktemp 20 | 21 | 22 | %description 23 | This a port of Solaris's slab allocator, libumem, to Linux. 24 | 25 | "A slab allocator is a cache management structure for efficient use 26 | of [...] memory. [...] It is targeted for use of many small pieces 27 | of memory chunks. By managing small memory chunks in the units 28 | called slabs, this mechanism enables lower fragmentation, fast allocation, 29 | and reclaming memory." (Description sourced from Wikipedia.) 30 | 31 | 32 | %prep 33 | %setup -q 34 | 35 | 36 | %build 37 | %configure 38 | %{__make} 39 | %{__make} check 40 | %{__make} html 41 | 42 | 43 | %install 44 | rm -rf $RPM_BUILD_ROOT 45 | %makeinstall 46 | 47 | # Remove the libtool files -- we don't want them. 48 | find $RPM_BUILD_ROOT%{_libdir} -name '*.la' | xargs rm -fv 49 | 50 | # Remove the symlink to the SONAME. Let ldconfig manage that. 51 | rm -fv $RPM_BUILD_ROOT%{_libdir}/*.so.[0-9] 52 | 53 | # Build the pkgconfig configurations. 54 | mkdir -p $RPM_BUILD_ROOT%{_libdir}/pkgconfig 55 | 56 | cat<$RPM_BUILD_ROOT%{_libdir}/pkgconfig/%{name}-%{version}.pc 57 | prefix=%{_prefix} 58 | exec_prefix=%{_exec_prefix} 59 | libdir=%{_libdir} 60 | includedir=%{_includedir} 61 | 62 | Name: %{name} 63 | Version: %{version} 64 | Description: Port of Solaris's slab allocator. 65 | URL: https://labs.omniti.com/trac/portableumem/ 66 | Requires: 67 | Libs: -L\${libdir} -lumem 68 | Cflags: 69 | EOT 70 | 71 | cat<$RPM_BUILD_ROOT%{_libdir}/pkgconfig/%{name}-malloc-%{version}.pc 72 | prefix=%{_prefix} 73 | exec_prefix=%{_exec_prefix} 74 | libdir=%{_libdir} 75 | includedir=%{_includedir} 76 | 77 | Name: %{name} 78 | Version: %{version} 79 | Description: Port of Solaris's slab allocator. Libc malloc replacement. 80 | URL: https://labs.omniti.com/trac/portableumem/ 81 | Requires: 82 | Libs: -L\${libdir} -lumem_malloc 83 | Cflags: 84 | EOT 85 | 86 | 87 | %clean 88 | rm -rf $RPM_BUILD_ROOT 89 | 90 | 91 | %pre 92 | /sbin/ldconfig 93 | 94 | 95 | %post 96 | /sbin/ldconfig 97 | 98 | 99 | %files 100 | %defattr(-,root,root,-) 101 | %doc AUTHORS COPYING COPYRIGHT INSTALL NEWS OPENSOLARIS.LICENSE README 102 | %{_libdir}/*.so.* 103 | 104 | 105 | %package devel 106 | 107 | Summary: Port of Solaris's slab allocator. 108 | 109 | Group: Development/Libraries 110 | 111 | Requires: pkgconfig 112 | 113 | 114 | %description devel 115 | 116 | This contains the libraries and header files for using this port 117 | of Solaris's slab allocator, libumem, to Linux. 118 | 119 | 120 | %files devel 121 | %defattr(-,root,root,-) 122 | %doc AUTHORS COPYING COPYRIGHT INSTALL NEWS OPENSOLARIS.LICENSE README TODO 123 | %doc docs/html 124 | %{_includedir}/*.h 125 | %{_includedir}/sys/*.h 126 | %{_libdir}/*.so 127 | %{_libdir}/*.a 128 | %{_mandir}/man*/* 129 | %{_libdir}/pkgconfig/*.pc 130 | -------------------------------------------------------------------------------- /umem_agent_support.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2002 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | * 26 | * Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved. 27 | */ 28 | 29 | /* #pragma ident "@(#)umem_agent_support.c 1.2 05/06/08 SMI" */ 30 | 31 | #include "config.h" 32 | #include "umem_base.h" 33 | 34 | #define AGENT_STACK_SIZE 4096 35 | 36 | #if 0 37 | char __umem_agent_stack_beg[AGENT_STACK_SIZE]; 38 | char *__umem_agent_stack_end = __umem_agent_stack_beg + AGENT_STACK_SIZE; 39 | 40 | void 41 | __umem_agent_free_bp(umem_cache_t *cp, void *buf) 42 | { 43 | extern void _breakpoint(void); /* inline asm */ 44 | 45 | _umem_cache_free(cp, buf); 46 | _breakpoint(); 47 | } 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /umem_alloc.3: -------------------------------------------------------------------------------- 1 | '\" te 2 | .\" CDDL HEADER START 3 | .\" 4 | .\" The contents of this file are subject to the terms of the 5 | .\" Common Development and Distribution License (the "License"). 6 | .\" You may not use this file except in compliance with the License. 7 | .\" 8 | .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 | .\" or http://www.opensolaris.org/os/licensing. 10 | .\" See the License for the specific language governing permissions 11 | .\" and limitations under the License. 12 | .\" 13 | .\" When distributing Covered Code, include this CDDL HEADER in each 14 | .\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 | .\" If applicable, add the following below this CDDL HEADER, with the 16 | .\" fields enclosed by brackets "[]" replaced with your own identifying 17 | .\" information: Portions Copyright [yyyy] [name of copyright owner] 18 | .\" 19 | .\" CDDL HEADER END 20 | .\" Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved. 21 | .TH umem_alloc 3MALLOC "26 Aug 2002" "SunOS 5.11" "Memory Allocation Library Functions" 22 | .SH NAME 23 | umem_alloc, umem_zalloc, umem_free, umem_nofail_callback \- fast, scalable memory allocation 24 | .SH SYNOPSIS 25 | .LP 26 | .nf 27 | cc [ \fIflag \&.\|.\|.\fR ] \fIfile\fR\&.\|.\|. \fB-lumem\fR [ \fIlibrary \&.\|.\|.\fR ] 28 | #include 29 | 30 | \fBvoid *\fR\fBumem_alloc\fR(\fBsize_t\fR \fIsize\fR, \fBint\fR \fIflags\fR); 31 | .fi 32 | .LP 33 | .nf 34 | \fBvoid *\fR\fBumem_zalloc\fR(\fBsize_t\fR \fIsize\fR, \fBint\fR \fIflags\fR); 35 | .fi 36 | .LP 37 | .nf 38 | \fBvoid\fR \fBumem_free\fR(\fBvoid *\fR\fIbuf\fR, \fBsize_t\fR \fIsize\fR); 39 | .fi 40 | .LP 41 | .nf 42 | \fBvoid\fR \fBumem_nofail_callback\fR(\fB(int (*\fR\fIcallback\fR)(void)); 43 | .fi 44 | .LP 45 | .nf 46 | \fBvoid *\fR\fBmalloc\fR(\fBsize_t\fR \fIsize\fR); 47 | .fi 48 | .LP 49 | .nf 50 | \fBvoid *\fR\fBcalloc\fR(\fBsize_t\fR \fInelem\fR, \fBsize_t\fR \fIelsize\fR); 51 | .fi 52 | .LP 53 | .nf 54 | \fBvoid\fR \fBfree\fR(\fBvoid *\fR\fIptr\fR); 55 | .fi 56 | .LP 57 | .nf 58 | \fBvoid *\fR\fBmemalign\fR(\fBsize_t\fR \fIalignment\fR, \fBsize_t\fR \fIsize\fR); 59 | .fi 60 | .LP 61 | .nf 62 | \fBvoid *\fR\fBrealloc\fR(\fBvoid *\fR\fIptr\fR, \fBsize_t\fR \fIsize\fR); 63 | .fi 64 | .LP 65 | .nf 66 | \fBvoid *\fR\fBvalloc\fR(\fBsize_t\fR \fIsize\fR); 67 | .fi 68 | 69 | .SH DESCRIPTION 70 | 71 | .LP 72 | The \fBumem_alloc()\fR function returns a pointer to a block of \fIsize\fR bytes suitably aligned for any variable type. The initial contents of memory allocated using \fBumem_alloc()\fR is undefined. The \fIflags\fR argument determines 73 | the behavior of \fBumem_alloc()\fR if it is unable to fulfill the request. The \fIflags\fR argument can take the following values: 74 | .sp 75 | 76 | .sp 77 | .ne 2 78 | .mk 79 | .na 80 | \fB\fBUMEM_DEFAULT\fR\fR 81 | .ad 82 | .RS 14n 83 | .rt 84 | Return \fINULL\fR on failure. 85 | .sp 86 | 87 | .RE 88 | 89 | .sp 90 | .ne 2 91 | .mk 92 | .na 93 | \fB\fBUMEM_NOFAIL\fR\fR 94 | .ad 95 | .RS 14n 96 | .rt 97 | Call an optional \fIcallback\fR (set with \fBumem_nofail_callback()\fR) on failure. The \fIcallback\fR takes no arguments and can finish by: 98 | .sp 99 | 100 | .sp 101 | .RS +4 102 | .TP 103 | .ie t \(bu 104 | .el o 105 | returning \fBUMEM_CALLBACK_RETRY\fR, in which case the allocation will be retried. If the allocation fails, the callback will be invoked again. 106 | .sp 107 | 108 | .RE 109 | 110 | .sp 111 | .RS +4 112 | .TP 113 | .ie t \(bu 114 | .el o 115 | returning \fBUMEM_CALLBACK_EXIT\fR(\fIstatus\fR), in which case 116 | \fBexit\fR(2) is invoked with \fIstatus\fR 117 | as its argument. The \fBexit()\fR function is called only once. If multiple threads return from the \fBUMEM_NOFAIL\fR callback with \fBUMEM_CALLBACK_EXIT\fR(\fIstatus\fR), one will call \fBexit()\fR while the other blocks until \fBexit()\fR terminates the program. 118 | .sp 119 | 120 | .RE 121 | 122 | .sp 123 | .RS +4 124 | .TP 125 | .ie t \(bu 126 | .el o 127 | invoking a context-changing function ( 128 | \fBsetcontext\fR(2)) or a non-local jump ( 129 | \fBlongjmp\fR(3C) or 130 | \fBsiglongjmp\fR(3C), or ending the current thread of control ( 131 | \fBthr_exit\fR(3C) or 132 | \fBpthread_exit\fR(3C). The application is responsible for any necessary cleanup. The state of \fBlibumem\fR remains consistent. 133 | .sp 134 | 135 | .RE 136 | 137 | If no callback has been set or the callback has been set to \fINULL\fR, \fBumem_alloc\fR(..., \fBUMEM_NOFAIL\fR) behaves as though the callback returned \fBUMEM_CALLBACK_EXIT\fR(255). 138 | .sp 139 | 140 | .sp 141 | The \fBlibumem\fR library can call callbacks from any place that a \fBUMEM_NOFAIL\fR allocation is issued. In multithreaded applications, callbacks are expected to perform their own concurrency management. 142 | .sp 143 | 144 | .RE 145 | 146 | .LP 147 | The function call \fBumem_alloc\fR(0, \fIflag\fR) always returns \fINULL\fR. The function call \fBumem_free\fR(\fINULL\fR, 0) is allowed. 148 | .sp 149 | 150 | .LP 151 | The \fBumem_zalloc()\fR function has the same semantics as \fBumem_alloc()\fR, but the block of memory is initialized to zeros before it is returned. 152 | .sp 153 | 154 | .LP 155 | The \fBumem_free()\fR function frees blocks previously allocated using \fBumem_alloc()\fR and \fBumem_zalloc()\fR. The buffer address and size must exactly match the original allocation. Memory must not be returned piecemeal. 156 | .sp 157 | 158 | .LP 159 | The \fBumem_nofail_callback()\fR function sets the process-wide UMEM_NOFAIL callback. See the description of UMEM_NOFAIL for more information. 160 | .sp 161 | 162 | .LP 163 | The \fBmalloc()\fR, \fBcalloc()\fR, \fBfree()\fR, \fBmemalign()\fR, \fBrealloc()\fR, and \fBvalloc()\fR functions are are as described in 164 | \fBmalloc\fR(3C). The \fBlibumem\fR library provides these functions for backwards-compatibility with the standard functions. 165 | .sp 166 | 167 | .SH ENVIRONMENT VARIABLES 168 | 169 | .LP 170 | See 171 | \fBumem_debug\fR(3MALLOC) for environment variables that effect the debugging features of the \fBlibumem\fR library. 172 | .sp 173 | 174 | .sp 175 | .ne 2 176 | .mk 177 | .na 178 | \fBUMEM_OPTIONS\fR 179 | .ad 180 | .RS 14n 181 | .rt 182 | Contains a list of comma-separated options. Unrecognized options are ignored. The options that are supported are: 183 | .sp 184 | 185 | .sp 186 | .ne 2 187 | .mk 188 | .na 189 | \fB\fBbackend\fR=\fBsbrk\fR\fR 190 | .ad 191 | .br 192 | .na 193 | \fB\fBbackend\fR=\fBmmap\fR\fR 194 | .ad 195 | .RS 14n 196 | .rt 197 | Set the underlying function used to allocate memory. This option can be set to \fBsbrk\fR (the default) for an 198 | \fBsbrk\fR(2)-based source or \fBmmap\fR for an 199 | \fBmmap\fR(2)-based 200 | source. If set to a value that is not supported, \fBsbrk\fR will be used. 201 | .sp 202 | 203 | .RE 204 | 205 | .RE 206 | 207 | .SH EXAMPLES 208 | .LP 209 | \fBExample 1 \fRUsing the \fBumem_alloc()\fR function. 210 | 211 | .LP 212 | .in +2 213 | .nf 214 | #include 215 | #include 216 | \&... 217 | char *buf = umem_alloc(1024, UMEM_DEFAULT); 218 | 219 | if (buf == NULL) { 220 | fprintf(stderr, "out of memory\en"); 221 | return (1); 222 | } 223 | /* cannot assume anything about buf's contents */ 224 | \&... 225 | umem_free(buf, 1024); 226 | \&... 227 | .fi 228 | .in -2 229 | .LP 230 | \fBExample 2 \fRUsing the \fBumem_zalloc()\fR function 231 | 232 | .LP 233 | .in +2 234 | .nf 235 | #include 236 | #include 237 | \&... 238 | char *buf = umem_zalloc(1024, UMEM_DEFAULT); 239 | 240 | if (buf == NULL) { 241 | fprintf(stderr, "out of memory\en"); 242 | return (1); 243 | } 244 | /* buf contains zeros */ 245 | \&... 246 | umem_free(buf, 1024); 247 | \&... 248 | .fi 249 | .in -2 250 | .LP 251 | \fBExample 3 \fRUsing UMEM_NOFAIL 252 | 253 | .LP 254 | .in +2 255 | .nf 256 | #include 257 | #include 258 | #include 259 | 260 | /* 261 | * Note that the allocation code below does not have to 262 | * check for umem_alloc() returning NULL 263 | */ 264 | int 265 | my_failure_handler(void) 266 | { 267 | (void) fprintf(stderr, "out of memory\en"); 268 | return (UMEM_CALLBACK_EXIT(255)); 269 | } 270 | \&... 271 | umem_nofail_callback(my_failure_handler); 272 | \&... 273 | int i; 274 | char *buf[100]; 275 | 276 | for (i = 0; i < 100; i++) 277 | buf[i] = umem_alloc(1024 * 1024, UMEM_NOFAIL); 278 | \&... 279 | for (i = 0; i < 100; i++) 280 | umem_free(buf[i], 1024 * 1024); 281 | \&... 282 | .fi 283 | .in -2 284 | .LP 285 | \fBExample 4 \fRUsing UMEM_NOFAIL in a multithreaded application 286 | 287 | .LP 288 | .in +2 289 | .nf 290 | #define _REENTRANT 291 | #include 292 | #include 293 | #include 294 | 295 | void * 296 | start_func(void *the_arg) 297 | { 298 | int *info = (int *)the_arg; 299 | char *buf = umem_alloc(1024 * 1024, UMEM_NOFAIL); 300 | 301 | /* does not need to check for buf == NULL */ 302 | buf[0] = 0; 303 | ... 304 | /* 305 | * if there were other UMEM_NOFAIL allocations, 306 | * we would need to arrange for buf to be 307 | * umem_free()ed upon failure. 308 | */ 309 | ... 310 | umem_free(buf, 1024 * 1024); 311 | return (the_arg); 312 | } 313 | \&... 314 | int 315 | my_failure_handler(void) 316 | { 317 | /* terminate the current thread with status NULL */ 318 | thr_exit(NULL); 319 | } 320 | \&... 321 | umem_nofail_callback(my_failure_handler); 322 | \&... 323 | int my_arg; 324 | 325 | thread_t tid; 326 | void *status; 327 | 328 | (void) thr_create(NULL, NULL, start_func, &my_arg, 0, 329 | NULL); 330 | \&... 331 | while (thr_join(0, &tid, &status) != 0) 332 | ; 333 | 334 | if (status == NULL) { 335 | (void) fprintf(stderr, "thread %d ran out of memory\en", 336 | tid); 337 | } 338 | \&... 339 | .fi 340 | .in -2 341 | 342 | .SH ATTRIBUTES 343 | 344 | .LP 345 | See 346 | \fBattributes\fR(5) for descriptions of the following attributes: 347 | .sp 348 | 349 | .LP 350 | 351 | .sp 352 | .TS 353 | tab() box; 354 | cw(2.75i) |cw(2.75i) 355 | lw(2.75i) |lw(2.75i) 356 | . 357 | ATTRIBUTE TYPEATTRIBUTE VALUE 358 | _ 359 | Interface StabilitySee below. 360 | _ 361 | MT-LevelMT-Safe 362 | .TE 363 | 364 | .LP 365 | The \fBmalloc()\fR, \fBcalloc()\fR, \fBfree()\fR, \fBrealloc()\fR, and \fBvalloc()\fR functions are Standard. The \fBmemalign()\fR function is Stable. The \fBumem_alloc()\fR, \fBumem_zalloc()\fR, \fBumem_free()\fR, and \fBumem_nofail_callback()\fR functions are Evolving. 366 | .sp 367 | 368 | .SH SEE ALSO 369 | 370 | .LP 371 | 372 | \fBexit\fR(2), 373 | \fBmmap\fR(2), 374 | \fBsbrk\fR(2), 375 | \fBbsdmalloc\fR(3MALLOC), 376 | \fBlibumem\fR(3LIB), 377 | \fBlongjmp\fR(3C), 378 | \fBmalloc\fR(3C), 379 | \fBmalloc\fR(3MALLOC), 380 | \fBmapmalloc\fR(3MALLOC), 381 | \fBpthread_exit\fR(3C), 382 | \fBthr_exit\fR(3C), 383 | \fBumem_cache_create\fR(3MALLOC), 384 | \fBumem_debug\fR(3MALLOC), 385 | \fBwatchmalloc\fR(3MALLOC), 386 | \fBattributes\fR(5), 387 | \fBstandards\fR(5) 388 | .sp 389 | 390 | .LP 391 | 392 | .sp 393 | 394 | .SH WARNINGS 395 | 396 | .LP 397 | Any of the following can cause undefined results: 398 | .sp 399 | 400 | .sp 401 | .RS +4 402 | .TP 403 | .ie t \(bu 404 | .el o 405 | Passing a pointer returned from \fBumem_alloc()\fR or \fBumem_zalloc()\fR to \fBfree()\fR or \fBrealloc()\fR. 406 | .sp 407 | 408 | .RE 409 | 410 | .sp 411 | .RS +4 412 | .TP 413 | .ie t \(bu 414 | .el o 415 | Passing a pointer returned from \fBmalloc()\fR, \fBcalloc()\fR, \fBvalloc()\fR, \fBmemalign()\fR, or \fBrealloc()\fR to \fBumem_free()\fR. 416 | .sp 417 | 418 | .RE 419 | 420 | .sp 421 | .RS +4 422 | .TP 423 | .ie t \(bu 424 | .el o 425 | Writing past the end of a buffer allocated using \fBumem_alloc()\fR or \fBumem_zalloc()\fR 426 | .sp 427 | 428 | .RE 429 | 430 | .sp 431 | .RS +4 432 | .TP 433 | .ie t \(bu 434 | .el o 435 | Performing \fBUMEM_NOFAIL\fR allocations from an 436 | \fBatexit\fR(3C) handler. 437 | .sp 438 | 439 | .RE 440 | 441 | .LP 442 | If the \fBUMEM_NOFAIL\fR callback performs \fBUMEM_NOFAIL\fR allocations, infinite recursion can occur. 443 | .sp 444 | 445 | .SH NOTES 446 | 447 | .LP 448 | The following list compares the features of the 449 | \fBmalloc\fR(3C), 450 | \fBbsdmalloc\fR(3MALLOC), 451 | \fBmalloc\fR(3MALLOC), 452 | \fBmtmalloc\fR(3MALLOC) , and the \fBlibumem\fR 453 | functions. 454 | .sp 455 | 456 | .sp 457 | .RS +4 458 | .TP 459 | .ie t \(bu 460 | .el o 461 | The 462 | \fBmalloc\fR(3C), 463 | \fBbsdmalloc\fR(3MALLOC), and 464 | \fBmalloc\fR(3MALLOC) functions have no support for concurrency. The \fBlibumem\fR and 465 | \fBmtmalloc\fR(3MALLOC) 466 | functions support concurrent allocations. 467 | .sp 468 | 469 | .RE 470 | 471 | .sp 472 | .RS +4 473 | .TP 474 | .ie t \(bu 475 | .el o 476 | The 477 | \fBbsdmalloc\fR(3MALLOC) functions afford better performance but are space-inefficient. 478 | .sp 479 | 480 | .RE 481 | 482 | .sp 483 | .RS +4 484 | .TP 485 | .ie t \(bu 486 | .el o 487 | The 488 | \fBmalloc\fR(3MALLOC) functions are space-efficient but have slower performance. 489 | .sp 490 | 491 | .RE 492 | 493 | .sp 494 | .RS +4 495 | .TP 496 | .ie t \(bu 497 | .el o 498 | The standard, fully SCD-compliant 499 | \fBmalloc\fR(3C) functions are a trade-off between performance and space-efficiency. 500 | .sp 501 | 502 | .RE 503 | 504 | .sp 505 | .RS +4 506 | .TP 507 | .ie t \(bu 508 | .el o 509 | The 510 | \fBmtmalloc\fR(3MALLOC) functions provide fast, concurrent \fBmalloc()\fR implementations that are not space-efficient. 511 | .sp 512 | 513 | .RE 514 | 515 | .sp 516 | .RS +4 517 | .TP 518 | .ie t \(bu 519 | .el o 520 | The \fBlibumem\fR functions provide a fast, concurrent allocation implementation that in most cases is more space-efficient than 521 | \fBmtmalloc\fR(3MALLOC). 522 | .sp 523 | 524 | .RE 525 | 526 | -------------------------------------------------------------------------------- /umem_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | */ 26 | 27 | #ifndef _UMEM_BASE_H 28 | #define _UMEM_BASE_H 29 | 30 | /* #pragma ident "@(#)umem_base.h 1.4 05/06/08 SMI" */ 31 | 32 | #include 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | #include "misc.h" 39 | 40 | extern size_t pagesize; 41 | #undef PAGESIZE 42 | #define PAGESIZE pagesize 43 | 44 | /* 45 | * umem.c: non-tunables 46 | */ 47 | extern vmem_t *umem_memalign_arena; 48 | 49 | extern int umem_ready; 50 | extern thread_t umem_init_thr; /* the thread doing the init */ 51 | 52 | extern int umem_init(void); /* do umem's initialization */ 53 | /* #pragma rarely_called(umem_init) */ 54 | 55 | extern umem_log_header_t *umem_transaction_log; 56 | extern umem_log_header_t *umem_content_log; 57 | extern umem_log_header_t *umem_failure_log; 58 | extern umem_log_header_t *umem_slab_log; 59 | 60 | extern mutex_t umem_init_lock; 61 | 62 | extern mutex_t umem_cache_lock; 63 | extern umem_cache_t umem_null_cache; 64 | 65 | extern mutex_t umem_flags_lock; 66 | 67 | extern mutex_t umem_update_lock; 68 | extern cond_t umem_update_cv; 69 | extern volatile thread_t umem_st_update_thr; 70 | extern thread_t umem_update_thr; 71 | extern struct timeval umem_update_next; 72 | 73 | extern volatile hrtime_t umem_reap_next; 74 | extern volatile uint32_t umem_reaping; 75 | #define UMEM_REAP_DONE 0x00000000 /* inactive */ 76 | #define UMEM_REAP_ADDING 0x00000001 /* umem_reap() is active */ 77 | #define UMEM_REAP_ACTIVE 0x00000002 /* update thread is reaping */ 78 | 79 | /* 80 | * umem.c: tunables 81 | */ 82 | extern uint32_t umem_max_ncpus; 83 | 84 | extern uint32_t umem_stack_depth; 85 | extern uint32_t umem_reap_interval; 86 | extern uint32_t umem_update_interval; 87 | extern uint32_t umem_depot_contention; 88 | extern uint32_t umem_abort; 89 | extern uint32_t umem_output; 90 | extern uint32_t umem_logging; 91 | extern uint32_t umem_mtbf; 92 | extern size_t umem_transaction_log_size; 93 | extern size_t umem_content_log_size; 94 | extern size_t umem_failure_log_size; 95 | extern size_t umem_slab_log_size; 96 | extern size_t umem_content_maxsave; 97 | extern size_t umem_lite_minsize; 98 | extern size_t umem_lite_maxalign; 99 | extern size_t umem_maxverify; 100 | extern size_t umem_minfirewall; 101 | 102 | extern uint32_t umem_flags; 103 | 104 | /* 105 | * umem.c: Internal aliases (to avoid PLTs) 106 | */ 107 | extern void *_umem_alloc(size_t size, int umflags); 108 | extern void *_umem_zalloc(size_t size, int umflags); 109 | extern void _umem_free(void *buf, size_t size); 110 | 111 | extern void *_umem_cache_alloc(umem_cache_t *cache, int flags); 112 | extern void _umem_cache_free(umem_cache_t *cache, void *buffer); 113 | 114 | /* 115 | * umem.c: private interfaces 116 | */ 117 | extern void umem_type_init(caddr_t, size_t, size_t); 118 | extern int umem_get_max_ncpus(void); 119 | extern void umem_process_updates(void); 120 | extern void umem_cache_applyall(void (*)(umem_cache_t *)); 121 | extern void umem_cache_update(umem_cache_t *); 122 | 123 | extern void umem_alloc_sizes_add(size_t); 124 | extern void umem_alloc_sizes_clear(void); 125 | extern void umem_alloc_sizes_remove(size_t); 126 | 127 | /* 128 | * umem_fork.c: private interfaces 129 | */ 130 | extern void umem_forkhandler_init(void); 131 | 132 | /* 133 | * umem_update_thread.c 134 | */ 135 | extern int umem_create_update_thread(void); 136 | 137 | /* 138 | * envvar.c: 139 | */ 140 | void umem_setup_envvars(int); 141 | void umem_process_envvars(void); 142 | 143 | #ifdef __cplusplus 144 | } 145 | #endif 146 | 147 | #endif /* _UMEM_BASE_H */ 148 | -------------------------------------------------------------------------------- /umem_debug.3: -------------------------------------------------------------------------------- 1 | '\" te 2 | .\" CDDL HEADER START 3 | .\" 4 | .\" The contents of this file are subject to the terms of the 5 | .\" Common Development and Distribution License (the "License"). 6 | .\" You may not use this file except in compliance with the License. 7 | .\" 8 | .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 | .\" or http://www.opensolaris.org/os/licensing. 10 | .\" See the License for the specific language governing permissions 11 | .\" and limitations under the License. 12 | .\" 13 | .\" When distributing Covered Code, include this CDDL HEADER in each 14 | .\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 | .\" If applicable, add the following below this CDDL HEADER, with the 16 | .\" fields enclosed by brackets "[]" replaced with your own identifying 17 | .\" information: Portions Copyright [yyyy] [name of copyright owner] 18 | .\" 19 | .\" CDDL HEADER END 20 | .\" Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved. 21 | .TH umem_debug 3MALLOC "26 July 2002" "SunOS 5.11" "Memory Allocation Library Functions" 22 | .SH NAME 23 | umem_debug \- debugging features of the umem library 24 | .SH SYNOPSIS 25 | .LP 26 | .nf 27 | \fBcc\fR [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lumem\fR [ \fIlibrary\fR\&.\|.\|. ] 28 | #include <\fBumem.h\fR> 29 | .fi 30 | 31 | .SH DESCRIPTION 32 | 33 | .LP 34 | The \fBlibumem\fR library provides debugging features that detect memory leaks, buffer overruns, multiple frees, use of uninitialized data, use of freed data, and many other common programming errors. The activation of the run-time debugging features is controlled by environment variables. 35 | .sp 36 | 37 | .LP 38 | When the library detects an error, it writes a description of the error to an internal buffer that is readable with the \fB::umem_status\fR 39 | \fBmdb\fR(1) \fIdcmd\fR and then calls 40 | \fBabort\fR(3C). 41 | .sp 42 | 43 | .SH ENVIRONMENT VARIABLES 44 | 45 | .sp 46 | .ne 2 47 | .mk 48 | .na 49 | \fBUMEM_DEBUG\fR 50 | .ad 51 | .RS 14n 52 | .rt 53 | This variable contains a list of comma-separated options. Unrecognized options are ignored. Possible options include: 54 | .sp 55 | 56 | .sp 57 | .ne 2 58 | .mk 59 | .na 60 | \fB\fBaudit\fR[=\fIframes\fR]\fR 61 | .ad 62 | .RS 18n 63 | .rt 64 | This option enables the recording of auditing information, including thread ID, high-resolution time stamp, and stack trace for the last action (allocation or free) on every allocation. If transaction logging 65 | (see UMEM_LOGGING) is enabled, this auditing information is also logged. 66 | .sp 67 | 68 | .sp 69 | The \fIframes\fR parameter sets the number of stack frames recorded in the auditing structure. The upper bound for frames is implementation-defined. If a larger value is requested, the upper bound is used instead. 70 | .sp 71 | 72 | .sp 73 | If \fIframes\fR is not specified or is not an integer, the default value of 15 is used. 74 | .sp 75 | 76 | .sp 77 | This option also enables the \fBguards\fR option. 78 | .sp 79 | 80 | .RE 81 | 82 | .sp 83 | .ne 2 84 | .mk 85 | .na 86 | \fB\fBcontents\fR[=\fIcount\fR]\fR 87 | .ad 88 | .RS 18n 89 | .rt 90 | If auditing and contents logging (see UMEM_LOGGING) are enabled, the first \fIcount\fR bytes of each buffer are logged when they are freed. If a buffer is shorter than \fIcount\fR bytes, it is logged in its entirety. 91 | .sp 92 | 93 | .sp 94 | If \fIcount\fR is not specified or is not an integer, the default value of 256 is used. 95 | .sp 96 | 97 | .RE 98 | 99 | .sp 100 | .ne 2 101 | .mk 102 | .na 103 | \fB\fBdefault\fR\fR 104 | .ad 105 | .RS 18n 106 | .rt 107 | This option is equivalent to \fBaudit\fR,\fBcontents\fR,\fBguards\fR. 108 | .sp 109 | 110 | .RE 111 | 112 | .sp 113 | .ne 2 114 | .mk 115 | .na 116 | \fB\fBguards\fR\fR 117 | .ad 118 | .RS 18n 119 | .rt 120 | This option enables filling allocated and freed buffers with special patterns to help detect the use of uninitialized data and previously freed buffers. It also enables an 8-byte redzone after each buffer that contains \fB0xfeedfacefeedfaceULL\fR. 121 | .sp 122 | 123 | .sp 124 | When an object is freed, it is filled with \fB0xdeadbeef\fR. When an object is allocated, the \fB0xdeadbeef\fR pattern is verified and replaced with \fB0xbaddcafe\fR. The redzone is checked every time a buffer is allocated or freed. 125 | .sp 126 | 127 | .sp 128 | For caches with either constructors or destructors, or both, 129 | \fBumem_cache_alloc\fR(3MALLOC) and 130 | \fBumem_cache_free\fR(3MALLOC) apply the cache's constructor and destructor, respectively, instead of caching constructed objects. The presence of 131 | \fBassert\fR(3C)s 132 | in the destructor verifying that the buffer is in the constructed state can be used to detect any objects returned in an improper state. See 133 | \fBumem_cache_create\fR(3MALLOC) for 134 | details. 135 | .sp 136 | 137 | .RE 138 | 139 | .sp 140 | .ne 2 141 | .mk 142 | .na 143 | \fB\fBverbose\fR\fR 144 | .ad 145 | .RS 18n 146 | .rt 147 | The library writes error descriptions to standard error before aborting. These messages are not localized. 148 | .sp 149 | 150 | .RE 151 | 152 | .RE 153 | 154 | .sp 155 | .ne 2 156 | .mk 157 | .na 158 | \fBUMEM_LOGGING\fR 159 | .ad 160 | .RS 14n 161 | .rt 162 | To be enabled, this variable should be set to a comma-separated list of in-memory logs. The logs available are: 163 | .sp 164 | 165 | .sp 166 | .ne 2 167 | .mk 168 | .na 169 | \fB\fBtransaction\fR[=\fIsize\fR]\fR 170 | .ad 171 | .RS 20n 172 | .rt 173 | If the \fBaudit\fR debugging option is set (see \fBUMEM_DEBUG\fR), the audit structures from previous transactions are entered into this log. 174 | .sp 175 | 176 | .RE 177 | 178 | .sp 179 | .ne 2 180 | .mk 181 | .na 182 | \fB\fBcontents\fR[=\fIsize\fR]\fR 183 | .ad 184 | .RS 20n 185 | .rt 186 | If the \fBaudit\fR debugging option is set, the contents of objects are recorded in this log as they are freed. 187 | .sp 188 | 189 | .sp 190 | If the "contents" debugging option was not set, 256 bytes of each freed buffer are saved. 191 | .sp 192 | 193 | .RE 194 | 195 | .sp 196 | .ne 2 197 | .mk 198 | .na 199 | \fB\fBfail\fR[=\fIsize\fR]\fR 200 | .ad 201 | .RS 20n 202 | .rt 203 | Records are entered into this log for every failed allocation. 204 | .sp 205 | 206 | .RE 207 | 208 | For any of these options, if \fIsize\fR is not specified, the default value of 64k is used. The \fIsize\fR parameter must be an integer that can be qualified with K, M, G, or T to specify kilobytes, megabytes, gigabytes, or terabytes, respectively. 209 | .sp 210 | 211 | .sp 212 | Logs that are not listed or that have either a size of 0 or an invalid size are disabled. 213 | .sp 214 | 215 | .sp 216 | The log is disabled if during initialization the requested amount of storage cannot be allocated. 217 | .sp 218 | 219 | .RE 220 | 221 | .SH ATTRIBUTES 222 | 223 | .LP 224 | See 225 | \fBattributes\fR(5) for descriptions of the following attributes: 226 | .sp 227 | 228 | .LP 229 | 230 | .sp 231 | .TS 232 | tab() box; 233 | cw(2.75i) |cw(2.75i) 234 | lw(2.75i) |lw(2.75i) 235 | . 236 | ATTRIBUTE TYPEATTRIBUTE VALUE 237 | _ 238 | Interface StabilityUnstable 239 | _ 240 | MT-LevelMT-Safe 241 | .TE 242 | 243 | .SH SEE ALSO 244 | 245 | .LP 246 | 247 | \fBmdb\fR(1), 248 | \fBabort\fR(3C), 249 | \fBsignal\fR(3C), 250 | \fBumem_cache_create\fR(3MALLOC), 251 | \fBattributes\fR(5) 252 | .sp 253 | 254 | .LP 255 | 256 | .sp 257 | 258 | .SH WARNINGS 259 | 260 | .LP 261 | When \fBlibumem\fR aborts the process using 262 | \fBabort\fR(3C), any existing signal handler for \fBSIGABRT\fR is called. If the signal handler performs allocations, undefined 263 | behavior can result. 264 | .sp 265 | 266 | .SH NOTES 267 | 268 | .LP 269 | Some of the debugging features work only for allocations smaller than 16 kilobytes in size. Allocations larger than 16 kilobytes could have reduced support. 270 | .sp 271 | 272 | .LP 273 | Activating any of the library's debugging features could significantly increase the library's memory footprint and decrease its performance. 274 | .sp 275 | 276 | -------------------------------------------------------------------------------- /umem_fail.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | 23 | /* 24 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 25 | * Use is subject to license terms. 26 | * 27 | * Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved. 28 | */ 29 | 30 | /* #pragma ident "@(#)umem_fail.c 1.4 05/06/08 SMI" */ 31 | 32 | /* 33 | * Failure routines for libumem (not standalone) 34 | */ 35 | 36 | #include "config.h" 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "misc.h" 44 | 45 | static volatile int umem_exiting = 0; 46 | #define UMEM_EXIT_ABORT 1 47 | 48 | static mutex_t umem_exit_lock = DEFAULTMUTEX; /* protects umem_exiting */ 49 | 50 | static int 51 | firstexit(int type) 52 | { 53 | if (umem_exiting) 54 | return (0); 55 | 56 | (void) mutex_lock(&umem_exit_lock); 57 | if (umem_exiting) { 58 | (void) mutex_unlock(&umem_exit_lock); 59 | return (0); 60 | } 61 | umem_exiting = type; 62 | (void) mutex_unlock(&umem_exit_lock); 63 | 64 | return (1); 65 | } 66 | 67 | /* 68 | * We can't use abort(3C), since it closes all of the standard library 69 | * FILEs, which can call free(). 70 | * 71 | * In addition, we can't just raise(SIGABRT), since the current handler 72 | * might do allocation. We give them once chance, though. 73 | */ 74 | static void __NORETURN 75 | umem_do_abort(void) 76 | { 77 | #ifdef _WIN32 78 | abort(); 79 | #else 80 | if (firstexit(UMEM_EXIT_ABORT)) { 81 | (void) raise(SIGABRT); 82 | } 83 | 84 | for (;;) { 85 | #if defined(__FreeBSD__) 86 | sigset_t set; 87 | struct sigaction sa; 88 | 89 | sa.sa_handler = SIG_DFL; 90 | (void) sigaction(SIGABRT, &sa, NULL); 91 | (void) sigemptyset (&set); 92 | (void) sigaddset (&set, SIGABRT); 93 | (void) sigprocmask (SIG_UNBLOCK, &set, NULL); 94 | (void) raise (SIGABRT); 95 | #else 96 | (void) signal(SIGABRT, SIG_DFL); 97 | (void) sigrelse(SIGABRT); 98 | (void) raise(SIGABRT); 99 | #endif 100 | } 101 | #endif 102 | } 103 | 104 | #define SKIP_FRAMES 1 /* skip the panic frame */ 105 | #define ERR_STACK_FRAMES 128 106 | 107 | static void 108 | print_stacktrace(void) 109 | { 110 | uintptr_t cur_stack[ERR_STACK_FRAMES]; 111 | 112 | /* 113 | * if we are in a signal context, checking for it will recurse 114 | */ 115 | uint_t nframes = getpcstack(cur_stack, ERR_STACK_FRAMES, 0); 116 | uint_t idx; 117 | 118 | if (nframes > SKIP_FRAMES) { 119 | umem_printf("stack trace:\n"); 120 | 121 | for (idx = SKIP_FRAMES; idx < nframes; idx++) { 122 | (void) print_sym((void *)cur_stack[idx]); 123 | umem_printf("\n"); 124 | } 125 | } 126 | } 127 | 128 | void 129 | umem_panic(const char *format, ...) 130 | { 131 | va_list va; 132 | 133 | va_start(va, format); 134 | umem_vprintf(format, va); 135 | va_end(va); 136 | 137 | if (format[strlen(format)-1] != '\n') 138 | umem_error_enter("\n"); 139 | 140 | print_stacktrace(); 141 | 142 | umem_do_abort(); 143 | } 144 | 145 | void 146 | umem_err_recoverable(const char *format, ...) 147 | { 148 | va_list va; 149 | 150 | va_start(va, format); 151 | umem_vprintf(format, va); 152 | va_end(va); 153 | 154 | if (format[strlen(format)-1] != '\n') 155 | umem_error_enter("\n"); 156 | 157 | print_stacktrace(); 158 | 159 | if (umem_abort > 0) 160 | umem_do_abort(); 161 | } 162 | 163 | int 164 | __umem_assert_failed(const char *assertion, const char *file, int line) 165 | { 166 | umem_panic("Assertion failed: %s, file %s, line %d\n", 167 | assertion, file, line); 168 | /*NOTREACHED*/ 169 | return (0); 170 | } 171 | -------------------------------------------------------------------------------- /umem_fork.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * 8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 | * or http://www.opensolaris.org/os/licensing. 10 | * See the License for the specific language governing permissions 11 | * and limitations under the License. 12 | * 13 | * When distributing Covered Code, include this CDDL HEADER in each 14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 | * If applicable, add the following below this CDDL HEADER, with the 16 | * fields enclosed by brackets "[]" replaced with your own identifying 17 | * information: Portions Copyright [yyyy] [name of copyright owner] 18 | * 19 | * CDDL HEADER END 20 | */ 21 | 22 | /* 23 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | */ 26 | 27 | #include "config.h" 28 | #include "umem_base.h" 29 | #include "vmem_base.h" 30 | 31 | #ifndef _WIN32 32 | #include 33 | 34 | /* 35 | * The following functions are for pre- and post-fork1(2) handling. See 36 | * "Lock Ordering" in lib/libumem/common/umem.c for the lock ordering used. 37 | */ 38 | 39 | static void 40 | umem_lockup_cache(umem_cache_t *cp) 41 | { 42 | int idx; 43 | int ncpus = cp->cache_cpu_mask + 1; 44 | 45 | for (idx = 0; idx < ncpus; idx++) 46 | (void) mutex_lock(&cp->cache_cpu[idx].cc_lock); 47 | 48 | (void) mutex_lock(&cp->cache_depot_lock); 49 | (void) mutex_lock(&cp->cache_lock); 50 | } 51 | 52 | static void 53 | umem_release_cache(umem_cache_t *cp) 54 | { 55 | int idx; 56 | int ncpus = cp->cache_cpu_mask + 1; 57 | 58 | (void) mutex_unlock(&cp->cache_lock); 59 | (void) mutex_unlock(&cp->cache_depot_lock); 60 | 61 | for (idx = 0; idx < ncpus; idx++) 62 | (void) mutex_unlock(&cp->cache_cpu[idx].cc_lock); 63 | } 64 | 65 | static void 66 | umem_lockup_log_header(umem_log_header_t *lhp) 67 | { 68 | int idx; 69 | if (lhp == NULL) 70 | return; 71 | for (idx = 0; idx < umem_max_ncpus; idx++) 72 | (void) mutex_lock(&lhp->lh_cpu[idx].clh_lock); 73 | 74 | (void) mutex_lock(&lhp->lh_lock); 75 | } 76 | 77 | static void 78 | umem_release_log_header(umem_log_header_t *lhp) 79 | { 80 | int idx; 81 | if (lhp == NULL) 82 | return; 83 | 84 | (void) mutex_unlock(&lhp->lh_lock); 85 | 86 | for (idx = 0; idx < umem_max_ncpus; idx++) 87 | (void) mutex_unlock(&lhp->lh_cpu[idx].clh_lock); 88 | } 89 | 90 | static void 91 | umem_lockup(void) 92 | { 93 | umem_cache_t *cp; 94 | 95 | (void) mutex_lock(&umem_init_lock); 96 | /* 97 | * If another thread is busy initializing the library, we must 98 | * wait for it to complete (by calling umem_init()) before allowing 99 | * the fork() to proceed. 100 | */ 101 | if (umem_ready == UMEM_READY_INITING && umem_init_thr != thr_self()) { 102 | (void) mutex_unlock(&umem_init_lock); 103 | (void) umem_init(); 104 | (void) mutex_lock(&umem_init_lock); 105 | } 106 | 107 | vmem_lockup(); 108 | vmem_sbrk_lockup(); 109 | 110 | (void) mutex_lock(&umem_cache_lock); 111 | (void) mutex_lock(&umem_update_lock); 112 | (void) mutex_lock(&umem_flags_lock); 113 | 114 | umem_lockup_cache(&umem_null_cache); 115 | for (cp = umem_null_cache.cache_prev; cp != &umem_null_cache; 116 | cp = cp->cache_prev) 117 | umem_lockup_cache(cp); 118 | 119 | umem_lockup_log_header(umem_transaction_log); 120 | umem_lockup_log_header(umem_content_log); 121 | umem_lockup_log_header(umem_failure_log); 122 | umem_lockup_log_header(umem_slab_log); 123 | 124 | (void) cond_broadcast(&umem_update_cv); 125 | 126 | } 127 | 128 | static void 129 | umem_do_release(int as_child) 130 | { 131 | umem_cache_t *cp; 132 | int cleanup_update = 0; 133 | 134 | /* 135 | * Clean up the update state if we are the child process and 136 | * another thread was processing updates. 137 | */ 138 | if (as_child) { 139 | if (umem_update_thr != thr_self()) { 140 | umem_update_thr = 0; 141 | cleanup_update = 1; 142 | } 143 | if (umem_st_update_thr != thr_self()) { 144 | umem_st_update_thr = 0; 145 | cleanup_update = 1; 146 | } 147 | } 148 | 149 | if (cleanup_update) { 150 | umem_reaping = UMEM_REAP_DONE; 151 | 152 | for (cp = umem_null_cache.cache_next; cp != &umem_null_cache; 153 | cp = cp->cache_next) { 154 | if (cp->cache_uflags & UMU_NOTIFY) 155 | cp->cache_uflags &= ~UMU_NOTIFY; 156 | 157 | /* 158 | * If the cache is active, we just re-add it to 159 | * the update list. This will re-do any active 160 | * updates on the cache, but that won't break 161 | * anything. 162 | * 163 | * The worst that can happen is a cache has 164 | * its magazines rescaled twice, instead of once. 165 | */ 166 | if (cp->cache_uflags & UMU_ACTIVE) { 167 | umem_cache_t *cnext, *cprev; 168 | 169 | ASSERT(cp->cache_unext == NULL && 170 | cp->cache_uprev == NULL); 171 | 172 | cp->cache_uflags &= ~UMU_ACTIVE; 173 | cp->cache_unext = cnext = &umem_null_cache; 174 | cp->cache_uprev = cprev = 175 | umem_null_cache.cache_uprev; 176 | cnext->cache_uprev = cp; 177 | cprev->cache_unext = cp; 178 | } 179 | } 180 | } 181 | 182 | umem_release_log_header(umem_slab_log); 183 | umem_release_log_header(umem_failure_log); 184 | umem_release_log_header(umem_content_log); 185 | umem_release_log_header(umem_transaction_log); 186 | 187 | for (cp = umem_null_cache.cache_next; cp != &umem_null_cache; 188 | cp = cp->cache_next) 189 | umem_release_cache(cp); 190 | umem_release_cache(&umem_null_cache); 191 | 192 | (void) mutex_unlock(&umem_flags_lock); 193 | (void) mutex_unlock(&umem_update_lock); 194 | (void) mutex_unlock(&umem_cache_lock); 195 | 196 | vmem_sbrk_release(); 197 | vmem_release(); 198 | 199 | (void) mutex_unlock(&umem_init_lock); 200 | } 201 | 202 | static void 203 | umem_release(void) 204 | { 205 | umem_do_release(0); 206 | } 207 | 208 | static void 209 | umem_release_child(void) 210 | { 211 | umem_do_release(1); 212 | } 213 | #endif 214 | 215 | void 216 | umem_forkhandler_init(void) 217 | { 218 | #ifndef _WIN32 219 | /* 220 | * There is no way to unregister these atfork functions, 221 | * but we don't need to. The dynamic linker and libc take 222 | * care of unregistering them if/when the library is unloaded. 223 | */ 224 | (void) pthread_atfork(umem_lockup, umem_release, umem_release_child); 225 | #endif 226 | } 227 | -------------------------------------------------------------------------------- /umem_impl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 | * 25 | * Portions Copyright 2012 Joyent, Inc. All rights reserved. 26 | * Use is subject to license terms. 27 | * 28 | * Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved. 29 | */ 30 | 31 | #ifndef _UMEM_IMPL_H 32 | #define _UMEM_IMPL_H 33 | 34 | /* #pragma ident "@(#)umem_impl.h 1.6 05/06/08 SMI" */ 35 | 36 | #include 37 | 38 | #ifdef HAVE_SYS_SYSMACROS_H 39 | #include 40 | #endif 41 | 42 | #if HAVE_SYS_TIME_H 43 | #include 44 | #endif 45 | 46 | #include 47 | #ifdef HAVE_THREAD_H 48 | # include 49 | #else 50 | # include "sol_compat.h" 51 | #endif 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | /* 58 | * umem memory allocator: implementation-private data structures 59 | */ 60 | 61 | /* 62 | * Internal flags for umem_cache_create 63 | */ 64 | #define UMC_QCACHE 0x00100000 65 | #define UMC_INTERNAL 0x80000000 66 | 67 | /* 68 | * Cache flags 69 | */ 70 | #define UMF_AUDIT 0x00000001 /* transaction auditing */ 71 | #define UMF_DEADBEEF 0x00000002 /* deadbeef checking */ 72 | #define UMF_REDZONE 0x00000004 /* redzone checking */ 73 | #define UMF_CONTENTS 0x00000008 /* freed-buffer content logging */ 74 | #define UMF_CHECKSIGNAL 0x00000010 /* abort when in signal context */ 75 | #define UMF_NOMAGAZINE 0x00000020 /* disable per-cpu magazines */ 76 | #define UMF_FIREWALL 0x00000040 /* put all bufs before unmapped pages */ 77 | #define UMF_LITE 0x00000100 /* lightweight debugging */ 78 | 79 | #define UMF_HASH 0x00000200 /* cache has hash table */ 80 | #define UMF_RANDOMIZE 0x00000400 /* randomize other umem_flags */ 81 | 82 | #define UMF_BUFTAG (UMF_DEADBEEF | UMF_REDZONE) 83 | #define UMF_TOUCH (UMF_BUFTAG | UMF_LITE | UMF_CONTENTS) 84 | #define UMF_RANDOM (UMF_TOUCH | UMF_AUDIT | UMF_NOMAGAZINE) 85 | #define UMF_DEBUG (UMF_RANDOM | UMF_FIREWALL) 86 | 87 | #define UMEM_STACK_DEPTH umem_stack_depth 88 | 89 | #define UMEM_FREE_PATTERN 0xdeadbeefdeadbeefULL 90 | #define UMEM_UNINITIALIZED_PATTERN 0xbaddcafebaddcafeULL 91 | #define UMEM_REDZONE_PATTERN 0xfeedfacefeedfaceULL 92 | #define UMEM_REDZONE_BYTE 0xbb 93 | 94 | #define UMEM_FATAL_FLAGS (UMEM_NOFAIL) 95 | #define UMEM_SLEEP_FLAGS (0) 96 | 97 | /* 98 | * Redzone size encodings for umem_alloc() / umem_free(). We encode the 99 | * allocation size, rather than storing it directly, so that umem_free() 100 | * can distinguish frees of the wrong size from redzone violations. 101 | */ 102 | #define UMEM_SIZE_ENCODE(x) (251 * (x) + 1) 103 | #define UMEM_SIZE_DECODE(x) ((x) / 251) 104 | #define UMEM_SIZE_VALID(x) ((x) % 251 == 1) 105 | 106 | /* 107 | * The bufctl (buffer control) structure keeps some minimal information 108 | * about each buffer: its address, its slab, and its current linkage, 109 | * which is either on the slab's freelist (if the buffer is free), or 110 | * on the cache's buf-to-bufctl hash table (if the buffer is allocated). 111 | * In the case of non-hashed, or "raw", caches (the common case), only 112 | * the freelist linkage is necessary: the buffer address is at a fixed 113 | * offset from the bufctl address, and the slab is at the end of the page. 114 | * 115 | * NOTE: bc_next must be the first field; raw buffers have linkage only. 116 | */ 117 | typedef struct umem_bufctl { 118 | struct umem_bufctl *bc_next; /* next bufctl struct */ 119 | void *bc_addr; /* address of buffer */ 120 | struct umem_slab *bc_slab; /* controlling slab */ 121 | } umem_bufctl_t; 122 | 123 | /* 124 | * The UMF_AUDIT version of the bufctl structure. The beginning of this 125 | * structure must be identical to the normal bufctl structure so that 126 | * pointers are interchangeable. 127 | */ 128 | 129 | #define UMEM_BUFCTL_AUDIT_SIZE_DEPTH(frames) \ 130 | ((size_t)(&((umem_bufctl_audit_t *)0)->bc_stack[frames])) 131 | 132 | /* 133 | * umem_bufctl_audits must be allocated from a UMC_NOHASH cache, so we 134 | * require that 2 of them, plus 2 buftags, plus a umem_slab_t, all fit on 135 | * a single page. 136 | * 137 | * For ILP32, this is about 1000 frames. 138 | * For LP64, this is about 490 frames. 139 | */ 140 | 141 | #define UMEM_BUFCTL_AUDIT_ALIGN 32 142 | 143 | #define UMEM_BUFCTL_AUDIT_MAX_SIZE \ 144 | (P2ALIGN((PAGESIZE - sizeof (umem_slab_t))/2 - \ 145 | sizeof (umem_buftag_t), UMEM_BUFCTL_AUDIT_ALIGN)) 146 | 147 | #define UMEM_MAX_STACK_DEPTH \ 148 | ((UMEM_BUFCTL_AUDIT_MAX_SIZE - \ 149 | UMEM_BUFCTL_AUDIT_SIZE_DEPTH(0)) / sizeof (uintptr_t)) 150 | 151 | typedef struct umem_bufctl_audit { 152 | struct umem_bufctl *bc_next; /* next bufctl struct */ 153 | void *bc_addr; /* address of buffer */ 154 | struct umem_slab *bc_slab; /* controlling slab */ 155 | umem_cache_t *bc_cache; /* controlling cache */ 156 | hrtime_t bc_timestamp; /* transaction time */ 157 | thread_t bc_thread; /* thread doing transaction */ 158 | struct umem_bufctl *bc_lastlog; /* last log entry */ 159 | void *bc_contents; /* contents at last free */ 160 | int bc_depth; /* stack depth */ 161 | uintptr_t bc_stack[1]; /* pc stack */ 162 | } umem_bufctl_audit_t; 163 | 164 | #define UMEM_LOCAL_BUFCTL_AUDIT(bcpp) \ 165 | *(bcpp) = (umem_bufctl_audit_t *) \ 166 | alloca(UMEM_BUFCTL_AUDIT_SIZE) 167 | 168 | #define UMEM_BUFCTL_AUDIT_SIZE \ 169 | UMEM_BUFCTL_AUDIT_SIZE_DEPTH(UMEM_STACK_DEPTH) 170 | 171 | /* 172 | * A umem_buftag structure is appended to each buffer whenever any of the 173 | * UMF_BUFTAG flags (UMF_DEADBEEF, UMF_REDZONE, UMF_VERIFY) are set. 174 | */ 175 | typedef struct umem_buftag { 176 | uint64_t bt_redzone; /* 64-bit redzone pattern */ 177 | umem_bufctl_t *bt_bufctl; /* bufctl */ 178 | intptr_t bt_bxstat; /* bufctl ^ (alloc/free) */ 179 | } umem_buftag_t; 180 | 181 | #define UMEM_BUFTAG(cp, buf) \ 182 | ((umem_buftag_t *)((char *)(buf) + (cp)->cache_buftag)) 183 | 184 | #define UMEM_BUFCTL(cp, buf) \ 185 | ((umem_bufctl_t *)((char *)(buf) + (cp)->cache_bufctl)) 186 | 187 | #define UMEM_BUF(cp, bcp) \ 188 | ((void *)((char *)(bcp) - (cp)->cache_bufctl)) 189 | 190 | #define UMEM_SLAB(cp, buf) \ 191 | ((umem_slab_t *)P2END((uintptr_t)(buf), (cp)->cache_slabsize) - 1) 192 | 193 | #define UMEM_CPU_CACHE(cp, cpu) \ 194 | (umem_cpu_cache_t *)((char *)cp + cpu->cpu_cache_offset) 195 | 196 | #define UMEM_MAGAZINE_VALID(cp, mp) \ 197 | (((umem_slab_t *)P2END((uintptr_t)(mp), PAGESIZE) - 1)->slab_cache == \ 198 | (cp)->cache_magtype->mt_cache) 199 | 200 | #define UMEM_SLAB_MEMBER(sp, buf) \ 201 | ((size_t)(buf) - (size_t)(sp)->slab_base < \ 202 | (sp)->slab_cache->cache_slabsize) 203 | 204 | #define UMEM_BUFTAG_ALLOC 0xa110c8edUL 205 | #define UMEM_BUFTAG_FREE 0xf4eef4eeUL 206 | 207 | typedef struct umem_slab { 208 | struct umem_cache *slab_cache; /* controlling cache */ 209 | void *slab_base; /* base of allocated memory */ 210 | struct umem_slab *slab_next; /* next slab on freelist */ 211 | struct umem_slab *slab_prev; /* prev slab on freelist */ 212 | struct umem_bufctl *slab_head; /* first free buffer */ 213 | long slab_refcnt; /* outstanding allocations */ 214 | long slab_chunks; /* chunks (bufs) in this slab */ 215 | } umem_slab_t; 216 | 217 | #define UMEM_HASH_INITIAL 64 218 | 219 | #define UMEM_HASH(cp, buf) \ 220 | ((cp)->cache_hash_table + \ 221 | (((uintptr_t)(buf) >> (cp)->cache_hash_shift) & (cp)->cache_hash_mask)) 222 | 223 | typedef struct umem_magazine { 224 | void *mag_next; 225 | void *mag_round[1]; /* one or more rounds */ 226 | } umem_magazine_t; 227 | 228 | /* 229 | * The magazine types for fast per-cpu allocation 230 | */ 231 | typedef struct umem_magtype { 232 | int mt_magsize; /* magazine size (number of rounds) */ 233 | int mt_align; /* magazine alignment */ 234 | size_t mt_minbuf; /* all smaller buffers qualify */ 235 | size_t mt_maxbuf; /* no larger buffers qualify */ 236 | umem_cache_t *mt_cache; /* magazine cache */ 237 | } umem_magtype_t; 238 | 239 | #if (defined(__PTHREAD_MUTEX_SIZE__) && __PTHREAD_MUTEX_SIZE__ >= 24) || defined(UMEM_PTHREAD_MUTEX_TOO_BIG) 240 | #define UMEM_CPU_CACHE_SIZE 128 /* must be power of 2 */ 241 | #else 242 | #define UMEM_CPU_CACHE_SIZE 64 /* must be power of 2 */ 243 | #endif 244 | #define UMEM_CPU_PAD (UMEM_CPU_CACHE_SIZE - sizeof (mutex_t) - \ 245 | 2 * sizeof (uint_t) - 2 * sizeof (void *) - 4 * sizeof (int)) 246 | #define UMEM_CACHE_SIZE(ncpus) \ 247 | ((size_t)(&((umem_cache_t *)0)->cache_cpu[ncpus])) 248 | 249 | typedef struct umem_cpu_cache { 250 | mutex_t cc_lock; /* protects this cpu's local cache */ 251 | uint_t cc_alloc; /* allocations from this cpu */ 252 | uint_t cc_free; /* frees to this cpu */ 253 | umem_magazine_t *cc_loaded; /* the currently loaded magazine */ 254 | umem_magazine_t *cc_ploaded; /* the previously loaded magazine */ 255 | int cc_rounds; /* number of objects in loaded mag */ 256 | int cc_prounds; /* number of objects in previous mag */ 257 | int cc_magsize; /* number of rounds in a full mag */ 258 | int cc_flags; /* CPU-local copy of cache_flags */ 259 | #if (!defined(_LP64) || defined(UMEM_PTHREAD_MUTEX_TOO_BIG)) && !defined(_WIN32) 260 | /* on win32, UMEM_CPU_PAD evaluates to zero, and the MS compiler 261 | * won't allow static initialization of arrays containing structures 262 | * that contain zero size arrays */ 263 | char cc_pad[UMEM_CPU_PAD]; /* for nice alignment (32-bit) */ 264 | #endif 265 | } umem_cpu_cache_t; 266 | 267 | /* 268 | * The magazine lists used in the depot. 269 | */ 270 | typedef struct umem_maglist { 271 | umem_magazine_t *ml_list; /* magazine list */ 272 | long ml_total; /* number of magazines */ 273 | long ml_min; /* min since last update */ 274 | long ml_reaplimit; /* max reapable magazines */ 275 | uint64_t ml_alloc; /* allocations from this list */ 276 | } umem_maglist_t; 277 | 278 | #define UMEM_CACHE_NAMELEN 31 279 | 280 | struct umem_cache { 281 | /* 282 | * Statistics 283 | */ 284 | uint64_t cache_slab_create; /* slab creates */ 285 | uint64_t cache_slab_destroy; /* slab destroys */ 286 | uint64_t cache_slab_alloc; /* slab layer allocations */ 287 | uint64_t cache_slab_free; /* slab layer frees */ 288 | uint64_t cache_alloc_fail; /* total failed allocations */ 289 | uint64_t cache_buftotal; /* total buffers */ 290 | uint64_t cache_bufmax; /* max buffers ever */ 291 | uint64_t cache_rescale; /* # of hash table rescales */ 292 | uint64_t cache_lookup_depth; /* hash lookup depth */ 293 | uint64_t cache_depot_contention; /* mutex contention count */ 294 | uint64_t cache_depot_contention_prev; /* previous snapshot */ 295 | 296 | /* 297 | * Cache properties 298 | */ 299 | char cache_name[UMEM_CACHE_NAMELEN + 1]; 300 | size_t cache_bufsize; /* object size */ 301 | size_t cache_align; /* object alignment */ 302 | umem_constructor_t *cache_constructor; 303 | umem_destructor_t *cache_destructor; 304 | umem_reclaim_t *cache_reclaim; 305 | void *cache_private; /* opaque arg to callbacks */ 306 | vmem_t *cache_arena; /* vmem source for slabs */ 307 | int cache_cflags; /* cache creation flags */ 308 | int cache_flags; /* various cache state info */ 309 | int cache_uflags; /* UMU_* flags */ 310 | uint32_t cache_mtbf; /* induced alloc failure rate */ 311 | umem_cache_t *cache_next; /* forward cache linkage */ 312 | umem_cache_t *cache_prev; /* backward cache linkage */ 313 | umem_cache_t *cache_unext; /* next in update list */ 314 | umem_cache_t *cache_uprev; /* prev in update list */ 315 | uint32_t cache_cpu_mask; /* mask for cpu offset */ 316 | 317 | /* 318 | * Slab layer 319 | */ 320 | mutex_t cache_lock; /* protects slab layer */ 321 | size_t cache_chunksize; /* buf + alignment [+ debug] */ 322 | size_t cache_slabsize; /* size of a slab */ 323 | size_t cache_bufctl; /* buf-to-bufctl distance */ 324 | size_t cache_buftag; /* buf-to-buftag distance */ 325 | size_t cache_verify; /* bytes to verify */ 326 | size_t cache_contents; /* bytes of saved content */ 327 | size_t cache_color; /* next slab color */ 328 | size_t cache_mincolor; /* maximum slab color */ 329 | size_t cache_maxcolor; /* maximum slab color */ 330 | size_t cache_hash_shift; /* get to interesting bits */ 331 | size_t cache_hash_mask; /* hash table mask */ 332 | umem_slab_t *cache_freelist; /* slab free list */ 333 | umem_slab_t cache_nullslab; /* end of freelist marker */ 334 | umem_cache_t *cache_bufctl_cache; /* source of bufctls */ 335 | umem_bufctl_t **cache_hash_table; /* hash table base */ 336 | /* 337 | * Depot layer 338 | */ 339 | mutex_t cache_depot_lock; /* protects depot */ 340 | umem_magtype_t *cache_magtype; /* magazine type */ 341 | umem_maglist_t cache_full; /* full magazines */ 342 | umem_maglist_t cache_empty; /* empty magazines */ 343 | 344 | /* 345 | * Per-CPU layer 346 | */ 347 | umem_cpu_cache_t cache_cpu[1]; /* cache_cpu_mask + 1 entries */ 348 | }; 349 | 350 | typedef struct umem_cpu_log_header { 351 | mutex_t clh_lock; 352 | char *clh_current; 353 | size_t clh_avail; 354 | int clh_chunk; 355 | int clh_hits; 356 | char clh_pad[UMEM_CPU_CACHE_SIZE - 357 | sizeof (mutex_t) - sizeof (char *) - 358 | sizeof (size_t) - 2 * sizeof (int)]; 359 | } umem_cpu_log_header_t; 360 | 361 | typedef struct umem_log_header { 362 | mutex_t lh_lock; 363 | char *lh_base; 364 | int *lh_free; 365 | size_t lh_chunksize; 366 | int lh_nchunks; 367 | int lh_head; 368 | int lh_tail; 369 | int lh_hits; 370 | umem_cpu_log_header_t lh_cpu[1]; /* actually umem_max_ncpus */ 371 | } umem_log_header_t; 372 | 373 | typedef struct umem_cpu { 374 | uint32_t cpu_cache_offset; 375 | uint32_t cpu_number; 376 | } umem_cpu_t; 377 | 378 | #define UMEM_MAXBUF 131072 379 | 380 | #define UMEM_ALIGN 8 /* min guaranteed alignment */ 381 | #define UMEM_ALIGN_SHIFT 3 /* log2(UMEM_ALIGN) */ 382 | #define UMEM_VOID_FRACTION 8 /* never waste more than 1/8 of slab */ 383 | 384 | /* 385 | * For 64 bits, buffers >= 16 bytes must be 16-byte aligned 386 | */ 387 | #ifdef _LP64 388 | #define UMEM_SECOND_ALIGN 16 389 | #else 390 | #define UMEM_SECOND_ALIGN UMEM_ALIGN 391 | #endif 392 | 393 | #define MALLOC_MAGIC 0x3a10c000 /* 8-byte tag */ 394 | #define MEMALIGN_MAGIC 0x3e3a1000 395 | 396 | #ifdef _LP64 397 | #define MALLOC_SECOND_MAGIC 0x16ba7000 /* 8-byte tag, 16-aligned */ 398 | #define MALLOC_OVERSIZE_MAGIC 0x06e47000 /* 16-byte tag, _LP64 */ 399 | #endif 400 | 401 | #define UMEM_MALLOC_ENCODE(type, sz) (uint32_t)((type) - (sz)) 402 | #define UMEM_MALLOC_DECODE(stat, sz) (uint32_t)((stat) + (sz)) 403 | #define UMEM_FREE_PATTERN_32 (uint32_t)(UMEM_FREE_PATTERN) 404 | 405 | #define UMU_MAGAZINE_RESIZE 0x00000001 406 | #define UMU_HASH_RESCALE 0x00000002 407 | #define UMU_REAP 0x00000004 408 | #define UMU_NOTIFY 0x08000000 409 | #define UMU_ACTIVE 0x80000000 410 | 411 | #define UMEM_READY_INIT_FAILED -1 412 | #define UMEM_READY_STARTUP 1 413 | #define UMEM_READY_INITING 2 414 | #define UMEM_READY 3 415 | 416 | #ifdef UMEM_STANDALONE 417 | extern void umem_startup(caddr_t, size_t, size_t, caddr_t, caddr_t); 418 | extern int umem_add(caddr_t, size_t); 419 | #endif 420 | 421 | #ifdef __cplusplus 422 | } 423 | #endif 424 | 425 | #endif /* _UMEM_IMPL_H */ 426 | -------------------------------------------------------------------------------- /umem_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "umem.h" 6 | 7 | #define UMEM_STANDALONE 1 8 | #include "umem_impl.h" 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | char *foo; 13 | 14 | umem_startup(NULL, 0, 0, NULL, NULL); 15 | 16 | foo = umem_alloc(32, UMEM_DEFAULT); 17 | 18 | strcpy(foo, "hello there"); 19 | 20 | printf("Hello %s\n", foo); 21 | 22 | umem_free(foo, 32); 23 | 24 | return EXIT_SUCCESS; 25 | } 26 | -------------------------------------------------------------------------------- /umem_test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "umem.h" 5 | 6 | static const char *TESTSTRINGS[] = { 7 | "fred", 8 | "fredfredfred", 9 | "thisisabitlongerthantheotherstrings", 10 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890", 11 | }; 12 | 13 | #define N_TESTSTRINGS (sizeof(TESTSTRINGS) / sizeof(TESTSTRINGS[0])) 14 | #define N_TESTS 1000 15 | 16 | int 17 | main (int argc, char *argv[]) 18 | { 19 | char *testcases[N_TESTSTRINGS][N_TESTS + 1]; 20 | size_t len[N_TESTSTRINGS]; 21 | int i, j; 22 | 23 | memset(testcases, 0, sizeof(testcases)); 24 | 25 | umem_startup(NULL, 0, 0, NULL, NULL); 26 | 27 | for (i = 0; i < N_TESTSTRINGS; ++i) 28 | { 29 | len[i] = strlen(TESTSTRINGS[i]) + 1; 30 | } 31 | 32 | puts("Allocating..."); 33 | 34 | for (j = 0; j < N_TESTS; ++j) 35 | { 36 | for (i = 0; i < N_TESTSTRINGS; ++i) 37 | { 38 | testcases[i][j] = umem_alloc(len[i], UMEM_DEFAULT); 39 | strcpy(testcases[i][j], TESTSTRINGS[i]); 40 | } 41 | } 42 | 43 | puts("Deallocating..."); 44 | 45 | for (j = 0; j < N_TESTS; ++j) 46 | { 47 | for (i = N_TESTSTRINGS - 1; i >= 0; --i) 48 | { 49 | umem_free(testcases[i][j], len[i]); 50 | } 51 | 52 | if ((j % 25) == 0) 53 | { 54 | puts("Reaping..."); 55 | umem_reap(); 56 | } 57 | } 58 | 59 | puts("Done"); 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /umem_test3.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) 7 | #include 8 | #endif 9 | 10 | static void minfo(void) 11 | { 12 | #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) 13 | struct mallinfo mi; 14 | mi = mallinfo(); 15 | printf(" fordblks = %d\n", mi.fordblks); 16 | malloc_stats(); 17 | printf("\n"); 18 | #endif 19 | } 20 | 21 | int 22 | main (void) 23 | { 24 | char *p; 25 | 26 | minfo(); 27 | p = malloc(10); 28 | free(p); 29 | minfo(); 30 | 31 | return EXIT_SUCCESS; 32 | } 33 | 34 | /* vim:ts=2:sw=2:et: 35 | */ 36 | -------------------------------------------------------------------------------- /umem_test4: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Check that LD_PRELOAD'ing libumem works. This is how it can be used 4 | # to replace malloc for any program. 5 | # 6 | 7 | FILE=Makefile.am 8 | TMPLOC=`mktemp -d /tmp/umem_test4.XXXXXX` 9 | trap 'rm -rf $TMPLOC' 1 2 15 10 | 11 | LD_PRELOAD=.libs/libumem.so /usr/bin/ldd /bin/ls >$TMPLOC/log 2>&1 12 | 13 | # Check we got the expected result 14 | ret=0 15 | grep -E '(symbol lookup error|undefined symbol)' $TMPLOC/log >/dev/null 2>&1 16 | if [ "$?" = "0" ]; then 17 | # Matched = failed to load up libumem 18 | ret=1 19 | fi 20 | 21 | rm -rf $TMPLOC 22 | 23 | exit $ret 24 | -------------------------------------------------------------------------------- /umem_update_thread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * 8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 | * or http://www.opensolaris.org/os/licensing. 10 | * See the License for the specific language governing permissions 11 | * and limitations under the License. 12 | * 13 | * When distributing Covered Code, include this CDDL HEADER in each 14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 | * If applicable, add the following below this CDDL HEADER, with the 16 | * fields enclosed by brackets "[]" replaced with your own identifying 17 | * information: Portions Copyright [yyyy] [name of copyright owner] 18 | * 19 | * CDDL HEADER END 20 | */ 21 | 22 | /* 23 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | * 26 | * Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved. 27 | */ 28 | 29 | /* #pragma ident "@(#)umem_update_thread.c 1.2 05/06/08 SMI" */ 30 | 31 | #include "config.h" 32 | #include "umem_base.h" 33 | #include "vmem_base.h" 34 | 35 | #include 36 | 37 | struct umem_suspend_signal_object { 38 | /* locked by creating thread; unlocked when umem_update_thread 39 | * can proceed */ 40 | pthread_mutex_t mtx; 41 | /* lock associated with the condition variable */ 42 | pthread_mutex_t cmtx; 43 | /* condition variable is signalled by umem_update_thread when 44 | * it has obtained the mtx; it is then safe for the creating 45 | * thread to clean up its stack (on which this object resides) */ 46 | pthread_cond_t cond; 47 | int flag; 48 | }; 49 | 50 | /*ARGSUSED*/ 51 | static THR_RETURN 52 | THR_API umem_update_thread(void *arg) 53 | { 54 | struct timeval now; 55 | int in_update = 0; 56 | struct umem_suspend_signal_object *obj = arg; 57 | 58 | pthread_mutex_lock(&obj->mtx); 59 | obj->flag = 1; 60 | pthread_cond_signal(&obj->cond); 61 | obj = NULL; 62 | 63 | (void) mutex_lock(&umem_update_lock); 64 | 65 | ASSERT(umem_update_thr == thr_self()); 66 | ASSERT(umem_st_update_thr == 0); 67 | 68 | for (;;) { 69 | umem_process_updates(); 70 | 71 | if (in_update) { 72 | in_update = 0; 73 | /* 74 | * we wait until now to set the next update time 75 | * so that the updates are self-throttling 76 | */ 77 | (void) gettimeofday(&umem_update_next, NULL); 78 | umem_update_next.tv_sec += umem_reap_interval; 79 | } 80 | 81 | switch (umem_reaping) { 82 | case UMEM_REAP_DONE: 83 | case UMEM_REAP_ADDING: 84 | break; 85 | 86 | case UMEM_REAP_ACTIVE: 87 | umem_reap_next = gethrtime() + 88 | (hrtime_t)umem_reap_interval * NANOSEC; 89 | umem_reaping = UMEM_REAP_DONE; 90 | break; 91 | 92 | default: 93 | ASSERT(umem_reaping == UMEM_REAP_DONE || 94 | umem_reaping == UMEM_REAP_ADDING || 95 | umem_reaping == UMEM_REAP_ACTIVE); 96 | break; 97 | } 98 | 99 | (void) gettimeofday(&now, NULL); 100 | if (now.tv_sec > umem_update_next.tv_sec || 101 | (now.tv_sec == umem_update_next.tv_sec && 102 | now.tv_usec >= umem_update_next.tv_usec)) { 103 | /* 104 | * Time to run an update 105 | */ 106 | (void) mutex_unlock(&umem_update_lock); 107 | 108 | vmem_update(NULL); 109 | /* 110 | * umem_cache_update can use umem_add_update to 111 | * request further work. The update is not complete 112 | * until all such work is finished. 113 | */ 114 | umem_cache_applyall(umem_cache_update); 115 | 116 | (void) mutex_lock(&umem_update_lock); 117 | in_update = 1; 118 | continue; /* start processing immediately */ 119 | } 120 | 121 | /* 122 | * if there is no work to do, we wait until it is time for 123 | * next update, or someone wakes us. 124 | */ 125 | if (umem_null_cache.cache_unext == &umem_null_cache) { 126 | int cancel_state; 127 | timespec_t abs_time; 128 | abs_time.tv_sec = umem_update_next.tv_sec; 129 | abs_time.tv_nsec = umem_update_next.tv_usec * 1000; 130 | 131 | (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 132 | &cancel_state); 133 | (void) cond_timedwait(&umem_update_cv, 134 | &umem_update_lock, &abs_time); 135 | (void) pthread_setcancelstate(cancel_state, NULL); 136 | } 137 | } 138 | /* LINTED no return statement */ 139 | } 140 | 141 | int 142 | umem_create_update_thread(void) 143 | { 144 | #ifndef _WIN32 145 | sigset_t sigmask, oldmask; 146 | #endif 147 | pthread_t newthread; 148 | pthread_attr_t attr; 149 | struct umem_suspend_signal_object obj; 150 | int cancel_state; 151 | 152 | ASSERT(MUTEX_HELD(&umem_update_lock)); 153 | ASSERT(umem_update_thr == 0); 154 | 155 | #ifndef _WIN32 156 | /* 157 | * The update thread handles no signals 158 | */ 159 | (void) sigfillset(&sigmask); 160 | (void) pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); 161 | #endif 162 | /* 163 | * drop the umem_update_lock; we cannot hold locks acquired in 164 | * pre-fork handler while calling thr_create or thr_continue(). 165 | */ 166 | 167 | (void) mutex_unlock(&umem_update_lock); 168 | 169 | pthread_attr_init(&attr); 170 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 171 | 172 | pthread_mutex_init(&obj.mtx, NULL); 173 | pthread_mutex_init(&obj.cmtx, NULL); 174 | pthread_cond_init(&obj.cond, NULL); 175 | obj.flag = 0; 176 | pthread_mutex_lock(&obj.mtx); 177 | 178 | if (pthread_create(&newthread, &attr, umem_update_thread, &obj) == 0) { 179 | #ifndef _WIN32 180 | (void) pthread_sigmask(SIG_SETMASK, &oldmask, NULL); 181 | #endif 182 | (void) mutex_lock(&umem_update_lock); 183 | /* 184 | * due to the locking in umem_reap(), only one thread can 185 | * ever call umem_create_update_thread() at a time. This 186 | * must be the case for this code to work. 187 | */ 188 | 189 | ASSERT(umem_update_thr == 0); 190 | umem_update_thr = newthread; 191 | (void) mutex_unlock(&umem_update_lock); 192 | 193 | /* tell the thread to continue */ 194 | pthread_mutex_unlock(&obj.mtx); 195 | 196 | pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); 197 | /* wait for it to be done with obj */ 198 | pthread_mutex_lock(&obj.cmtx); 199 | do { 200 | if (obj.flag) { 201 | break; 202 | } 203 | ASSERT(pthread_cond_wait(&obj.cond, &obj.cmtx) == 0); 204 | } while (1); 205 | pthread_setcancelstate(cancel_state, NULL); 206 | pthread_mutex_destroy(&obj.mtx); 207 | pthread_mutex_destroy(&obj.cmtx); 208 | pthread_cond_destroy(&obj.cond); 209 | 210 | (void) mutex_lock(&umem_update_lock); 211 | 212 | return (1); 213 | } else { /* thr_create failed */ 214 | (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 215 | (void) mutex_lock(&umem_update_lock); 216 | pthread_mutex_destroy(&obj.mtx); 217 | pthread_mutex_destroy(&obj.cmtx); 218 | pthread_cond_destroy(&obj.cond); 219 | } 220 | return (0); 221 | } 222 | -------------------------------------------------------------------------------- /vmem_base.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * 8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 | * or http://www.opensolaris.org/os/licensing. 10 | * See the License for the specific language governing permissions 11 | * and limitations under the License. 12 | * 13 | * When distributing Covered Code, include this CDDL HEADER in each 14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 | * If applicable, add the following below this CDDL HEADER, with the 16 | * fields enclosed by brackets "[]" replaced with your own identifying 17 | * information: Portions Copyright [yyyy] [name of copyright owner] 18 | * 19 | * CDDL HEADER END 20 | */ 21 | 22 | /* 23 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | * 26 | * Portions Copyright 2012 Joyent, Inc. All rights reserved. 27 | */ 28 | 29 | /* #pragma ident "@(#)vmem_base.c 1.6 05/06/08 SMI" */ 30 | 31 | /* #include "mtlib.h" */ 32 | #include "config.h" 33 | #include "vmem_base.h" 34 | #include "umem_base.h" 35 | 36 | uint_t vmem_backend = 0; 37 | uint_t vmem_allocator = VM_BESTFIT; 38 | 39 | vmem_t * 40 | vmem_heap_arena(vmem_alloc_t **allocp, vmem_free_t **freep) 41 | { 42 | static mutex_t arena_mutex = DEFAULTMUTEX; 43 | 44 | /* 45 | * Allow the init thread through, block others until the init completes 46 | */ 47 | if (umem_ready != UMEM_READY && umem_init_thr != thr_self() && 48 | umem_init() == 0) 49 | return (NULL); 50 | 51 | (void) mutex_lock(&arena_mutex); 52 | if (vmem_heap == NULL) 53 | vmem_heap_init(); 54 | (void) mutex_unlock(&arena_mutex); 55 | 56 | if (allocp != NULL) 57 | *allocp = vmem_heap_alloc; 58 | if (freep != NULL) 59 | *freep = vmem_heap_free; 60 | return (vmem_heap); 61 | } 62 | -------------------------------------------------------------------------------- /vmem_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, (the "License"). 6 | You may not use this file except in compliance with the License. 7 | * 8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 | * or http://www.opensolaris.org/os/licensing. 10 | * See the License for the specific language governing permissions 11 | * and limitations under the License. 12 | * 13 | * When distributing Covered Code, include this CDDL HEADER in each 14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 | * If applicable, add the following below this CDDL HEADER, with the 16 | * fields enclosed by brackets "[]" replaced with your own identifying 17 | * information: Portions Copyright [yyyy] [name of copyright owner] 18 | * 19 | * CDDL HEADER END 20 | */ 21 | /* 22 | * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 | * Use is subject to license terms. 24 | * 25 | * Portions Copyright 2012 Joyent, Inc. All rights reserved. 26 | */ 27 | 28 | #ifndef _VMEM_BASE_H 29 | #define _VMEM_BASE_H 30 | 31 | /* #pragma ident "@(#)vmem_base.h 1.3 05/06/08 SMI" */ 32 | 33 | #include 34 | #include 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | #include "misc.h" 41 | 42 | extern void vmem_startup(void); 43 | extern vmem_t *vmem_init(const char *parent_name, size_t parent_quantum, 44 | vmem_alloc_t *parent_alloc, vmem_free_t *parent_free, 45 | const char *heap_name, 46 | void *heap_start, size_t heap_size, size_t heap_quantum, 47 | vmem_alloc_t *heap_alloc, vmem_free_t *heap_free); 48 | 49 | extern void *_vmem_extend_alloc(vmem_t *vmp, void *vaddr, size_t size, 50 | size_t alloc, int vmflag); 51 | 52 | extern vmem_t *vmem_heap_arena(vmem_alloc_t **, vmem_free_t **); 53 | extern void vmem_heap_init(void); 54 | 55 | extern vmem_t *vmem_sbrk_arena(vmem_alloc_t **, vmem_free_t **); 56 | extern vmem_t *vmem_mmap_arena(vmem_alloc_t **, vmem_free_t **); 57 | extern vmem_t *vmem_stand_arena(vmem_alloc_t **, vmem_free_t **); 58 | 59 | extern void vmem_update(void *); 60 | extern void vmem_reap(void); /* vmem_populate()-safe reap */ 61 | 62 | extern size_t pagesize; 63 | extern size_t vmem_sbrk_pagesize; 64 | extern size_t vmem_sbrk_minalloc; 65 | 66 | extern uint_t vmem_backend; 67 | #define VMEM_BACKEND_SBRK 0x0000001 68 | #define VMEM_BACKEND_MMAP 0x0000002 69 | #define VMEM_BACKEND_STAND 0x0000003 70 | 71 | extern uint_t vmem_allocator; 72 | 73 | extern vmem_t *vmem_heap; 74 | extern vmem_alloc_t *vmem_heap_alloc; 75 | extern vmem_free_t *vmem_heap_free; 76 | 77 | extern void vmem_lockup(void); 78 | extern void vmem_release(void); 79 | 80 | extern void vmem_sbrk_lockup(void); 81 | extern void vmem_sbrk_release(void); 82 | 83 | extern void vmem_no_debug(void); 84 | 85 | #ifdef __cplusplus 86 | } 87 | #endif 88 | 89 | #endif /* _VMEM_BASE_H */ 90 | -------------------------------------------------------------------------------- /vmem_mmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * 8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 | * or http://www.opensolaris.org/os/licensing. 10 | * See the License for the specific language governing permissions 11 | * and limitations under the License. 12 | * 13 | * When distributing Covered Code, include this CDDL HEADER in each 14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 | * If applicable, add the following below this CDDL HEADER, with the 16 | * fields enclosed by brackets "[]" replaced with your own identifying 17 | * information: Portions Copyright [yyyy] [name of copyright owner] 18 | * 19 | * CDDL HEADER END 20 | */ 21 | 22 | /* 23 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | * 26 | * Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved. 27 | */ 28 | 29 | /* #pragma ident "@(#)vmem_mmap.c 1.2 05/06/08 SMI" */ 30 | 31 | #include "config.h" 32 | #include 33 | 34 | #if HAVE_SYS_MMAN_H 35 | #include 36 | #endif 37 | 38 | #ifdef HAVE_SYS_SYSMACROS_H 39 | #include 40 | #endif 41 | 42 | #include 43 | 44 | #include "vmem_base.h" 45 | 46 | #define ALLOC_PROT PROT_READ | PROT_WRITE | PROT_EXEC 47 | #define FREE_PROT PROT_NONE 48 | 49 | #define ALLOC_FLAGS MAP_PRIVATE | MAP_ANON 50 | #define FREE_FLAGS MAP_PRIVATE | MAP_ANON | MAP_NORESERVE 51 | 52 | #ifdef MAP_ALIGN 53 | #define CHUNKSIZE (64*1024) /* 64 kilobytes */ 54 | #else 55 | static size_t CHUNKSIZE; 56 | #endif 57 | 58 | static vmem_t *mmap_heap; 59 | 60 | static void * 61 | vmem_mmap_alloc(vmem_t *src, size_t size, int vmflags) 62 | { 63 | void *ret; 64 | int old_errno = errno; 65 | 66 | ret = vmem_alloc(src, size, vmflags); 67 | #ifndef _WIN32 68 | if (ret != NULL && 69 | mmap(ret, size, ALLOC_PROT, ALLOC_FLAGS | MAP_FIXED, -1, 0) == 70 | MAP_FAILED) { 71 | vmem_free(src, ret, size); 72 | vmem_reap(); 73 | 74 | ASSERT((vmflags & VM_NOSLEEP) == VM_NOSLEEP); 75 | errno = old_errno; 76 | return (NULL); 77 | } 78 | #endif 79 | 80 | errno = old_errno; 81 | return (ret); 82 | } 83 | 84 | static void 85 | vmem_mmap_free(vmem_t *src, void *addr, size_t size) 86 | { 87 | int old_errno = errno; 88 | #ifdef _WIN32 89 | VirtualFree(addr, size, MEM_RELEASE); 90 | #else 91 | (void) mmap(addr, size, FREE_PROT, FREE_FLAGS | MAP_FIXED, -1, 0); 92 | #endif 93 | vmem_free(src, addr, size); 94 | errno = old_errno; 95 | } 96 | 97 | static void * 98 | vmem_mmap_top_alloc(vmem_t *src, size_t size, int vmflags) 99 | { 100 | void *ret; 101 | void *buf; 102 | int old_errno = errno; 103 | 104 | ret = vmem_alloc(src, size, VM_NOSLEEP); 105 | 106 | if (ret) { 107 | errno = old_errno; 108 | return (ret); 109 | } 110 | /* 111 | * Need to grow the heap 112 | */ 113 | #ifdef _WIN32 114 | buf = VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); 115 | if (buf == NULL) buf = MAP_FAILED; 116 | #elif defined(MAP_ALIGN) 117 | buf = mmap((void*)CHUNKSIZE, size, FREE_PROT, FREE_FLAGS | MAP_ALIGN, 118 | -1, 0); 119 | #else 120 | buf = mmap(0, size, FREE_PROT, FREE_FLAGS, -1, 0); 121 | #endif 122 | 123 | if (buf != MAP_FAILED) { 124 | ret = _vmem_extend_alloc(src, buf, size, size, vmflags); 125 | if (ret != NULL) 126 | return (ret); 127 | else { 128 | (void) munmap(buf, size); 129 | errno = old_errno; 130 | return (NULL); 131 | } 132 | } else { 133 | /* 134 | * Growing the heap failed. The allocation above will 135 | * already have called umem_reap(). 136 | */ 137 | ASSERT((vmflags & VM_NOSLEEP) == VM_NOSLEEP); 138 | 139 | errno = old_errno; 140 | return (NULL); 141 | } 142 | } 143 | 144 | vmem_t * 145 | vmem_mmap_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) 146 | { 147 | #ifdef _WIN32 148 | SYSTEM_INFO info; 149 | size_t pagesize; 150 | #else 151 | size_t pagesize = _sysconf(_SC_PAGESIZE); 152 | #endif 153 | 154 | #ifdef _WIN32 155 | GetSystemInfo(&info); 156 | pagesize = info.dwPageSize; 157 | CHUNKSIZE = info.dwAllocationGranularity; 158 | #elif !defined(MAP_ALIGN) 159 | CHUNKSIZE = pagesize; 160 | #endif 161 | 162 | if (mmap_heap == NULL) { 163 | mmap_heap = vmem_init("mmap_top", CHUNKSIZE, 164 | vmem_mmap_top_alloc, vmem_free, 165 | "mmap_heap", NULL, 0, pagesize, 166 | vmem_mmap_alloc, vmem_mmap_free); 167 | } 168 | 169 | if (a_out != NULL) 170 | *a_out = vmem_mmap_alloc; 171 | if (f_out != NULL) 172 | *f_out = vmem_mmap_free; 173 | 174 | return (mmap_heap); 175 | } 176 | -------------------------------------------------------------------------------- /vmem_sbrk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * 8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 | * or http://www.opensolaris.org/os/licensing. 10 | * See the License for the specific language governing permissions 11 | * and limitations under the License. 12 | * 13 | * When distributing Covered Code, include this CDDL HEADER in each 14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 | * If applicable, add the following below this CDDL HEADER, with the 16 | * fields enclosed by brackets "[]" replaced with your own identifying 17 | * information: Portions Copyright [yyyy] [name of copyright owner] 18 | * 19 | * CDDL HEADER END 20 | */ 21 | 22 | /* 23 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | * 26 | * Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved. 27 | */ 28 | 29 | /* #pragma ident "@(#)vmem_sbrk.c 1.4 05/06/08 SMI" */ 30 | 31 | /* 32 | * The structure of the sbrk backend: 33 | * 34 | * +-----------+ 35 | * | sbrk_top | 36 | * +-----------+ 37 | * | (vmem_sbrk_alloc(), vmem_free()) 38 | * | 39 | * +-----------+ 40 | * | sbrk_heap | 41 | * +-----------+ 42 | * | | ... | (vmem_alloc(), vmem_free()) 43 | * 44 | * 45 | * The sbrk_top arena holds all controlled memory. vmem_sbrk_alloc() handles 46 | * allocations from it, including growing the heap when we run low. 47 | * 48 | * Growing the heap is complicated by the fact that we have to extend the 49 | * sbrk_top arena (using _vmem_extend_alloc()), and that can fail. Since 50 | * other threads may be actively allocating, we can't return the memory. 51 | * 52 | * Instead, we put it on a doubly-linked list, sbrk_fails, which we search 53 | * before calling sbrk(). 54 | */ 55 | 56 | #include "config.h" 57 | /* #include "mtlib.h" */ 58 | #include 59 | #include 60 | #ifdef HAVE_SYS_SYSMACROS_H 61 | #include 62 | #endif 63 | #include 64 | #include 65 | 66 | #include "vmem_base.h" 67 | 68 | #include "misc.h" 69 | 70 | size_t vmem_sbrk_pagesize = 0; /* the preferred page size of the heap */ 71 | 72 | #define VMEM_SBRK_MINALLOC (64 * 1024) 73 | size_t vmem_sbrk_minalloc = VMEM_SBRK_MINALLOC; /* minimum allocation */ 74 | 75 | static size_t real_pagesize; 76 | static vmem_t *sbrk_heap; 77 | 78 | typedef struct sbrk_fail { 79 | struct sbrk_fail *sf_next; 80 | struct sbrk_fail *sf_prev; 81 | void *sf_base; /* == the sbrk_fail's address */ 82 | size_t sf_size; /* the size of this buffer */ 83 | } sbrk_fail_t; 84 | 85 | static sbrk_fail_t sbrk_fails = { 86 | &sbrk_fails, 87 | &sbrk_fails, 88 | NULL, 89 | 0 90 | }; 91 | 92 | static mutex_t sbrk_faillock = DEFAULTMUTEX; 93 | static mutex_t sbrk_lock = DEFAULTMUTEX; 94 | 95 | /* 96 | * _sbrk_grow_aligned() aligns the old break to a low_align boundry, 97 | * adds min_size, aligns to a high_align boundry, and calls _brk_unlocked() 98 | * to set the new break. The low_aligned-aligned value is returned, and 99 | * the actual space allocated is returned through actual_size. 100 | * 101 | * Unlike sbrk(2), _sbrk_grow_aligned takes an unsigned size, and does 102 | * not allow shrinking the heap. 103 | */ 104 | static void * 105 | _sbrk_grow_aligned(size_t min_size, size_t low_align, size_t high_align, 106 | size_t *actual_size) 107 | { 108 | uintptr_t old_brk; 109 | uintptr_t ret_brk; 110 | uintptr_t high_brk; 111 | uintptr_t new_brk; 112 | int brk_result; 113 | 114 | #define ALIGNSZ 16 115 | #define BRKALIGN(x) (caddr_t)P2ROUNDUP((uintptr_t)(x), ALIGNSZ) 116 | 117 | if ((low_align & (low_align - 1)) != 0 || 118 | (high_align & (high_align - 1)) != 0) { 119 | errno = EINVAL; 120 | return ((void *)-1); 121 | } 122 | low_align = MAX(low_align, ALIGNSZ); 123 | high_align = MAX(high_align, ALIGNSZ); 124 | 125 | mutex_lock(&sbrk_lock); 126 | 127 | old_brk = (uintptr_t)BRKALIGN(sbrk(0)); 128 | ret_brk = P2ROUNDUP(old_brk, low_align); 129 | high_brk = ret_brk + min_size; 130 | new_brk = P2ROUNDUP(high_brk, high_align); 131 | 132 | /* 133 | * Check for overflow 134 | */ 135 | if (ret_brk < old_brk || high_brk < ret_brk || new_brk < high_brk) { 136 | mutex_unlock(&sbrk_lock); 137 | errno = ENOMEM; 138 | return ((void *)-1); 139 | } 140 | 141 | brk_result = brk((void *)new_brk); 142 | mutex_unlock(&sbrk_lock); 143 | 144 | if (brk_result != 0) 145 | return ((void *)-1); 146 | 147 | if (actual_size != NULL) 148 | *actual_size = (new_brk - ret_brk); 149 | return ((void *)ret_brk); 150 | } 151 | 152 | /* 153 | * Try to extend src with [pos, pos + size). 154 | * 155 | * If it fails, add the block to the sbrk_fails list. 156 | */ 157 | static void * 158 | vmem_sbrk_extend_alloc(vmem_t *src, void *pos, size_t size, size_t alloc, 159 | int vmflags) 160 | { 161 | sbrk_fail_t *fnext, *fprev, *fp; 162 | void *ret; 163 | 164 | ret = _vmem_extend_alloc(src, pos, size, alloc, vmflags); 165 | if (ret != NULL) 166 | return (ret); 167 | 168 | fp = (sbrk_fail_t *)pos; 169 | 170 | ASSERT(sizeof (sbrk_fail_t) <= size); 171 | 172 | fp->sf_base = pos; 173 | fp->sf_size = size; 174 | 175 | (void) mutex_lock(&sbrk_faillock); 176 | fp->sf_next = fnext = &sbrk_fails; 177 | fp->sf_prev = fprev = sbrk_fails.sf_prev; 178 | fnext->sf_prev = fp; 179 | fprev->sf_next = fp; 180 | (void) mutex_unlock(&sbrk_faillock); 181 | 182 | return (NULL); 183 | } 184 | 185 | /* 186 | * Try to add at least size bytes to src, using the sbrk_fails list 187 | */ 188 | static void * 189 | vmem_sbrk_tryfail(vmem_t *src, size_t size, int vmflags) 190 | { 191 | sbrk_fail_t *fp; 192 | 193 | (void) mutex_lock(&sbrk_faillock); 194 | for (fp = sbrk_fails.sf_next; fp != &sbrk_fails; fp = fp->sf_next) { 195 | if (fp->sf_size >= size) { 196 | fp->sf_next->sf_prev = fp->sf_prev; 197 | fp->sf_prev->sf_next = fp->sf_next; 198 | fp->sf_next = fp->sf_prev = NULL; 199 | break; 200 | } 201 | } 202 | (void) mutex_unlock(&sbrk_faillock); 203 | 204 | if (fp != &sbrk_fails) { 205 | ASSERT(fp->sf_base == (void *)fp); 206 | return (vmem_sbrk_extend_alloc(src, fp, fp->sf_size, size, 207 | vmflags)); 208 | } 209 | /* 210 | * nothing of the right size on the freelist 211 | */ 212 | return (NULL); 213 | } 214 | 215 | static void * 216 | vmem_sbrk_alloc(vmem_t *src, size_t size, int vmflags) 217 | { 218 | void *ret; 219 | void *buf; 220 | size_t buf_size; 221 | 222 | int old_errno = errno; 223 | 224 | ret = vmem_alloc(src, size, VM_NOSLEEP); 225 | if (ret != NULL) { 226 | errno = old_errno; 227 | return (ret); 228 | } 229 | 230 | /* 231 | * The allocation failed. We need to grow the heap. 232 | * 233 | * First, try to use any buffers which failed earlier. 234 | */ 235 | if (sbrk_fails.sf_next != &sbrk_fails && 236 | (ret = vmem_sbrk_tryfail(src, size, vmflags)) != NULL) 237 | return (ret); 238 | 239 | buf_size = MAX(size, vmem_sbrk_minalloc); 240 | 241 | /* 242 | * buf_size gets overwritten with the actual allocated size 243 | */ 244 | buf = _sbrk_grow_aligned(buf_size, real_pagesize, vmem_sbrk_pagesize, 245 | &buf_size); 246 | 247 | if (buf != MAP_FAILED) { 248 | ret = vmem_sbrk_extend_alloc(src, buf, buf_size, size, vmflags); 249 | if (ret != NULL) { 250 | errno = old_errno; 251 | return (ret); 252 | } 253 | } 254 | 255 | /* 256 | * Growing the heap failed. The vmem_alloc() above called umem_reap(). 257 | */ 258 | ASSERT((vmflags & VM_NOSLEEP) == VM_NOSLEEP); 259 | 260 | errno = old_errno; 261 | return (NULL); 262 | } 263 | 264 | /* 265 | * fork1() support 266 | */ 267 | void 268 | vmem_sbrk_lockup(void) 269 | { 270 | (void) mutex_lock(&sbrk_faillock); 271 | } 272 | 273 | void 274 | vmem_sbrk_release(void) 275 | { 276 | (void) mutex_unlock(&sbrk_faillock); 277 | } 278 | 279 | vmem_t * 280 | vmem_sbrk_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) 281 | { 282 | if (sbrk_heap == NULL) { 283 | size_t heap_size; 284 | 285 | real_pagesize = sysconf(_SC_PAGESIZE); 286 | 287 | heap_size = vmem_sbrk_pagesize; 288 | 289 | if (issetugid()) { 290 | heap_size = 0; 291 | } else if (heap_size != 0 && !ISP2(heap_size)) { 292 | heap_size = 0; 293 | log_message("ignoring bad pagesize: 0x%p\n", heap_size); 294 | } 295 | if (heap_size <= real_pagesize) { 296 | heap_size = real_pagesize; 297 | } else { 298 | #ifdef MHA_MAPSIZE_BSSBRK 299 | struct memcntl_mha mha; 300 | mha.mha_cmd = MHA_MAPSIZE_BSSBRK; 301 | mha.mha_flags = 0; 302 | mha.mha_pagesize = heap_size; 303 | 304 | if (memcntl(NULL, 0, MC_HAT_ADVISE, (char *)&mha, 0, 0) 305 | == -1) { 306 | log_message("unable to set MAPSIZE_BSSBRK to " 307 | "0x%p\n", heap_size); 308 | heap_size = real_pagesize; 309 | } 310 | #else 311 | heap_size = real_pagesize; 312 | #endif 313 | } 314 | vmem_sbrk_pagesize = heap_size; 315 | 316 | /* validate vmem_sbrk_minalloc */ 317 | if (vmem_sbrk_minalloc < VMEM_SBRK_MINALLOC) 318 | vmem_sbrk_minalloc = VMEM_SBRK_MINALLOC; 319 | vmem_sbrk_minalloc = P2ROUNDUP(vmem_sbrk_minalloc, heap_size); 320 | 321 | sbrk_heap = vmem_init("sbrk_top", real_pagesize, 322 | vmem_sbrk_alloc, vmem_free, 323 | "sbrk_heap", NULL, 0, real_pagesize, 324 | vmem_alloc, vmem_free); 325 | } 326 | 327 | if (a_out != NULL) 328 | *a_out = vmem_alloc; 329 | if (f_out != NULL) 330 | *f_out = vmem_free; 331 | 332 | return (sbrk_heap); 333 | } 334 | -------------------------------------------------------------------------------- /vmem_stand.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | */ 26 | 27 | #pragma ident "@(#)vmem_stand.c 1.4 05/06/08 SMI" 28 | 29 | /* 30 | * Standalone-specific vmem routines 31 | * 32 | * The standalone allocator operates on a pre-existing blob of memory, the 33 | * location and dimensions of which are set using vmem_stand_setsize(). We 34 | * then hand out CHUNKSIZE-sized pieces of this blob, until we run out. 35 | */ 36 | 37 | #define DEF_CHUNKSIZE (64 * 1024) /* 64K */ 38 | 39 | #define DEF_NREGIONS 2 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "vmem_base.h" 49 | #include "misc.h" 50 | 51 | static vmem_t *stand_heap; 52 | 53 | static size_t stand_chunksize; 54 | 55 | typedef struct stand_region { 56 | caddr_t sr_base; 57 | caddr_t sr_curtop; 58 | size_t sr_left; 59 | } stand_region_t; 60 | 61 | static stand_region_t stand_regions[DEF_NREGIONS]; 62 | static int stand_nregions; 63 | 64 | extern void membar_producer(void); 65 | 66 | void 67 | vmem_stand_init(void) 68 | { 69 | stand_chunksize = MAX(DEF_CHUNKSIZE, pagesize); 70 | 71 | stand_nregions = 0; 72 | } 73 | 74 | int 75 | vmem_stand_add(caddr_t base, size_t len) 76 | { 77 | stand_region_t *sr = &stand_regions[stand_nregions]; 78 | 79 | ASSERT(pagesize != 0); 80 | 81 | if (stand_nregions == DEF_NREGIONS) { 82 | errno = ENOSPC; 83 | return (-1); /* we don't have room -- throw it back */ 84 | } 85 | 86 | /* 87 | * We guarantee that only one call to `vmem_stand_add' will be 88 | * active at a time, but we can't ensure that the allocator won't be 89 | * in use while this function is being called. As such, we have to 90 | * ensure that sr is populated and visible to other processors before 91 | * allowing the allocator to access the new region. 92 | */ 93 | sr->sr_base = base; 94 | sr->sr_curtop = (caddr_t)P2ROUNDUP((ulong_t)base, stand_chunksize); 95 | sr->sr_left = P2ALIGN(len - (size_t)(sr->sr_curtop - sr->sr_base), 96 | stand_chunksize); 97 | membar_producer(); 98 | 99 | stand_nregions++; 100 | 101 | return (0); 102 | } 103 | 104 | static void * 105 | stand_parent_alloc(vmem_t *src, size_t size, int vmflags) 106 | { 107 | int old_errno = errno; 108 | stand_region_t *sr; 109 | size_t chksize; 110 | void *ret; 111 | int i; 112 | 113 | if ((ret = vmem_alloc(src, size, VM_NOSLEEP)) != NULL) { 114 | errno = old_errno; 115 | return (ret); 116 | } 117 | 118 | /* We need to allocate another chunk */ 119 | chksize = roundup(size, stand_chunksize); 120 | 121 | for (sr = stand_regions, i = 0; i < stand_nregions; i++, sr++) { 122 | if (sr->sr_left >= chksize) 123 | break; 124 | } 125 | 126 | if (i == stand_nregions) { 127 | /* 128 | * We don't have enough in any of our regions to satisfy the 129 | * request. 130 | */ 131 | errno = old_errno; 132 | return (NULL); 133 | } 134 | 135 | if ((ret = _vmem_extend_alloc(src, sr->sr_curtop, chksize, size, 136 | vmflags)) == NULL) { 137 | errno = old_errno; 138 | return (NULL); 139 | } 140 | 141 | bzero(sr->sr_curtop, chksize); 142 | 143 | sr->sr_curtop += chksize; 144 | sr->sr_left -= chksize; 145 | 146 | return (ret); 147 | } 148 | 149 | vmem_t * 150 | vmem_stand_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) 151 | { 152 | ASSERT(stand_nregions == 1); 153 | 154 | stand_heap = vmem_init("stand_parent", stand_chunksize, 155 | stand_parent_alloc, vmem_free, 156 | "stand_heap", NULL, 0, pagesize, vmem_alloc, vmem_free); 157 | 158 | if (a_out != NULL) 159 | *a_out = vmem_alloc; 160 | if (f_out != NULL) 161 | *f_out = vmem_free; 162 | 163 | return (stand_heap); 164 | } 165 | -------------------------------------------------------------------------------- /vmem_stand.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CDDL HEADER START 3 | * 4 | * The contents of this file are subject to the terms of the 5 | * Common Development and Distribution License, Version 1.0 only 6 | * (the "License"). You may not use this file except in compliance 7 | * with the License. 8 | * 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 | * or http://www.opensolaris.org/os/licensing. 11 | * See the License for the specific language governing permissions 12 | * and limitations under the License. 13 | * 14 | * When distributing Covered Code, include this CDDL HEADER in each 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 | * If applicable, add the following below this CDDL HEADER, with the 17 | * fields enclosed by brackets "[]" replaced with your own identifying 18 | * information: Portions Copyright [yyyy] [name of copyright owner] 19 | * 20 | * CDDL HEADER END 21 | */ 22 | /* 23 | * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 | * Use is subject to license terms. 25 | */ 26 | 27 | #ifndef _VMEM_STAND_H 28 | #define _VMEM_STAND_H 29 | 30 | /* #pragma ident "@(#)vmem_stand.h 1.3 05/06/08 SMI" */ 31 | 32 | /* 33 | * additional functions defined by the standalone backend 34 | */ 35 | 36 | #include 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | extern void vmem_stand_init(void); 43 | extern int vmem_stand_add(caddr_t, size_t); 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | 49 | #endif /* _VMEM_STAND_H */ 50 | --------------------------------------------------------------------------------